Selaa lähdekoodia

初始化视频教程后台管理系统

yusm 2 kuukautta sitten
vanhempi
commit
e5ab6eb2f4
87 muutettua tiedostoa jossa 6472 lisäystä ja 0 poistoa
  1. BIN
      fhKeeper/formulahousekeeper/course-manager/0AAE1300
  2. BIN
      fhKeeper/formulahousekeeper/course-manager/ED622300
  3. 1 0
      fhKeeper/formulahousekeeper/course-manager/build_package.bat
  4. BIN
      fhKeeper/formulahousekeeper/course-manager/chi_sim.traineddata
  5. 61 0
      fhKeeper/formulahousekeeper/course-manager/courseManager.log
  6. BIN
      fhKeeper/formulahousekeeper/course-manager/opencv/opencv-420.jar
  7. BIN
      fhKeeper/formulahousekeeper/course-manager/opencv/x64/opencv_java420.dll
  8. BIN
      fhKeeper/formulahousekeeper/course-manager/opencv/x86/opencv_java420.dll
  9. 142 0
      fhKeeper/formulahousekeeper/course-manager/pom.xml
  10. 21 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/PlatformStartApplication.java
  11. 79 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/aop/AopLogConfiguration.java
  12. 35 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/BeanConfig.java
  13. 14 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/Config.java
  14. 81 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/RefererInterceptor.java
  15. 23 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/RefererProperties.java
  16. 20 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/RestTemplateConfig.java
  17. 22 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/SchedulerConfig.java
  18. 28 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/WebConfig.java
  19. 38 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/constant/Constant.java
  20. 27 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/constant/MybatisPlusPageConfig.java
  21. 44 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/constant/Parameter.java
  22. 126 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CommonUploadController.java
  23. 21 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CompanyController.java
  24. 92 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CourseInfoController.java
  25. 21 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/UserController.java
  26. 175 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/Company.java
  27. 106 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/CourseInfo.java
  28. 204 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/Task.java
  29. 293 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/User.java
  30. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/CompanyMapper.java
  31. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/CourseInfoMapper.java
  32. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/UserMapper.java
  33. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/CompanyService.java
  34. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/CourseInfoService.java
  35. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/UserService.java
  36. 20 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/CompanyServiceImpl.java
  37. 20 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/CourseInfoServiceImpl.java
  38. 20 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/UserServiceImpl.java
  39. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/chi_sim.traineddata
  40. 1 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/configs/api_config
  41. 1 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/configs/digits
  42. 1 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/configs/hocr
  43. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/eng.traineddata
  44. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/osd.traineddata
  45. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/pdf.ttf
  46. 793 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/pdf.ttx
  47. 96 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/AuthService.java
  48. 73 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/CRC16Util.java
  49. 211 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/CodeGenerator.java
  50. 35 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/CodeUtil.java
  51. 204 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/ColorUtil.java
  52. 69 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/DateTimeUtil.java
  53. 347 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/DingCallbackCrypto.java
  54. 41 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/DocumentTypeUtil.java
  55. 167 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/ExcelUtil.java
  56. 72 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/FileCopyToFolderUtil.java
  57. 141 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/FileUtil.java
  58. 28 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/GsonUtils.java
  59. 292 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/HttpKit.java
  60. 43 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/HttpRespMsg.java
  61. 77 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/HttpUtil.java
  62. 159 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/ListUtil.java
  63. 134 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/MD5Util.java
  64. 18 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/MathUtil.java
  65. 61 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/PageUtil.java
  66. 74 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/Sha1Util.java
  67. 124 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/SnowFlake.java
  68. 54 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/UploadFileToFileNameUtil.java
  69. 7 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/UserNotFoundException.java
  70. 194 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/WorkDayCalculateUtils.java
  71. 59 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/AesException.java
  72. 26 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/ByteGroup.java
  73. 68 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/PKCS7Encoder.java
  74. 61 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/SHA1.java
  75. 290 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/WXBizMsgCrypt.java
  76. 106 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/XMLParse.java
  77. 99 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/application-dev.yml
  78. 100 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/application-prod.yml
  79. 105 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/application.yml
  80. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/lib/jodconverter-core-3.0.jar
  81. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/lib/taobao-sdk-java-auto_1479188381469-20210623.jar
  82. 92 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/logback.xml
  83. 36 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/CompanyMapper.xml
  84. 25 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/CourseInfoMapper.xml
  85. 58 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/UserMapper.xml
  86. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/新模板.docx
  87. BIN
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/模板.docx

BIN
fhKeeper/formulahousekeeper/course-manager/0AAE1300


BIN
fhKeeper/formulahousekeeper/course-manager/ED622300


+ 1 - 0
fhKeeper/formulahousekeeper/course-manager/build_package.bat

@@ -0,0 +1 @@
+mvn package

BIN
fhKeeper/formulahousekeeper/course-manager/chi_sim.traineddata


+ 61 - 0
fhKeeper/formulahousekeeper/course-manager/courseManager.log

@@ -0,0 +1,61 @@
+2025-04-11 13:43:18.659 [main] INFO  c.m.p.PlatformStartApplication - [logStarting,50] - Starting PlatformStartApplication on Yurk with PID 26932 (D:\WorkSpeace\manHourHousekeeper\fhKeeper\formulahousekeeper\course-manager\target\classes started by 123 in D:\WorkSpeace\manHourHousekeeper\fhKeeper\formulahousekeeper\course-manager)
+2025-04-11 13:43:18.661 [main] INFO  c.m.p.PlatformStartApplication - [logStartupProfileInfo,648] - No active profile set, falling back to default profiles: default
+2025-04-11 13:43:19.020 [main] WARN  o.m.s.m.ClassPathMapperScanner - [warn,44] - No MyBatis mapper was found in '[com.management.platform.mapper]' package. Please check your configuration.
+2025-04-11 13:43:19.022 [main] WARN  o.m.s.m.ClassPathMapperScanner - [warn,44] - No MyBatis mapper was found in '[com.management.platform.mapper]' package. Please check your configuration.
+2025-04-11 13:43:19.104 [main] WARN  o.m.s.m.ClassPathMapperScanner - [warn,44] - No MyBatis mapper was found in '[com.management.platform]' package. Please check your configuration.
+2025-04-11 13:43:19.108 [main] DEBUG o.m.s.b.a.MybatisAutoConfiguration - [registerBeanDefinitions,199] - Searching for mappers annotated with @Mapper
+2025-04-11 13:43:19.109 [main] DEBUG o.m.s.b.a.MybatisAutoConfiguration - [lambda$registerBeanDefinitions$0,203] - Using auto-configuration base package 'com.management.platform'
+2025-04-11 13:43:19.126 [main] WARN  o.m.s.m.ClassPathMapperScanner - [warn,44] - No MyBatis mapper was found in '[com.management.platform]' package. Please check your configuration.
+2025-04-11 13:43:19.485 [main] ERROR o.a.c.c.AprLifecycleListener - [log,173] - An incompatible version [1.1.32] of the APR based Apache Tomcat Native library is installed, while Tomcat requires version [1.2.14]
+2025-04-11 13:43:19.599 [main] ERROR o.a.c.c.AprLifecycleListener - [log,173] - An incompatible version [1.1.32] of the APR based Apache Tomcat Native library is installed, while Tomcat requires version [1.2.14]
+2025-04-11 13:43:19.661 [main] ERROR o.a.c.c.AprLifecycleListener - [log,173] - An incompatible version [1.1.32] of the APR based Apache Tomcat Native library is installed, while Tomcat requires version [1.2.14]
+2025-04-11 13:43:19.662 [main] INFO  o.a.c.h.Http11NioProtocol - [log,173] - Initializing ProtocolHandler ["http-nio-10030"]
+2025-04-11 13:43:19.666 [main] INFO  o.a.c.c.StandardService - [log,173] - Starting service [Tomcat]
+2025-04-11 13:43:19.666 [main] INFO  o.a.c.c.StandardEngine - [log,173] - Starting Servlet engine: [Apache Tomcat/9.0.29]
+2025-04-11 13:43:19.765 [main] INFO  o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring embedded WebApplicationContext
+2025-04-11 13:43:19.766 [main] DEBUG o.s.w.c.ContextLoader - [prepareWebApplicationContext,278] - Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
+2025-04-11 13:43:19.766 [main] INFO  o.s.w.c.ContextLoader - [prepareWebApplicationContext,284] - Root WebApplicationContext: initialization completed in 1080 ms
+2025-04-11 13:43:20.144 [main] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping - [detectHandlerMethods,279] - 
+	o.s.b.a.w.s.e.BasicErrorController:
+	{ /error}: error(HttpServletRequest)
+	{ /error, produces [text/html]}: errorHtml(HttpServletRequest,HttpServletResponse)
+2025-04-11 13:43:20.147 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - [handlerMethodsInitialized,351] - 2 mappings in 'requestMappingHandlerMapping'
+2025-04-11 13:43:20.160 [main] DEBUG o.s.w.s.h.BeanNameUrlHandlerMapping - [detectHandlers,86] - Detected 0 mappings in 'beanNameHandlerMapping'
+2025-04-11 13:43:20.187 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerAdapter - [initControllerAdviceCache,620] - ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
+2025-04-11 13:43:20.206 [main] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - [initExceptionHandlerAdviceCache,303] - ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice
+2025-04-11 13:43:20.306 [main] WARN  c.z.h.HikariConfig - [validateNumerics,973] - HikariPool-1 - idleTimeout is close to or more than maxLifetime, disabling it.
+2025-04-11 13:43:20.306 [main] INFO  c.z.h.HikariDataSource - [getConnection,110] - HikariPool-1 - Starting...
+2025-04-11 13:43:20.710 [main] INFO  c.z.h.HikariDataSource - [getConnection,123] - HikariPool-1 - Start completed.
+2025-04-11 13:43:20.723 [main] DEBUG o.m.s.b.a.MybatisAutoConfiguration - [afterPropertiesSet,242] - No org.mybatis.spring.mapper.MapperFactoryBean found.
+2025-04-11 13:43:21.025 [main] TRACE o.s.w.s.r.ResourceUrlProvider - [detectResourceHandlers,155] - No resource handling mappings found
+2025-04-11 13:43:21.027 [main] INFO  o.a.c.h.Http11NioProtocol - [log,173] - Starting ProtocolHandler ["http-nio-10030"]
+2025-04-11 13:43:21.085 [main] ERROR o.a.c.c.AprLifecycleListener - [log,173] - An incompatible version [1.1.32] of the APR based Apache Tomcat Native library is installed, while Tomcat requires version [1.2.14]
+2025-04-11 13:43:21.096 [main] ERROR o.a.c.c.AprLifecycleListener - [log,173] - An incompatible version [1.1.32] of the APR based Apache Tomcat Native library is installed, while Tomcat requires version [1.2.14]
+2025-04-11 13:43:21.102 [main] ERROR o.a.c.c.AprLifecycleListener - [log,173] - An incompatible version [1.1.32] of the APR based Apache Tomcat Native library is installed, while Tomcat requires version [1.2.14]
+2025-04-11 13:43:21.102 [main] INFO  o.a.c.h.Http11NioProtocol - [log,173] - Initializing ProtocolHandler ["http-nio-10019"]
+2025-04-11 13:43:21.102 [main] INFO  o.a.c.c.StandardService - [log,173] - Starting service [Tomcat]
+2025-04-11 13:43:21.103 [main] INFO  o.a.c.c.StandardEngine - [log,173] - Starting Servlet engine: [Apache Tomcat/9.0.29]
+2025-04-11 13:43:21.133 [main] INFO  o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring embedded WebApplicationContext
+2025-04-11 13:43:21.133 [main] DEBUG o.s.w.c.ContextLoader - [prepareWebApplicationContext,278] - Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
+2025-04-11 13:43:21.133 [main] INFO  o.s.w.c.ContextLoader - [prepareWebApplicationContext,284] - Root WebApplicationContext: initialization completed in 89 ms
+2025-04-11 13:43:21.152 [main] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping - [detectHandlerMethods,279] - 
+	o.s.b.a.a.w.s.ManagementErrorEndpoint:
+	{ /error}: invoke(ServletWebRequest)
+2025-04-11 13:43:21.153 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - [handlerMethodsInitialized,351] - 1 mappings in 'requestMappingHandlerMapping'
+2025-04-11 13:43:21.153 [main] DEBUG o.s.w.s.h.BeanNameUrlHandlerMapping - [detectHandlers,86] - Detected 0 mappings in 'beanNameHandlerMapping'
+2025-04-11 13:43:21.161 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerAdapter - [initControllerAdviceCache,620] - ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
+2025-04-11 13:43:21.164 [main] TRACE o.s.w.s.r.ResourceUrlProvider - [detectResourceHandlers,155] - No resource handling mappings found
+2025-04-11 13:43:21.164 [main] TRACE o.s.w.s.r.ResourceUrlProvider - [detectResourceHandlers,155] - No resource handling mappings found
+2025-04-11 13:43:21.164 [main] INFO  o.a.c.h.Http11NioProtocol - [log,173] - Starting ProtocolHandler ["http-nio-10019"]
+2025-04-11 13:43:21.168 [main] INFO  c.m.p.PlatformStartApplication - [logStarted,59] - Started PlatformStartApplication in 2.727 seconds (JVM running for 3.419)
+2025-04-11 13:43:21.753 [RMI TCP Connection(1)-192.168.2.38] INFO  o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2025-04-11 13:43:21.753 [RMI TCP Connection(1)-192.168.2.38] INFO  o.s.w.s.DispatcherServlet - [initServletBean,525] - Initializing Servlet 'dispatcherServlet'
+2025-04-11 13:43:21.753 [RMI TCP Connection(1)-192.168.2.38] TRACE o.s.w.s.DispatcherServlet - [initMultipartResolver,523] - Detected org.springframework.web.multipart.support.StandardServletMultipartResolver@489bc8fd
+2025-04-11 13:43:21.754 [RMI TCP Connection(1)-192.168.2.38] TRACE o.s.w.s.DispatcherServlet - [initLocaleResolver,557] - No LocaleResolver 'localeResolver': using default [AcceptHeaderLocaleResolver]
+2025-04-11 13:43:21.755 [RMI TCP Connection(1)-192.168.2.38] TRACE o.s.w.s.DispatcherServlet - [initThemeResolver,582] - No ThemeResolver 'themeResolver': using default [FixedThemeResolver]
+2025-04-11 13:43:21.757 [RMI TCP Connection(1)-192.168.2.38] TRACE o.s.w.s.DispatcherServlet - [initRequestToViewNameTranslator,725] - No RequestToViewNameTranslator 'viewNameTranslator': using default [DefaultRequestToViewNameTranslator]
+2025-04-11 13:43:21.759 [RMI TCP Connection(1)-192.168.2.38] TRACE o.s.w.s.DispatcherServlet - [initFlashMapManager,789] - No FlashMapManager 'flashMapManager': using default [SessionFlashMapManager]
+2025-04-11 13:43:21.759 [RMI TCP Connection(1)-192.168.2.38] DEBUG o.s.w.s.DispatcherServlet - [initServletBean,542] - enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
+2025-04-11 13:43:21.759 [RMI TCP Connection(1)-192.168.2.38] INFO  o.s.w.s.DispatcherServlet - [initServletBean,547] - Completed initialization in 6 ms
+2025-04-11 14:08:54.240 [Thread-9] INFO  c.z.h.HikariDataSource - [close,350] - HikariPool-1 - Shutdown initiated...
+2025-04-11 14:08:54.241 [Thread-9] INFO  c.z.h.HikariDataSource - [close,352] - HikariPool-1 - Shutdown completed.

BIN
fhKeeper/formulahousekeeper/course-manager/opencv/opencv-420.jar


BIN
fhKeeper/formulahousekeeper/course-manager/opencv/x64/opencv_java420.dll


BIN
fhKeeper/formulahousekeeper/course-manager/opencv/x86/opencv_java420.dll


+ 142 - 0
fhKeeper/formulahousekeeper/course-manager/pom.xml

@@ -0,0 +1,142 @@
+<?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>formulahousekeeper</artifactId>
+        <groupId>com.hssx.parent</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.hssx.parent</groupId>
+    <artifactId>course-manager</artifactId>
+    <version>1.0</version>
+
+    <dependencies>
+        <!-- 基本Spring Boot依赖 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+         <dependency>
+             <groupId>org.apache.velocity</groupId>
+             <artifactId>velocity-engine-core</artifactId>
+            <version>2.0</version>
+             <optional>true</optional>
+        </dependency>
+
+        <!-- 添加HttpClient依赖 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.13</version> <!-- 或使用Spring Boot管理的版本 -->
+        </dependency>
+        <!-- mybatis-plus代码生成器依赖 -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <!-- 数据库相关 -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 工具类 -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+
+        <!-- 文件处理 -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
+
+        <!-- 配置处理器 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- AOP支持 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+        </dependency>
+
+        <!-- 文件操作 -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.11.0</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+    <!--配置阿里云仓库-->
+    <repositories>
+        <repository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+</project>

+ 21 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/PlatformStartApplication.java

@@ -0,0 +1,21 @@
+package com.management.platform;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+/**
+ * Author: 屈跃庭
+ * Date : 2019 - 12 - 31 9:23
+ * Description:<描述>
+ * Version: 1.0
+ */
+@SpringBootApplication
+@MapperScan("com.management.platform.mapper")
+@EnableTransactionManagement //开启事务支持
+public class PlatformStartApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(PlatformStartApplication.class, args);
+    }
+
+}

+ 79 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/aop/AopLogConfiguration.java

@@ -0,0 +1,79 @@
+package com.management.platform.aop;
+
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 08 - 30 13:59
+ * Description:<描述> 开启aop配置
+ * Version: 1.0
+ */
+@Slf4j
+@Aspect
+@Configuration
+public class AopLogConfiguration {
+    //切入点表达式
+    @Pointcut("execution(public * com.management.*.service.*.*(..)) || execution(public * com.management.*.controller.*.*(..))")
+    public void logPointcut(){
+
+    }
+
+    /**
+     * 前置通知
+     */
+    @Before("logPointcut()")
+    public void  methodBefore(JoinPoint joinPoint){
+        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
+        if (requestAttributes == null) return;
+        HttpServletRequest request = requestAttributes.getRequest();
+        if(request.getRequestURL().toString().contains("/imageProcessing")){
+            return;
+        }
+        //打印请求内容
+
+        String methodName = joinPoint.getSignature().getName();
+        if (!"loginAdmin".equals(methodName)) {
+            log.info("请求方法:"+request.getRequestURL().toString()+", 参数: "+Arrays.toString(joinPoint.getArgs()));
+        }
+    }
+
+    /**
+     * 后置通知
+     */
+    @AfterReturning(returning = "o",pointcut = "logPointcut()")
+    public void methodAfterReturning(Object o){
+        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
+        if (requestAttributes == null) return;
+        HttpServletRequest request = requestAttributes.getRequest();
+        if(request.getRequestURL().toString().contains("/imageProcessing")){
+        }
+    }
+
+    /**
+     * 异常通知
+     */
+    @AfterThrowing(pointcut = "logPointcut()",throwing = "e")
+    public void logThrowing(JoinPoint joinPoint,Throwable e){
+        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
+        if (requestAttributes == null) {
+            return ;
+        }
+        HttpServletRequest request = requestAttributes.getRequest();
+        if(request.getRequestURL().toString().contains("/imageProcessing")){
+            return;
+        }
+        log.info("***************抛出异常***************");
+        log.info("请求类方法:"+joinPoint.getSignature().getName());
+        log.info("异常内容:"+e);
+        log.info("***************抛出异常***************");
+    }
+
+}

+ 35 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/BeanConfig.java

@@ -0,0 +1,35 @@
+package com.management.platform.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+@EnableAsync
+public class BeanConfig {
+
+    @Bean
+    public TaskExecutor taskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        // 设置核心线程数
+        executor.setCorePoolSize(5);
+        // 设置最大线程数
+        executor.setMaxPoolSize(10);
+        // 设置队列容量
+        executor.setQueueCapacity(20);
+        // 设置线程活跃时间(秒)
+        executor.setKeepAliveSeconds(60);
+        // 设置默认线程名称
+        executor.setThreadNamePrefix("worktime-");
+        // 设置拒绝策略
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        // 等待所有任务结束后再关闭线程池
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        System.out.println("初始化TaskExecutor");
+        return executor;
+    }
+}

+ 14 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/Config.java

@@ -0,0 +1,14 @@
+package com.management.platform.config;
+
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class Config {
+  @Bean
+  public RestTemplate restTemplate(RestTemplateBuilder builder){
+    return builder.build();
+  }
+}

+ 81 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/RefererInterceptor.java

@@ -0,0 +1,81 @@
+package com.management.platform.config;
+
+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.util.AntPathMatcher;
+import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.MalformedURLException;
+
+public class RefererInterceptor extends HandlerInterceptorAdapter {
+    static final Logger LOGGER = LoggerFactory.getLogger(RefererInterceptor.class);
+
+    // URL匹配器
+    private final AntPathMatcher matcher = new AntPathMatcher();
+    @Resource
+    private RefererProperties properties;
+
+    @Value(value = "${excludeUrls}")
+    private String excludeUrls;
+
+    @Override
+    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
+        String referer = req.getHeader("referer");
+        String host = req.getServerName();
+        //对外开放的回调url排除在外
+        String reqUrl = req.getRequestURI();
+//        System.out.println(reqUrl);
+        if (!StringUtils.isEmpty(excludeUrls)) {
+            String[] split = excludeUrls.split(",");
+            boolean isPass = false;
+            for (String pattern: split) {
+                if (matcher.match(pattern, reqUrl)) {
+                    isPass = true;
+                    break;
+                }
+            }
+            if (isPass) {
+                return true;
+            }
+        }
+        // 只验证POST请求
+        if ("POST".equals(req.getMethod())) {
+            if (referer == null) {
+                System.out.println("===referer为Null, 返回404,拦截==");
+                // 状态置为404
+                resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return false;
+            }
+            java.net.URL url = null;
+            try {
+                url = new java.net.URL(referer);
+            } catch (MalformedURLException e) {
+                // URL解析异常,也置为404
+                resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return false;
+            }
+            LOGGER.info("host="+host+", refer host="+url.getHost());
+            boolean isSame = host.equals(url.getHost());
+            // 首先判断请求域名和referer域名是否相同
+            if (!isSame) {
+                // 如果不等,判断是否在白名单中
+                if (properties.getRefererDomain() != null) {
+                    for (String s : properties.getRefererDomain()) {
+                        if (s.equals(url.getHost())) {
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+}
+

+ 23 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/RefererProperties.java

@@ -0,0 +1,23 @@
+package com.management.platform.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+@ConfigurationProperties(prefix = "referer")
+public class RefererProperties {
+    // 白名单域名
+    private List<String> refererDomain;
+    //setter,getter方法
+
+
+    public List<String> getRefererDomain() {
+        return refererDomain;
+    }
+
+    public void setRefererDomain(List<String> refererDomain) {
+        this.refererDomain = refererDomain;
+    }
+}

+ 20 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/RestTemplateConfig.java

@@ -0,0 +1,20 @@
+package com.management.platform.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class RestTemplateConfig {
+    @Bean
+    public RestTemplate getRestTemplate() {
+        //配置HTTP超时时间
+        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
+        httpRequestFactory.setConnectionRequestTimeout(60000);
+        httpRequestFactory.setConnectTimeout(60000);
+        httpRequestFactory.setReadTimeout(60000);
+        return new RestTemplate(httpRequestFactory);
+    }
+}
+

+ 22 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/SchedulerConfig.java

@@ -0,0 +1,22 @@
+package com.management.platform.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+
+@Configuration
+@EnableScheduling
+public class SchedulerConfig {
+    @Bean
+    public TaskScheduler taskScheduler() {
+        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
+        //线程池大小
+        scheduler.setPoolSize(10);
+        //线程名字前缀
+        scheduler.setThreadNamePrefix("spring-task-thread");
+        return scheduler;
+    }
+}
+

+ 28 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/config/WebConfig.java

@@ -0,0 +1,28 @@
+package com.management.platform.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@EnableWebMvc
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+    @Bean
+    public RefererInterceptor refererInterceptor() {
+        return new RefererInterceptor();
+    }
+
+    /**
+     * 注册拦截器
+     */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        //referer拦截
+        registry.addInterceptor(refererInterceptor());
+    }
+
+
+}

+ 38 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/constant/Constant.java

@@ -0,0 +1,38 @@
+package com.management.platform.constant;
+
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Author: 屈跃庭
+ * Date : 2019 - 07 - 24 16:00
+ * Description:<描述>常量配置类
+ * Version: 1.0
+ */
+@Component
+public class Constant {
+//    public static final String API_KEY = "gtImOYhgcFBzwuT29tB7tM0Z";//百度文字识别apiKey
+//    public static final String SECRET_KEY = "RipT5kfF3Zqp7S2vTXPlNcMiYcA76jfq";//百度文字识别secretKey
+    public static final String API_KEY = "UgceK95dGkVbQKicVDU9D6s2";//百度文字识别apiKey
+    public static final String SECRET_KEY = "fGCbfC9CR1v8Pf1u6kG4fM9KEXHgitAA";//百度文字识别secretKey
+    public static final Integer UN_HANDLE = 0;//定时任务未处理的状态码
+    public static final String PIC_PATH_PREFIX = "";//定时任务未处理的状态码
+    public static final String COMMON_SOFTWARE_KEYWORDS = "keyWords";//常用软件关键字
+    public static final String[] keyWords = new String[]{"IntelliJ IDEA","Eclipse",
+            "Postman","MyEclipse","Visual Studio Code",
+            "Navicat","Pycharm","Android Studio",
+            "WebStorm","SQLyog","PhpStorm",
+            "JetBrains Datagrip","JetBrains Rider",
+            "Android Studio","Photoshop","Illustrator",
+            "Adobe After Effects","Axure RP","Sketch"};//定时任务未处理的状态码
+//    public static final String ACCESS_KEY = "280d6f0e4a774117905ba789a9f0b978";//百度图像识别accessKey
+//    public static final String SECRET_KEY = "43b460e124eb474c8cdb7441dc30d66d";//百度图像识别secretKey
+    //角色定义
+    public static final String[] ROLE_NAMES = {"普通员工","超级管理员", "系统管理员", "无","财务管理员","项目管理员","公司领导","项目经理"};
+
+    public static final String ROLE_SUPER_MANAGER = "超级管理员";
+
+    public static String[] DEFAULT_BASE_COST_ITEMS = {"人工成本","一般费用","外包费用","其他"};
+}

+ 27 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/constant/MybatisPlusPageConfig.java

@@ -0,0 +1,27 @@
+package com.management.platform.constant;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+//Spring boot方式
+@EnableTransactionManagement
+@Configuration
+@MapperScan("com.management.platform.mapper")
+public class MybatisPlusPageConfig {
+
+    @Bean
+    public PaginationInterceptor paginationInterceptor() {
+        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
+        // paginationInterceptor.setOverflow(false);
+        // 设置最大单页限制数量,默认 500 条,-1 不受限制
+        // paginationInterceptor.setLimit(500);
+        // 开启 count 的 join 优化,只针对部分 left join
+        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
+        return paginationInterceptor;
+    }
+}

+ 44 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/constant/Parameter.java

@@ -0,0 +1,44 @@
+package com.management.platform.constant;
+
+/**
+ * Author: 屈跃庭
+ * Date : 2020 - 01 - 06 11:19
+ * Description:<描述> 参数枚举
+ * Version: 1.0
+ */
+public enum Parameter {
+    //accessToken
+    ACCESS_TOKEN("accessToken", "accessToken"),
+    //accessToken 的有效时间 单位:s
+    EXPIRES_IN("expiresIn", "expiresIn");
+
+    private String code;
+    private String name;
+
+    Parameter(String code, String name) {
+        this.code = code;
+//        this.name = name();
+        this.name = name;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+//    public static void main(String[] args) {
+//        System.out.println(Parameter.API_KEY.getName());
+//    }
+
+}

+ 126 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CommonUploadController.java

@@ -0,0 +1,126 @@
+package com.management.platform.controller;
+
+import com.management.platform.util.HttpRespMsg;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.UUID;
+
+@RestController
+@RequestMapping("/common")
+@Slf4j
+public class CommonUploadController {
+
+    
+    @Value(value = "${upload.path}")
+    private String path;
+
+    @Value(value = "${upload.tempUpdatePath}")
+    private String tempUpdatePath;
+
+    @Value(value = "${logging.path}")
+    private String logPath;
+
+    @RequestMapping(value="uploadFile")
+    public HttpRespMsg uploadFile(MultipartFile multipartFile) {
+        HttpRespMsg msg = new HttpRespMsg();
+
+        //然后处理文件
+        String fileName = multipartFile.getOriginalFilename();
+        String[] split = fileName.split("\\.");
+        String serverName = UUID.randomUUID().toString().replaceAll("-", "") + "."+split[split.length-1];
+
+        //检查目录
+        File dir = new File(path);
+        if (!dir.exists()) {
+            dir.mkdir();
+        }
+        File file = new File(dir, serverName);
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+        try {
+            inputStream = multipartFile.getInputStream();
+            outputStream = new FileOutputStream(file);
+            byte[] buffer = new byte[4096];
+            int temp = 0;
+            while ((temp = inputStream.read(buffer, 0, 4096)) != -1) {
+                outputStream.write(buffer, 0, temp);
+            }
+            inputStream.close();
+            outputStream.close();
+            msg.data = serverName;
+        } catch (Exception exception) {
+            exception.printStackTrace();
+            log.error(exception.getMessage());
+        }
+        return msg;
+    }
+
+    @RequestMapping(value="uploadUpdateFile")
+    public HttpRespMsg uploadUpdateFile(MultipartFile multipartFile) {
+        HttpRespMsg msg = new HttpRespMsg();
+
+        //然后处理文件
+        String fileName = multipartFile.getOriginalFilename();
+        String[] split = fileName.split("\\.");
+        String serverName = UUID.randomUUID().toString().replaceAll("-", "") + "."+split[split.length-1];
+
+        //检查目录
+        File dir = new File(tempUpdatePath);
+        if (!dir.exists()) {
+            dir.mkdir();
+        }
+        File file = new File(dir, serverName);
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+        try {
+            inputStream = multipartFile.getInputStream();
+            outputStream = new FileOutputStream(file);
+            byte[] buffer = new byte[4096];
+            int temp = 0;
+            while ((temp = inputStream.read(buffer, 0, 4096)) != -1) {
+                outputStream.write(buffer, 0, temp);
+            }
+            inputStream.close();
+            outputStream.close();
+            msg.data = serverName;
+        } catch (Exception exception) {
+            exception.printStackTrace();
+            log.error(exception.getMessage());
+        }
+
+        return msg;
+    }
+
+    @RequestMapping("/downLoadLog")
+    public ResponseEntity<byte[]> downLoadLog() throws IOException {
+        // 🧐🧐🧐读取本地的文件
+        // 获取File对象
+        System.out.println("读取目录=="+logPath);
+        log.info("读取目录=={}"+logPath);
+        String fileName = "workshop.out";
+        File readFile=new File(logPath+fileName);
+        // 🐳🐳🐳设置响应头,把文件名称放入响应头中,确保文件可下载
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Content-Disposition", "attachment;filename=" + URLEncoder.encode(readFile.getName(), "UTF-8"));
+        // 🐳🐳🐳设置内容类型为「application/octet-stream」二进制流
+        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+
+        Path path = Paths.get(readFile.toURI());
+        // 获取File对象的字节码文件
+        byte[] bytes = Files.readAllBytes(path);
+        //return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
+        return ResponseEntity.ok().headers(headers).body(bytes);
+    }
+}

+ 21 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CompanyController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@RestController
+@RequestMapping("/company")
+public class CompanyController {
+
+}
+

+ 92 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CourseInfoController.java

@@ -0,0 +1,92 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.CourseInfo;
+import com.management.platform.entity.User;
+import com.management.platform.service.CourseInfoService;
+import com.management.platform.service.UserService;
+import com.management.platform.util.HttpRespMsg;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.UUID;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@RestController
+@RequestMapping("/course-info")
+@Slf4j
+public class CourseInfoController {
+
+    @Resource
+    private UserService userService;
+
+    @Resource
+    private CourseInfoService courseInfoService ;
+
+
+    /**
+     * 保存或新增
+     * @param courseInfo
+     * @param request
+     * @return
+     */
+    @RequestMapping(value="/saveOrUpdate")
+    public HttpRespMsg saveOrUpdate(CourseInfo courseInfo, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("Token");
+        User user = userService.getById(token);
+        //新增
+        if (courseInfo.getId() == null) {
+            courseInfo.setCompanyId(user.getCompanyId());
+            courseInfoService.save(courseInfo);
+        }
+        //修改
+        else {
+            courseInfoService.updateById(courseInfo);
+        }
+        return msg;
+    }
+
+    /**
+     * 获取详情
+     * @param id
+     * @return
+     */
+    @RequestMapping(value="/getDetail")
+    public HttpRespMsg getDetail(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        CourseInfo courseInfo = courseInfoService.getById(id);
+        msg.setData(courseInfo);
+        return msg;
+    }
+
+    @RequestMapping(value="/deleteCourse")
+    public HttpRespMsg deleteCourse(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        CourseInfo courseInfo = courseInfoService.getById(id);
+        if (courseInfo == null || courseInfo.getCourseStatus() == 1) {
+            msg.setError("课程已上架不能删除或课程不存在");
+            return msg;
+        }
+        courseInfoService.removeById(id);
+        return msg;
+    }
+}
+

+ 21 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/UserController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@RestController
+@RequestMapping("/user")
+public class UserController {
+
+}
+

+ 175 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/Company.java

@@ -0,0 +1,175 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class Company extends Model<Company> {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 公司表主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 公司名
+     */
+    @TableField("company_name")
+    private String companyName;
+
+    /**
+     * 公司规模
+     */
+    @TableField("staff_count_max")
+    private Integer staffCountMax;
+
+    /**
+     * 会员到期时间
+     */
+    @TableField("expiration_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate expirationDate;
+
+    /**
+     * 是否签约
+     */
+    @TableField("set_meal")
+    private Integer setMeal;
+
+    /**
+     * 工时平台
+     */
+    @TableField("package_worktime")
+    private Integer packageWorktime;
+
+    /**
+     * 项目协作平台
+     */
+    @TableField("package_project")
+    private Integer packageProject;
+
+    /**
+     * 合同平台
+     */
+    @TableField("package_contract")
+    private Integer packageContract;
+
+    /**
+     * OA平台;请假,出差等
+     */
+    @TableField("package_oa")
+    private Integer packageOa;
+
+    /**
+     * 生产车间平台
+     */
+    @TableField("package_etimecard")
+    private Integer packageEtimecard;
+
+    /**
+     * 费用报销
+     */
+    @TableField("package_expense")
+    private Integer packageExpense;
+
+    /**
+     * 客户管理
+     */
+    @TableField("package_customer")
+    private Integer packageCustomer;
+
+    /**
+     * 工程专业
+     */
+    @TableField("package_engineering")
+    private Integer packageEngineering;
+
+    /**
+     * 简单表格版本
+     */
+    @TableField("package_simple")
+    private Integer packageSimple;
+
+    /**
+     * 财务核算成本
+     */
+    @TableField("package_finance")
+    private Integer packageFinance;
+
+    /**
+     * 供应商模块
+     */
+    @TableField("package_provider")
+    private Integer packageProvider;
+
+    /**
+     * 立项管理
+     */
+    @TableField("package_project_approval")
+    private Integer packageProjectApproval;
+
+    /**
+     * 设备管理模块
+     */
+    @TableField("package_device")
+    private Integer packageDevice;
+
+    /**
+     * 是否是国际化版本
+     */
+    @TableField("is_international")
+    private Integer isInternational;
+
+    /**
+     * 创建日期
+     */
+    @TableField("create_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate createDate;
+
+    /**
+     * 注册来源
+     */
+    @TableField("reg_from")
+    private String regFrom;
+
+    /**
+     * 非项目简单模式,该模式下非项目日报由部门主要负责人审核
+     */
+    @TableField("non_project_simple")
+    private Integer nonProjectSimple;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 106 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/CourseInfo.java

@@ -0,0 +1,106 @@
+package com.management.platform.entity;
+
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class CourseInfo extends Model<CourseInfo> {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 课程名称
+     */
+    @TableField("course_name")
+    private String courseName;
+
+    /**
+     * 课程介绍
+     */
+    @TableField("course_desc")
+    private String courseDesc;
+
+    /**
+     * 课程讲师
+     */
+    @TableField("course_instructor")
+    private String courseInstructor;
+
+    /**
+     * 课程价格
+     */
+    @TableField("course_price")
+    private BigDecimal coursePrice;
+
+    /**
+     * 课程是否上架 0未上架,1已上架
+     */
+    @TableField("course_status")
+    private Integer courseStatus;
+
+    /**
+     * 讲师级别
+     */
+    @TableField("instructor_type")
+    private String instructorType;
+
+    /**
+     * 讲师头像url
+     */
+    @TableField("instructor_img")
+    private String instructorImg;
+
+    /**
+     * 讲师介绍
+     */
+    @TableField("instructor_desc")
+    private String instructorDesc;
+
+    /**
+     * 上传日期
+     */
+    @TableField("create_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate createDate;
+
+    /**
+     * 公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 204 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/Task.java

@@ -0,0 +1,204 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2022-03-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class Task extends Model<Task> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 任务内容
+     */
+    @TableField("name")
+    private String name;
+
+    /**
+     * 任务描述
+     */
+    @TableField("task_desc")
+    private String taskDesc;
+
+    /**
+     * 创建人id
+     */
+    @TableField("creater_id")
+    private String createrId;
+
+    /**
+     * 创建人姓名
+     */
+    @TableField("creater_name")
+    private String createrName;
+
+    @TableField("creator_color")
+    private String creatorColor;
+
+    /**
+     * 执行人id
+     */
+    @TableField("executor_id")
+    private String executorId;
+
+    /**
+     * 执行人姓名
+     */
+    @TableField("executor_name")
+    private String executorName;
+
+    @TableField("executor_color")
+    private String executorColor;
+
+    /**
+     * 任务级别,0-一般 1-重要 2-紧急
+     */
+    @TableField("task_level")
+    private Integer taskLevel;
+
+    /**
+     * 任务状态,0-进行中 1-已完成 2-已撤销
+     */
+    @TableField("task_status")
+    private Integer taskStatus;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate createDate;
+
+    /**
+     * 截止时间
+     */
+    @TableField("end_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+    /**
+     * 项目id
+     */
+    @TableField("project_id")
+    private Integer projectId;
+
+    /**
+     * 当前阶段id
+     */
+    @TableField("stages_id")
+    private Integer stagesId;
+
+    /**
+     * 公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+    /**
+     * 创建时间戳
+     */
+    @TableField("indate")
+    private LocalDateTime indate;
+
+    /**
+     * 父任务id
+     */
+    @TableField("parent_tid")
+    private Integer parentTid;
+
+    /**
+     * 任务分组id
+     */
+    @TableField("group_id")
+    private Integer groupId;
+
+    /**
+     * 排序位置
+     */
+    @TableField("seq")
+    private Integer seq;
+
+    /**
+     * 计划工时
+     */
+    @TableField("plan_hours")
+    private Integer planHours;
+
+    /**
+     * 0-任务,1-里程碑,2-风险
+     */
+    @TableField("task_type")
+    private Integer taskType;
+
+    /**
+     * 父任务名称
+     */
+    @TableField("parent_tname")
+    private String parentTname;
+
+
+    /**
+     * 完成日期
+     */
+    @TableField("finish_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate finishDate;
+
+    @TableField(exist = false)
+    private List<Task> subTaskList;
+
+    @TableField(exist = false)
+    private int subTaskFinishNum;
+    @TableField(exist = false)
+    private String stagesName;
+
+
+
+    @TableField(exist = false)
+    private String projectName;
+    /**
+     * 开始日期
+     */
+    @TableField("start_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+
+    @TableField(exist = false)
+    private String executorListStr;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 293 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/User.java

@@ -0,0 +1,293 @@
+package com.management.platform.entity;
+
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class User extends Model<User> {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 主键 雪花算法生成
+     */
+    @TableId("id")
+    private String id;
+
+    /**
+     * 名字
+     */
+    @TableField("name")
+    private String name;
+
+    /**
+     * 手机号 登录账号,全系统唯一
+     */
+    @TableField("phone")
+    private String phone;
+
+    /**
+     * 密码
+     */
+    @TableField("password")
+    private String password;
+
+    /**
+     * 头像图片地址
+     */
+    @TableField("portrait_url")
+    private String portraitUrl;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+    private LocalDateTime createTime;
+
+    /**
+     * 角色权限 0-员工 1-负责人 2-管理员,3-公司高层,4-人事管理员,5-项目管理员
+     */
+    @TableField("role")
+    private Integer role;
+
+    /**
+     * 公司表外键
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+    /**
+     * 部门表外键
+     */
+    @TableField("department_id")
+    private Integer departmentId;
+
+    /**
+     * 部门层级
+     */
+    @TableField("department_cascade")
+    private String departmentCascade;
+
+    /**
+     * 时薪
+     */
+    @TableField("cost")
+    private BigDecimal cost;
+
+    /**
+     * 月薪
+     */
+    @TableField("month_cost")
+    private BigDecimal monthCost;
+
+    /**
+     * 薪资模式:0-固定月薪,1-计时工资
+     */
+    @TableField("salary_type")
+    private Integer salaryType;
+
+    /**
+     * 管理的部门
+     */
+    @TableField("manage_dept_id")
+    private Integer manageDeptId;
+
+    /**
+     * 头像颜色
+     */
+    @TableField("color")
+    private String color;
+
+    /**
+     * 是否激活
+     */
+    @TableField("is_active")
+    private Integer isActive;
+
+    /**
+     * 微信openid
+     */
+    @TableField("wx_openid")
+    private String wxOpenid;
+
+    /**
+     * 新版权限角色的id
+     */
+    @TableField("role_id")
+    private Integer roleId;
+
+    /**
+     * 新版权限角色的名称
+     */
+    @TableField("role_name")
+    private String roleName;
+
+    /**
+     * 成本生效日期
+     */
+    @TableField("cost_apply_date")
+    private String costApplyDate;
+
+    /**
+     * 钉钉userid
+     */
+    @TableField("dingding_userid")
+    private String dingdingUserid;
+
+    /**
+     * 钉钉unionid
+     */
+    @TableField("dingding_unionid")
+    private String dingdingUnionid;
+
+    /**
+     * 企业微信用户openuserid
+     */
+    @TableField("corpwx_userid")
+    private String corpwxUserid;
+
+    /**
+     * 入职日期
+     */
+    @TableField("induction_date")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate inductionDate;
+
+    /**
+     * 离职日期
+     */
+    @TableField("inactive_date")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate inactiveDate;
+
+    /**
+     * 岗位职级
+     */
+    @TableField("position")
+    private String position;
+
+    /**
+     * 0-需要填报 1-不需填报
+     */
+    @TableField("report_status")
+    private Integer reportStatus;
+
+    /**
+     * 直属上级
+     */
+    @TableField("superior_id")
+    private String superiorId;
+
+    @TableField("plate1")
+    private String plate1;
+
+    @TableField("plate2")
+    private String plate2;
+
+    @TableField("plate3")
+    private String plate3;
+
+    @TableField("plate4")
+    private String plate4;
+
+    @TableField("plate5")
+    private String plate5;
+
+    /**
+     * 是否可以登录八爪鱼系统
+     */
+    @TableField("is_ops")
+    private Integer isOps;
+
+    /**
+     * 员工工号,公司内唯一
+     */
+    @TableField("job_number")
+    private String jobNumber;
+
+    /**
+     * 员工在企业微信中的部门id
+     */
+    @TableField("corpwx_deptid")
+    private Integer corpwxDeptid;
+
+    /**
+     * 企业微信用户userid
+     */
+    @TableField("corpwx_real_userid")
+    private String corpwxRealUserid;
+
+    /**
+     * 0-否 1-是
+     */
+    @TableField("is_first_login")
+    private Integer isFirstLogin;
+
+    /**
+     * 0-否 1-是
+     */
+    @TableField("is_mob_first_login")
+    private Integer isMobFirstLogin;
+
+    /**
+     * 飞书人员id
+     */
+    @TableField("feishu_userid")
+    private String feishuUserid;
+
+    /**
+     * 飞书部门id
+     */
+    @TableField("feishu_deptid")
+    private String feishuDeptid;
+
+    /**
+     * 仅直属或部门一层审核,在report_audit_type=6时有效
+     */
+    @TableField("only_audit_once")
+    private Integer onlyAuditOnce;
+
+    /**
+     * 人员所属分组
+     */
+    @TableField("user_group_id")
+    private Integer userGroupId;
+
+    /**
+     * 1-否 2-是 是否属于机械费用下方人员
+     */
+    @TableField("is_machine_cost")
+    private Boolean isMachineCost;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/CompanyMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.Company;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+public interface CompanyMapper extends BaseMapper<Company> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/CourseInfoMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.CourseInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+public interface CourseInfoMapper extends BaseMapper<CourseInfo> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/UserMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.User;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+public interface UserMapper extends BaseMapper<User> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/CompanyService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.Company;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+public interface CompanyService extends IService<Company> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/CourseInfoService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.CourseInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+public interface CourseInfoService extends IService<CourseInfo> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/UserService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.User;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+public interface UserService extends IService<User> {
+
+}

+ 20 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/CompanyServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.Company;
+import com.management.platform.mapper.CompanyMapper;
+import com.management.platform.service.CompanyService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@Service
+public class CompanyServiceImpl extends ServiceImpl<CompanyMapper, Company> implements CompanyService {
+
+}

+ 20 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/CourseInfoServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.CourseInfo;
+import com.management.platform.mapper.CourseInfoMapper;
+import com.management.platform.service.CourseInfoService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@Service
+public class CourseInfoServiceImpl extends ServiceImpl<CourseInfoMapper, CourseInfo> implements CourseInfoService {
+
+}

+ 20 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/UserServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.User;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.UserService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-11
+ */
+@Service
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
+
+}

BIN
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/chi_sim.traineddata


+ 1 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/configs/api_config

@@ -0,0 +1 @@
+tessedit_zero_rejection T

+ 1 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/configs/digits

@@ -0,0 +1 @@
+tessedit_char_whitelist 0123456789-.

+ 1 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/configs/hocr

@@ -0,0 +1 @@
+tessedit_create_hocr 1

BIN
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/eng.traineddata


BIN
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/osd.traineddata


BIN
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/pdf.ttf


+ 793 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/tessdata/pdf.ttx

@@ -0,0 +1,793 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="2.4">
+
+  <GlyphOrder>
+    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="glyph00001"/>
+    <GlyphID id="2" name="glyph00002"/>
+    <GlyphID id="3" name="glyph00003"/>
+    <GlyphID id="4" name="glyph00004"/>
+    <GlyphID id="5" name="glyph00005"/>
+    <GlyphID id="6" name="glyph00006"/>
+    <GlyphID id="7" name="glyph00007"/>
+    <GlyphID id="8" name="glyph00008"/>
+    <GlyphID id="9" name="glyph00009"/>
+    <GlyphID id="10" name="glyph00010"/>
+    <GlyphID id="11" name="glyph00011"/>
+    <GlyphID id="12" name="glyph00012"/>
+    <GlyphID id="13" name="glyph00013"/>
+    <GlyphID id="14" name="glyph00014"/>
+    <GlyphID id="15" name="glyph00015"/>
+    <GlyphID id="16" name="glyph00016"/>
+    <GlyphID id="17" name="glyph00017"/>
+    <GlyphID id="18" name="glyph00018"/>
+    <GlyphID id="19" name="glyph00019"/>
+    <GlyphID id="20" name="glyph00020"/>
+    <GlyphID id="21" name="glyph00021"/>
+    <GlyphID id="22" name="glyph00022"/>
+    <GlyphID id="23" name="glyph00023"/>
+    <GlyphID id="24" name="glyph00024"/>
+    <GlyphID id="25" name="glyph00025"/>
+    <GlyphID id="26" name="glyph00026"/>
+    <GlyphID id="27" name="glyph00027"/>
+    <GlyphID id="28" name="glyph00028"/>
+    <GlyphID id="29" name="glyph00029"/>
+    <GlyphID id="30" name="glyph00030"/>
+    <GlyphID id="31" name="glyph00031"/>
+    <GlyphID id="32" name="glyph00032"/>
+    <GlyphID id="33" name="glyph00033"/>
+    <GlyphID id="34" name="glyph00034"/>
+    <GlyphID id="35" name="glyph00035"/>
+    <GlyphID id="36" name="glyph00036"/>
+    <GlyphID id="37" name="glyph00037"/>
+    <GlyphID id="38" name="glyph00038"/>
+    <GlyphID id="39" name="glyph00039"/>
+    <GlyphID id="40" name="glyph00040"/>
+    <GlyphID id="41" name="glyph00041"/>
+    <GlyphID id="42" name="glyph00042"/>
+    <GlyphID id="43" name="glyph00043"/>
+    <GlyphID id="44" name="glyph00044"/>
+    <GlyphID id="45" name="glyph00045"/>
+    <GlyphID id="46" name="glyph00046"/>
+    <GlyphID id="47" name="glyph00047"/>
+    <GlyphID id="48" name="glyph00048"/>
+    <GlyphID id="49" name="glyph00049"/>
+    <GlyphID id="50" name="glyph00050"/>
+    <GlyphID id="51" name="glyph00051"/>
+    <GlyphID id="52" name="glyph00052"/>
+    <GlyphID id="53" name="glyph00053"/>
+    <GlyphID id="54" name="glyph00054"/>
+    <GlyphID id="55" name="glyph00055"/>
+    <GlyphID id="56" name="glyph00056"/>
+    <GlyphID id="57" name="glyph00057"/>
+    <GlyphID id="58" name="glyph00058"/>
+    <GlyphID id="59" name="glyph00059"/>
+    <GlyphID id="60" name="glyph00060"/>
+    <GlyphID id="61" name="glyph00061"/>
+    <GlyphID id="62" name="glyph00062"/>
+    <GlyphID id="63" name="glyph00063"/>
+    <GlyphID id="64" name="glyph00064"/>
+    <GlyphID id="65" name="glyph00065"/>
+    <GlyphID id="66" name="glyph00066"/>
+    <GlyphID id="67" name="glyph00067"/>
+    <GlyphID id="68" name="glyph00068"/>
+    <GlyphID id="69" name="glyph00069"/>
+    <GlyphID id="70" name="glyph00070"/>
+    <GlyphID id="71" name="glyph00071"/>
+    <GlyphID id="72" name="glyph00072"/>
+    <GlyphID id="73" name="glyph00073"/>
+    <GlyphID id="74" name="glyph00074"/>
+    <GlyphID id="75" name="glyph00075"/>
+    <GlyphID id="76" name="glyph00076"/>
+    <GlyphID id="77" name="glyph00077"/>
+    <GlyphID id="78" name="glyph00078"/>
+    <GlyphID id="79" name="glyph00079"/>
+    <GlyphID id="80" name="glyph00080"/>
+    <GlyphID id="81" name="glyph00081"/>
+    <GlyphID id="82" name="glyph00082"/>
+    <GlyphID id="83" name="glyph00083"/>
+    <GlyphID id="84" name="glyph00084"/>
+    <GlyphID id="85" name="glyph00085"/>
+    <GlyphID id="86" name="glyph00086"/>
+    <GlyphID id="87" name="glyph00087"/>
+    <GlyphID id="88" name="glyph00088"/>
+    <GlyphID id="89" name="glyph00089"/>
+    <GlyphID id="90" name="glyph00090"/>
+    <GlyphID id="91" name="glyph00091"/>
+    <GlyphID id="92" name="glyph00092"/>
+    <GlyphID id="93" name="glyph00093"/>
+    <GlyphID id="94" name="glyph00094"/>
+    <GlyphID id="95" name="glyph00095"/>
+    <GlyphID id="96" name="glyph00096"/>
+    <GlyphID id="97" name="glyph00097"/>
+    <GlyphID id="98" name="glyph00098"/>
+    <GlyphID id="99" name="glyph00099"/>
+    <GlyphID id="100" name="glyph00100"/>
+    <GlyphID id="101" name="glyph00101"/>
+    <GlyphID id="102" name="glyph00102"/>
+    <GlyphID id="103" name="glyph00103"/>
+    <GlyphID id="104" name="glyph00104"/>
+    <GlyphID id="105" name="glyph00105"/>
+    <GlyphID id="106" name="glyph00106"/>
+    <GlyphID id="107" name="glyph00107"/>
+    <GlyphID id="108" name="glyph00108"/>
+    <GlyphID id="109" name="glyph00109"/>
+    <GlyphID id="110" name="glyph00110"/>
+    <GlyphID id="111" name="glyph00111"/>
+    <GlyphID id="112" name="glyph00112"/>
+    <GlyphID id="113" name="glyph00113"/>
+    <GlyphID id="114" name="glyph00114"/>
+    <GlyphID id="115" name="glyph00115"/>
+    <GlyphID id="116" name="glyph00116"/>
+  </GlyphOrder>
+
+  <head>
+    <!-- Most of this table will be recalculated by the compiler -->
+    <tableVersion value="1.0"/>
+    <fontRevision value="2.31999206543"/>
+    <checkSumAdjustment value="0xd4fdc458"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00011111"/>
+    <unitsPerEm value="2048"/>
+    <created value="Fri Sep 10 06:45:17 2010"/>
+    <modified value="Fri Sep 10 06:45:17 2010"/>
+    <xMin value="0"/>
+    <yMin value="0"/>
+    <xMax value="1000"/>
+    <yMax value="1000"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="8"/>
+    <fontDirectionHint value="0"/>
+    <indexToLocFormat value="1"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="1.0"/>
+    <ascent value="1000"/>
+    <descent value="0"/>
+    <lineGap value="0"/>
+    <advanceWidthMax value="3554"/>
+    <minLeftSideBearing value="-2090"/>
+    <minRightSideBearing value="-1455"/>
+    <xMaxExtent value="3442"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+    <numberOfHMetrics value="117"/>
+  </hhea>
+
+  <maxp>
+    <!-- Most of this table will be recalculated by the compiler -->
+    <tableVersion value="0x10000"/>
+    <numGlyphs value="117"/>
+    <maxPoints value="852"/>
+    <maxContours value="43"/>
+    <maxCompositePoints value="104"/>
+    <maxCompositeContours value="12"/>
+    <maxZones value="2"/>
+    <maxTwilightPoints value="16"/>
+    <maxStorage value="153"/>
+    <maxFunctionDefs value="8"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="1045"/>
+    <maxSizeOfInstructions value="534"/>
+    <maxComponentElements value="8"/>
+    <maxComponentDepth value="4"/>
+  </maxp>
+
+  <hmtx>
+    <mtx name=".notdef" width="1000" lsb="0"/>
+    <mtx name="glyph00001" width="1000" lsb="0"/>
+    <mtx name="glyph00002" width="1000" lsb="0"/>
+    <mtx name="glyph00003" width="1000" lsb="0"/>
+    <mtx name="glyph00004" width="1000" lsb="0"/>
+    <mtx name="glyph00005" width="1000" lsb="0"/>
+    <mtx name="glyph00006" width="1000" lsb="0"/>
+    <mtx name="glyph00007" width="1000" lsb="0"/>
+    <mtx name="glyph00008" width="1000" lsb="0"/>
+    <mtx name="glyph00009" width="1000" lsb="0"/>
+    <mtx name="glyph00010" width="1000" lsb="0"/>
+    <mtx name="glyph00011" width="1000" lsb="0"/>
+    <mtx name="glyph00012" width="1000" lsb="0"/>
+    <mtx name="glyph00013" width="1000" lsb="0"/>
+    <mtx name="glyph00014" width="1000" lsb="0"/>
+    <mtx name="glyph00015" width="1000" lsb="0"/>
+    <mtx name="glyph00016" width="1000" lsb="0"/>
+    <mtx name="glyph00017" width="1000" lsb="0"/>
+    <mtx name="glyph00018" width="1000" lsb="0"/>
+    <mtx name="glyph00019" width="1000" lsb="0"/>
+    <mtx name="glyph00020" width="1000" lsb="0"/>
+    <mtx name="glyph00021" width="1000" lsb="0"/>
+    <mtx name="glyph00022" width="1000" lsb="0"/>
+    <mtx name="glyph00023" width="1000" lsb="0"/>
+    <mtx name="glyph00024" width="1000" lsb="0"/>
+    <mtx name="glyph00025" width="1000" lsb="0"/>
+    <mtx name="glyph00026" width="1000" lsb="0"/>
+    <mtx name="glyph00027" width="1000" lsb="0"/>
+    <mtx name="glyph00028" width="1000" lsb="0"/>
+    <mtx name="glyph00029" width="1000" lsb="0"/>
+    <mtx name="glyph00030" width="1000" lsb="0"/>
+    <mtx name="glyph00031" width="1000" lsb="0"/>
+    <mtx name="glyph00032" width="1000" lsb="0"/>
+    <mtx name="glyph00033" width="1000" lsb="0"/>
+    <mtx name="glyph00034" width="1000" lsb="0"/>
+    <mtx name="glyph00035" width="1000" lsb="0"/>
+    <mtx name="glyph00036" width="1000" lsb="0"/>
+    <mtx name="glyph00037" width="1000" lsb="0"/>
+    <mtx name="glyph00038" width="1000" lsb="0"/>
+    <mtx name="glyph00039" width="1000" lsb="0"/>
+    <mtx name="glyph00040" width="1000" lsb="0"/>
+    <mtx name="glyph00041" width="1000" lsb="0"/>
+    <mtx name="glyph00042" width="1000" lsb="0"/>
+    <mtx name="glyph00043" width="1000" lsb="0"/>
+    <mtx name="glyph00044" width="1000" lsb="0"/>
+    <mtx name="glyph00045" width="1000" lsb="0"/>
+    <mtx name="glyph00046" width="1000" lsb="0"/>
+    <mtx name="glyph00047" width="1000" lsb="0"/>
+    <mtx name="glyph00048" width="1000" lsb="0"/>
+    <mtx name="glyph00049" width="1000" lsb="0"/>
+    <mtx name="glyph00050" width="1000" lsb="0"/>
+    <mtx name="glyph00051" width="1000" lsb="0"/>
+    <mtx name="glyph00052" width="1000" lsb="0"/>
+    <mtx name="glyph00053" width="1000" lsb="0"/>
+    <mtx name="glyph00054" width="1000" lsb="0"/>
+    <mtx name="glyph00055" width="1000" lsb="0"/>
+    <mtx name="glyph00056" width="1000" lsb="0"/>
+    <mtx name="glyph00057" width="1000" lsb="0"/>
+    <mtx name="glyph00058" width="1000" lsb="0"/>
+    <mtx name="glyph00059" width="1000" lsb="0"/>
+    <mtx name="glyph00060" width="1000" lsb="0"/>
+    <mtx name="glyph00061" width="1000" lsb="0"/>
+    <mtx name="glyph00062" width="1000" lsb="0"/>
+    <mtx name="glyph00063" width="1000" lsb="0"/>
+    <mtx name="glyph00064" width="1000" lsb="0"/>
+    <mtx name="glyph00065" width="1000" lsb="0"/>
+    <mtx name="glyph00066" width="1000" lsb="0"/>
+    <mtx name="glyph00067" width="1000" lsb="0"/>
+    <mtx name="glyph00068" width="1000" lsb="0"/>
+    <mtx name="glyph00069" width="1000" lsb="0"/>
+    <mtx name="glyph00070" width="1000" lsb="0"/>
+    <mtx name="glyph00071" width="1000" lsb="0"/>
+    <mtx name="glyph00072" width="1000" lsb="0"/>
+    <mtx name="glyph00073" width="1000" lsb="0"/>
+    <mtx name="glyph00074" width="1000" lsb="0"/>
+    <mtx name="glyph00075" width="1000" lsb="0"/>
+    <mtx name="glyph00076" width="1000" lsb="0"/>
+    <mtx name="glyph00077" width="1000" lsb="0"/>
+    <mtx name="glyph00078" width="1000" lsb="0"/>
+    <mtx name="glyph00079" width="1000" lsb="0"/>
+    <mtx name="glyph00080" width="1000" lsb="0"/>
+    <mtx name="glyph00081" width="1000" lsb="0"/>
+    <mtx name="glyph00082" width="1000" lsb="0"/>
+    <mtx name="glyph00083" width="1000" lsb="0"/>
+    <mtx name="glyph00084" width="1000" lsb="0"/>
+    <mtx name="glyph00085" width="1000" lsb="0"/>
+    <mtx name="glyph00086" width="1000" lsb="0"/>
+    <mtx name="glyph00087" width="1000" lsb="0"/>
+    <mtx name="glyph00088" width="1000" lsb="0"/>
+    <mtx name="glyph00089" width="1000" lsb="0"/>
+    <mtx name="glyph00090" width="1000" lsb="0"/>
+    <mtx name="glyph00091" width="1000" lsb="0"/>
+    <mtx name="glyph00092" width="1000" lsb="0"/>
+    <mtx name="glyph00093" width="1000" lsb="0"/>
+    <mtx name="glyph00094" width="1000" lsb="0"/>
+    <mtx name="glyph00095" width="1000" lsb="0"/>
+    <mtx name="glyph00096" width="1000" lsb="0"/>
+    <mtx name="glyph00097" width="1000" lsb="0"/>
+    <mtx name="glyph00098" width="1000" lsb="0"/>
+    <mtx name="glyph00099" width="1000" lsb="0"/>
+    <mtx name="glyph00100" width="1000" lsb="0"/>
+    <mtx name="glyph00101" width="1000" lsb="0"/>
+    <mtx name="glyph00102" width="1000" lsb="0"/>
+    <mtx name="glyph00103" width="1000" lsb="0"/>
+    <mtx name="glyph00104" width="1000" lsb="0"/>
+    <mtx name="glyph00105" width="1000" lsb="0"/>
+    <mtx name="glyph00106" width="1000" lsb="0"/>
+    <mtx name="glyph00107" width="1000" lsb="0"/>
+    <mtx name="glyph00108" width="1000" lsb="0"/>
+    <mtx name="glyph00109" width="1000" lsb="0"/>
+    <mtx name="glyph00110" width="1000" lsb="0"/>
+    <mtx name="glyph00111" width="1000" lsb="0"/>
+    <mtx name="glyph00112" width="1000" lsb="0"/>
+    <mtx name="glyph00113" width="1000" lsb="0"/>
+    <mtx name="glyph00114" width="1000" lsb="0"/>
+    <mtx name="glyph00115" width="1000" lsb="0"/>
+    <mtx name="glyph00116" width="1000" lsb="0"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_4 platformID="3" platEncID="0" language="0">
+      <map code="0xf000" name=".notdef"/>
+      <map code="0xf001" name="glyph00001"/>
+      <map code="0xf002" name="glyph00002"/>
+      <map code="0xf003" name="glyph00003"/>
+      <map code="0xf004" name="glyph00004"/>
+      <map code="0xf005" name="glyph00005"/>
+      <map code="0xf006" name="glyph00006"/>
+      <map code="0xf007" name="glyph00007"/>
+      <map code="0xf008" name="glyph00008"/>
+      <map code="0xf009" name="glyph00009"/>
+      <map code="0xf00a" name="glyph00010"/>
+      <map code="0xf00b" name="glyph00011"/>
+      <map code="0xf00c" name="glyph00012"/>
+      <map code="0xf00d" name="glyph00013"/>
+      <map code="0xf00e" name="glyph00014"/>
+      <map code="0xf00f" name="glyph00015"/>
+      <map code="0xf010" name="glyph00016"/>
+      <map code="0xf011" name="glyph00017"/>
+      <map code="0xf012" name="glyph00018"/>
+      <map code="0xf013" name="glyph00019"/>
+      <map code="0xf014" name="glyph00020"/>
+      <map code="0xf015" name="glyph00021"/>
+      <map code="0xf016" name="glyph00022"/>
+      <map code="0xf017" name="glyph00023"/>
+      <map code="0xf018" name="glyph00024"/>
+      <map code="0xf019" name="glyph00025"/>
+      <map code="0xf01a" name="glyph00026"/>
+      <map code="0xf01b" name="glyph00027"/>
+      <map code="0xf01c" name="glyph00028"/>
+      <map code="0xf01d" name="glyph00029"/>
+      <map code="0xf01e" name="glyph00030"/>
+      <map code="0xf01f" name="glyph00031"/>
+      <map code="0xf020" name="glyph00032"/>
+      <map code="0xf021" name="glyph00033"/>
+      <map code="0xf022" name="glyph00034"/>
+      <map code="0xf023" name="glyph00035"/>
+      <map code="0xf024" name="glyph00036"/>
+      <map code="0xf025" name="glyph00037"/>
+      <map code="0xf026" name="glyph00038"/>
+      <map code="0xf027" name="glyph00039"/>
+      <map code="0xf028" name="glyph00040"/>
+      <map code="0xf029" name="glyph00041"/>
+      <map code="0xf02a" name="glyph00042"/>
+      <map code="0xf02b" name="glyph00043"/>
+      <map code="0xf02c" name="glyph00044"/>
+      <map code="0xf02d" name="glyph00045"/>
+      <map code="0xf02e" name="glyph00046"/>
+      <map code="0xf02f" name="glyph00047"/>
+      <map code="0xf030" name="glyph00048"/>
+      <map code="0xf031" name="glyph00049"/>
+      <map code="0xf032" name="glyph00050"/>
+      <map code="0xf033" name="glyph00051"/>
+      <map code="0xf034" name="glyph00052"/>
+      <map code="0xf035" name="glyph00053"/>
+      <map code="0xf036" name="glyph00054"/>
+      <map code="0xf037" name="glyph00055"/>
+      <map code="0xf038" name="glyph00056"/>
+      <map code="0xf039" name="glyph00057"/>
+      <map code="0xf03a" name="glyph00058"/>
+      <map code="0xf03b" name="glyph00059"/>
+      <map code="0xf03c" name="glyph00060"/>
+      <map code="0xf03d" name="glyph00061"/>
+      <map code="0xf03e" name="glyph00062"/>
+      <map code="0xf03f" name="glyph00063"/>
+      <map code="0xf040" name="glyph00064"/>
+      <map code="0xf041" name="glyph00065"/>
+      <map code="0xf042" name="glyph00066"/>
+      <map code="0xf043" name="glyph00067"/>
+      <map code="0xf044" name="glyph00068"/>
+      <map code="0xf045" name="glyph00069"/>
+      <map code="0xf046" name="glyph00070"/>
+      <map code="0xf047" name="glyph00071"/>
+      <map code="0xf048" name="glyph00072"/>
+      <map code="0xf049" name="glyph00073"/>
+      <map code="0xf04a" name="glyph00074"/>
+      <map code="0xf04b" name="glyph00075"/>
+      <map code="0xf04c" name="glyph00076"/>
+      <map code="0xf04d" name="glyph00077"/>
+      <map code="0xf04e" name="glyph00078"/>
+      <map code="0xf04f" name="glyph00079"/>
+      <map code="0xf050" name="glyph00080"/>
+      <map code="0xf051" name="glyph00081"/>
+      <map code="0xf052" name="glyph00082"/>
+      <map code="0xf053" name="glyph00083"/>
+      <map code="0xf054" name="glyph00084"/>
+      <map code="0xf055" name="glyph00085"/>
+      <map code="0xf056" name="glyph00086"/>
+      <map code="0xf057" name="glyph00087"/>
+      <map code="0xf058" name="glyph00088"/>
+      <map code="0xf059" name="glyph00089"/>
+      <map code="0xf05a" name="glyph00090"/>
+      <map code="0xf05b" name="glyph00091"/>
+      <map code="0xf05c" name="glyph00092"/>
+      <map code="0xf05d" name="glyph00093"/>
+      <map code="0xf05e" name="glyph00094"/>
+      <map code="0xf05f" name="glyph00095"/>
+      <map code="0xf060" name="glyph00096"/>
+      <map code="0xf061" name="glyph00097"/>
+      <map code="0xf062" name="glyph00098"/>
+      <map code="0xf063" name="glyph00099"/>
+      <map code="0xf064" name="glyph00100"/>
+      <map code="0xf065" name="glyph00101"/>
+      <map code="0xf066" name="glyph00102"/>
+      <map code="0xf067" name="glyph00103"/>
+      <map code="0xf068" name="glyph00104"/>
+      <map code="0xf069" name="glyph00105"/>
+      <map code="0xf06a" name="glyph00106"/>
+      <map code="0xf06b" name="glyph00107"/>
+      <map code="0xf06c" name="glyph00108"/>
+      <map code="0xf06d" name="glyph00109"/>
+      <map code="0xf06e" name="glyph00110"/>
+      <map code="0xf06f" name="glyph00111"/>
+      <map code="0xf070" name="glyph00112"/>
+      <map code="0xf071" name="glyph00113"/>
+      <map code="0xf072" name="glyph00114"/>
+      <map code="0xf073" name="glyph00115"/>
+      <map code="0xf074" name="glyph00116"/>
+    </cmap_format_4>
+    <cmap_format_6 platformID="1" platEncID="0" language="0">
+      <map code="0x0" name=".notdef"/>
+      <map code="0x1" name="glyph00001"/>
+      <map code="0x2" name="glyph00002"/>
+      <map code="0x3" name="glyph00003"/>
+      <map code="0x4" name="glyph00004"/>
+      <map code="0x5" name="glyph00005"/>
+      <map code="0x6" name="glyph00006"/>
+      <map code="0x7" name="glyph00007"/>
+      <map code="0x8" name="glyph00008"/>
+      <map code="0x9" name="glyph00009"/>
+      <map code="0xa" name="glyph00010"/>
+      <map code="0xb" name="glyph00011"/>
+      <map code="0xc" name="glyph00012"/>
+      <map code="0xd" name="glyph00013"/>
+      <map code="0xe" name="glyph00014"/>
+      <map code="0xf" name="glyph00015"/>
+      <map code="0x10" name="glyph00016"/>
+      <map code="0x11" name="glyph00017"/>
+      <map code="0x12" name="glyph00018"/>
+      <map code="0x13" name="glyph00019"/>
+      <map code="0x14" name="glyph00020"/>
+      <map code="0x15" name="glyph00021"/>
+      <map code="0x16" name="glyph00022"/>
+      <map code="0x17" name="glyph00023"/>
+      <map code="0x18" name="glyph00024"/>
+      <map code="0x19" name="glyph00025"/>
+      <map code="0x1a" name="glyph00026"/>
+      <map code="0x1b" name="glyph00027"/>
+      <map code="0x1c" name="glyph00028"/>
+      <map code="0x1d" name="glyph00029"/>
+      <map code="0x1e" name="glyph00030"/>
+      <map code="0x1f" name="glyph00031"/>
+      <map code="0x20" name="glyph00032"/>
+      <map code="0x21" name="glyph00033"/>
+      <map code="0x22" name="glyph00034"/>
+      <map code="0x23" name="glyph00035"/>
+      <map code="0x24" name="glyph00036"/>
+      <map code="0x25" name="glyph00037"/>
+      <map code="0x26" name="glyph00038"/>
+      <map code="0x27" name="glyph00039"/>
+      <map code="0x28" name="glyph00040"/>
+      <map code="0x29" name="glyph00041"/>
+      <map code="0x2a" name="glyph00042"/>
+      <map code="0x2b" name="glyph00043"/>
+      <map code="0x2c" name="glyph00044"/>
+      <map code="0x2d" name="glyph00045"/>
+      <map code="0x2e" name="glyph00046"/>
+      <map code="0x2f" name="glyph00047"/>
+      <map code="0x30" name="glyph00048"/>
+      <map code="0x31" name="glyph00049"/>
+      <map code="0x32" name="glyph00050"/>
+      <map code="0x33" name="glyph00051"/>
+      <map code="0x34" name="glyph00052"/>
+      <map code="0x35" name="glyph00053"/>
+      <map code="0x36" name="glyph00054"/>
+      <map code="0x37" name="glyph00055"/>
+      <map code="0x38" name="glyph00056"/>
+      <map code="0x39" name="glyph00057"/>
+      <map code="0x3a" name="glyph00058"/>
+      <map code="0x3b" name="glyph00059"/>
+      <map code="0x3c" name="glyph00060"/>
+      <map code="0x3d" name="glyph00061"/>
+      <map code="0x3e" name="glyph00062"/>
+      <map code="0x3f" name="glyph00063"/>
+      <map code="0x40" name="glyph00064"/>
+      <map code="0x41" name="glyph00065"/>
+      <map code="0x42" name="glyph00066"/>
+      <map code="0x43" name="glyph00067"/>
+      <map code="0x44" name="glyph00068"/>
+      <map code="0x45" name="glyph00069"/>
+      <map code="0x46" name="glyph00070"/>
+      <map code="0x47" name="glyph00071"/>
+      <map code="0x48" name="glyph00072"/>
+      <map code="0x49" name="glyph00073"/>
+      <map code="0x4a" name="glyph00074"/>
+      <map code="0x4b" name="glyph00075"/>
+      <map code="0x4c" name="glyph00076"/>
+      <map code="0x4d" name="glyph00077"/>
+      <map code="0x4e" name="glyph00078"/>
+      <map code="0x4f" name="glyph00079"/>
+      <map code="0x50" name="glyph00080"/>
+      <map code="0x51" name="glyph00081"/>
+      <map code="0x52" name="glyph00082"/>
+      <map code="0x53" name="glyph00083"/>
+      <map code="0x54" name="glyph00084"/>
+      <map code="0x55" name="glyph00085"/>
+      <map code="0x56" name="glyph00086"/>
+      <map code="0x57" name="glyph00087"/>
+      <map code="0x58" name="glyph00088"/>
+      <map code="0x59" name="glyph00089"/>
+      <map code="0x5a" name="glyph00090"/>
+      <map code="0x5b" name="glyph00091"/>
+      <map code="0x5c" name="glyph00092"/>
+      <map code="0x5d" name="glyph00093"/>
+      <map code="0x5e" name="glyph00094"/>
+      <map code="0x5f" name="glyph00095"/>
+      <map code="0x60" name="glyph00096"/>
+      <map code="0x61" name="glyph00097"/>
+      <map code="0x62" name="glyph00098"/>
+      <map code="0x63" name="glyph00099"/>
+      <map code="0x64" name="glyph00100"/>
+      <map code="0x65" name="glyph00101"/>
+      <map code="0x66" name="glyph00102"/>
+      <map code="0x67" name="glyph00103"/>
+      <map code="0x68" name="glyph00104"/>
+      <map code="0x69" name="glyph00105"/>
+      <map code="0x6a" name="glyph00106"/>
+      <map code="0x6b" name="glyph00107"/>
+      <map code="0x6c" name="glyph00108"/>
+      <map code="0x6d" name="glyph00109"/>
+      <map code="0x6e" name="glyph00110"/>
+      <map code="0x6f" name="glyph00111"/>
+      <map code="0x70" name="glyph00112"/>
+      <map code="0x71" name="glyph00113"/>
+      <map code="0x72" name="glyph00114"/>
+      <map code="0x73" name="glyph00115"/>
+      <map code="0x74" name="glyph00116"/>
+    </cmap_format_6>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <!-- The xMin, yMin, xMax and yMax values
+         will be recalculated by the compiler. -->
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="1000" yMax="1000">
+      <contour>
+      </contour>
+      <instructions><assembly>
+        </assembly></instructions>
+    </TTGlyph>
+    <TTGlyph name="glyph00001" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00002" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00003" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00004" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00005" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00006" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00007" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00008" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00009" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00010" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00011" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00012" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00013" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00014" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00015" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00016" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00017" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00018" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00019" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00020" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00021" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00022" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00023" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00024" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00025" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00026" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00027" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00028" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00029" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00030" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00031" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00032" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00033" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00034" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00035" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00036" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00037" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00038" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00039" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00040" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00041" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00042" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00043" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00044" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00045" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00046" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00047" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00048" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00049" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00050" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00051" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00052" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00053" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00054" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00055" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00056" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00057" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00058" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00059" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00060" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00061" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00062" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00063" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00064" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00065" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00066" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00067" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00068" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00069" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00070" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00071" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00072" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00073" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00074" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00075" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00076" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00077" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00078" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00079" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00080" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00081" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00082" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00083" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00084" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00085" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00086" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00087" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00088" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00089" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00090" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00091" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00092" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00093" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00094" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00095" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00096" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00097" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00098" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00099" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00100" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00101" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00102" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00103" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00104" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00105" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00106" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00107" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00108" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00109" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00110" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00111" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00112" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00113" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00114" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00115" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+    <TTGlyph name="glyph00116" xMin="0" yMin="0" xMax="1000" yMax="1000">
+    </TTGlyph>
+  </glyf>
+</ttFont>

+ 96 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/AuthService.java

@@ -0,0 +1,96 @@
+package com.management.platform.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.management.platform.constant.Constant;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 08 - 30 13:59
+ * Description:<描述> 百度api识别图片里的文字,获取token类工具类
+ * Version: 1.0
+ */
+public class AuthService {
+    /**
+     * 获取权限token
+     * @return 返回示例:
+     * {
+     * "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567",
+     * "expires_in": 2592000
+     * }
+     */
+    public static Map<String, Object> getAuth() {
+        // 官网获取的 API Key 更新为你注册的
+        String clientId = Constant.API_KEY;
+        // 官网获取的 Secret Key 更新为你注册的
+        String clientSecret = Constant.SECRET_KEY;
+        return getAuth(clientId, clientSecret);
+    }
+
+    /**
+     * 获取API访问token
+     * 该token有一定的有效期,需要自行管理,当失效时需重新获取.
+     * @param ak - 百度云官网获取的 API Key
+     * @param sk - 百度云官网获取的 Securet Key
+     * @return assess_token 示例:
+     * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
+     */
+    public static Map<String, Object> getAuth(String ak, String sk) {
+        // 获取token地址
+        String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
+        String getAccessTokenUrl = authHost
+                // 1. grant_type为固定参数
+                + "grant_type=client_credentials"
+                // 2. 官网获取的 API Key
+                + "&client_id=" + ak
+                // 3. 官网获取的 Secret Key
+                + "&client_secret=" + sk;
+        try {
+            URL realUrl = new URL(getAccessTokenUrl);
+            // 打开和URL之间的连接
+            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
+            connection.setRequestMethod("GET");
+            connection.connect();
+            // 获取所有响应头字段
+            Map<String, List<String>> map = connection.getHeaderFields();
+            // 遍历所有的响应头字段
+            for (String key : map.keySet()) {
+                System.err.println(key + "--->" + map.get(key));
+            }
+            // 定义 BufferedReader输入流来读取URL的响应
+            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+            String result = "";
+            String line;
+            while ((line = in.readLine()) != null) {
+                result += line;
+            }
+            /**
+             * 返回结果示例
+             */
+            System.err.println("result:" + result);
+            JSONObject jsonObject =JSONObject.parseObject(result);
+            System.out.println(jsonObject);
+            String access_token = jsonObject.getString("access_token");
+            Long expires_in = jsonObject.getLong("expires_in");
+            Map<String,Object> mapResult = new HashMap<>();
+            mapResult.put("accessToken",access_token);
+            mapResult.put("expiresIn",expires_in);
+            return mapResult;
+        } catch (Exception e) {
+            System.err.print("获取token失败!");
+            e.printStackTrace(System.err);
+        }
+        return null;
+    }
+
+    public static void main(String[] args) {
+        Map<String,Object> map = getAuth();
+        System.out.println("auth---->"+map);
+    }
+}

+ 73 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/CRC16Util.java

@@ -0,0 +1,73 @@
+package com.management.platform.util;
+public class CRC16Util {
+    /**
+     * 计算CRC16校验码
+     *
+     * @param data 需要校验的字符串
+     * @return 校验码
+     */
+    public static String getCRC(String data) {
+        data = data.replace(" ", "");
+        int len = data.length();
+        if (!(len % 2 == 0)) {
+            return "0000";
+        }
+        int num = len / 2;
+        byte[] para = new byte[num];
+        for (int i = 0; i < num; i++) {
+            int value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16);
+            para[i] = (byte) value;
+        }
+        return getCRC(para);
+    }
+ 
+ 
+    /**
+     * 计算CRC16校验码
+     *
+     * @param bytes 字节数组
+     * @return {@link String} 校验码
+     * @since 1.0
+     */
+    public static String getCRC(byte[] bytes) {
+        //CRC寄存器全为1
+        int CRC = 0x0000ffff;
+        //多项式校验值
+        int POLYNOMIAL = 0x0000a001;
+        int i, j;
+        for (i = 0; i < bytes.length; i++) {
+            CRC ^= ((int) bytes[i] & 0x000000ff);
+            for (j = 0; j < 8; j++) {
+                if ((CRC & 0x00000001) != 0) {
+                    CRC >>= 1;
+                    CRC ^= POLYNOMIAL;
+                } else {
+                    CRC >>= 1;
+                }
+            }
+        }
+        System.out.println("CRC"+CRC);
+        //结果转换为16进制
+        String result = Integer.toHexString(CRC).toUpperCase();
+        System.out.println("result"+result);
+        if (result.length() != 4) {
+            StringBuffer sb = new StringBuffer("0000");
+            result = sb.replace(4 - result.length(), 4, result).toString();
+        }
+//        return result;
+//        交换高低位
+        return result.substring(2, 4) + result.substring(0, 2);//高位在前,低位在后
+    }
+ 
+ 
+    public static void main(String[] args) {
+        //01 03 20 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 8C 45
+        //01 03 00 00 00 08 44 0C
+        //01 03 10 00 8F 02 4E 00 91 02 44 00 92 02 5A 00 8B 02 47 40 D8
+//        System.out.println(getCRC("01 03 20 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF"));
+//        System.out.println(getCRC("01 03 00 00 00 08"));
+//        System.out.println(getCRC("01 03 10 00 8F 02 4E 00 91 02 44 00 92 02 5A 00 8B 02 47"));
+    	String crc = getCRC("FA AF 00 07 01 1e 78 1e 50 00 3C");
+        System.out.println(crc);
+    }
+}

+ 211 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/CodeGenerator.java

@@ -0,0 +1,211 @@
+package com.management.platform.util;
+
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.FileType;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * mybatis-plus代码生成器
+ *  使用该类需要添加以下依赖,在此之前请移除所有与mybatis有关的其他依赖,防止冲突
+ *   <dependency>
+ *      <groupId>com.baomidou</groupId>
+ *       <artifactId>mybatis-plus-generator</artifactId>
+ *       <version>3.1.2</version>
+ *  </dependency>
+ *
+ *  <dependency>
+ *        <groupId>com.baomidou</groupId>
+ *        <artifactId>mybatis-plus-boot-starter</artifactId>
+ *        <version>3.1.2</version>
+ *   </dependency>
+ *
+ */
+// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
+public class CodeGenerator {
+
+    /**
+     * <p>
+     * 读取控制台内容
+     * </p>
+     */
+    public static String scanner(String tip) {
+        Scanner scanner = new Scanner(System.in);
+        System.out.println("请输入" + tip + ":");
+        if (scanner.hasNext()) {
+            String ipt = scanner.next();
+            if (StringUtils.isNotEmpty(ipt)) {
+                return ipt;
+            }
+        }
+        throw new MybatisPlusException("请输入正确的" + tip + "!");
+    }
+
+    public static void main(String[] args) {
+        // 代码生成器
+        AutoGenerator mpg = new AutoGenerator();
+
+        // 全局配置
+        GlobalConfig gc = new GlobalConfig();
+        // 全局配置
+
+
+        // 自定义文件命名,注意 %s 会自动填充表实体属性!
+//        gc.setMapperName("%sDao");
+//        gc.setXmlName("%sMapper");
+//        gc.setServiceName("%sService");
+//        gc.setServiceImplName("%sServiceImap");
+//        gc.setControllerName("%sController");
+        //生成的代码存放到某个路径下,这里是E盘,
+//        gc.setOutputDir("E://");
+        //生成的代码位置为当前项目
+        String projectPath = System.getProperty("user.dir");
+        gc.setOutputDir(projectPath + "/src/main/java");
+        gc.setAuthor("Seyason");
+        gc.setOpen(false);
+        gc.setFileOverride(true);
+        gc.setActiveRecord(true);
+        //%s是实体类类名占位符,不配置这行的话,对于User会生成IUserService,配置后即可生成UserService;
+        gc.setServiceName("%sService");
+        // XML 二级缓存
+//      gc.setEnableCache(true);
+        // XML ResultMap
+        gc.setBaseResultMap(true);
+        // XML columList
+        gc.setBaseColumnList(true);
+        //
+        // gc.setSwagger2(true); 实体属性 Swagger2 注解
+        mpg.setGlobalConfig(gc);
+
+        // 数据源配置
+        DataSourceConfig dsc = new DataSourceConfig();
+        dsc.setUrl("jdbc:mysql://1.94.62.58:17089/course_manager?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8");
+//        dsc.setSchemaName("public");
+        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
+        dsc.setUsername("root");
+        dsc.setPassword("P011430@Huoshi*");
+        mpg.setDataSource(dsc);
+
+        // 包配置
+        PackageConfig pc = new PackageConfig();
+        //若果需要在Parent(此处即com.example.plus)下新建模块时打开下面注释,后续在控制台提示输入模块时,输入想要新建的模块名就可以
+//        pc.setModuleName(scanner("模块名"));
+        pc.setParent("com.management.platform");
+        mpg.setPackageInfo(pc);
+
+        // 自定义配置
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                // to do nothing
+            }
+        };
+        //以下为两种模板来生成*mapper.xml文件,任选一种即可,不同的模板对应不同的依赖
+        // 如果模板引擎是 freemarker,请添加以下依赖。
+        /**
+         *         <dependency>
+         *             <groupId>org.freemarker</groupId>
+         *             <artifactId>freemarker</artifactId>
+         *             <version>2.3.23</version>
+         *         </dependency>
+         */
+//        String templatePath = "/templates/mapper.xml.ftl";
+        // 如果模板引擎是 velocity 请添加以下依赖。
+        /**
+         *         <dependency>
+         *             <groupId>org.apache.velocity</groupId>
+         *             <artifactId>velocity-engine-core</artifactId>
+         *             <version>2.0</version>
+         *         </dependency>
+         */
+         String templatePath = "/templates/mapper.xml.vm";
+
+        // 自定义输出配置
+        List<FileOutConfig> focList = new ArrayList<>();
+        // 自定义配置会被优先输出
+        focList.add(new FileOutConfig(templatePath) {
+            @Override
+            public String outputFile(TableInfo tableInfo) {
+                if(pc.getModuleName() == null){
+                    return projectPath + "/src/main/resources/mapper/"
+                            + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
+                }else{
+                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
+                    return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+                            + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
+                }
+
+            }
+
+        });
+
+        cfg.setFileCreate(new IFileCreate() {
+            @Override
+            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
+                // 判断自定义文件夹是否需要创建,这里调用默认的方法
+                checkDir(filePath);
+                //对于已存在的文件,只需重复生成 entity 和 mapper.xml
+                File file = new File(filePath);
+                boolean exist = file.exists();
+                if(exist){
+                    return filePath.endsWith("Mapper.xml") || FileType.ENTITY == fileType;
+                }
+                //不存在的文件都需要创建
+                return  true;
+            }
+        });
+
+        cfg.setFileOutConfigList(focList);
+        mpg.setCfg(cfg);
+        mpg.setTemplate(new TemplateConfig().setXml(null));
+
+        // 配置模板
+//        TemplateConfig templateConfig = new TemplateConfig();
+//
+//        // 配置自定义输出模板
+//        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
+//        // templateConfig.setEntity("templates/entity2.java");
+//        // templateConfig.setService();
+//        // templateConfig.setController();
+//
+//        templateConfig.setXml(null);
+//        mpg.setTemplate(templateConfig);
+
+        // 策略配置
+        StrategyConfig strategy = new StrategyConfig();
+        strategy.setNaming(NamingStrategy.underline_to_camel);
+        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+        //若想要生成的实体类继承某个类,则可打开下面注释。写上需要继承的类的位置即可
+//        strategy.setSuperEntityClass("com.baomidou.ant.common.BaseEntity");
+        //【实体】是否为lombok模型(默认 false)
+        strategy.setEntityLombokModel(true);
+        //对控制器生成 @RestController 注解
+        strategy.setRestControllerStyle(true);
+        //是否生成实体时,生成字段注解
+        strategy.setEntityTableFieldAnnotationEnable(true);
+//        strategy.setEntitySerialVersionUID(false)//加此行不生成生成实体类序列化编号,不加默认生成
+        //若想要生成的实体类继承某个Controller,则可打开下面注释。写上需要继承的Controller的位置即可
+//        strategy.setSuperControllerClass("com.baomidou.ant.common.BaseController");
+        //此处user是表名,多个英文逗号分割
+//        strategy.setInclude("project,project_docfolder,project_document,stages,task,task_comment,task_file,task_log");
+//        strategy.setExclude();//数据库表全生成
+        strategy.setInclude(scanner("请输入表名").split(","));//表名,多个英文逗号分割
+        strategy.setControllerMappingHyphenStyle(true);
+        //数据库表前缀,不配置这行的话,生成的类会带有T如:TUser,配置后即可将前缀去掉
+//        strategy.setTablePrefix("tb_");
+        mpg.setStrategy(strategy);
+//        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
+        mpg.execute();
+    }
+}

+ 35 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/CodeUtil.java

@@ -0,0 +1,35 @@
+package com.management.platform.util;
+
+import java.util.Random;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 10 - 24 16:23
+ * Description:验证码生成工具
+ * Version: 1.0
+ */
+public class CodeUtil {
+
+
+    public HttpRespMsg getVcode(String mobile) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (mobile != null) {
+            Random r = new Random();
+            int val = r.nextInt(10000);
+            if (val < 1000) {
+                val += 1000;
+            }
+            String codeValStr = "" + val;
+//            Vcode record = new Vcode();
+//            record.setMobile(mobile);
+//            record.setVcode("" + val);
+//            vcodeMapper.insertSelective(record);
+//            try {
+//                SendSmsResponse sendSmsResponse = SmsDemo.sendSms(mobile, record.getVcode());
+//            } catch (ClientException e) {
+//                e.printStackTrace();
+//            }
+        }
+        return msg;
+    }
+}

+ 204 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/ColorUtil.java

@@ -0,0 +1,204 @@
+package com.management.platform.util;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+
+public class ColorUtil {
+    public static String[] COLORS = {"#1E90FF","#FF1493", "#FF7F50", "#2E8B57", "#778899"};
+
+    public static String randomColor() {
+        int rand = new Random().nextInt(COLORS.length);
+        return COLORS[rand];
+    }
+
+    public static void main(String[] args) {
+        String[] str = new String[]{"18658127122",
+                "13958019678",
+                "13777870711",
+                "18857154912",
+                "15557161578",
+                "15397126535",
+                "13456906403",
+                "18868860034",
+                "13588345506",
+                "13777419005",
+                "15268555322",
+                "15397023915",
+                "18069703196",
+                "13456735736",
+                "13805726051",
+                "18698555982",
+                "18958046862",
+                "15868845002",
+                "13575738161",
+                "15990199772",
+                "18658872590",
+                "13867169056",
+                "18158182525",
+                "15088689713",
+                "13585961039",
+                "18668017529",
+                "18057128645",
+                "15257582246",
+                "13735844966",
+                "18106532040",
+                "13716269811",
+                "17682330355",
+                "15958035195",
+                "15874924072",
+                "15158005335",
+                "17858936083",
+                "18457061976",
+                "18518207024",
+                "15921722090",
+                "13575489658",
+                "15202181434",
+                "18621559970",
+                "13309236572",
+                "15617169920",
+                "13992062944",
+                "18792624855",
+                "18158771827",
+                "13022966965",
+                "18629391086",
+                "18857114810",
+                "17606869224",
+                "18609654280",
+                "15309252997",
+                "13666166105",
+                "18782259249",
+                "18066953451",
+                "15129233575",
+                "18011265989",
+                "15224092347",
+                "15829070933",
+                "18200376799",
+                "18601666475",
+                "13700279481",
+                "15319957089",
+                "18792475086",
+                "13572160817",
+                "15167118084",
+                "13281865290",
+                "18616761341",
+                "15897721636",
+                "17816891567",
+                "13214327825",
+                "13567105150",
+                "13596260933",
+                "15200744011",
+                "18857866308",
+                "19883270311",
+                "13891857170",
+                "18392138744",
+                "15924058876",
+                "13227892017",
+                "15715817791",
+                "15824304746",
+                "15209256108",
+                "15282690951",
+                "13208101965",
+                "13173612375",
+                "18069809196",
+                "18402868212",
+                "13588015853",
+                "15828344349",
+                "13758183719",
+                "15101135063",
+                "18767157952",
+                "15158172465",
+                "17682308747",
+                "17733397108",
+                "18767180985",
+                "18508233670",
+                "13758200824",
+                "17348510010",
+                "17705737070",
+                "15058125780",
+                "15669067889",
+                "13516713029",
+                "13223014721",
+                "18868875984",
+                "15158866871",
+                "13666699169",
+                "15937664749",
+                "15102756101",
+                "17858606393",
+                "13588905589",
+                "15267163086",
+                "17791776120",
+                "19857124399",
+                "15858297095",
+                "18279055251",
+                "17682300802",
+                "15228949530",
+                "13524587246",
+                "15620552019",
+                "18683616506",
+                "13408015748",
+                "13913730634",
+                "15332315975",
+                "18868802950",
+                "18230107901",
+                "18367821189",
+                "15651615092",
+                "15680573913",
+                "15328183610",
+                "18270824772",
+                "15757189113",
+                "18706805139",
+                "13424441897",
+                "15375687185",
+                "18482270702",
+                "15850561758",
+                "13957795236",
+                "19817711781",
+                "18092719836",
+                "13488477632",
+                "13895461198",
+                "18758271681",
+                "17858603330",
+                "15621023159",
+                "15738531696",
+                "13525071538",
+                "15858181363",
+                "15178725899",
+                "18768417808",
+                "13289815592",
+                "13508506578",
+                "17639411957",
+                "13757174079",
+                "15191024238",
+                "17764558635",
+                "15957152408",
+                "18888928715",
+                "15988879266",
+                "13572525540",
+                "17858955042",
+                "15868157451",
+                "13735485537",
+                "18368497686",
+                "13736912611",
+                "15168483201",
+                "15922337143",
+                "17396247720",
+                "15707722551",
+                "18768110676",
+                "13957983264",
+                "13588810732",
+                "15112445545",
+                "18868101349",
+                "18611395335",
+                "15814404625",
+                "18605227853",
+                "15757517964",
+                "18096049625"};
+        List<String> phoneList = Arrays.asList(str);
+        for (int i=0;i<phoneList.size(); i++) {
+
+        }
+
+    }
+}

+ 69 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/DateTimeUtil.java

@@ -0,0 +1,69 @@
+package com.management.platform.util;
+
+import org.apache.tomcat.jni.Local;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Arrays;
+
+public class DateTimeUtil {
+    public static final String[] WEEK_DAYS = {"周一","周二","周三","周四","周五","周六", "周日"};
+
+
+    //把秒转化为时间
+    public static String getTimeFromSeconds(int seconds) {
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime localDateTime = now.withSecond(0).withHour(0).withMinute(0).withNano(0);
+        localDateTime = localDateTime.plusSeconds(seconds);
+        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm");
+        String format = dateTimeFormatter.format(localDateTime);
+        System.out.println(format);
+        return format;
+    }
+
+    //把时间转为为秒,方便计算时长
+    public static int getSecondsFromTime(String time) {
+        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+        LocalDateTime date = LocalDateTime.parse("2022-01-01 "+time, dateTimeFormatter);
+        int intSeconds = date.getHour() * 3600 + date.getMinute() * 60 + date.getSecond();
+        return intSeconds;
+    }
+
+    //把时长秒转化为小时
+    public static double getHoursFromSeconds(int seconds) {
+        double hours = 1.0f * seconds/3600;
+        return hours;
+    }
+
+    /**
+     * 返回四舍五入到整数的部分
+     */
+    public static double getHoursFromDouble(double time) {
+        BigDecimal decimal = new BigDecimal(time);
+        return decimal.setScale(0, RoundingMode.HALF_UP).doubleValue();
+    }
+
+    public static LocalDate getLocalDateFromSeconds(long time) {
+        LocalDate localDate = LocalDateTime.ofInstant(Instant.ofEpochSecond(time), ZoneId.systemDefault()).toLocalDate();
+        return localDate;
+    }
+
+    public static String getWeekDayTxt(int day) {
+        return WEEK_DAYS[day-1];
+    }
+
+
+    public static void main(String[] args) {
+
+        DateTimeFormatter mdFormat = DateTimeFormatter.ofPattern("yyyy/M/d");
+        LocalDate parse = LocalDate.parse("2022/1/29", mdFormat);
+        LocalDate parse2 = LocalDate.parse("2022/1/29", mdFormat);
+        System.out.println(parse.isEqual(parse2));
+    }
+}

+ 347 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/DingCallbackCrypto.java

@@ -0,0 +1,347 @@
+package com.management.platform.util;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.alibaba.fastjson.JSON;
+
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * 钉钉开放平台加解密方法
+ * 在ORACLE官方网站下载JCE无限制权限策略文件
+ * JDK6的下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
+ * JDK7的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
+ * JDK8的下载地址 https://www.oracle.com/java/technologies/javase-jce8-downloads.html
+ */
+public class DingCallbackCrypto {
+
+    private static final Charset CHARSET = StandardCharsets.UTF_8;
+    private static final Base64 base64 = new Base64();
+    private final byte[] aesKey;
+    private final String token;
+    private final String corpId;
+    /**
+     * ask getPaddingBytes key固定长度
+     **/
+    private static final Integer AES_ENCODE_KEY_LENGTH = 43;
+    /**
+     * 加密随机字符串字节长度
+     **/
+    private static final Integer RANDOM_LENGTH = 16;
+
+    /**
+     * 构造函数
+     *
+     * @param token          钉钉开放平台上,开发者设置的token
+     * @param encodingAesKey 钉钉开放台上,开发者设置的EncodingAESKey
+     * @param corpId         企业自建应用-事件订阅, 使用appKey
+     *                       企业自建应用-注册回调地址, 使用corpId
+     *                       第三方企业应用, 使用suiteKey
+     *
+     * @throws DingTalkEncryptException 执行失败,请查看该异常的错误码和具体的错误信息
+     */
+    public DingCallbackCrypto(String token, String encodingAesKey, String corpId) throws DingTalkEncryptException {
+        if (null == encodingAesKey || encodingAesKey.length() != AES_ENCODE_KEY_LENGTH) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.AES_KEY_ILLEGAL);
+        }
+        this.token = token;
+        this.corpId = corpId;
+        aesKey = Base64.decodeBase64(encodingAesKey + "=");
+    }
+
+    public Map<String, String> getEncryptedMap(String plaintext) throws DingTalkEncryptException {
+        return getEncryptedMap(plaintext, System.currentTimeMillis(), Utils.getRandomStr(16));
+    }
+
+    /**
+     * 将和钉钉开放平台同步的消息体加密,返回加密Map
+     *
+     * @param plaintext 传递的消息体明文
+     * @param timeStamp 时间戳
+     * @param nonce     随机字符串
+     * @return
+     * @throws DingTalkEncryptException
+     */
+    public Map<String, String> getEncryptedMap(String plaintext, Long timeStamp, String nonce)
+        throws DingTalkEncryptException {
+        if (null == plaintext) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_PLAINTEXT_ILLEGAL);
+        }
+        if (null == timeStamp) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_TIMESTAMP_ILLEGAL);
+        }
+        if (null == nonce || nonce.length() != 16) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_NONCE_ILLEGAL);
+        }
+        // 加密
+        String encrypt = encrypt(Utils.getRandomStr(RANDOM_LENGTH), plaintext);
+        String signature = getSignature(token, String.valueOf(timeStamp), nonce, encrypt);
+        Map<String, String> resultMap = new HashMap<String, String>();
+        resultMap.put("msg_signature", signature);
+        resultMap.put("encrypt", encrypt);
+        resultMap.put("timeStamp", String.valueOf(timeStamp));
+        resultMap.put("nonce", nonce);
+        return resultMap;
+    }
+
+    /**
+     * 密文解密
+     *
+     * @param msgSignature 签名串
+     * @param timeStamp    时间戳
+     * @param nonce        随机串
+     * @param encryptMsg   密文
+     * @return 解密后的原文
+     * @throws DingTalkEncryptException
+     */
+    public String getDecryptMsg(String msgSignature, String timeStamp, String nonce, String encryptMsg)
+        throws DingTalkEncryptException {
+        //校验签名
+        String signature = getSignature(token, timeStamp, nonce, encryptMsg);
+        if (!signature.equals(msgSignature)) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_SIGNATURE_ERROR);
+        }
+        // 解密
+        String result = decrypt(encryptMsg);
+        return result;
+    }
+
+    /*
+     * 对明文加密.
+     * @param text 需要加密的明文
+     * @return 加密后base64编码的字符串
+     */
+    private String encrypt(String random, String plaintext) throws DingTalkEncryptException {
+        try {
+            byte[] randomBytes = random.getBytes(CHARSET);
+            byte[] plainTextBytes = plaintext.getBytes(CHARSET);
+            byte[] lengthByte = Utils.int2Bytes(plainTextBytes.length);
+            byte[] corpidBytes = corpId.getBytes(CHARSET);
+            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+            byteStream.write(randomBytes);
+            byteStream.write(lengthByte);
+            byteStream.write(plainTextBytes);
+            byteStream.write(corpidBytes);
+            byte[] padBytes = PKCS7Padding.getPaddingBytes(byteStream.size());
+            byteStream.write(padBytes);
+            byte[] unencrypted = byteStream.toByteArray();
+            byteStream.close();
+            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+            IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+            byte[] encrypted = cipher.doFinal(unencrypted);
+            String result = base64.encodeToString(encrypted);
+            return result;
+        } catch (Exception e) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_ENCRYPT_TEXT_ERROR);
+        }
+    }
+
+    /*
+     * 对密文进行解密.
+     * @param text 需要解密的密文
+     * @return 解密得到的明文
+     */
+    private String decrypt(String text) throws DingTalkEncryptException {
+        byte[] originalArr;
+        try {
+            // 设置解密模式为AES的CBC模式
+            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
+            cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
+            // 使用BASE64对密文进行解码
+            byte[] encrypted = Base64.decodeBase64(text);
+            // 解密
+            originalArr = cipher.doFinal(encrypted);
+        } catch (Exception e) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_ERROR);
+        }
+
+        String plainText;
+        String fromCorpid;
+        try {
+            // 去除补位字符
+            byte[] bytes = PKCS7Padding.removePaddingBytes(originalArr);
+            // 分离16位随机字符串,网络字节序和corpId
+            byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
+            int plainTextLegth = Utils.bytes2int(networkOrder);
+            plainText = new String(Arrays.copyOfRange(bytes, 20, 20 + plainTextLegth), CHARSET);
+            fromCorpid = new String(Arrays.copyOfRange(bytes, 20 + plainTextLegth, bytes.length), CHARSET);
+        } catch (Exception e) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_LENGTH_ERROR);
+        }
+
+        // corpid不相同的情况
+        if (!fromCorpid.equals(corpId)) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_CORPID_ERROR);
+        }
+        return plainText;
+    }
+
+    /**
+     * 数字签名
+     *
+     * @param token     isv token
+     * @param timestamp 时间戳
+     * @param nonce     随机串
+     * @param encrypt   加密文本
+     * @return
+     * @throws DingTalkEncryptException
+     */
+    public String getSignature(String token, String timestamp, String nonce, String encrypt)
+        throws DingTalkEncryptException {
+        try {
+            String[] array = new String[] {token, timestamp, nonce, encrypt};
+            Arrays.sort(array);
+            System.out.println(JSON.toJSONString(array));
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < 4; i++) {
+                sb.append(array[i]);
+            }
+            String str = sb.toString();
+            System.out.println(str);
+            MessageDigest md = MessageDigest.getInstance("SHA-1");
+            md.update(str.getBytes());
+            byte[] digest = md.digest();
+
+            StringBuffer hexstr = new StringBuffer();
+            String shaHex = "";
+            for (int i = 0; i < digest.length; i++) {
+                shaHex = Integer.toHexString(digest[i] & 0xFF);
+                if (shaHex.length() < 2) {
+                    hexstr.append(0);
+                }
+                hexstr.append(shaHex);
+            }
+            return hexstr.toString();
+        } catch (Exception e) {
+            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_SIGNATURE_ERROR);
+        }
+    }
+
+    public static class Utils {
+        public Utils() {
+        }
+
+        public static String getRandomStr(int count) {
+            String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+            Random random = new Random();
+            StringBuffer sb = new StringBuffer();
+
+            for (int i = 0; i < count; ++i) {
+                int number = random.nextInt(base.length());
+                sb.append(base.charAt(number));
+            }
+
+            return sb.toString();
+        }
+
+        public static byte[] int2Bytes(int count) {
+            byte[] byteArr = new byte[] {(byte)(count >> 24 & 255), (byte)(count >> 16 & 255), (byte)(count >> 8 & 255),
+                (byte)(count & 255)};
+            return byteArr;
+        }
+
+        public static int bytes2int(byte[] byteArr) {
+            int count = 0;
+
+            for (int i = 0; i < 4; ++i) {
+                count <<= 8;
+                count |= byteArr[i] & 255;
+            }
+
+            return count;
+        }
+    }
+
+    public static class PKCS7Padding {
+        private static final Charset CHARSET = StandardCharsets.UTF_8;
+        private static final int BLOCK_SIZE = 32;
+
+        public PKCS7Padding() {
+        }
+
+        public static byte[] getPaddingBytes(int count) {
+            int amountToPad = 32 - count % 32;
+            if (amountToPad == 0) {
+                amountToPad = 32;
+            }
+
+            char padChr = chr(amountToPad);
+            String tmp = "";
+
+            for (int index = 0; index < amountToPad; ++index) {
+                tmp = tmp + padChr;
+            }
+
+            return tmp.getBytes(CHARSET);
+        }
+
+        public static byte[] removePaddingBytes(byte[] decrypted) {
+            int pad = decrypted[decrypted.length - 1];
+            if (pad < 1 || pad > 32) {
+                pad = 0;
+            }
+
+            return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+        }
+
+        private static char chr(int a) {
+            byte target = (byte)(a & 255);
+            return (char)target;
+        }
+    }
+
+    public static class DingTalkEncryptException extends Exception {
+        public static final int SUCCESS = 0;
+        public static final int ENCRYPTION_PLAINTEXT_ILLEGAL = 900001;
+        public static final int ENCRYPTION_TIMESTAMP_ILLEGAL = 900002;
+        public static final int ENCRYPTION_NONCE_ILLEGAL = 900003;
+        public static final int AES_KEY_ILLEGAL = 900004;
+        public static final int SIGNATURE_NOT_MATCH = 900005;
+        public static final int COMPUTE_SIGNATURE_ERROR = 900006;
+        public static final int COMPUTE_ENCRYPT_TEXT_ERROR = 900007;
+        public static final int COMPUTE_DECRYPT_TEXT_ERROR = 900008;
+        public static final int COMPUTE_DECRYPT_TEXT_LENGTH_ERROR = 900009;
+        public static final int COMPUTE_DECRYPT_TEXT_CORPID_ERROR = 900010;
+        private static final Map<Integer, String> msgMap = new HashMap();
+        private final Integer code;
+
+        static {
+            msgMap.put(0, "成功");
+            msgMap.put(900001, "加密明文文本非法");
+            msgMap.put(900002, "加密时间戳参数非法");
+            msgMap.put(900003, "加密随机字符串参数非法");
+            msgMap.put(900005, "签名不匹配");
+            msgMap.put(900006, "签名计算失败");
+            msgMap.put(900004, "不合法的aes key");
+            msgMap.put(900007, "计算加密文字错误");
+            msgMap.put(900008, "计算解密文字错误");
+            msgMap.put(900009, "计算解密文字长度不匹配");
+            msgMap.put(900010, "计算解密文字corpid不匹配");
+        }
+
+        public Integer getCode() {
+            return this.code;
+        }
+
+        public DingTalkEncryptException(Integer exceptionCode) {
+            super(msgMap.get(exceptionCode));
+            this.code = exceptionCode;
+        }
+    }
+
+}

+ 41 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/DocumentTypeUtil.java

@@ -0,0 +1,41 @@
+package com.management.platform.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DocumentTypeUtil {
+	/**
+	 * documentType文件类型
+	 * 0-图片文件,1-文本文件 ,2-压缩文件,3-txt,4-excle文件,5-压缩文件,6-视频文件,7-音频文件
+	 */
+
+	public static Integer DocumentType(String fileSuffix) {
+		if(".gif".equals(fileSuffix)) {
+			return 0;
+		}else if(".jpg".equals(fileSuffix)) {
+			return 0;
+		}else if(".png".equals(fileSuffix)) {
+			return 0;
+		}else if(".bmp".equals(fileSuffix)) {
+			return 0;
+		}else if(".doc".equals(fileSuffix) || ".docx".equals(fileSuffix)) {
+			return 1;
+		}else if(".txt".equals(fileSuffix)) {
+			return 2;
+		}else if(".xls".equals(fileSuffix) || ".xlsx".equals(fileSuffix)) {
+			return 3;
+		}else if(".zip".equals(fileSuffix) || ".rar".equals(fileSuffix)) {
+			return 4;
+		}else if(".avi".equals(fileSuffix) || ".rmvb".equals(fileSuffix)
+				|| ".3gp".equals(fileSuffix) || ".mp4".equals(fileSuffix)) {
+			return 5;
+		} else if(".mp3".equals(fileSuffix)) {
+			return 6;
+		} else if(".pdf".equals(fileSuffix)) {
+			return 7;
+		} else{
+			//其他文件
+			return -1;
+		}
+	}
+}

+ 167 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/ExcelUtil.java

@@ -0,0 +1,167 @@
+package com.management.platform.util;
+
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.usermodel.*;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.util.List;
+
+public class ExcelUtil {
+    /**
+     * 简单Excel导出
+     * @param title     标题
+     * @param list      数据
+     * @return
+     */
+    public static String exportGeneralExcelByTitleAndList(String title, List<List<String>> list, String downloadPath) {
+        String result="系统提示:Excel文件导出成功!";
+        String fileName= title+".xls";
+        try {
+//            response.reset();
+//            response.setHeader("Content-disposition",
+//                "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
+//            //设置文件头编码格式
+//            response.setContentType("APPLICATION/OCTET-STREAM;charset=UTF-8");//设置类型
+//            response.setHeader("Cache-Control","no-cache");//设置头
+//            response.setDateHeader("Expires", 0);//设置日期头
+            // 创建工作簿
+            HSSFWorkbook workBook = new HSSFWorkbook();
+            // 创建工作类
+            HSSFSheet sheet = workBook.createSheet();
+            //设置首行冻结
+            sheet.createFreezePane(0, 1);
+            sheet.setDefaultColumnWidth(16);
+            //设置字体样式
+            HSSFFont headFont = workBook.createFont();
+            headFont.setBold(true);
+            headFont.setFontHeightInPoints((short) 10);
+            headFont.setFontName("黑体");
+
+            HSSFFont titleFont = workBook.createFont();
+            titleFont.setBold(true);
+            titleFont.setFontHeightInPoints((short) 10);
+            titleFont.setFontName("黑体");
+
+            HSSFFont font = workBook.createFont();
+            font.setFontHeightInPoints((short) 10);
+            font.setFontName("宋体");
+
+            //设置单元格样式
+            CellStyle headStyle = workBook.createCellStyle();
+            headStyle.setFont(headFont);
+            headStyle.setAlignment(HorizontalAlignment.CENTER);
+            headStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            headStyle.setWrapText(true);
+            headStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            headStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            headStyle.setBorderTop(BorderStyle.THIN);//上边框
+            headStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            String color = "c0c0c0";    //此处得到的color为16进制的字符串
+            //转为RGB码
+            int r = Integer.parseInt((color.substring(0,2)),16);   //转为16进制
+            int g = Integer.parseInt((color.substring(2,4)),16);
+            int b = Integer.parseInt((color.substring(4,6)),16);
+
+            //自定义cell颜色
+            HSSFPalette palette = workBook.getCustomPalette();
+            //这里的9是索引
+            palette.setColorAtIndex((short)9, (byte) r, (byte) g, (byte) b);
+
+            CellStyle titleStyle = workBook.createCellStyle();
+            titleStyle.setFont(titleFont);
+            titleStyle.setAlignment(HorizontalAlignment.CENTER);
+            titleStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);  //填充单元格
+            titleStyle.setFillForegroundColor((short)9);    //填色
+            titleStyle.setWrapText(true);
+            titleStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            titleStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            titleStyle.setBorderTop(BorderStyle.THIN);//上边框
+            titleStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            CellStyle cellStyle = workBook.createCellStyle();
+            cellStyle.setFont(font);
+            cellStyle.setAlignment(HorizontalAlignment.CENTER);
+            cellStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            cellStyle.setWrapText(true);
+            cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            cellStyle.setBorderTop(BorderStyle.THIN);//上边框
+            cellStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            if(list.size() > 0) {
+                //标题(如果需要在EXCEL内容最上面加标题,请打开下面的注释,修改start)
+                /*
+                HSSFRow titleRow = sheet.createRow(0);
+                titleRow.setHeightInPoints(30);
+                HSSFCell titleCell = titleRow.createCell(0);
+                titleCell.setCellStyle(headStyle);
+                titleCell.setCellValue(title);
+                //合并单元格
+                CellRangeAddress cellRangeAddress = new CellRangeAddress(0,0,0, list.get(0).size() - 1);
+                //加入合并单元格对象
+                sheet.addMergedRegion(cellRangeAddress);
+                //使用RegionUtil类为合并后的单元格添加边框
+			    RegionUtil.setBorderBottom(BorderStyle.THIN, cellRangeAddress, sheet); // 下边框
+                RegionUtil.setBorderLeft(BorderStyle.THIN, cellRangeAddress, sheet); // 左边框
+                RegionUtil.setBorderRight(BorderStyle.THIN, cellRangeAddress, sheet); // 有边框
+                RegionUtil.setBorderTop(BorderStyle.THIN, cellRangeAddress, sheet); // 上边框
+                */
+                int start = 0;
+                for(List<String> rowList : list) {
+                    HSSFRow row = sheet.createRow(start);
+                    row.setHeightInPoints(24);
+
+                    for(int i = 0; i < rowList.size(); i++) {
+                        HSSFCell cell = row.createCell(i);
+                        if(start == 0) {
+                            cell.setCellStyle(titleStyle);
+                        }else {
+                            cell.setCellStyle(cellStyle);
+                        }
+                        cell.setCellValue(rowList.get(i));
+                    }
+                    start++;
+                }
+            }
+            //用于非传统ajax;
+//            String headStr = "attachment; filename=\"" + fileName + "\"";
+//            response.setContentType("APPLICATION/OCTET-STREAM");//返回格式为流
+//            response.setHeader("Content-Disposition", headStr);
+//            //普通下载不需要以上三行,注掉即可
+//            OutputStream os = response.getOutputStream();//在线下载
+            File dir = null;
+            dir = new File(downloadPath);
+            // D://cloud/upload 文件上传后所存储的位置,部署到服务器上时配置服务器地址即可
+            if (!dir.exists()) {
+                dir.mkdirs();
+            }
+            FileOutputStream os = new FileOutputStream(downloadPath+fileName);//保存到本地
+            workBook.write(os);
+            os.flush();
+            os.close();
+        }catch(Exception e) {
+            System.out.println(result);
+            e.printStackTrace();
+        }
+        return "/upload/"+fileName;
+//        return "";
+    }
+
+    public static boolean isRowEmpty(Row row){
+        for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
+            Cell cell = row.getCell(i);
+            if (cell != null && cell.getCellTypeEnum() != CellType.BLANK){
+                System.out.println(i+":"+cell.getCellTypeEnum());
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 72 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/FileCopyToFolderUtil.java

@@ -0,0 +1,72 @@
+package com.management.platform.util;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 08 - 30 13:59
+ * Description:<描述>
+ * Version: 1.0
+ */
+public class FileCopyToFolderUtil {
+    public static void main(String[] args) throws IOException {
+        Date date = new Date();
+        long time1 = date.getTime();
+        List<String>  sourceFileUrls = new ArrayList<>();
+        sourceFileUrls.add("D:\\软件\\ideaIU-2018.1.5.exe");
+        copy(sourceFileUrls, "D:\\775");
+        date = new Date();
+        long time2 = date.getTime();
+        System.out.println("耗时===》"+(time2-time1)/1000);
+        File file = new File("D:\\776");
+        if (file.exists()) {
+            file.delete();
+            //创建文件夹
+            file.mkdirs();
+        } else {
+            file.mkdirs();
+        }
+        System.out.println(file.getPath());
+    }
+    public static String copy(List<String>  sourceFileUrls, String destinationFolder) throws IOException {
+        //新文件夾
+        File file = new File(destinationFolder);
+        if (file.exists()) {
+            file.delete();
+            //创建文件夹
+            file.mkdirs();
+        } else {
+            file.mkdirs();
+        }
+        //如果源文件存在就复制
+        for (String sourceFileUrl : sourceFileUrls) {
+            //目标源文件夹
+            File source = new File(sourceFileUrl);
+            if (source.exists()) {
+                //新文件夹的路径
+                File newFile = new File(file + File.separator + source.getName());
+                if (source.isFile()) {
+                    FileInputStream in = new FileInputStream(source);
+                    BufferedInputStream bis= new BufferedInputStream(in);
+                    FileOutputStream out = new FileOutputStream(newFile);
+                    BufferedOutputStream bos= new BufferedOutputStream(out);
+                    byte[] bs = new byte[4096*10];
+                    int count = 0;
+//循环把源文件的内容写入新文件
+                    while ((count = bis.read(bs, 0, bs.length)) != -1) {
+                        bos.write(bs, 0, count);
+                    }
+//关闭流
+                    out.flush();
+                    out.close();
+                    in.close();
+                }
+            }
+        }
+        return file.getPath();
+    }
+
+}

+ 141 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/FileUtil.java

@@ -0,0 +1,141 @@
+package com.management.platform.util;
+
+import com.fasterxml.jackson.annotation.ObjectIdGenerators;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+
+/**
+ * 文件读取工具类
+ */
+public class FileUtil {
+
+    /**
+     * 获取容易识别的文件大小,比如KB, MB, GB
+     * @param size
+     * @return
+     */
+    public static String getReadableFileSize(long size) {
+        if (size < 1024) {//1K以内
+            return size + "byte";
+        } else if (size < 1024 * 1024) {//1M以内
+            return String.format("%.1fKB", (size*1.0f/1024));
+        } else if (size < 1024 * 1024 * 1024) {//1G以内
+            return String.format("%.1fMB", (size*1.0f/1024/1024));
+        } else {
+            return String.format("%.1fGB", (size*1.0f/1024/1024/1024));
+        }
+    }
+
+
+    /**
+     * 读取文件内容,作为字符串返回
+     */
+    public static String readFileAsString(String filePath) throws IOException {
+        File file = new File(filePath);
+        if (!file.exists()) {
+            throw new FileNotFoundException(filePath);
+        }
+
+        if (file.length() > 1024 * 1024 * 1024) {
+            throw new IOException("File is too large");
+        }
+
+        StringBuilder sb = new StringBuilder((int) (file.length()));
+        // 创建字节输入流  
+        FileInputStream fis = new FileInputStream(filePath);
+        // 创建一个长度为10240的Buffer
+        byte[] bbuf = new byte[10240];
+        // 用于保存实际读取的字节数  
+        int hasRead = 0;
+        while ((hasRead = fis.read(bbuf)) > 0) {
+            sb.append(new String(bbuf, 0, hasRead));
+        }
+        fis.close();
+        return sb.toString();
+    }
+
+    /**
+     * 根据文件路径读取byte[] 数组
+     */
+    public static byte[] readFileByBytes(String filePath) throws IOException {
+        File file = new File(filePath);
+        if (!file.exists()) {
+            throw new FileNotFoundException(filePath);
+        } else {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
+            BufferedInputStream in = null;
+
+            try {
+                in = new BufferedInputStream(new FileInputStream(file));
+                short bufSize = 1024;
+                byte[] buffer = new byte[bufSize];
+                int len1;
+                while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
+                    bos.write(buffer, 0, len1);
+                }
+
+                byte[] var7 = bos.toByteArray();
+                return var7;
+            } finally {
+                try {
+                    if (in != null) {
+                        in.close();
+                    }
+                } catch (IOException var14) {
+                    var14.printStackTrace();
+                }
+
+                bos.close();
+            }
+        }
+    }
+
+    /**
+     * 根据文件路径读取byte[] 数组
+     */
+    public static byte[] readFileByBytes(File file) throws IOException {
+        if (file == null) {
+            throw new FileNotFoundException("file is not null");
+        } else {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
+            BufferedInputStream in = null;
+            try {
+                in = new BufferedInputStream(new FileInputStream(file));
+                short bufSize = 1024;
+                byte[] buffer = new byte[bufSize];
+                int len1;
+                while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
+                    bos.write(buffer, 0, len1);
+                }
+
+                byte[] var7 = bos.toByteArray();
+                return var7;
+            } finally {
+                try {
+                    if (in != null) {
+                        in.close();
+                    }
+                } catch (IOException var14) {
+                    var14.printStackTrace();
+                }
+
+                bos.close();
+            }
+        }
+    }
+
+
+    /**
+     * 删除
+     *
+     * @param files
+     */
+    private void deleteFile(File... files) {
+        for (File file : files) {
+            if (file.exists()) {
+                file.delete();
+            }
+        }
+    }
+}

+ 28 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/GsonUtils.java

@@ -0,0 +1,28 @@
+///*
+// * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+// */
+//package com.management.platform.util;
+//
+//import com.google.gson.Gson;
+//import com.google.gson.GsonBuilder;
+//import com.google.gson.JsonParseException;
+//import java.lang.reflect.Type;
+//
+///**
+// * Json工具类.
+// */
+//public class GsonUtils {
+//    private static Gson gson = new GsonBuilder().create();
+//
+//    public static String toJson(Object value) {
+//        return gson.toJson(value);
+//    }
+//
+//    public static <T> T fromJson(String json, Class<T> classOfT) throws JsonParseException {
+//        return gson.fromJson(json, classOfT);
+//    }
+//
+//    public static <T> T fromJson(String json, Type typeOfT) throws JsonParseException {
+//        return (T) gson.fromJson(json, typeOfT);
+//    }
+//}

+ 292 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/HttpKit.java

@@ -0,0 +1,292 @@
+package com.management.platform.util;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+import java.util.Map.Entry;
+
+@Slf4j
+public class HttpKit {
+    
+    private static final String DEFAULT_CHARSET = "UTF-8";
+    /**
+     * 发送Get请求
+     * @param url
+     * @return
+     * @throws NoSuchProviderException 
+     * @throws NoSuchAlgorithmException 
+     * @throws IOException 
+     * @throws KeyManagementException 
+     */
+    public static String get(String url) throws NoSuchAlgorithmException, NoSuchProviderException, IOException, KeyManagementException {
+        StringBuffer bufferRes = null;
+        TrustManager[] tm = { new MyX509TrustManager() };  
+        SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
+        sslContext.init(null, tm, new java.security.SecureRandom());  
+        // 从上述SSLContext对象中得到SSLSocketFactory对象  
+        SSLSocketFactory ssf = sslContext.getSocketFactory();
+        
+        URL urlGet = new URL(url);
+        HttpsURLConnection http = (HttpsURLConnection) urlGet.openConnection();
+        // 连接超时
+        http.setConnectTimeout(25000);
+        // 读取超时 --服务器响应比较慢,增大时间
+        http.setReadTimeout(25000);
+        http.setRequestMethod("GET");
+        http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
+        http.setSSLSocketFactory(ssf);
+        http.setDoOutput(true);
+        http.setDoInput(true);
+        http.connect();
+        
+        InputStream in = http.getInputStream();
+        BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET));
+        String valueString = null;
+        bufferRes = new StringBuffer();
+        while ((valueString = read.readLine()) != null){
+            bufferRes.append(valueString);
+        }
+        in.close();
+        if (http != null) {
+            // 关闭连接
+            http.disconnect();
+        }
+        return bufferRes.toString();
+    }
+    
+    /**
+     * 发送Get请求
+     * @param url
+     * @return
+     * @throws NoSuchProviderException 
+     * @throws NoSuchAlgorithmException 
+     * @throws IOException 
+     * @throws KeyManagementException 
+     */
+    public static String get(String url,Boolean https) throws NoSuchAlgorithmException, NoSuchProviderException, IOException, KeyManagementException {
+     if(https != null && https){
+      return get(url);
+     }else{
+      StringBuffer bufferRes = null;
+            URL urlGet = new URL(url);
+            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
+            // 连接超时
+            http.setConnectTimeout(25000);
+            // 读取超时 --服务器响应比较慢,增大时间
+            http.setReadTimeout(25000);
+            http.setRequestMethod("GET");
+            http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
+            http.setDoOutput(true);
+            http.setDoInput(true);
+            http.connect();
+            
+            InputStream in = http.getInputStream();
+            BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET));
+            String valueString = null;
+            bufferRes = new StringBuffer();
+            while ((valueString = read.readLine()) != null){
+                bufferRes.append(valueString);
+            }
+            in.close();
+            if (http != null) {
+                // 关闭连接
+                http.disconnect();
+            }
+            return bufferRes.toString();
+     }
+    }
+    /**
+     *  发送Get请求
+     * @param url
+     * @param params
+     * @return
+     * @throws IOException 
+     * @throws NoSuchProviderException 
+     * @throws NoSuchAlgorithmException 
+     * @throws KeyManagementException 
+     */
+    public static String get(String url, Map<String, String> params) throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, IOException {
+        return get(initParams(url, params));
+    }
+    /**
+     *  发送Post请求
+     * @param url
+     * @param params
+     * @return
+     * @throws IOException 
+     * @throws NoSuchProviderException 
+     * @throws NoSuchAlgorithmException 
+     * @throws KeyManagementException 
+     */
+    public static String post(String url, String params) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
+     StringBuffer bufferRes = null;
+        TrustManager[] tm = { new MyX509TrustManager() };
+        SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
+        sslContext.init(null, tm, new java.security.SecureRandom());
+        // 从上述SSLContext对象中得到SSLSocketFactory对象  
+        SSLSocketFactory ssf = sslContext.getSocketFactory();
+        URL urlGet = new URL(url);
+        HttpsURLConnection http = (HttpsURLConnection) urlGet.openConnection();
+        // 连接超时
+        http.setConnectTimeout(25000);
+        // 读取超时 --服务器响应比较慢,增大时间
+        http.setReadTimeout(25000);
+        http.setRequestMethod("POST");
+        http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
+        http.setSSLSocketFactory(ssf);
+        http.setDoOutput(true);
+        http.setDoInput(true);
+        http.connect();
+        OutputStream out = http.getOutputStream();
+        out.write(params.getBytes(StandardCharsets.UTF_8));
+        out.flush();
+        out.close();
+        InputStream in = http.getInputStream();
+        BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET));
+        String valueString = null;
+        bufferRes = new StringBuffer();
+        while ((valueString = read.readLine()) != null){
+            bufferRes.append(valueString);
+        }
+        in.close();
+        if (http != null) {
+            // 关闭连接
+            http.disconnect();
+        }
+        return bufferRes.toString();
+    }
+    
+    /**
+     * 上传媒体文件
+     * @param url
+     * @param file
+     * @return
+     * @throws IOException
+     * @throws NoSuchAlgorithmException
+     * @throws NoSuchProviderException
+     * @throws KeyManagementException
+     */
+    public static String upload(String url,File file) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
+        String BOUNDARY = "----WebKitFormBoundaryiDGnV9zdZA1eM1yL"; // 定义数据分隔线  
+        StringBuffer bufferRes = null;
+        URL urlGet = new URL(url);
+        HttpURLConnection conn = (HttpURLConnection) urlGet.openConnection();
+        conn.setDoOutput(true);  
+        conn.setDoInput(true);  
+        conn.setUseCaches(false);  
+        conn.setRequestMethod("POST");  
+        conn.setRequestProperty("connection", "Keep-Alive");  
+        conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36");  
+        conn.setRequestProperty("Charsert", "UTF-8");   
+        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);  
+          
+        OutputStream out = new DataOutputStream(conn.getOutputStream());  
+        byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();// 定义最后数据分隔线  
+        String sb = "--" +
+                BOUNDARY +
+                "\r\n" +
+                "Content-Disposition: form-data;name=\"media\";filename=\"" + file.getName() + "\"\r\n" +
+                "Content-Type:application/octet-stream\r\n\r\n";
+        byte[] data = sb.getBytes();
+        out.write(data);  
+        DataInputStream fs = new DataInputStream(new FileInputStream(file));  
+        int bytes = 0;  
+        byte[] bufferOut = new byte[1024];  
+        while ((bytes = fs.read(bufferOut)) != -1) {  
+            out.write(bufferOut, 0, bytes);  
+        }  
+        out.write("\r\n".getBytes()); //多个文件时,二个文件之间加入这个  
+        fs.close();  
+        out.write(end_data);  
+        out.flush();    
+        out.close();   
+          
+        // 定义BufferedReader输入流来读取URL的响应  
+        InputStream in = conn.getInputStream();
+        BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET));
+        String valueString = null;
+        bufferRes = new StringBuffer();
+        while ((valueString = read.readLine()) != null){
+            bufferRes.append(valueString);
+        }
+        in.close();
+        if (conn != null) {
+            // 关闭连接
+         conn.disconnect();
+        }
+        return bufferRes.toString();
+    }
+    
+    /**
+     * 构造url
+     * @param url
+     * @param params
+     * @return
+     */
+    private static String initParams(String url, Map<String, String> params){
+        if (null == params || params.isEmpty()) {
+            return url;
+        }
+        StringBuilder sb = new StringBuilder(url);
+        if (url.indexOf("?") == -1) {
+            sb.append("?");
+        } else {
+            sb.append("&");
+        }
+        boolean first = true;
+        for (Entry<String, String> entry : params.entrySet()) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append("&");
+            }
+            String key = entry.getKey();
+            String value = entry.getValue();
+            sb.append(key).append("=");
+            if (StringUtils.isNotEmpty(value)) {
+                try {
+                    sb.append(URLEncoder.encode(value, DEFAULT_CHARSET));
+                } catch (UnsupportedEncodingException e) {
+                    e.printStackTrace();
+                    log.error(url,e);
+                }
+            }
+        }
+        return sb.toString();
+    }
+    
+    public static void main(String[] args) {
+     String fname = "dsasdas.mp4";
+     String s = fname.substring(0, fname.lastIndexOf("."));
+     String f = fname.substring(s.length()+1);
+  System.out.println(f);
+ }
+}
+
+/**
+ * 证书管理
+ */
+class MyX509TrustManager implements X509TrustManager {
+    public X509Certificate[] getAcceptedIssuers() {
+        return null;  
+    }
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+    }
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+    }
+}

+ 43 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/HttpRespMsg.java

@@ -0,0 +1,43 @@
+package com.management.platform.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.io.Serializable;
+
+public class HttpRespMsg implements Serializable {
+
+    //status code, ok or error.
+    public String code;
+
+
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public String msg;
+
+    //data content, in jsonformat, or zipped string when format is gzip
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public Object data;
+
+    public HttpRespMsg() {
+        code = "ok";
+    }
+
+    public void setError(String errorMsg) {
+        code = "error";
+        msg = errorMsg;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+
+    public String toJSONStr() {
+        JSONObject json = new JSONObject();
+        json.put("code", code);
+        json.put("data", data);
+        json.put("msg", msg);
+
+        return json.toJSONString();
+    }
+}

+ 77 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/HttpUtil.java

@@ -0,0 +1,77 @@
+package com.management.platform.util;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * http 工具类
+ */
+public class HttpUtil {
+
+    public static String post(String requestUrl, String accessToken, String params)
+            throws Exception {
+        String contentType = "application/x-www-form-urlencoded";
+        return HttpUtil.post(requestUrl, accessToken, contentType, params);
+    }
+
+    public static String post(String requestUrl, String accessToken, String contentType, String params)
+            throws Exception {
+        String encoding = "UTF-8";
+        if (requestUrl.contains("nlp")) {
+            encoding = "GBK";
+        }
+        return HttpUtil.post(requestUrl, accessToken, contentType, params, encoding);
+    }
+
+    public static String post(String requestUrl, String accessToken, String contentType, String params, String encoding)
+            throws Exception {
+        String url = requestUrl + "?access_token=" + accessToken;
+        return HttpUtil.postGeneralUrl(url, contentType, params, encoding);
+    }
+
+    public static String postGeneralUrl(String generalUrl, String contentType, String params, String encoding)
+            throws Exception {
+        URL url = new URL(generalUrl);
+        // 打开和URL之间的连接
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        connection.setRequestMethod("POST");
+        // 设置通用的请求属性
+        connection.setRequestProperty("Content-Type", contentType);
+        connection.setRequestProperty("Connection", "Keep-Alive");
+        connection.setUseCaches(false);
+        connection.setDoOutput(true);
+        connection.setDoInput(true);
+
+        // 得到请求的输出流对象
+        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
+        out.write(params.getBytes(encoding));
+        out.flush();
+        out.close();
+
+        // 建立实际的连接
+        connection.connect();
+        // 获取所有响应头字段
+        Map<String, List<String>> headers = connection.getHeaderFields();
+        // 遍历所有的响应头字段
+        for (String key : headers.keySet()) {
+            System.err.println(key + "--->" + headers.get(key));
+        }
+        // 定义 BufferedReader输入流来读取URL的响应
+        BufferedReader in = null;
+        in = new BufferedReader(
+                new InputStreamReader(connection.getInputStream(), encoding));
+        String result = "";
+        String getLine;
+        while ((getLine = in.readLine()) != null) {
+            result += getLine;
+        }
+        in.close();
+        System.err.println("result:" + result);
+        return result;
+    }
+}

+ 159 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/ListUtil.java

@@ -0,0 +1,159 @@
+package com.management.platform.util;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 07 - 25 16:56
+ * Description:<描述>处理字符串转成集合的
+ * Version: 1.0
+ */
+
+public class ListUtil {
+	/**
+	 * 
+	 * @param idStr 1,2,3,4,5字符串
+	 * @return List<Long>
+	 */
+	public static List<Long> convertIdsArrayToList(String idStr) {
+		String[] array = idStr.split(",");
+		List<Long> ids = new ArrayList<Long>();
+		for (String a : array) {
+			if (a != null && a.length() > 0) {
+				ids.add(Long.valueOf(a));
+			}
+		}
+		return ids;
+	}
+
+	/**
+	 * Long
+	 * @param idStr  1,2,3,4,5字符串
+	 * @return
+	 */
+	public static List<String> convertLongIdsArrayToList(String idStr) {
+		String[] array = idStr.split(",");
+		List<String> ids = new ArrayList<String>();
+		for (String a : array) {
+			if (a != null && a.length() > 0) {
+				ids.add(a);
+			}
+		}
+		return ids;
+	}
+	/**
+	 * Long
+	 * @param idStr  1,2,3,4,5字符串
+	 * @return
+	 */
+	public static List<Integer> convertIntegerIdsArrayToList(String idStr) {
+		String[] array = idStr.split(",");
+		List<Integer> ids = new ArrayList<Integer>();
+		for (String a : array) {
+			if (a != null && a.length() > 0) {
+				ids.add(Integer.parseInt(a));
+			}
+		}
+		return ids;
+	}
+
+	public static List<Integer> extractIdFromList(List object, String key) {
+		List<Integer> list = new ArrayList<Integer>();
+        for (Object obj : object) {
+            // 得到类对象
+            Class userCla = obj.getClass();
+            /* 得到类中的所有属性集合 */
+            Field[] fs = userCla.getDeclaredFields();
+            for (int i = 0; i < fs.length; i++) {
+                Field f = fs[i];
+                f.setAccessible(true); // 设置些属性是可以访问的
+                try {
+                    if (f.getName().equals(key)) {
+                        list.add((Integer)f.get(obj));
+                    }
+                } catch (IllegalArgumentException e) {
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return list;
+	}
+	
+	
+	public static List<String> extractNameFromList(List object, String key) {
+		List<String> list = new ArrayList<String>();
+		for (Object obj : object) {
+			// 得到类对象
+			Class userCla = obj.getClass();
+			/* 得到类中的所有属性集合 */
+			Field[] fs = userCla.getDeclaredFields();
+			for (int i = 0; i < fs.length; i++) {
+				Field f = fs[i];
+				f.setAccessible(true); // 设置些属性是可以访问的
+				try {
+					if (f.getName().equals(key)) {
+						list.add((String)f.get(obj));
+					}
+				} catch (IllegalArgumentException e) {
+					e.printStackTrace();
+				} catch (IllegalAccessException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		return list;
+	}
+	
+	public static List<Integer> addList(String ids,List<Integer> idList){
+		String[] joinStr = ids.split(",");
+		boolean isCf = false;
+		for(String id : joinStr){
+			if (id != null && id.length() > 0) {
+				for(int i = 0;i<idList.size();i++){
+					if(Integer.valueOf(id).intValue() != idList.get(i).intValue()){
+						isCf = false;
+					}else{
+						isCf = true;
+						break;
+					}
+				}
+				if(!isCf){
+					idList.add(Integer.valueOf(id));
+				}
+			}
+		}
+		
+		return idList;
+	}
+	
+	//去重
+	public static List removeDuplicateData(List list) {
+		HashSet set = new HashSet();
+		set.addAll(list);
+		list.clear();
+		list.addAll(set);
+		return list;
+	}
+	
+	public static void main(String[] args) {
+		Integer a = new Integer(1);
+		Integer b = new Integer(1);
+		List<Integer> list = new ArrayList<>();
+		list.add(a);
+
+		System.out.println(list.contains(b));
+	}
+
+	public static List<Integer> fromIntegers(int[] data) {
+		List<Integer> ids = new ArrayList<>();
+		for (int i : data) {
+			ids.add(i);
+		}
+		return ids;
+	}
+}

+ 134 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/MD5Util.java

@@ -0,0 +1,134 @@
+package com.management.platform.util;
+
+import org.springframework.util.DigestUtils;
+import sun.security.rsa.RSASignature;
+
+import java.security.MessageDigest;
+import java.text.ParseException;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 07 - 25 16:56
+ * Description:<描述>MD5加密工具
+ * Version: 1.0
+ */
+public class MD5Util {
+
+    private static final String[] hexDigits = { "0", "1", "2", "3", "4", "5",
+            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
+
+    public static String getPassword(String password) {
+        return DigestUtils.md5DigestAsHex(password.getBytes());
+    }
+
+    public static void main(String[] args) throws ParseException {
+        System.out.println(getPassword("工时管家"));
+
+    }
+
+//    public void zipDemo() {
+//        //需要压缩的文件--包括文件地址和文件名
+//        String[] path = {"D:\\666.jpg", "D:\\777.jpg"};
+//        // 要生成的压缩文件地址和文件名称
+//        String desPath = "D:\\new.zip";
+//        File zipFile = new File(desPath);
+//        ZipOutputStream zipStream = null;
+//        FileInputStream zipSource = null;
+//        BufferedInputStream bufferStream = null;
+//        try {
+//            //构造最终压缩包的输出流
+//            zipStream = new ZipOutputStream(new FileOutputStream(zipFile));
+//            for (int i = 0; i < path.length; i++) {
+//                File file = new File(path[i]);
+//                //将需要压缩的文件格式化为输入流
+//                zipSource = new FileInputStream(file);
+//                //压缩条目不是具体独立的文件,而是压缩包文件列表中的列表项,称为条目,就像索引一样
+//                ZipEntry zipEntry = new ZipEntry(i + "2222.jpg");//"2222.jpg"是添加到压缩包里的源文件的名字加i是防止名字相同出错
+//                //定位该压缩条目位置,开始写入文件到压缩包中
+//                zipStream.putNextEntry(zipEntry);
+//                //输入缓冲流
+//                bufferStream = new BufferedInputStream(zipSource, 1024 * 10);
+//                int read = 0;
+//                //创建读写缓冲区
+//                byte[] buf = new byte[1024 * 10];
+//                while ((read = bufferStream.read(buf, 0, 1024 * 10)) != -1) {
+//                    zipStream.write(buf, 0, read);
+//                }
+//            }
+//
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        } finally {
+//            //关闭流
+//            try {
+//                if (null != bufferStream) bufferStream.close();
+//                if (null != zipStream) zipStream.close();
+//                if (null != zipSource) zipSource.close();
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//            }
+//        }
+//    }
+//
+//    public static void zip4jDemo(){
+//// 生成的压缩文件
+//        ZipFile zipFile = null;
+//        try {
+//            zipFile = new ZipFile("D:\\aa.zip");
+//
+//        ZipParameters parameters = new ZipParameters();
+//        // 压缩方式
+//        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
+//        // 压缩级别
+//        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
+//        // 要打包的文件夹
+//        File currentFile = new File("D:\\666");
+//        File[] fs = currentFile.listFiles();
+//        // 遍历test文件夹下所有的文件、文件夹
+//        for (File f : fs) {
+//            if (f.isDirectory()) {
+//                zipFile.addFolder(f.getPath(), parameters);
+//            } else {
+//                zipFile.addFile(f, parameters);
+//            }
+//        }
+//            zipFile.addFolder("D:\\666", parameters);
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//    }
+
+
+    private static String byteArrayToHexString(byte[] b) {
+        StringBuffer resultSb = new StringBuffer();
+        for (int i = 0; i < b.length; i++)
+            resultSb.append(byteToHexString(b[i]));
+
+        return resultSb.toString();
+    }
+
+    private static String byteToHexString(byte b) {
+        int n = b;
+        if (n < 0)
+            n += 256;
+        int d1 = n / 16;
+        int d2 = n % 16;
+        return hexDigits[d1] + hexDigits[d2];
+    }
+
+    public static String MD5Encode(String origin, String charsetname) {
+        String resultString = null;
+        try {
+            resultString = origin;
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            if (charsetname == null || "".equals(charsetname))
+                resultString = byteArrayToHexString(md.digest(resultString
+                        .getBytes()));
+            else
+                resultString = byteArrayToHexString(md.digest(resultString
+                        .getBytes(charsetname)));
+        } catch (Exception exception) {
+        }
+        return resultString;
+    }
+}

+ 18 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/MathUtil.java

@@ -0,0 +1,18 @@
+package com.management.platform.util;
+
+import java.util.regex.Pattern;
+
+public class MathUtil {
+    public static boolean isIntegerOrDigital(String str) {
+        if (str == null || str.trim().length() == 0) {
+            return false;
+        }
+        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*[\\.]?[\\d]*$");
+        return pattern.matcher(str).matches();
+    }
+
+    public static void main(String[] args) {
+        String str = "";
+        System.out.println(isIntegerOrDigital(str));
+    }
+}

+ 61 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/PageUtil.java

@@ -0,0 +1,61 @@
+package com.management.platform.util;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 07 - 27 9:25
+ * Description:<描述> 模仿pagehelper参数的分页封装类
+ * Version: 1.0
+ */
+@Data
+public class PageUtil<T> {
+    private Integer pageNum = 1;
+    private Integer total;
+    private Integer pageSize = 10;
+    private Integer pages;
+    private List<T> list = new ArrayList<>();
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getTotal() {
+        return total;
+    }
+
+    public void setTotal(Integer total) {
+        this.total = total;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPages() {
+        return pages;
+    }
+
+    public void setPages(Integer total) {
+        this.pages = total % this.pageSize == 0 ? total / this.pageSize : total / this.pageSize + 1;
+    }
+
+    public List<T> getList() {
+        return list;
+    }
+
+    public void setList(List<T> list) {
+        this.list = list;
+    }
+}

+ 74 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/Sha1Util.java

@@ -0,0 +1,74 @@
+package com.management.platform.util;
+
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.util.*;
+
+/*
+'============================================================================
+'api说明:
+'createSHA1Sign创建签名SHA1
+'getSha1()Sha1签名
+'============================================================================
+'*/
+public class Sha1Util {
+
+    public static void main(String[] args) {
+        String str = "jsapi_ticket=kgt8ON7yVITDhtdwci0qecaNzS34qhbQACy88uRm_S0XvT3hcWiBONbLzKnA5o5uPukt2sA3a8bBfETg4TyaQg&noncestr=10907813b97e249163587e6246612e21&timestamp=1516590573&url=http://www.dzjy.com/payHtml.html?num=1&code=001EjC0a2q6qoO0fn2Z92E6D0a2EjC0D&state=1";
+        String sign = getSha1(str);
+        System.out.println(sign);
+    }
+
+    public static String getNonceStr() {
+        Random random = new Random();
+        return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");
+    }
+    public static String getTimeStamp() {
+        return String.valueOf(System.currentTimeMillis() / 1000);
+    }
+
+    //创建签名SHA1
+    public static String createSHA1Sign(SortedMap<String, String> signParams) throws Exception {
+        StringBuffer sb = new StringBuffer();
+        Set es = signParams.entrySet();
+        Iterator it = es.iterator();
+        while (it.hasNext()) {
+            Map.Entry entry = (Map.Entry) it.next();
+            String k = (String) entry.getKey();
+            String v = (String) entry.getValue();
+            sb.append(k + "=" + v + "&");
+            //要采用URLENCODER的原始值!
+        }
+        String params = sb.substring(0, sb.lastIndexOf("&"));
+        System.out.println("sha1之前:" + params);
+        System.out.println("SHA1签名为:"+getSha1(params));
+        return getSha1(params);
+    }
+    //Sha1签名
+    public static String getSha1(String str) {
+        if (str == null || str.length() == 0) {
+            return null;
+        }
+        char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+                'a', 'b', 'c', 'd', 'e', 'f' };
+
+        try {
+            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
+            mdTemp.update(str.getBytes(StandardCharsets.UTF_8));
+
+            byte[] md = mdTemp.digest();
+            int j = md.length;
+            char[] buf = new char[j * 2];
+            int k = 0;
+            for (int i = 0; i < j; i++) {
+                byte byte0 = md[i];
+                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
+                buf[k++] = hexDigits[byte0 & 0xf];
+            }
+            return new String(buf);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}

+ 124 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/SnowFlake.java

@@ -0,0 +1,124 @@
+package com.management.platform.util;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+
+public class SnowFlake {
+    private final static long twepoch = 12888349746579L;
+    // 机器标识位数
+    private final static long workerIdBits = 5L;
+    // 数据中心标识位数
+    private final static long datacenterIdBits = 5L;
+
+    // 毫秒内自增位数
+    private final static long sequenceBits = 12L;
+    // 机器ID偏左移12位
+    private final static long workerIdShift = sequenceBits;
+    // 数据中心ID左移17位
+    private final static long datacenterIdShift = sequenceBits + workerIdBits;
+    // 时间毫秒左移22位
+    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+    //sequence掩码,确保sequnce不会超出上限
+    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
+    //上次时间戳
+    private static long lastTimestamp = -1L;
+    //序列
+    private long sequence = 0L;
+    //服务器ID
+    private long workerId = 1L;
+    private static final long workerMask = -1L ^ (-1L << workerIdBits);
+    //进程编码
+    private long processId = 1L;
+    private static final long processMask = -1L ^ (-1L << datacenterIdBits);
+
+    private static SnowFlake snowFlake = null;
+
+    static{
+        snowFlake = new SnowFlake();
+    }
+    public static synchronized long nextId(){
+        return snowFlake.getNextId();
+    }
+
+    private SnowFlake() {
+
+        //获取机器编码
+        this.workerId=this.getMachineNum();
+        //获取进程编码
+        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
+        this.processId=Long.valueOf(runtimeMXBean.getName().split("@")[0]).longValue();
+
+        //避免编码超出最大值
+        this.workerId=workerId & workerMask;
+        this.processId=processId & processMask;
+    }
+
+    public synchronized long getNextId() {
+        //获取时间戳
+        long timestamp = timeGen();
+        //如果时间戳小于上次时间戳则报错
+        if (timestamp < lastTimestamp) {
+            try {
+                throw new Exception("Clock moved backwards.  Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        //如果时间戳与上次时间戳相同
+        if (lastTimestamp == timestamp) {
+            // 当前毫秒内,则+1,与sequenceMask确保sequence不会超出上限
+            sequence = (sequence + 1) & sequenceMask;
+            if (sequence == 0) {
+                // 当前毫秒内计数满了,则等待下一秒
+                timestamp = tilNextMillis(lastTimestamp);
+            }
+        } else {
+            sequence = 0;
+        }
+        lastTimestamp = timestamp;
+        // ID偏移组合生成最终的ID,并返回ID
+        long nextId = ((timestamp - twepoch) << timestampLeftShift) | (processId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
+        return nextId;
+    }
+
+    /**
+     * 再次获取时间戳直到获取的时间戳与现有的不同
+     * @param lastTimestamp
+     * @return 下一个时间戳
+     */
+    private long tilNextMillis(final long lastTimestamp) {
+        long timestamp = this.timeGen();
+        while (timestamp <= lastTimestamp) {
+            timestamp = this.timeGen();
+        }
+        return timestamp;
+    }
+
+    private long timeGen() {
+        return System.currentTimeMillis();
+    }
+
+    /**
+     * 获取机器编码
+     * @return
+     */
+    private long getMachineNum(){
+        long machinePiece;
+        StringBuilder sb = new StringBuilder();
+        Enumeration<NetworkInterface> e = null;
+        try {
+            e = NetworkInterface.getNetworkInterfaces();
+        } catch (SocketException e1) {
+            e1.printStackTrace();
+        }
+        while (e.hasMoreElements()) {
+            NetworkInterface ni = e.nextElement();
+            sb.append(ni.toString());
+        }
+        machinePiece = sb.toString().hashCode();
+        return machinePiece;
+    }
+}

+ 54 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/UploadFileToFileNameUtil.java

@@ -0,0 +1,54 @@
+package com.management.platform.util;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Author: 屈跃庭 cuiyi@itany.com
+ * Date : 2019 - 10 - 16 13:47
+ * Description:<描述>
+ * Version: 1.0
+ */
+public class UploadFileToFileNameUtil {
+
+    public static Map<String, Object> uploadFile(MultipartFile file, String path) {
+        Map<String,Object> map = new HashMap<String, Object>();
+        String afterUploadFileName = "";
+        if (file != null) {
+            File dir = null;
+            dir = new File(path);
+            // D://dolphin/upload 文件上传后所存储的位置,部署到服务器上时配置服务器地址即可
+            if (!dir.exists()) {
+                dir.mkdirs();
+            }
+            String fileName = "";
+            if (file != null) {
+                fileName = file.getOriginalFilename();
+                System.out.println("上传文件名称" + file.getName() + ", dir = " + dir.getAbsolutePath());
+                int pos = fileName.lastIndexOf(".");
+                String rand = UUID.randomUUID().toString().replaceAll("-", "");
+                String sufix = fileName.substring(pos);
+                fileName = rand + sufix;
+                afterUploadFileName = "/upload/" + fileName;
+                map.put("sqlFilePath",afterUploadFileName);
+                File saveFile = new File(dir, fileName);
+                try {
+                    saveFile.createNewFile();
+                    file.transferTo(saveFile);
+                    map.put("newFile",saveFile.getAbsolutePath());
+                } catch (IOException e) {
+                    e.printStackTrace();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        return map;
+    }
+}

+ 7 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/UserNotFoundException.java

@@ -0,0 +1,7 @@
+package com.management.platform.util;
+
+public class UserNotFoundException extends Exception {
+    public UserNotFoundException(String msg) {
+        super(msg);
+    }
+}

+ 194 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/util/WorkDayCalculateUtils.java

@@ -0,0 +1,194 @@
+package com.management.platform.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+public class WorkDayCalculateUtils {
+    public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+    public static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+    private static final String KEY_SPECIAL_WORK_DAYS = "work";
+    private static final String KEY_SPECIAL_REST_DAYS = "rest";
+
+    private static final HashMap<String, HashMap> YEAR_DEFINE = new HashMap<>();
+    static {
+        HashMap<String, String[]> map2019 = new HashMap<>();
+        //2019年的除了周末的特殊工作日
+        map2019.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2019-02-02","2019-02-03","2019-04-28","2019-05-05"});
+        //2019年除了周末的特殊休息日,例如国庆中秋春节
+        map2019.put(KEY_SPECIAL_REST_DAYS, new String[]{"2019-01-01",//元旦
+                "2019-02-04", "2019-02-05", "2019-02-06", "2019-02-07", "2021-02-08",//春节
+                "2019-04-05",//清明节
+                "2019-05-01","2019-05-02","2019-05-03",//劳动节
+                "2019-06-07",//端午节
+                "2019-10-01", "2019-10-02","2019-10-03","2019-10-04","2019-10-05","2019-10-06","2019-10-07",//国庆节
+                 });
+        YEAR_DEFINE.put("2019", map2019);
+
+        HashMap<String, String[]> map2020 = new HashMap<>();
+        //2020年的除了周末的特殊工作日
+        map2020.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2020-01-19","2020-04-26","2020-05-09","2020-06-28","2020-10-10"});
+        //2020年除了周末的特殊休息日,例如国庆中秋春节
+        map2020.put(KEY_SPECIAL_REST_DAYS, new String[]{"2020-01-01",//元旦
+                "2020-01-24", "2020-01-27", "2020-02-28", "2020-02-29", "2020-02-30","2020-02-31",//春节
+                "2020-04-04",//清明节
+                "2020-05-01","2020-05-02","2020-05-03","2020-05-04","2020-05-05",//劳动节
+                "2020-06-25","2020-06-26",//端午节
+                "2020-10-01", "2020-10-02","2020-10-03","2020-10-04","2020-10-05","2020-10-06","2020-10-07","2020-10-08",//国庆节
+        });
+        YEAR_DEFINE.put("2020", map2020);
+
+        HashMap<String, String[]> map2021 = new HashMap<>();
+        //除了周末的特殊工作日
+        map2021.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2021-02-07","2021-02-20","2021-04-25","2021-05-08","2021-09-18","2021-09-26","2021-10-09"});
+        //除了周末的特殊休息日,例如国庆中秋春节
+        map2021.put(KEY_SPECIAL_REST_DAYS, new String[]{
+                "2021-01-01",//元旦
+                "2021-02-11", "2021-02-12", "2021-02-15", "2021-02-16", "2021-02-17",//春节
+                "2021-04-05",//清明节
+                "2021-05-03","2021-05-04","2021-05-05",//劳动节
+                "2021-06-14",//端午节
+                "2021-09-20","2021-09-21",//中秋节
+                "2021-10-01", "2021-10-02","2021-10-03","2021-10-04","2021-10-05","2021-10-06","2021-10-07",//国庆节
+        });
+        YEAR_DEFINE.put("2021", map2021);
+
+        HashMap<String, String[]> map2022 = new HashMap<>();
+        //除了周末的特殊工作日
+        map2022.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2022-01-29","2022-01-30","2022-04-02","2022-04-24","2022-05-07","2022-10-08","2022-10-09",});
+        //除了周末的特殊休息日,例如国庆中秋春节
+        map2022.put(KEY_SPECIAL_REST_DAYS, new String[]{
+                "2022-01-03",//元旦
+                "2022-01-31", "2022-02-01", "2022-02-02", "2022-02-03", "2022-02-04",//春节
+                "2022-04-04","2022-04-05",//清明节
+                "2022-05-02","2022-05-03","2022-05-04",//劳动节
+                "2022-06-03",//端午节
+                "2022-09-20","2022-09-21",//中秋节
+                "2022-10-01", "2022-10-02","2022-10-03","2022-10-04","2022-10-05","2022-10-06","2022-10-07",//国庆节
+        });
+        YEAR_DEFINE.put("2022", map2022);
+
+//        HashMap<String, String[]> map2023 = new HashMap<>();
+//        //除了周末的特殊工作日
+//        map2023.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2022-01-29","2022-01-30","2022-04-02","2022-04-24","2022-05-07","2022-10-08","2022-10-09",});
+//        //除了周末的特殊休息日,例如国庆中秋春节
+//        map2023.put(KEY_SPECIAL_REST_DAYS, new String[]{
+//                "2022-01-03",//元旦
+//                "2022-01-31", "2022-02-01", "2022-02-02", "2022-02-03", "2022-02-04",//春节
+//                "2022-04-04","2022-04-05",//清明节
+//                "2022-05-02","2022-05-03","2022-05-04",//劳动节
+//                "2022-06-03",//端午节
+//                "2022-09-20","2022-09-21",//中秋节
+//                "2022-10-01", "2022-10-02","2022-10-03","2022-10-04","2022-10-05","2022-10-06","2022-10-07",//国庆节
+//        });
+//        YEAR_DEFINE.put("2023", map2023);
+
+    }
+
+    /**
+     * 计算给定时间范围内的工作日列表
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    public static List<LocalDate> getWorkDaysListInRange(String startDate, String endDate) {
+        int daysOffset = 0;
+        LocalDate localStartDate = LocalDate.parse(startDate, dateTimeFormatter);
+        LocalDate localEndDate = LocalDate.parse(endDate, dateTimeFormatter);
+        List<LocalDate> list = new ArrayList<>();
+        while(true) {
+            localStartDate = localStartDate.plusDays(daysOffset);
+            if (isWorkDay(localStartDate)) {
+                list.add(localStartDate);
+            }
+            //到达结束日期,结束计算
+            if (localStartDate.isEqual(localEndDate)) {
+                break;
+            }
+            //每次加一天
+            if (daysOffset == 0) {
+                daysOffset = 1;
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 计算给定时间范围内的工作日天数
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    public static int getWorkDaysCountInRange(String startDate, String endDate) {
+        int daysOffset = 0;
+        LocalDate localStartDate = LocalDate.parse(startDate, dateTimeFormatter);
+        LocalDate localEndDate = LocalDate.parse(endDate, dateTimeFormatter);
+        int count = 0;
+        while(true) {
+            localStartDate = localStartDate.plusDays(daysOffset);
+            if (isWorkDay(localStartDate)) {
+                count++;
+            }
+            //到达结束日期,结束计算
+            if (localStartDate.isEqual(localEndDate)) {
+                break;
+            }
+            //每次加一天
+            if (daysOffset == 0) {
+                daysOffset = 1;
+            }
+        }
+        return count;
+    }
+
+    private static boolean isInArray(String key, String[] array) {
+        for (int i=0;i<array.length; i++) {
+            if (array[i].equals(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isWorkDay(LocalDate date) {
+        int year = date.getYear();
+        try {
+            String dateStr = dateTimeFormatter.format(date);
+            Date d = simpleDateFormat.parse(dateStr);
+            boolean isWeekend = date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY;
+            if (isWeekend) {
+                //判断周末是否是特殊工作日
+                HashMap<String, String[]> map = YEAR_DEFINE.get(year + "");
+                if (map == null) {
+                    //特殊日期年份尚未录入,周末不算是工作日
+                    return false;
+                }
+                String[] list = map.get(KEY_SPECIAL_WORK_DAYS);
+                //存在特殊工作日
+                return isInArray(dateStr, list);
+            } else {
+                //判断常规周一到周五,是否是特殊节假日
+                HashMap<String, String[]> map = YEAR_DEFINE.get(year+"");
+                if (map == null) {
+                    //特殊日期年份尚未录入,工作日正常上班
+                    return true;
+                }
+                String[] list = map.get(KEY_SPECIAL_REST_DAYS);
+                return !isInArray(dateStr, list);
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+            System.out.println(e.getMessage());
+        }
+        return true;
+    }
+
+
+    public static void main(String[] args) {
+        System.out.println(getWorkDaysCountInRange("2019-01-01","2019-12-31"));
+    }
+}

+ 59 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/AesException.java

@@ -0,0 +1,59 @@
+package com.qq.weixin.mp.aes;
+
+@SuppressWarnings("serial")
+public class AesException extends Exception {
+
+	public final static int OK = 0;
+	public final static int ValidateSignatureError = -40001;
+	public final static int ParseXmlError = -40002;
+	public final static int ComputeSignatureError = -40003;
+	public final static int IllegalAesKey = -40004;
+	public final static int ValidateCorpidError = -40005;
+	public final static int EncryptAESError = -40006;
+	public final static int DecryptAESError = -40007;
+	public final static int IllegalBuffer = -40008;
+	//public final static int EncodeBase64Error = -40009;
+	//public final static int DecodeBase64Error = -40010;
+	//public final static int GenReturnXmlError = -40011;
+
+	private final int code;
+
+	private static String getMessage(int code) {
+		switch (code) {
+			case ValidateSignatureError:
+				return "签名验证错误";
+			case ParseXmlError:
+				return "xml解析失败";
+			case ComputeSignatureError:
+				return "sha加密生成签名失败";
+			case IllegalAesKey:
+				return "SymmetricKey非法";
+			case ValidateCorpidError:
+				return "corpid校验失败";
+			case EncryptAESError:
+				return "aes加密失败";
+			case DecryptAESError:
+				return "aes解密失败";
+			case IllegalBuffer:
+				return "解密后得到的buffer非法";
+//		case EncodeBase64Error:
+//			return "base64加密错误";
+//		case DecodeBase64Error:
+//			return "base64解密错误";
+//		case GenReturnXmlError:
+//			return "xml生成失败";
+			default:
+				return null; // cannot be
+		}
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	AesException(int code) {
+		super(getMessage(code));
+		this.code = code;
+	}
+
+}

+ 26 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/ByteGroup.java

@@ -0,0 +1,26 @@
+package com.qq.weixin.mp.aes;
+
+import java.util.ArrayList;
+
+class ByteGroup {
+	ArrayList<Byte> byteContainer = new ArrayList<Byte>();
+
+	public byte[] toBytes() {
+		byte[] bytes = new byte[byteContainer.size()];
+		for (int i = 0; i < byteContainer.size(); i++) {
+			bytes[i] = byteContainer.get(i);
+		}
+		return bytes;
+	}
+
+	public ByteGroup addBytes(byte[] bytes) {
+		for (byte b : bytes) {
+			byteContainer.add(b);
+		}
+		return this;
+	}
+
+	public int size() {
+		return byteContainer.size();
+	}
+}

+ 68 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/PKCS7Encoder.java

@@ -0,0 +1,68 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.qq.weixin.mp.aes;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * 提供基于PKCS7算法的加解密接口.
+ */
+class PKCS7Encoder {
+	static Charset CHARSET = StandardCharsets.UTF_8;
+	static int BLOCK_SIZE = 32;
+
+	/**
+	 * 获得对明文进行补位填充的字节.
+	 * 
+	 * @param count 需要进行填充补位操作的明文字节个数
+	 * @return 补齐用的字节数组
+	 */
+	static byte[] encode(int count) {
+		// 计算需要填充的位数
+		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
+		if (amountToPad == 0) {
+			amountToPad = BLOCK_SIZE;
+		}
+		// 获得补位所用的字符
+		char padChr = chr(amountToPad);
+		String tmp = "";
+		for (int index = 0; index < amountToPad; index++) {
+			tmp += padChr;
+		}
+		return tmp.getBytes(CHARSET);
+	}
+
+	/**
+	 * 删除解密后明文的补位字符
+	 * 
+	 * @param decrypted 解密后的明文
+	 * @return 删除补位字符后的明文
+	 */
+	static byte[] decode(byte[] decrypted) {
+		int pad = decrypted[decrypted.length - 1];
+		if (pad < 1 || pad > 32) {
+			pad = 0;
+		}
+		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+	}
+
+	/**
+	 * 将数字转化成ASCII码对应的字符,用于对明文进行补码
+	 * 
+	 * @param a 需要转化的数字
+	 * @return 转化得到的字符
+	 */
+	static char chr(int a) {
+		byte target = (byte) (a & 0xFF);
+		return (char) target;
+	}
+
+}

+ 61 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/SHA1.java

@@ -0,0 +1,61 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.qq.weixin.mp.aes;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+/**
+ * SHA1 class
+ *
+ * 计算消息签名接口.
+ */
+class SHA1 {
+
+	/**
+	 * 用SHA1算法生成安全签名
+	 * @param token 票据
+	 * @param timestamp 时间戳
+	 * @param nonce 随机字符串
+	 * @param encrypt 密文
+	 * @return 安全签名
+	 * @throws AesException 
+	 */
+	public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
+			  {
+		try {
+			String[] array = new String[] { token, timestamp, nonce, encrypt };
+			StringBuffer sb = new StringBuffer();
+			// 字符串排序
+			Arrays.sort(array);
+			for (int i = 0; i < 4; i++) {
+				sb.append(array[i]);
+			}
+			String str = sb.toString();
+			// SHA1签名生成
+			MessageDigest md = MessageDigest.getInstance("SHA-1");
+			md.update(str.getBytes());
+			byte[] digest = md.digest();
+
+			StringBuffer hexstr = new StringBuffer();
+			String shaHex = "";
+			for (int i = 0; i < digest.length; i++) {
+				shaHex = Integer.toHexString(digest[i] & 0xFF);
+				if (shaHex.length() < 2) {
+					hexstr.append(0);
+				}
+				hexstr.append(shaHex);
+			}
+			return hexstr.toString();
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.ComputeSignatureError);
+		}
+	}
+}

+ 290 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/WXBizMsgCrypt.java

@@ -0,0 +1,290 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * 针对org.apache.commons.codec.binary.Base64,
+ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
+ * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
+ */
+package com.qq.weixin.mp.aes;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * 提供接收和推送给企业微信消息的加解密接口(UTF8编码的字符串).
+ * <ol>
+ * 	<li>第三方回复加密消息给企业微信</li>
+ * 	<li>第三方收到企业微信发送的消息,验证消息的安全性,并对消息进行解密。</li>
+ * </ol>
+ * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
+ * <ol>
+ * 	<li>在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
+ *      http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>
+ * 	<li>下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt</li>
+ * 	<li>如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件</li>
+ * 	<li>如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件</li>
+ * </ol>
+ */
+public class WXBizMsgCrypt {
+	static Charset CHARSET = StandardCharsets.UTF_8;
+	Base64 base64 = new Base64();
+	byte[] aesKey;
+	String token;
+	String receiveid;
+
+	/**
+	 * 构造函数
+	 * @param token 企业微信后台,开发者设置的token
+	 * @param encodingAesKey 企业微信后台,开发者设置的EncodingAESKey
+	 * @param receiveid, 不同场景含义不同,详见文档
+	 * 
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public WXBizMsgCrypt(String token, String encodingAesKey, String receiveid) throws AesException {
+		if (encodingAesKey.length() != 43) {
+			throw new AesException(AesException.IllegalAesKey);
+		}
+
+		this.token = token;
+		this.receiveid = receiveid;
+		aesKey = Base64.decodeBase64(encodingAesKey + "=");
+	}
+
+	// 生成4个字节的网络字节序
+	byte[] getNetworkBytesOrder(int sourceNumber) {
+		byte[] orderBytes = new byte[4];
+		orderBytes[3] = (byte) (sourceNumber & 0xFF);
+		orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
+		orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
+		orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
+		return orderBytes;
+	}
+
+	// 还原4个字节的网络字节序
+	int recoverNetworkBytesOrder(byte[] orderBytes) {
+		int sourceNumber = 0;
+		for (int i = 0; i < 4; i++) {
+			sourceNumber <<= 8;
+			sourceNumber |= orderBytes[i] & 0xff;
+		}
+		return sourceNumber;
+	}
+
+	// 随机生成16位字符串
+	String getRandomStr() {
+		String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+		Random random = new Random();
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0; i < 16; i++) {
+			int number = random.nextInt(base.length());
+			sb.append(base.charAt(number));
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 对明文进行加密.
+	 * 
+	 * @param text 需要加密的明文
+	 * @return 加密后base64编码的字符串
+	 * @throws AesException aes加密失败
+	 */
+	String encrypt(String randomStr, String text) throws AesException {
+		ByteGroup byteCollector = new ByteGroup();
+		byte[] randomStrBytes = randomStr.getBytes(CHARSET);
+		byte[] textBytes = text.getBytes(CHARSET);
+		byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
+		byte[] receiveidBytes = receiveid.getBytes(CHARSET);
+
+		// randomStr + networkBytesOrder + text + receiveid
+		byteCollector.addBytes(randomStrBytes);
+		byteCollector.addBytes(networkBytesOrder);
+		byteCollector.addBytes(textBytes);
+		byteCollector.addBytes(receiveidBytes);
+
+		// ... + pad: 使用自定义的填充方式对明文进行补位填充
+		byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
+		byteCollector.addBytes(padBytes);
+
+		// 获得最终的字节流, 未加密
+		byte[] unencrypted = byteCollector.toBytes();
+
+		try {
+			// 设置加密模式为AES的CBC模式
+			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+			SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+			IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+			cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+
+			// 加密
+			byte[] encrypted = cipher.doFinal(unencrypted);
+
+			// 使用BASE64对加密后的字符串进行编码
+			String base64Encrypted = base64.encodeToString(encrypted);
+
+			return base64Encrypted;
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.EncryptAESError);
+		}
+	}
+
+	/**
+	 * 对密文进行解密.
+	 * 
+	 * @param text 需要解密的密文
+	 * @return 解密得到的明文
+	 * @throws AesException aes解密失败
+	 */
+	String decrypt(String text) throws AesException {
+		byte[] original;
+		try {
+			// 设置解密模式为AES的CBC模式
+			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+			SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
+			IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
+			cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
+
+			// 使用BASE64对密文进行解码
+			byte[] encrypted = Base64.decodeBase64(text);
+
+			// 解密
+			original = cipher.doFinal(encrypted);
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.DecryptAESError);
+		}
+
+		String xmlContent, from_receiveid;
+		try {
+			// 去除补位字符
+			byte[] bytes = PKCS7Encoder.decode(original);
+
+			// 分离16位随机字符串,网络字节序和receiveid
+			byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
+
+			int xmlLength = recoverNetworkBytesOrder(networkOrder);
+
+			xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
+			from_receiveid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
+					CHARSET);
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.IllegalBuffer);
+		}
+
+		// receiveid不相同的情况
+		if (!from_receiveid.equals(receiveid)) {
+			throw new AesException(AesException.ValidateCorpidError);
+		}
+		return xmlContent;
+
+	}
+
+	/**
+	 * 将企业微信回复用户的消息加密打包.
+	 * <ol>
+	 * 	<li>对要发送的消息进行AES-CBC加密</li>
+	 * 	<li>生成安全签名</li>
+	 * 	<li>将消息密文和安全签名打包成xml格式</li>
+	 * </ol>
+	 * 
+	 * @param replyMsg 企业微信待回复用户的消息,xml格式的字符串
+	 * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp
+	 * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce
+	 * 
+	 * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
+		// 加密
+		String encrypt = encrypt(getRandomStr(), replyMsg);
+
+		// 生成安全签名
+		if (timeStamp == "") {
+			timeStamp = Long.toString(System.currentTimeMillis());
+		}
+
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
+
+		// System.out.println("发送给平台的签名是: " + signature[1].toString());
+		// 生成发送的xml
+		String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
+		return result;
+	}
+
+	/**
+	 * 检验消息的真实性,并且获取解密后的明文.
+	 * <ol>
+	 * 	<li>利用收到的密文生成安全签名,进行签名验证</li>
+	 * 	<li>若验证通过,则提取xml中的加密消息</li>
+	 * 	<li>对消息进行解密</li>
+	 * </ol>
+	 * 
+	 * @param msgSignature 签名串,对应URL参数的msg_signature
+	 * @param timeStamp 时间戳,对应URL参数的timestamp
+	 * @param nonce 随机串,对应URL参数的nonce
+	 * @param postData 密文,对应POST请求的数据
+	 * 
+	 * @return 解密后的原文
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
+			throws AesException {
+
+		// 密钥,公众账号的app secret
+		// 提取密文
+		Object[] encrypt = XMLParse.extract(postData);
+
+		// 验证安全签名
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
+
+		// 和URL中的签名比较是否相等
+		 System.out.println("第三方收到URL中的签名:" + msgSignature);
+		 System.out.println("第三方校验签名:" + signature);
+		if (!signature.equals(msgSignature)) {
+			throw new AesException(AesException.ValidateSignatureError);
+		}
+
+		// 解密
+		String result = decrypt(encrypt[1].toString());
+		return result;
+	}
+
+	/**
+	 * 验证URL
+	 * @param msgSignature 签名串,对应URL参数的msg_signature
+	 * @param timeStamp 时间戳,对应URL参数的timestamp
+	 * @param nonce 随机串,对应URL参数的nonce
+	 * @param echoStr 随机串,对应URL参数的echostr
+	 * 
+	 * @return 解密之后的echostr
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
+			throws AesException {
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
+
+		if (!signature.equals(msgSignature)) {
+			throw new AesException(AesException.ValidateSignatureError);
+		}
+
+		String result = decrypt(echoStr);
+		return result;
+	}
+
+}

+ 106 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/qq/weixin/mp/aes/XMLParse.java

@@ -0,0 +1,106 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.qq.weixin.mp.aes;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * XMLParse class
+ *
+ * 提供提取消息格式中的密文及生成回复消息格式的接口.
+ */
+class XMLParse {
+
+	/**
+	 * 提取出xml数据包中的加密消息
+	 * @param xmltext 待提取的xml字符串
+	 * @return 提取出的加密消息字符串
+	 * @throws AesException 
+	 */
+	public static Object[] extract(String xmltext) throws AesException     {
+		Object[] result = new Object[3];
+		try {
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			
+			String FEATURE = null;
+			// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
+			// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
+			FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
+			dbf.setFeature(FEATURE, true);
+			
+			// If you can't completely disable DTDs, then at least do the following:
+			// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
+			// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
+			// JDK7+ - http://xml.org/sax/features/external-general-entities 
+			FEATURE = "http://xml.org/sax/features/external-general-entities";
+			dbf.setFeature(FEATURE, false);
+			
+			// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
+			// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
+			// JDK7+ - http://xml.org/sax/features/external-parameter-entities 
+			FEATURE = "http://xml.org/sax/features/external-parameter-entities";
+			dbf.setFeature(FEATURE, false);
+			
+			// Disable external DTDs as well
+			FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+			dbf.setFeature(FEATURE, false);
+			
+			// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
+			dbf.setXIncludeAware(false);
+			dbf.setExpandEntityReferences(false);
+			
+			// And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then 
+			// ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
+			// (http://cwe.mitre.org/data/definitions/918.html) and denial 
+			// of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."
+			
+			// remaining parser logic
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			StringReader sr = new StringReader(xmltext);
+			InputSource is = new InputSource(sr);
+			Document document = db.parse(is);
+
+			Element root = document.getDocumentElement();
+			NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+			NodeList nodelist2 = root.getElementsByTagName("ToUserName");
+			result[0] = 0;
+			result[1] = nodelist1.item(0).getTextContent();
+			result[2] = nodelist2.item(0).getTextContent();
+			return result;
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.ParseXmlError);
+		}
+	}
+
+	/**
+	 * 生成xml消息
+	 * @param encrypt 加密后的消息密文
+	 * @param signature 安全签名
+	 * @param timestamp 时间戳
+	 * @param nonce 随机字符串
+	 * @return 生成的xml字符串
+	 */
+	public static String generate(String encrypt, String signature, String timestamp, String nonce) {
+
+		String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
+				+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
+				+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" + "</xml>";
+		return String.format(format, encrypt, signature, timestamp, nonce);
+
+	}
+}

+ 99 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/application-dev.yml

@@ -0,0 +1,99 @@
+server:
+  port: 10018
+  tomcat:
+    uri-encoding: utf-8
+    max-http-form-post-size: -1
+    connection-timeout: 18000000s
+spring:
+  servlet:
+    multipart:
+      # 配置上传文件的大小设置
+      # Single file max size  即单个文件大小
+      max-file-size: 100MB
+      max-request-size: 100MB
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://1.94.62.58:17089/man_dev?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
+    username: root
+    password: P011430@Huoshi*
+    hikari:
+      maximum-pool-size: 10
+      minimum-idle: 3
+      max-lifetime: 30000
+      connection-test-query: SELECT 1
+    #######redis配置######
+    # redis
+    redis:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 3
+      # password:
+      pool:
+        minIdle: 1
+        maxIdle: 10
+        maxWait: 3
+        maxActive: 8
+    ####全局配置时间返回格式#####
+  jackson:
+    #参数意义:
+    #JsonInclude.Include.ALWAYS       默认
+    #JsonInclude.Include.NON_DEFAULT   属性为默认值不序列化
+    #JsonInclude.Include.NON_EMPTY     属性为 空(””) 或者为 NULL 都不序列化
+    #JsonInclude.Include.NON_NULL      属性为NULL  不序列化
+    default-property-inclusion: ALWAYS
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+
+##########日志配置
+logging:
+  level:
+    root: info
+    org.mybatis: error
+    java.sql: error
+    org.springframework.web: error
+    #打印sql语句
+    com.management.platform.mapper: error
+  path: /log/
+  file: octopus.log
+##########
+mybatis-plus:
+  #  mapper-locations: classpath:mapper/*/*.xml
+  #  #实体扫描,多个package用逗号或者分号分隔
+  #  typeAliasesPackage: com.hssx.cloudmodel
+  global-config:
+    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
+    id-type: 0
+    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
+    field-strategy: 2
+    db-column-underline: true
+    refresh-mapper:
+    #################插入和更新非null判断
+    db-config:
+      insert-strategy: not_null
+      update-strategy: not_null
+  configuration:
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+######mybstis配置#######
+mybatis:
+  type-aliases-package: com.management.platform.entity
+  mapper-locations: mappers/*Mapper.xml
+#####配置图片上传路径####
+upload:
+  path: /www/staticproject/courseManager/upload/
+logDownLoad:
+  path: /www/webapps/worktime/wt_print.log
+##actuator健康检查配置
+management:
+  security:
+    enabled:false:
+  server:
+    port: 10019
+  #  endpoints:
+  #    web:
+  #      exposure:
+  #        include: "*"
+
+  health:
+    redis:
+      enabled: false

+ 100 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/application-prod.yml

@@ -0,0 +1,100 @@
+server:
+  port: 10018
+  tomcat:
+    uri-encoding: utf-8
+    max-http-form-post-size: -1
+    connection-timeout: 18000000s
+spring:
+  servlet:
+    multipart:
+      # 配置上传文件的大小设置
+      # Single file max size  即单个文件大小
+      max-file-size: 100MB
+      max-request-size: 100MB
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://localhost:3306/man_xin?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
+    username: root
+    password: 123456
+    hikari:
+      maximum-pool-size: 10
+      minimum-idle: 3
+      max-lifetime: 30000
+      connection-test-query: SELECT 1
+    #######redis配置######
+    # redis
+    redis:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 3
+      # password:
+      pool:
+        minIdle: 1
+        maxIdle: 10
+        maxWait: 3
+        maxActive: 8
+    ####全局配置时间返回格式#####
+  jackson:
+    #参数意义:
+    #JsonInclude.Include.ALWAYS       默认
+    #JsonInclude.Include.NON_DEFAULT   属性为默认值不序列化
+    #JsonInclude.Include.NON_EMPTY     属性为 空(””) 或者为 NULL 都不序列化
+    #JsonInclude.Include.NON_NULL      属性为NULL  不序列化
+    default-property-inclusion: ALWAYS
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+
+##########日志配置
+logging:
+  level:
+    root: info
+    org.mybatis: error
+    java.sql: error
+    org.springframework.web: error
+    #打印sql语句
+    com.management.platform.mapper: error
+  path: /log/
+  file: octopus.log
+##########
+mybatis-plus:
+  #  mapper-locations: classpath:mapper/*/*.xml
+  #  #实体扫描,多个package用逗号或者分号分隔
+  #  typeAliasesPackage: com.hssx.cloudmodel
+  global-config:
+    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
+    id-type: 0
+    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
+    field-strategy: 2
+    db-column-underline: true
+    refresh-mapper:
+    #################插入和更新非null判断
+    db-config:
+      insert-strategy: not_null
+      update-strategy: not_null
+  configuration:
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+######mybstis配置#######
+mybatis:
+  type-aliases-package: com.management.platform.entity
+  mapper-locations: mappers/*Mapper.xml
+#####配置图片上传路径####
+upload:
+  path: /www/staticproject/octopus_vue/upload/
+
+logDownLoad:
+  path: /www/webapps/worktime/wt_print.log
+##actuator健康检查配置
+management:
+  security:
+    enabled:false:
+  server:
+    port: 10019
+  #  endpoints:
+  #    web:
+  #      exposure:
+  #        include: "*"
+
+  health:
+    redis:
+      enabled: false

+ 105 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/application.yml

@@ -0,0 +1,105 @@
+server:
+  port: 10030
+  tomcat:
+    uri-encoding: utf-8
+    max-http-form-post-size: -1
+    connection-timeout: 18000000s
+spring:
+  servlet:
+    multipart:
+      # 配置上传文件的大小设置
+      # Single file max size  即单个文件大小
+      max-file-size: 100MB
+      max-request-size: 100MB
+      location: C:/upload/
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://1.94.62.58:17089/course_manager?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
+    username: root
+    password: P011430@Huoshi*
+    hikari:
+      maximum-pool-size: 10
+      minimum-idle: 3
+      max-lifetime: 30000
+      connection-test-query: SELECT 1
+  #######redis配置######
+    # redis
+  ####全局配置时间返回格式#####
+  jackson:
+    #参数意义:
+    #JsonInclude.Include.ALWAYS       默认
+    #JsonInclude.Include.NON_DEFAULT   属性为默认值不序列化
+    #JsonInclude.Include.NON_EMPTY     属性为 空(””) 或者为 NULL 都不序列化
+    #JsonInclude.Include.NON_NULL      属性为NULL  不序列化
+    default-property-inclusion: ALWAYS
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+
+##########日志配置
+logging:
+  level:
+    root: info
+    org.mybatis: debug
+    java.sql: debug
+    org.springframework.web: trace
+    #打印sql语句
+    com.management.platform.mapper: debug
+  path: C:/
+##########
+mybatis-plus:
+#  mapper-locations: classpath:mapper/*/*.xml
+#  #实体扫描,多个package用逗号或者分号分隔
+#  typeAliasesPackage: com.hssx.cloudmodel
+  global-config:
+    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
+    id-type: 0
+    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
+    field-strategy: 2
+    db-column-underline: true
+    refresh-mapper:
+#################插入和更新非null判断
+    db-config:
+      insert-strategy: not_null
+      update-strategy: not_null
+  configuration:
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+######mybstis配置#######
+mybatis:
+  type-aliases-package: com.management.platform.entity
+  mapper-locations: mappers/*Mapper.xml
+#####配置图片上传路径####
+upload:
+  path: C:/upload/
+
+logDownLoad:
+  path: C:/upload/wt_print.log
+
+##actuator健康检查配置
+management:
+  security:
+    enabled:false:
+  server:
+    port: 10019
+#  endpoints:
+#    web:
+#      exposure:
+#        include: "*"
+
+  health:
+    redis:
+      enabled: false
+
+referer:
+  refererDomain:
+    - localhost
+    - ttkuaiban.com
+    - ops.ttkuaiban.com
+    - 47.101.180.183
+    - mldworktime.ttkuaiban.com
+excludeUrls: /wxcorp/*,/wxcorp/*/*,/dingding/*,/error,/testClient,/corpWXAuth,/wx-corp-info/*,/clean/*,/innerRoles/*,/operation-record/*
+syncDDMembUrl: http://worktime.ttkuaiban.com/api/dingding/syncCorpMembs
+
+
+
+

BIN
fhKeeper/formulahousekeeper/course-manager/src/main/resources/lib/jodconverter-core-3.0.jar


BIN
fhKeeper/formulahousekeeper/course-manager/src/main/resources/lib/taobao-sdk-java-auto_1479188381469-20210623.jar


+ 92 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/logback.xml

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 ./表示当前运行目录-->
+	<property name="log.path" value="./" />
+    <!-- 日志输出格式 -->
+	<property name="log.pattern" value="%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+	<!-- 控制台输出 -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+	</appender>
+	
+	<!-- 系统日志输出 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/courseManager.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/octopus.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
+			<!-- 日志最大的历史 7天 -->
+			<maxHistory>7</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+<!--	<filter class="ch.qos.logback.classic.filter.LevelFilter">
+            &lt;!&ndash; 过滤的级别 &ndash;&gt;
+            <level>DEBUG</level>
+            &lt;!&ndash; 匹配时的操作:接收(记录) &ndash;&gt;
+            <onMatch>ACCEPT</onMatch>
+            &lt;!&ndash; 不匹配时的操作:拒绝(不记录) &ndash;&gt;
+            <onMismatch>DENY</onMismatch>
+        </filter>-->
+	</appender>
+	
+	<!--<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-error.log</file>
+        &lt;!&ndash; 循环政策:基于时间创建日志文件 &ndash;&gt;
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            &lt;!&ndash; 日志文件名格式 &ndash;&gt;
+            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			&lt;!&ndash; 日志最大的历史 60天 &ndash;&gt;
+			<maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            &lt;!&ndash; 过滤的级别 &ndash;&gt;
+            <level>DEBUG</level>
+			&lt;!&ndash; 匹配时的操作:接收(记录) &ndash;&gt;
+            <onMatch>ACCEPT</onMatch>
+			&lt;!&ndash; 不匹配时的操作:拒绝(不记录) &ndash;&gt;
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>-->
+	
+	<!-- 用户访问日志输出  -->
+    <!--<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            &lt;!&ndash; 按天回滚 daily &ndash;&gt;
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            &lt;!&ndash; 日志最大的历史 60天 &ndash;&gt;
+            <maxHistory>2</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>-->
+	
+	<!-- 系统模块日志级别控制  -->
+	<logger name="com.management.platform.mapper" level="debug" />
+	<!-- Spring日志级别控制  -->
+	<logger name="org.springframework" level="warn" />
+
+	<root level="info">
+		<appender-ref ref="console" />
+	</root>
+	
+	<!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+    </root>
+	
+	<!--系统用户操作日志-->
+    <!--<logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>-->
+</configuration> 

+ 36 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/CompanyMapper.xml

@@ -0,0 +1,36 @@
+<?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.management.platform.mapper.CompanyMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.Company">
+        <id column="id" property="id" />
+        <result column="company_name" property="companyName" />
+        <result column="staff_count_max" property="staffCountMax" />
+        <result column="expiration_date" property="expirationDate" />
+        <result column="set_meal" property="setMeal" />
+        <result column="package_worktime" property="packageWorktime" />
+        <result column="package_project" property="packageProject" />
+        <result column="package_contract" property="packageContract" />
+        <result column="package_oa" property="packageOa" />
+        <result column="package_etimecard" property="packageEtimecard" />
+        <result column="package_expense" property="packageExpense" />
+        <result column="package_customer" property="packageCustomer" />
+        <result column="package_engineering" property="packageEngineering" />
+        <result column="package_simple" property="packageSimple" />
+        <result column="package_finance" property="packageFinance" />
+        <result column="package_provider" property="packageProvider" />
+        <result column="package_project_approval" property="packageProjectApproval" />
+        <result column="package_device" property="packageDevice" />
+        <result column="is_international" property="isInternational" />
+        <result column="create_date" property="createDate" />
+        <result column="reg_from" property="regFrom" />
+        <result column="non_project_simple" property="nonProjectSimple" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, company_name, staff_count_max, expiration_date, set_meal, package_worktime, package_project, package_contract, package_oa, package_etimecard, package_expense, package_customer, package_engineering, package_simple, package_finance, package_provider, package_project_approval, package_device, is_international, create_date, reg_from, non_project_simple
+    </sql>
+
+</mapper>

+ 25 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/CourseInfoMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.CourseInfoMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.CourseInfo">
+        <id column="id" property="id" />
+        <result column="course_name" property="courseName" />
+        <result column="course_desc" property="courseDesc" />
+        <result column="course_instructor" property="courseInstructor" />
+        <result column="course_price" property="coursePrice" />
+        <result column="course_status" property="courseStatus" />
+        <result column="instructor_type" property="instructorType" />
+        <result column="instructor_img" property="instructorImg" />
+        <result column="instructor_desc" property="instructorDesc" />
+        <result column="create_date" property="createDate" />
+        <result column="company_id" property="companyId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, course_name, course_desc, course_instructor, course_price, course_status, instructor_type, instructor_img, instructor_desc, create_date, company_id
+    </sql>
+
+</mapper>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 58 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/UserMapper.xml


BIN
fhKeeper/formulahousekeeper/course-manager/src/main/resources/新模板.docx


BIN
fhKeeper/formulahousekeeper/course-manager/src/main/resources/模板.docx