Browse Source

first commit

liyan 3 years ago
parent
commit
ead3ccaad1
66 changed files with 2851 additions and 0 deletions
  1. 73 0
      apps/svs-all-in-one/build.gradle.kts
  2. 10 0
      apps/svs-all-in-one/script/start.sh
  3. 11 0
      apps/svs-all-in-one/script/stop.sh
  4. 1 0
      apps/svs-all-in-one/script/version
  5. 46 0
      apps/svs-all-in-one/src/main/kotlin/llh/svs/allinone/AllInOneApplication.kt
  6. 27 0
      apps/svs-all-in-one/src/main/kotlin/llh/svs/allinone/StatusControllerAdvice.kt
  7. 47 0
      apps/svs-all-in-one/src/main/kotlin/llh/svs/allinone/bean/FactoryBean.kt
  8. 17 0
      apps/svs-all-in-one/src/main/resources/application-mysql.yml
  9. 104 0
      apps/svs-all-in-one/src/main/resources/application-routes.yml
  10. 5 0
      apps/svs-all-in-one/src/main/resources/application-service.yml
  11. 60 0
      apps/svs-all-in-one/src/main/resources/application.yml
  12. 25 0
      apps/svs-all-in-one/src/main/resources/logback-spring.xml
  13. 386 0
      apps/svs-all-in-one/src/main/resources/menu/items-full.json
  14. 134 0
      apps/svs-all-in-one/src/main/resources/menu/items-lite.json
  15. 22 0
      apps/svs-all-in-one/src/main/resources/menu/menus.json
  16. 54 0
      apps/svs-init/build.gradle.kts
  17. 1 0
      apps/svs-init/script/init.sh
  18. 1 0
      apps/svs-init/script/version
  19. 21 0
      apps/svs-init/src/main/kotlin/llh/svs/allinone/SvsInitApplication.kt
  20. 26 0
      apps/svs-init/src/main/resources/application-mysql.yml
  21. 32 0
      apps/svs-init/src/main/resources/application.yml
  22. 8 0
      apps/svs-init/src/main/resources/sql/mysql/data.sql
  23. 3 0
      apps/svs-init/src/main/resources/sql/mysql/dict.sql
  24. 127 0
      apps/svs-init/src/main/resources/sql/mysql/schema-gaf.sql
  25. 19 0
      apps/svs-init/src/main/resources/sql/mysql/schema-svs.sql
  26. 43 0
      apps/svs-init/src/main/resources/sql/mysql/trigger-gaf.sql
  27. 81 0
      build.gradle.kts
  28. 12 0
      gradle.properties
  29. BIN
      gradle/wrapper/gradle-wrapper.jar
  30. 5 0
      gradle/wrapper/gradle-wrapper.properties
  31. 234 0
      gradlew
  32. 89 0
      gradlew.bat
  33. 26 0
      platform/build.gradle.kts
  34. 123 0
      services/build.gradle.kts
  35. 68 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/DBBackupController.kt
  36. 11 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/SysApplication.kt
  37. 55 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/SysConfigController.kt
  38. 9 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/SystemConfig.kt
  39. 19 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/SystemConfiguration.kt
  40. 28 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/SystemResController.kt
  41. 6 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/AutoBackupStatus.kt
  42. 6 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/BackupFileResult.kt
  43. 5 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/ServerDate.kt
  44. 15 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/SystemResInfo.kt
  45. 180 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/service/DBBackupService.kt
  46. 57 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/service/ServerConfigService.kt
  47. 23 0
      services/service-system/src/main/kotlin/llh/svs/core/services/sys/service/ServerResService.kt
  48. 5 0
      services/service-system/src/main/resources/application-service.yml
  49. 11 0
      services/service-task/src/main/kotlin/llh/svs/core/services/task/TaskApplication.kt
  50. 42 0
      services/service-task/src/main/kotlin/llh/svs/core/services/task/TaskController.kt
  51. 7 0
      services/service-task/src/main/kotlin/llh/svs/core/services/task/dao/SvsTaskLogDAO.kt
  52. 83 0
      services/service-task/src/main/kotlin/llh/svs/core/services/task/entity/SvsTaskLog.kt
  53. 88 0
      services/service-task/src/main/kotlin/llh/svs/core/services/task/service/SvsTaskLogService.kt
  54. 9 0
      services/service-task/src/main/kotlin/llh/svs/core/services/task/support/TaskStatus.kt
  55. 7 0
      services/service-task/src/main/kotlin/llh/svs/core/services/task/support/TaskType.kt
  56. 5 0
      settings.gradle.kts
  57. 67 0
      shared/build.gradle.kts
  58. 41 0
      shared/src/main/kotlin/llh/svs/core/util/FileDealTool.kt
  59. 38 0
      shared/src/main/kotlin/llh/svs/core/util/LinuxCmdExecutor.kt
  60. 59 0
      shared/src/main/kotlin/llh/svs/core/util/SysHWInfoUtil.kt
  61. 3 0
      shared/src/main/kotlin/llh/svs/core/util/domain/CpuInfo.kt
  62. 3 0
      shared/src/main/kotlin/llh/svs/core/util/domain/DiskInfo.kt
  63. 3 0
      shared/src/main/kotlin/llh/svs/core/util/domain/MemInfo.kt
  64. 11 0
      src/main/kotlin/com/llh/svscore/SvsCoreApplication.kt
  65. 1 0
      src/main/resources/application.properties
  66. 13 0
      src/test/kotlin/com/llh/svscore/SvsCoreApplicationTests.kt

+ 73 - 0
apps/svs-all-in-one/build.gradle.kts

@@ -0,0 +1,73 @@
+group = "llh.svs"
+version = rootProject.version
+
+plugins {
+    id("java")
+    id("io.spring.dependency-management")
+    id("org.springframework.boot")
+    kotlin("jvm")
+    kotlin("plugin.spring")
+    kotlin("plugin.jpa")
+}
+
+dependencies {
+    api(platform(project(":platform")))
+    implementation(kotlin("reflect"))
+    implementation(kotlin("stdlib-jdk8"))
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive")
+    implementation("net.sourceforge.jexcelapi:jxl")
+    implementation("commons-io:commons-io")
+    implementation("org.apache.commons:commons-dbcp2")
+    implementation("cc-lotus.gaf3:gaf-core-shared")
+    implementation("cc-lotus.gaf3:gaf-core-services")
+    implementation("cc-lotus.gaf3:gaf-core-gateway")
+    implementation("com.alibaba:fastjson")
+    implementation("io.jsonwebtoken:jjwt-api")
+    implementation("io.jsonwebtoken:jjwt-impl")
+    implementation("io.jsonwebtoken:jjwt-jackson")
+    implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
+    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
+    implementation("org.springframework.boot:spring-boot-starter-data-redis")
+    implementation("org.springframework.boot:spring-boot-starter-webflux")
+    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
+    implementation("org.springframework.boot:spring-boot-configuration-processor")
+    implementation("org.springframework.cloud:spring-cloud-starter-gateway")
+    implementation("org.springframework.cloud:spring-cloud-gateway-webflux")
+    implementation("io.github.openfeign:feign-jackson:10.9")
+    implementation("org.mongodb:bson")
+    implementation("com.belerweb:pinyin4j:2.5.1")
+    implementation(project(path = ":services:service-system", configuration = "lib"))
+    implementation(project(path = ":services:service-task", configuration = "lib"))
+    implementation(project(path = ":shared", configuration = "lib"))
+    implementation("com.squareup.okhttp3:okhttp:4.10.0-RC1")
+    implementation("com.github.oshi:oshi-core:6.1.4")
+    runtimeOnly("mysql:mysql-connector-java")
+    runtimeOnly(fileTree("$rootDir/libs") { include("*.jar") })
+}
+
+
+dependencyManagement {
+    imports {
+        mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
+    }
+}
+
+tasks.register<Sync>("script") {
+    from("script")
+    into("$buildDir/script")
+
+    val disableAppVersion: String? by project
+    if (disableAppVersion == "true") {
+        expand("name" to project.name, "version" to version)
+    } else {
+        expand("name" to "${project.name}-$version", "version" to version)
+    }
+}
+
+tasks.register<Copy>("dist") {
+    dependsOn(tasks.named("bootJar"), tasks.named("script"))
+    into("$rootDir/dist/${project.name}")
+    from(tasks["bootJar"].outputs)
+    from("$buildDir/script")
+}

+ 10 - 0
apps/svs-all-in-one/script/start.sh

@@ -0,0 +1,10 @@
+#!/bin/bash
+app=${name}.jar
+pid=`ps -ef|grep \$app|grep -v "grep"|awk '{print \$2}'`
+if [ -z \$pid ]
+then
+  nohup java -cp \$app -Dxms.secret.mech=SM3 -Ddb.matcher=CONTAINING -Dloader.path=lib -Dfile.encoding="UTF-8" org.springframework.boot.loader.PropertiesLauncher &
+  echo 'Start service ok!'
+else
+  echo 'Error: service is started!'
+fi

+ 11 - 0
apps/svs-all-in-one/script/stop.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+app=${name}.jar
+pid=`ps -ef|grep \$app|grep -v "grep"|awk '{print \$2}'`
+if [ -z \$pid ]
+then
+  echo 'service not start!'
+else
+  kill \$pid
+  echo \$pid
+  echo 'service is killed!'
+fi

+ 1 - 0
apps/svs-all-in-one/script/version

@@ -0,0 +1 @@
+${version}

+ 46 - 0
apps/svs-all-in-one/src/main/kotlin/llh/svs/allinone/AllInOneApplication.kt

@@ -0,0 +1,46 @@
+package llh.svs.allinone
+
+import gaf3.core.cloud.GafCloudConfiguration
+import gaf3.core.gateway.GatewayController
+import gaf3.core.jpa.GafJpaConfiguration
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.autoconfigure.domain.EntityScan
+import org.springframework.boot.runApplication
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.ComponentScan
+import org.springframework.context.annotation.Configuration
+import org.springframework.context.annotation.Import
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories
+import org.springframework.http.HttpStatus
+import org.springframework.http.server.reactive.ServerHttpResponse
+import org.springframework.stereotype.Controller
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.ResponseBody
+import reactor.core.publisher.Mono
+
+@SpringBootApplication
+@Configuration
+@Import(GafCloudConfiguration::class, GafJpaConfiguration::class)
+@EntityScan(basePackages = ["gaf3.core.services", "llh.svs.core.services"])
+@EnableJpaRepositories(basePackages = ["gaf3.core.services", "llh.svs.core.services"])
+@ComponentScan(
+    basePackages = ["gaf3.core.services", "llh.svs.core.services"],
+    basePackageClasses = [AllInOneApplication::class]
+)
+@Controller
+class AllInOneApplication {
+
+    @Bean
+    fun gatewayController(): GatewayController {
+        return GatewayController()
+    }
+
+    @Bean
+    fun statusControllerAdvice(): StatusControllerAdvice {
+        return StatusControllerAdvice()
+    }
+}
+
+fun main(args: Array<String>) {
+    runApplication<AllInOneApplication>(*args)
+}

+ 27 - 0
apps/svs-all-in-one/src/main/kotlin/llh/svs/allinone/StatusControllerAdvice.kt

@@ -0,0 +1,27 @@
+package llh.svs.allinone
+
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.springframework.context.annotation.Bean
+import org.springframework.core.annotation.Order
+import org.springframework.http.server.reactive.ServerHttpRequest
+import org.springframework.stereotype.Component
+import org.springframework.web.bind.annotation.ExceptionHandler
+import org.springframework.web.bind.annotation.ResponseBody
+import org.springframework.web.bind.annotation.RestControllerAdvice
+import org.springframework.web.server.ResponseStatusException
+
+
+@RestControllerAdvice
+class StatusControllerAdvice {
+    val log: Logger = LoggerFactory.getLogger(StatusControllerAdvice::class.java)
+
+    @ExceptionHandler(ResponseStatusException::class)
+    @ResponseBody
+    @Order(-1)
+    fun handleError(ex: ResponseStatusException, req: ServerHttpRequest) {
+        log.warn("ResponseStatusException:{}-{}", ex.status, ex.reason)
+        log.debug("handleError", ex)
+        throw ex
+    }
+}

+ 47 - 0
apps/svs-all-in-one/src/main/kotlin/llh/svs/allinone/bean/FactoryBean.kt

@@ -0,0 +1,47 @@
+package llh.svs.allinone.bean
+
+import gaf3.core.gateway.filter.factory.*
+import gaf3.core.gateway.handler.predicate.JwtRoutePredicateFactory
+import gaf3.core.services.log.config.GafLogConfigure
+import gaf3.core.services.log.service.LogService
+import gaf3.core.services.verify.service.VerifyCodeService
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+
+@Configuration
+class FactoryBean {
+    @Bean
+    fun forwardGatewayFilterFactory(): ForwardGatewayFilterFactory {
+        return ForwardGatewayFilterFactory()
+    }
+
+    @Bean
+    fun verifyCodeGatewayFilterFactory(service: VerifyCodeService): VerifyCodeGatewayFilterFactory {
+        return VerifyCodeGatewayFilterFactory(service)
+    }
+
+    @Bean
+    fun logGatewayFilterFactory(service: LogService, config: GafLogConfigure): LogGatewayFilterFactory {
+        return LogGatewayFilterFactory(service, config)
+    }
+
+    @Bean
+    fun peekResGatewayFilterFactory(): PeekResponseBodyGatewayFilterFactory {
+        return PeekResponseBodyGatewayFilterFactory()
+    }
+
+    @Bean
+    fun peekReqGatewayFilterFactory(): PeekRequestBodyGatewayFilterFactory {
+        return PeekRequestBodyGatewayFilterFactory()
+    }
+
+    @Bean
+    fun jwtRoutePredicateFactory(): JwtRoutePredicateFactory {
+        return JwtRoutePredicateFactory()
+    }
+
+    @Bean
+    fun setRequestParameterGatewayFilterFactory(): SetRequestParameterGatewayFilterFactory {
+        return SetRequestParameterGatewayFilterFactory()
+    }
+}

+ 17 - 0
apps/svs-all-in-one/src/main/resources/application-mysql.yml

@@ -0,0 +1,17 @@
+# 数据库配置
+---
+spring:
+  datasource:
+    username: root
+    password: 123456
+    url: jdbc:mysql://127.0.0.1:3306/svs?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    platform: mysql
+  jpa:
+    database-platform: org.hibernate.dialect.MySQL8Dialect
+    show-sql: true
+    hibernate:
+      naming:
+        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
+        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
+      ddl-auto: none

+ 104 - 0
apps/svs-all-in-one/src/main/resources/application-routes.yml

@@ -0,0 +1,104 @@
+# 默认路由规则
+---
+gateway.response.body.peek-size: 200
+spring:
+  config:
+    activate:
+      on-profile: routes
+  cloud:
+    gateway:
+      default-filters:
+        #- PrefixPath=/httpbin
+        #- JwtParser=.*/login
+        - AddResponseHeader=Cache-Control, no-cache
+        - AddResponseHeader=Pragma, no-cache
+        - AddResponseHeader=Expires, -1
+        # - RewritePath=/api/gaf/(?<segment>.*), /gaf/$\{segment}
+
+      routes:
+        # 登录认证接口
+        - id: gaf_login
+          uri: forward:///gaf/auth/login
+          predicates:
+            - Path=/api/gaf/login
+          filters:
+            - VerifyCode
+            - PeekResponseBody
+            - PeekRequestBody
+        # 字典接口
+        - id: gaf_code
+          uri: ${uri.gaf}
+          predicates:
+            - Path=/api/gaf/code/**
+            - Method=Get
+          filters:
+            - RewritePath=/api/gaf/(?<segment>.*), /gaf/$\{segment}
+            - Forward
+        # 验证码接口
+        - id: gaf_verify
+          uri: ${uri.gaf}
+          predicates:
+            - Path=/api/gaf/verify/**
+          filters:
+            - RewritePath=/api/gaf/(?<segment>.*), /gaf/$\{segment}
+            - Forward
+        # 菜单接口
+        - id: gaf_menu
+          uri: ${uri.gaf}
+          predicates:
+            - Path=/api/gaf/menu/**
+            - Method=Get
+          filters:
+            - RewritePath=/api/(?<segment>.*), /$\{segment}
+            - Forward
+        # 角色查询接口
+        - id: gaf_role_items
+          uri: ${uri.gaf}
+          predicates:
+            - Path=/api/gaf/role/items
+            - Method=Get
+          filters:
+            - RewritePath=/api/(?<segment>.*), /$\{segment}
+            - Forward
+        # GAF接口服务
+        - id: gaf_core_get
+          uri: ${uri.gaf}
+          predicates:
+            - Path=/api/gaf/**
+            - Method=Get
+            - Jwt=issuer, gaf
+          filters:
+            - RewritePath=/api/gaf/(?<segment>.*), /gaf/$\{segment}
+            - Forward
+        # GAF接口服务
+        - id: gaf_core
+          uri: ${uri.gaf}
+          predicates:
+            - Path=/api/gaf/**
+            - Jwt=issuer, gaf
+          filters:
+            - RewritePath=/api/gaf/(?<segment>.*), /gaf/$\{segment}
+            - Forward
+            - PeekResponseBody
+        # SVS接口服务
+        - id: svs_core
+          uri: ${uri.svs}
+          predicates:
+            - Path=/api/svs/**
+          filters:
+            - RewritePath=/api/(?<segment>.*), /$\{segment}
+            - Forward
+          # == 默认处理 ==
+        - id: index
+          uri: forward:///index # default for unauthorized
+          predicates:
+            - Path=/
+          filters:
+            - RedirectTo=302, /admin/index.html
+        - id: api_default
+          uri: forward:///401 # default for unauthorized
+          order: 1000
+          predicates:
+            - Path=/api/**
+          filters:
+            - SetStatus=401

+ 5 - 0
apps/svs-all-in-one/src/main/resources/application-service.yml

@@ -0,0 +1,5 @@
+svs:
+  service:
+    system:
+      db-backup:
+        filepath: /usr/backup

+ 60 - 0
apps/svs-all-in-one/src/main/resources/application.yml

@@ -0,0 +1,60 @@
+# 全局配置
+jwt.secret: &jwtSecret "GafJwtSecret!@#"
+agent.jwt-secret: *jwtSecret
+api.host: 127.0.0.1
+uri:
+  gaf: http://${api.host}:8001
+  svs: http://${api.host}:8003
+gaf:
+  auth:
+    jwt-secret: *jwtSecret
+    jwt-issuer: gaf
+    jwt-validity: 5h
+  web:
+    spa:
+      index-paths:
+        - /admin/gaf
+        - /admin/xms
+        - /admin/log
+        - /admin
+        - /register
+        - /user
+  menu:
+    store-type: file
+    # example: file:config/menu/items.json 、classpath:/menu/items.json
+    items-file: file:config/menu/items.json #default: classpath:/menu/items.json
+    menus-file: file:config/menu/menus.json   #default: classpath:/menu/menus.json
+  code.store-type: hybrid
+  cache.verify.validity: 300s
+
+
+server:
+  port: 18080
+  servlet:
+    encoding:
+      charset: utf-8
+spring:
+  profiles:
+    include: routes, mysql, service
+    active: local
+  resources:
+    static-locations: file:public/,file:dist/public/,classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
+  main:
+    allow-bean-definition-overriding: true
+
+---
+spring:
+  config:
+    activate:
+      on-profile: local
+
+gaf:
+  menu:
+    items-file: classpath:/menu/items-full.json #default: classpath:/menu/tree.json
+    menus-file: classpath:/menu/menus.json   #default: classpath:/menu/bar.json
+
+logging.level.gaf3.core.*: DEBUG
+logging.level.llh.svs.*: DEBUG
+#logging.level.jit.xms.core.services.sync.service.*: trace
+#logging.level.org.hibernate.type.descriptor.sql.BasicBinder: trace
+#debug: true

+ 25 - 0
apps/svs-all-in-one/src/main/resources/logback-spring.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/base.xml" />
+
+    <appender name="STARTUP" class="ch.qos.logback.core.FileAppender">
+        <file>logs/startup.log</file>
+        <append>true</append>
+        <!-- set immediateFlush to false for much higher logging throughput -->
+        <immediateFlush>true</immediateFlush>
+        <!-- encoders are assigned the type
+             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:--} --- [%logger] %m%n</pattern>
+            <charset>${FILE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <logger name="Startup" level="INFO">
+        <appender-ref ref="STARTUP" />
+    </logger>
+
+    <logger name="Shutdown" level="INFO">
+        <appender-ref ref="STARTUP" />
+    </logger>
+</configuration>

+ 386 - 0
apps/svs-all-in-one/src/main/resources/menu/items-full.json

@@ -0,0 +1,386 @@
+[
+  {
+    "id": "dashboard",
+    "title": "工作台",
+    "path": "/xms/dashboard",
+    "icon": "home",
+    "module": "@user"
+  },
+  {
+    "id": "xms_user",
+    "title": "用户管理",
+    "path": "/xms/user",
+    "icon": "idcard",
+    "module": "@user",
+    "children": [
+      {
+        "id": "xms_user_info",
+        "title": "用户信息",
+        "path": "/xms/user",
+        "icon": "idcard"
+      },
+      {
+        "id": "xms_user_org",
+        "title": "机构管理",
+        "path": "/xms/org",
+        "icon": "dept"
+      },
+      {
+        "id": "xms_user_group",
+        "title": "群组管理",
+        "path": "/xms/group",
+        "icon": "users"
+      },
+      {
+        "id": "xms_user_acct",
+        "title": "帐号管理",
+        "path": "/xms/acct",
+        "icon": "user"
+      },
+      {
+        "id": "xms_user_cert",
+        "title": "证书管理",
+        "path": "/xms/cert",
+        "icon": "cert"
+      },
+      {
+        "id": "xms_user_blacklist",
+        "title": "黑名单管理",
+        "path": "/xms/blacklist",
+        "icon": "user1"
+      },
+      {
+        "id": "xms_user_rule",
+        "title": "用户规则",
+        "path": "/xms/rule",
+        "icon": "el-icon-s-order"
+      },
+      {
+        "id": "xms_user_reset",
+        "title": "帐号重置管理",
+        "path": "/xms/acct-reset",
+        "icon": "idok"
+      }
+    ]
+  },
+  {
+    "id": "xms_register",
+    "title": "用户审核",
+    "path": "/xms/register",
+    "icon": "idok",
+    "module": "@user",
+    "children": [
+      {
+        "id": "xms_register_0",
+        "title": "待审核",
+        "path": "/xms/register/pending",
+        "icon": "prompt"
+      },
+      {
+        "id": "xms_register_1",
+        "title": "已审核",
+        "path": "/xms/register/done",
+        "icon": "success"
+      },
+      {
+        "id": "xms_register_2",
+        "title": "已驳回",
+        "path": "/xms/register/rejected",
+        "icon": "error"
+      }
+    ]
+  },
+  {
+    "id": "xms_auth",
+    "title": "授权管理",
+    "path": "/xms/auth/org",
+    "icon": "auth",
+    "module": "@authorize",
+    "children": [
+      {
+        "id": "xms_auth_org",
+        "title": "机构授权",
+        "path": "/xms/auth/org",
+        "icon": "dept"
+      },
+      {
+        "id": "xms_auth_group",
+        "title": "群组授权",
+        "path": "/xms/auth/group",
+        "icon": "users"
+      },
+      {
+        "id": "xms_auth_rule",
+        "title": "规则授权",
+        "path": "/xms/auth/rule",
+        "icon": "users"
+      }
+    ]
+  },
+  {
+    "id": "xms_cred",
+    "title": "凭证管理",
+    "path": "/xms/cred",
+    "icon": "cert",
+    "module": "@cred",
+    "children": [
+      {
+        "id": "xms_cred_fingervein",
+        "title": "指静脉信息",
+        "path": "/xms/cred/fingervein",
+        "icon": "tags"
+      },
+      {
+        "id": "xms_cred_ukey",
+        "title": "UKey证书",
+        "path": "/xms/cred/ukey",
+        "icon": "tags"
+      },
+      {
+        "id": "xms_cred_token",
+        "title": "动态口令",
+        "path": "/xms/cred/token",
+        "icon": "tags"
+      }
+    ]
+  },
+  {
+    "id": "xms_dev",
+    "title": "设备管理",
+    "path": "/xms/dev",
+    "icon": "mobile",
+    "module": "@cred",
+    "children": [
+      {
+        "id": "xms_dev_ukey",
+        "title": "证书UKey",
+        "path": "/xms/dev/ukey",
+        "icon": "tag"
+      },
+      {
+        "id": "xms_dev_token",
+        "title": "动态口令",
+        "path": "/xms/dev/token",
+        "icon": "tag",
+        "pid": "5"
+      },
+      {
+        "id": "xms_dev_identity",
+        "title": "用户身份卡",
+        "path": "/xms/dev/identity",
+        "icon": "tag"
+      },
+      {
+        "id": "xms_dev_tf",
+        "title": "证书TF卡",
+        "path": "/xms/dev/tf",
+        "icon": "tag",
+        "pid": "5"
+      }
+    ]
+  },
+  {
+    "id": "xms_app",
+    "title": "应用管理",
+    "path": "/xms/app",
+    "icon": "column",
+    "module": "@app",
+    "children": [
+      {
+        "id": "xms_app_info",
+        "title": "应用信息",
+        "path": "/xms/app",
+        "icon": "bill"
+      },
+      {
+        "id": "xms_app_res",
+        "title": "资源管理",
+        "path": "/xms/resources",
+        "icon": "tags"
+      },
+      {
+        "id": "xms_app_role",
+        "title": "角色管理",
+        "path": "/xms/roles",
+        "icon": "tag"
+      },
+      {
+        "id": "xms_app_batch_role",
+        "title": "组合角色管理",
+        "path": "/xms/batch-role",
+        "icon": "tag"
+      }
+    ]
+  },
+  {
+    "id": "xms_log_list",
+    "title": "日志审计",
+    "path": "/log/list/f1",
+    "icon": "log",
+    "module": "@log",
+    "children": [
+      {
+        "id": "xms_log_list_f1",
+        "title": "启动停止日志",
+        "path": "/log/list/f1",
+        "icon": "bill"
+      },
+      {
+        "id": "xms_log_list_f2",
+        "title": "登录认证日志",
+        "path": "/log/list/f2",
+        "icon": "bill"
+      },
+      {
+        "id": "xms_log_list_f3",
+        "title": "操作使用日志",
+        "path": "/log/list/f3",
+        "icon": "bill"
+      },
+      {
+        "id": "xms_log_list_f4",
+        "title": "运行状态日志",
+        "path": "/log/list/f4",
+        "icon": "bill"
+      }
+    ]
+  },
+  {
+    "id": "xms_log_stat",
+    "title": "行为审计",
+    "path": "",
+    "icon": "report",
+    "module": "@log",
+    "children": [
+      {
+        "id": "xms_log_stat_login_time",
+        "title": "用户登录时段分布",
+        "path": "/log/stat/login_time",
+        "icon": "report1"
+      },
+      {
+        "id": "xms_log_stat_login_device",
+        "title": "用户登录IP统计",
+        "path": "/log/stat/login_device",
+        "icon": "report1"
+      },
+      {
+        "id": "xms_log_stat_app_time",
+        "title": "应用访问时段分布",
+        "path": "/log/stat/app_time",
+        "icon": "report1"
+      },
+      {
+        "id": "xms_log_audit_dead_user",
+        "title": "僵尸用户审计",
+        "path": "/log/audit/dead-user",
+        "icon": "user-del"
+      }
+    ]
+  },
+  {
+    "id": "xms_log_audit",
+    "title": "责任认定",
+    "path": "",
+    "icon": "auth3",
+    "module": "@log",
+    "children": [
+      {
+        "id": "xms_log_audit_break_user",
+        "title": "失信日志审计",
+        "path": "/log/audit/break-user",
+        "icon": "user-warn"
+      },
+      {
+        "id": "xms_log_audit_break_rule",
+        "title": "失信行为定义",
+        "path": "/log/audit/break-rule",
+        "icon": "idcard"
+      }
+    ]
+  },
+  {
+    "id": "xms_policy",
+    "title": "策略管理",
+    "path": "/xms/policy",
+    "icon": "caogao",
+    "module": "@policy",
+    "children": [
+      {
+        "id": "xms_policy_auth",
+        "title": "认证策略",
+        "path": "/xms/policy/config/AUTH_POLICY",
+        "icon": "caogao"
+      },
+      {
+        "id": "xms_policy_sync",
+        "title": "同步策略",
+        "path": "/xms/policy/config/SYNC_POLICY",
+        "icon": "caogao"
+      },
+      {
+        "id": "xms_policy_access",
+        "title": "访问控制策略",
+        "path": "/xms/policy/access",
+        "icon": "caogao"
+      },
+      {
+        "id": "xms_policy_system",
+        "title": "系统策略",
+        "path": "/xms/policy/config/SYSTEM_PROPS",
+        "icon": "caogao"
+      }
+    ]
+  },
+  {
+    "id": "xms_system",
+    "title": "系统管理",
+    "path": "/gaf/user",
+    "icon": "system",
+    "module": "@gaf",
+    "children": [
+      {
+        "id": "gaf_user",
+        "title": "系统用户",
+        "path": "/gaf/user",
+        "icon": "account"
+      },
+      {
+        "id": "gaf_dict",
+        "title": "数据字典",
+        "path": "/gaf/dict",
+        "icon": "dict"
+      },
+      {
+        "id": "gaf_menu",
+        "title": "菜单管理",
+        "path": "/gaf/menu",
+        "icon": "menu"
+      },
+      {
+        "id": "xms_sync_user",
+        "title": "用户同步管理",
+        "path": "/xms/sync/user",
+        "icon": "log"
+      },
+      {
+        "id": "xms_sync_offline",
+        "title": "离线同步管理",
+        "path": "/xms/sync/offline",
+        "icon": "log"
+      },
+      {
+        "id": "xms_task",
+        "title": "任务管理",
+        "path": "/xms/task",
+        "icon": "log"
+      },
+      {
+        "id": "xms_dbbackup",
+        "title": "备份恢复",
+        "path": "/xms/backups",
+        "icon": "log"
+      }
+    ]
+  }
+]

+ 134 - 0
apps/svs-all-in-one/src/main/resources/menu/items-lite.json

@@ -0,0 +1,134 @@
+[
+  {
+    "id": "xms_user",
+    "title": "用户管理",
+    "path": "/xms/user",
+    "icon": "account",
+    "module": "@user",
+    "children": [
+      {
+        "id":"xms_user_info",
+        "title": "用户信息",
+        "path": "/xms/user",
+        "icon": "account"
+      },
+      {
+        "id": "xms_user_org",
+        "title": "机构管理",
+        "path": "/xms/org",
+        "icon": "dept"
+      },
+      {
+        "id": "xms_user_group",
+        "title": "群组管理",
+        "path": "/xms/group",
+        "icon": "users"
+      },
+      {
+        "id": "xms_register",
+        "title": "注册审核",
+        "path": "/xms/register",
+        "icon": "audit"
+      },
+      {
+        "id": "xms_user_cert",
+        "title": "证书管理",
+        "path": "/xms/cert",
+        "icon": "cert"
+      },
+      {
+        "id": "xms_user_blacklist",
+        "title": "黑名单管理",
+        "path": "/xms/blacklist",
+        "icon": "user1"
+      }
+    ]
+  },
+  {
+    "id": "xms_auth",
+    "title": "授权管理",
+    "path": "/xms/authorize/org",
+    "icon": "auth",
+    "module": "@authorize",
+    "children": [
+      {
+        "id": "xms_auth_org",
+        "title": "机构授权",
+        "path": "/xms/authorize/org",
+        "icon": "dept"
+      },
+      {
+        "id": "xms_auth_group",
+        "title": "群组授权",
+        "path": "/xms/authorize/group",
+        "icon": "users"
+      }
+    ]
+  },
+  {
+    "id": "xms_app",
+    "title": "应用管理",
+    "path": "/xms/app",
+    "icon": "column",
+    "module": "@app",
+    "children": [
+      {
+        "id": "xms_app_info",
+        "title": "应用信息",
+        "path": "/xms/app",
+        "icon": "bill"
+      },
+      {
+        "id": "xms_app_res",
+        "title": "资源管理",
+        "path": "/xms/resources",
+        "icon": "tags"
+      },
+      {
+        "id": "xms_app_role",
+        "title": "角色管理",
+        "path": "/xms/roles",
+        "icon": "tag"
+      }
+    ]
+  },
+  {
+    "id": "gaf_system",
+    "title": "系统管理",
+    "path": "/gaf/user",
+    "icon": "system",
+    "module": "@gaf",
+    "children": [
+      {
+        "id": "gaf_user",
+        "title": "系统用户",
+        "path": "/gaf/user",
+        "icon": "account"
+      },
+      {
+        "id": "gaf_dept",
+        "title": "用户部门",
+        "path": "/gaf/dept",
+        "icon": "dept"
+      },
+      {
+        "id": "gaf_dict",
+        "title": "数据字典",
+        "path": "/gaf/dict",
+        "icon": "dict"
+      },
+      {
+        "id": "gaf_menu",
+        "title": "菜单管理",
+        "path": "/gaf/menu",
+        "icon": "menu"
+      },
+      {
+        "id": "gaf_log",
+        "title": "日志审计",
+        "path": "/gaf/log",
+        "icon": "log"
+      }
+    ]
+  }
+]

+ 22 - 0
apps/svs-all-in-one/src/main/resources/menu/menus.json

@@ -0,0 +1,22 @@
+[
+  {
+    "title": "用户管理",
+    "path": "/xms",
+    "module": "@user"
+  },
+  {
+    "title": "授权管理",
+    "path": "/xms",
+    "module": "@empower"
+  },
+  {
+    "title": "应用管理",
+    "path": "/xms",
+    "module": "@app"
+  },
+  {
+    "title": "系统管理",
+    "path": "/gaf",
+    "module": "@gaf"
+  }
+]

+ 54 - 0
apps/svs-init/build.gradle.kts

@@ -0,0 +1,54 @@
+
+group = "llh.svs"
+version = rootProject.version
+
+
+plugins {
+    id("java")
+    id("io.spring.dependency-management")
+    id("org.springframework.boot")
+    kotlin("jvm")
+    kotlin("plugin.spring")
+    kotlin("plugin.jpa")
+}
+
+repositories {
+    // 阿里云镜像
+    maven { url = uri("https://maven.aliyun.com/repository/public") }
+    maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
+    maven { url = uri("https://maven.aliyun.com/repository/spring") }
+    maven { url = uri("https://maven.aliyun.com/repository/spring-plugin") }
+    // gradle
+    maven { url = uri("https://plugins.gradle.org/m2/") }
+}
+
+dependencies {
+    api(platform(project(":platform")))
+    implementation(kotlin("reflect"))
+    implementation(kotlin("stdlib-jdk8"))
+    implementation("commons-io:commons-io")
+    implementation("org.apache.commons:commons-dbcp2")
+    implementation("org.springframework.boot:spring-boot-starter-jdbc")
+    runtimeOnly("mysql:mysql-connector-java")
+    runtimeOnly(fileTree("$rootDir/libs") { include("*.jar") })
+}
+
+tasks.register<Sync>("script") {
+    from("script")
+    into("$buildDir/script")
+
+    val disableAppVersion: String? by project
+    if (disableAppVersion == "true") {
+        expand("name" to project.name, "version" to version)
+    } else {
+        expand("name" to "${project.name}-$version", "version" to version)
+    }
+}
+
+
+tasks.register<Copy>("dist") {
+    dependsOn(tasks.named("bootJar"), tasks.named("script"))
+    into("$rootDir/dist/${project.name}")
+    from(tasks["bootJar"].outputs)
+    from("$buildDir/script")
+}

+ 1 - 0
apps/svs-init/script/init.sh

@@ -0,0 +1 @@
+java -cp ${name}.jar -Dloader.path=lib -Dfile.encoding="UTF-8" org.springframework.boot.loader.PropertiesLauncher

+ 1 - 0
apps/svs-init/script/version

@@ -0,0 +1 @@
+${version}

+ 21 - 0
apps/svs-init/src/main/kotlin/llh/svs/allinone/SvsInitApplication.kt

@@ -0,0 +1,21 @@
+package llh.svs.allinone
+
+import org.slf4j.LoggerFactory
+import org.springframework.boot.CommandLineRunner
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.runApplication
+
+@SpringBootApplication
+class SvsInitApplication : CommandLineRunner {
+    override fun run(vararg args: String?) {
+        log.info("!!!!!! SVS DB Initialize Success! !!!!!!")
+    }
+
+    companion object {
+        private val log = LoggerFactory.getLogger(SvsInitApplication::class.java)
+    }
+}
+
+fun main(args: Array<String>) {
+    runApplication<SvsInitApplication>(*args)
+}

+ 26 - 0
apps/svs-init/src/main/resources/application-mysql.yml

@@ -0,0 +1,26 @@
+# 数据库配置
+---
+spring:
+  datasource:
+    username: root
+    password:
+    url: jdbc:mysql://127.0.0.1:3306/svs?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
+    driver-class-name: com.mysql.cj.jdbc.Driver
+  jpa:
+    database-platform: org.hibernate.dialect.MySQL8Dialect
+    show-sql: false
+    hibernate:
+      naming:
+        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
+        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
+      ddl-auto: none
+  sql:
+    init:
+      platform: mysql
+      schema-locations:
+        - classpath:/sql/mysql/schema-gaf.sql
+        - classpath:/sql/mysql/trigger-gaf.sql
+        - classpath:/sql/mysql/schema-svs.sql
+      data-locations:
+        - classpath:/sql/mysql/data.sql
+        - classpath:/sql/mysql/dict.sql

+ 32 - 0
apps/svs-init/src/main/resources/application.yml

@@ -0,0 +1,32 @@
+# 全局配置
+
+spring:
+  profiles:
+    active: local, init
+    include: mysql
+  main:
+    allow-bean-definition-overriding: true
+  datasource:
+    type: org.apache.commons.dbcp2.BasicDataSource
+    dbcp2:
+      initial-size: 5
+      max-total: 20
+      max-idle: 10
+      min-idle: 5
+
+---
+spring:
+  profiles: local
+
+#logging.level.gaf3.core.*: DEBUG
+#logging.level.org.hibernate.type.descriptor.sql.BasicBinder: trace
+#debug: true
+
+---
+spring:
+  profiles: init
+  sql:
+    init:
+      mode: always
+      continue-on-error: false
+      separator: $$

+ 8 - 0
apps/svs-init/src/main/resources/sql/mysql/data.sql

@@ -0,0 +1,8 @@
+insert into GAF_USER_INFO (USER_ID, NAME, STATUS, CREATED_AT, UPDATED_AT, ORIGIN) values ('00000000-0000-0000-0000-000000000000', '系统管理员', '0', now(), now(), 'default') $$
+insert into GAF_USER_ACCT ( USER_ID, ACCOUNT, SECRET, STATUS, EXPIRED, CREATED_AT, UPDATED_AT) values ('00000000-0000-0000-0000-000000000000', 'admin', '12345678', '0', 0, now(), now()) $$
+insert into GAF_ROLE_ITEM ( ID, ITEM_TYPE, CODE, NAME, PRESET, RANKING)
+values
+    ('00000000-0000-0000-0000-000000000001', '0', 'admin', '系统管理员', '1', 1),
+    ('00000000-0000-0000-0000-000000000002', '0', 'audit', '安全审计员', '1', 2),
+    ('00000000-0000-0000-0000-000000000003', '0', 'secadm', '安全管理员', '1', 3) $$
+

+ 3 - 0
apps/svs-init/src/main/resources/sql/mysql/dict.sql

@@ -0,0 +1,3 @@
+insert into GAF_CODE_ITEM ( ID, ITEM_TYPE, CODE, NAME, ALIAS, STATUS, PRESET) values (uuid(), 'group', '01', '启用状态', 'usage', '0', '1');
+insert into GAF_CODE_ITEM ( ID, ITEM_TYPE, CODE, NAME, STATUS, PRESET) values (uuid(), '01', '0', '正常', '0', '1');
+insert into GAF_CODE_ITEM ( ID, ITEM_TYPE, CODE, NAME, STATUS, PRESET) values (uuid(), '01', '1', '停用', '0', '1');

+ 127 - 0
apps/svs-init/src/main/resources/sql/mysql/schema-gaf.sql

@@ -0,0 +1,127 @@
+drop table IF EXISTS GAF_BIND_ITEM $$
+drop table IF EXISTS GAF_CODE_ITEM $$
+drop table IF EXISTS GAF_DEPT_ITEM $$
+drop table IF EXISTS GAF_LOG $$
+drop table IF EXISTS GAF_MENU_ITEM $$
+drop table IF EXISTS GAF_ROLE_ITEM $$
+drop table IF EXISTS GAF_USER_ACCT $$
+drop table IF EXISTS GAF_USER_INFO $$
+
+create table GAF_BIND_ITEM
+(
+    ID         varchar(48) not null
+        primary key,
+    BIND_TYPE  varchar(48) not null,
+    SOURCE     varchar(48),
+    TARGET     varchar(48),
+    PARAM      varchar(255),
+    CREATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    REMARK     varchar(255)
+) $$
+
+create table GAF_CODE_ITEM
+(
+    ID        varchar(48) not null
+        primary key,
+    CODE      varchar(48),
+    NAME      varchar(48),
+    ITEM_TYPE varchar(48),
+    STATUS    varchar(48),
+    ALIAS     varchar(48),
+    PRESET    int,
+    REMARK    varchar(255)
+) $$
+
+create table GAF_DEPT_ITEM
+(
+    ID         varchar(48) not null
+        primary key,
+    PID        varchar(48),
+    CODE       varchar(48),
+    NAME       varchar(48),
+    CREATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    UPDATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    REMARK     varchar(255)
+) $$
+
+create table GAF_LOG
+(
+    ID         varchar(48) not null
+        primary key,
+    LOG_TYPE   varchar(48),
+    LEVEL      varchar(48),
+    MODULE     varchar(48),
+    EVENT      varchar(48),
+    ACTION     varchar(48),
+    PARAM      varchar(255),
+    TARGET     varchar(48),
+    RESULT     varchar(48),
+    DETAIL     varchar(500),
+    EVENT_TIME varchar(48),
+    TIMESTAMP  bigint,
+    EXTRA      varchar(500),
+    USER_NAME  varchar(48),
+    USER_ACCT  varchar(48),
+    USER_IP    varchar(48),
+    CREATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    UPDATED_AT timestamp DEFAULT CURRENT_TIMESTAMP
+) $$
+
+create table GAF_MENU_ITEM
+(
+    ID      varchar(48) not null
+        primary key,
+    PID     varchar(48),
+    TITLE   varchar(48),
+    ICON    varchar(48),
+    MODE    varchar(48),
+    MODULE  varchar(48),
+    PATH    varchar(255),
+    URL     varchar(255),
+    TARGET  varchar(48),
+    VISIBLE boolean,
+    RANKING bigint,
+    PRESET  int,
+    REMARK  varchar(255)
+) $$
+
+create table GAF_ROLE_ITEM
+(
+    ID        varchar(48) not null
+        primary key,
+    CODE      varchar(48),
+    NAME      varchar(48),
+    ITEM_TYPE varchar(48),
+    PRESET    int,
+    RANKING   bigint,
+    REMARK    varchar(255)
+) $$
+
+create table GAF_USER_ACCT
+(
+    USER_ID    varchar(48) not null
+        primary key,
+    ACCOUNT    varchar(48),
+    SECRET     varchar(128),
+    STATUS     varchar(48),
+    EXPIRED    bigint,
+    CREATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    UPDATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    REMARK     varchar(255)
+) $$
+
+create table GAF_USER_INFO
+(
+    USER_ID    varchar(48) not null
+        primary key,
+    NAME       varchar(48),
+    TITLE      varchar(48),
+    GENDER     varchar(48),
+    MOBILE     varchar(48),
+    EMAIL      varchar(100),
+    STATUS     varchar(48),
+    ORIGIN     varchar(48),
+    CREATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    UPDATED_AT timestamp DEFAULT CURRENT_TIMESTAMP,
+    REMARK     varchar(255)
+) $$

+ 19 - 0
apps/svs-init/src/main/resources/sql/mysql/schema-svs.sql

@@ -0,0 +1,19 @@
+drop table IF EXISTS SVS_TASK_LOG $$
+
+create table SVS_TASK_LOG
+(
+    TASK_ID    varchar(48) not null primary key,
+    TASK_TYPE  varchar(48),
+    DATA_TYPE  varchar(48),
+    STATUS     varchar(48),
+    PROGRESS   int(5),
+    SUMMARY    varchar(255),
+    START_TIME datetime(0) null default null,
+    END_TIME   datetime(0) null default null,
+    FILE_PATH  varchar(500),
+    FILE_TYPE  varchar(48),
+    EXTRA      varchar(255),
+    REMARK     varchar(255),
+    CREATED_AT datetime(0),
+    UPDATED_AT datetime(0)
+) $$

+ 43 - 0
apps/svs-init/src/main/resources/sql/mysql/trigger-gaf.sql

@@ -0,0 +1,43 @@
+
+/* TRIGGER STRUCTURE FOR TABLE `GAF_USER_INFO` */
+DROP TRIGGER IF EXISTS `GAF_DELETE_USER` $$
+
+CREATE TRIGGER `GAF_DELETE_USER` AFTER DELETE ON `GAF_USER_INFO` FOR EACH ROW BEGIN
+	/*删除一对多关系*/
+	/*1.删除帐号关联*/
+	DELETE FROM GAF_USER_ACCT
+	WHERE USER_ID = OLD.USER_ID;
+	/*删除多对多关系*/
+	DELETE FROM  GAF_BIND_ITEM
+	WHERE SOURCE = OLD.USER_ID
+		AND SUBSTRING_INDEX(BIND_TYPE,'-',1) = 'user';
+	DELETE FROM  GAF_BIND_ITEM
+	WHERE TARGET = OLD.USER_ID
+		AND SUBSTRING_INDEX(BIND_TYPE,'-',-1) = 'user';
+    END $$
+
+/* TRIGGER STRUCTURE FOR TABLE `GAF_DEPT_ITEM` */
+DROP TRIGGER IF EXISTS `GAF_DELETE_DEPT` $$
+
+CREATE TRIGGER `GAF_DELETE_DEPT` AFTER DELETE ON `GAF_DEPT_ITEM` FOR EACH ROW BEGIN
+	/*删除多对多关系*/
+	DELETE FROM  GAF_BIND_ITEM
+	WHERE SOURCE = OLD.ID
+		AND SUBSTRING_INDEX(BIND_TYPE,'-',1) = 'dept';
+	DELETE FROM  GAF_BIND_ITEM
+	WHERE TARGET = OLD.ID
+		AND SUBSTRING_INDEX(BIND_TYPE,'-',-1) = 'dept';
+    END $$
+
+/* TRIGGER STRUCTURE FOR TABLE `GAF_ROLE_ITEM` */
+DROP TRIGGER IF EXISTS `GAF_DELETE_ROLE` $$
+
+CREATE TRIGGER `GAF_DELETE_ROLE` AFTER DELETE ON `GAF_ROLE_ITEM` FOR EACH ROW BEGIN
+	/*删除多对多关系*/
+	DELETE FROM  GAF_BIND_ITEM
+	WHERE SOURCE = OLD.ID
+		AND SUBSTRING_INDEX(BIND_TYPE,'-',1) = 'role';
+	DELETE FROM  GAF_BIND_ITEM
+	WHERE TARGET = OLD.ID
+		AND SUBSTRING_INDEX(BIND_TYPE,'-',-1) = 'role';
+    END $$

+ 81 - 0
build.gradle.kts

@@ -0,0 +1,81 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+    java
+    id("maven-publish")
+    id("io.spring.dependency-management") version "1.0.11.RELEASE"
+    id("org.springframework.boot") version "2.4.13" apply false
+    kotlin("jvm") version "1.5.10"
+    kotlin("plugin.spring") version "1.5.10" apply false
+    kotlin("plugin.jpa") version "1.5.10" apply false
+}
+
+val buildVersion: String by project
+val gafVersion: String by project
+
+group = "llh.svs"
+version = buildVersion
+extra["gafVersion"] = gafVersion
+extra["springCloudVersion"] = "2020.0.4"
+extra["fastjsonVersion"] = "1.2.72"
+extra["jjwtVersion"] = "0.10.5"
+
+val repoConf: String = System.getProperty("repoPath") ?: "/var/repo"
+val repoPath: String = file("$rootDir").toPath().root.resolve(repoConf).toString()
+
+repositories {
+    // 阿里云镜像
+    maven { url = uri("https://maven.aliyun.com/repository/public") }
+    maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
+    maven { url = uri("https://maven.aliyun.com/repository/spring") }
+    maven { url = uri("https://maven.aliyun.com/repository/spring-plugin") }
+}
+
+configure(subprojects.filter { it.name != "platform" }) {
+    apply(plugin = "java")
+    apply(plugin = "maven-publish")
+    apply(plugin = "org.jetbrains.kotlin.jvm")
+
+    java {
+        disableAutoTargetJvm()
+    }
+
+    tasks.withType<JavaCompile> {
+        options.encoding = "UTF-8"
+        sourceCompatibility = "1.8"
+        targetCompatibility = "1.8"
+    }
+
+    tasks.withType<KotlinCompile> {
+        kotlinOptions {
+            freeCompilerArgs = listOf("-Xjsr305=strict")
+            jvmTarget = "1.8"
+        }
+    }
+
+    repositories {
+        maven {
+            name = "localRepo"
+            url = uri("file://$repoPath")
+        }
+        maven {
+            name = "cc-lotus"
+            url = uri("https://maven.cc-lotus.info/repository/maven-public/")
+        }
+        // 阿里云镜像
+        maven { url = uri("https://maven.aliyun.com/repository/public") }
+        maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
+        maven { url = uri("https://maven.aliyun.com/repository/spring") }
+        maven { url = uri("https://maven.aliyun.com/repository/spring-plugin") }
+        mavenCentral()
+    }
+
+    publishing {
+        repositories {
+            maven {
+                name = "localRepo"
+                url = uri("file://$repoPath")
+            }
+        }
+    }
+}

+ 12 - 0
gradle.properties

@@ -0,0 +1,12 @@
+systemProp.repoPath = /var/repo
+
+# custom build config, would replace by environment variable
+buildVersion = 0.0.1
+patchVersion = 1
+gafVersion = 3.1.1224
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+org.gradle.jvmargs=-Xmx1024m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar


+ 5 - 0
gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

+ 234 - 0
gradlew

@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"

+ 89 - 0
gradlew.bat

@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 26 - 0
platform/build.gradle.kts

@@ -0,0 +1,26 @@
+plugins {
+    `java-platform`
+}
+javaPlatform.allowDependencies()
+
+dependencies {
+    // The platform declares constraints on all components that
+
+    // require alignment
+    constraints {
+//        api(project(":shared"))
+        api("org.bouncycastle:bcprov-jdk15on:1.68")
+        api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
+        api("org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.5.0")
+        api("org.apache.commons:commons-dbcp2:2.7.0")
+        api("commons-io:commons-io:2.6")
+        api("net.sourceforge.jexcelapi:jxl:2.6.12")
+        api("com.alibaba:fastjson:${property("fastjsonVersion")}")
+        api("io.jsonwebtoken:jjwt-api:${property("jjwtVersion")}")
+        api("io.jsonwebtoken:jjwt-impl:${property("jjwtVersion")}")
+        api("io.jsonwebtoken:jjwt-jackson:${property("jjwtVersion")}")
+        api("cc-lotus.gaf3:gaf-core-shared:${property("gafVersion")}")
+        api("cc-lotus.gaf3:gaf-core-services:${property("gafVersion")}")
+        api("cc-lotus.gaf3:gaf-core-gateway:${property("gafVersion")}")
+    }
+}

+ 123 - 0
services/build.gradle.kts

@@ -0,0 +1,123 @@
+group = "llh.svs"
+version = rootProject.version
+
+val dbUser: String by project
+
+plugins {
+    id("java")
+    id("maven-publish")
+    id("io.spring.dependency-management")
+    kotlin("jvm")
+    kotlin("plugin.spring")
+    kotlin("plugin.jpa")
+}
+
+subprojects {
+    group = "llh.svs.services"
+    version = rootProject.version
+
+    apply(plugin = "java")
+    apply(plugin = "org.springframework.boot")
+    apply(plugin = "io.spring.dependency-management")
+    apply(plugin = "org.jetbrains.kotlin.jvm")
+    apply(plugin = "org.jetbrains.kotlin.plugin.spring")
+    apply(plugin = "org.jetbrains.kotlin.plugin.jpa")
+
+    dependencies {
+        api(platform(project(":platform")))
+        implementation(project(path = ":shared", configuration = "lib"))
+        implementation(kotlin("reflect"))
+        implementation(kotlin("stdlib-jdk8"))
+        implementation("org.springframework.boot:spring-boot-starter-webflux")
+        implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
+        implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
+        implementation("org.springframework.boot:spring-boot-configuration-processor")
+        implementation("cc-lotus.gaf3:gaf-core-shared")
+        implementation("cc-lotus.gaf3:gaf-core-services")
+        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
+        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive")
+        implementation("com.alibaba:fastjson")
+        implementation("net.sourceforge.jexcelapi:jxl")
+        implementation("javax.validation:validation-api")
+        runtimeOnly("org.hibernate.validator:hibernate-validator")
+        testImplementation("org.springframework.boot:spring-boot-starter-test")
+        testImplementation("junit", "junit", "4.12")
+    }
+    dependencyManagement {
+        imports {
+            mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
+        }
+    }
+
+    tasks {
+        processResources {
+            filesMatching("application.yml") {
+                expand(project.properties)
+            }
+        }
+    }
+
+    tasks.register<Jar>(name = "libJar") {
+        archiveBaseName.set("svs-${project.name}-lib")
+        from(sourceSets["main"].output)
+        include("llh/svs/**", "META-INF/**")
+        exclude {
+            it.name.endsWith("Application.class")
+        }
+        exclude {
+            it.name.endsWith("ApplicationKt.class")
+        }
+
+    }
+    tasks.build { dependsOn(tasks.named("libJar")) }
+
+    configurations {
+        create("lib")
+    }
+
+    artifacts {
+        add("lib", tasks["libJar"])
+    }
+}
+
+configure(subprojects.filter { it.name != "service-system" }) {
+    dependencies {
+        implementation("org.springframework.boot:spring-boot-starter-data-jpa")
+        runtimeOnly("mysql:mysql-connector-java")
+    }
+}
+
+project("service-system") {
+    dependencies {
+        implementation("com.github.oshi:oshi-core:6.1.4")
+        implementation(project(path = ":services:service-task", configuration = "lib"))
+    }
+}
+
+
+tasks.jar {
+    archiveBaseName.set("svs-core-${project.name}")
+//    configure {
+    from(tasks.withType<JavaCompile>())
+    from(tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>())
+    include("llh/**")
+    exclude {
+        it.name.endsWith("Application.class")
+    }
+    exclude {
+        it.name.endsWith("ApplicationKt.class")
+    }
+    exclude {
+        it.name.endsWith("Application${'$'}Companion.class")
+    }
+//    }
+}
+publishing {
+    publications {
+        create<MavenPublication>("maven") {
+            artifactId = "svs-core-${project.name}"
+            from(components["java"])
+        }
+    }
+}
+

+ 68 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/DBBackupController.kt

@@ -0,0 +1,68 @@
+package llh.svs.core.services.sys
+
+import gaf3.core.data.ErrorResult
+import gaf3.core.data.PagedData
+import llh.svs.core.services.sys.domain.BackupFileResult
+import llh.svs.core.services.sys.service.DBBackupService
+import llh.svs.core.services.task.entity.SvsTaskLog
+import llh.svs.core.util.FileDealTool
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.core.io.Resource
+import org.springframework.http.ResponseEntity
+import org.springframework.http.codec.multipart.FilePart
+import org.springframework.util.Assert
+import org.springframework.web.bind.annotation.*
+
+@RestController
+@RequestMapping(path = ["/svs/system/database"])
+class DBBackupController {
+
+    @Autowired
+    lateinit var service: DBBackupService
+
+    /**
+     * 手动备份数据库
+     */
+    @GetMapping(path = ["/backup"])
+    fun backupDatabase(@RequestParam filename: String?): ErrorResult {
+        service.backupDatabase(filename)
+        return ErrorResult(0, "ok")
+    }
+
+    /**
+     * 获取所有备份文件名列表
+     */
+    @GetMapping(path = ["/filelist"])
+    fun fileList(skip: Int?, limit: Int?): PagedData<BackupFileResult> {
+        return service.getAllBackupFile(skip ?: 0, limit ?: 10)
+    }
+
+    /**
+     * 下载备份文件,根据备份文件名下载
+     */
+    @GetMapping(path = ["/downbackup"])
+    fun downloadBackupFile(filename: String?): ResponseEntity<Resource> {
+        val file = service.downloadBackupFile(filename)
+        return FileDealTool.getDownFileResponseEntity(file, file.nameWithoutExtension)
+    }
+
+    /**
+     * 删除备份文件,根据文件名删除备份
+     */
+    @PostMapping(path = ["/delbackup"])
+    fun deleteBackupFile(filename: String?): ErrorResult {
+        service.deleteBackupFile(filename)
+        return ErrorResult(0, "ok")
+    }
+
+    /**
+     * 根据用户上传的备份文件恢复数据库
+     */
+    @PostMapping(path = ["/recovery"])
+    fun recovery(@RequestPart(name = "file") file: FilePart): SvsTaskLog {
+        val filename = file.filename()
+        Assert.isTrue(filename.substring(filename.lastIndexOf('.')) == ".sql", "文件类型不合法")
+        return service.createTask(FileDealTool.dealMultiFile(file))
+    }
+
+}

+ 11 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/SysApplication.kt

@@ -0,0 +1,11 @@
+package llh.svs.core.services.sys
+
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.runApplication
+
+@SpringBootApplication
+class SysApplication
+
+fun main(args: Array<String>) {
+    runApplication<SysApplication>(*args)
+}

+ 55 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/SysConfigController.kt

@@ -0,0 +1,55 @@
+package llh.svs.core.services.sys
+
+import gaf3.core.data.ErrorResult
+import llh.svs.core.services.sys.domain.ServerDate
+import llh.svs.core.services.sys.service.ServerConfigService
+import llh.svs.core.services.sys.service.ServerResService
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.http.codec.multipart.FilePart
+import org.springframework.web.bind.annotation.*
+
+/**
+ * 服务器硬件配置
+ */
+@RestController
+@RequestMapping(path = ["/svs/system"])
+class SysConfigController {
+
+    @Autowired
+    lateinit var serverConfigService: ServerConfigService
+
+    /**
+     * 获取系统时间
+     */
+    @GetMapping(path = ["/time"])
+    fun getServerTime(): ServerDate {
+        return serverConfigService.getServerTime()
+    }
+
+    /**
+     * 设置系统时间
+     * @param date 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @PostMapping(path = ["/time"])
+    fun setServerTime(@RequestBody date: ServerDate): ErrorResult {
+        serverConfigService.setServerTime(date)
+        return ErrorResult(0, "ok")
+    }
+
+    /**
+     * 重启服务器
+     */
+    @PostMapping(path = ["/reboot"])
+    fun rebootServer() {
+        serverConfigService.reboot()
+    }
+
+    /**
+     * 设置license
+     */
+    @PostMapping(path = ["/license"])
+    fun setLicense(@RequestPart(name = "file") file: FilePart): ErrorResult {
+        // todo 接收license处理并验证license
+        return ErrorResult(0, "ok")
+    }
+}

+ 9 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/SystemConfig.kt

@@ -0,0 +1,9 @@
+package llh.svs.core.services.sys
+
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.context.annotation.Configuration
+
+@Configuration
+@EnableConfigurationProperties(SystemConfiguration::class)
+class SystemConfig {
+}

+ 19 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/SystemConfiguration.kt

@@ -0,0 +1,19 @@
+package llh.svs.core.services.sys
+
+import org.springframework.boot.context.properties.ConfigurationProperties
+
+@ConfigurationProperties(prefix = "svs.service.system")
+class SystemConfiguration {
+    /**
+     * 数据库备份相关信息设置
+     */
+    var dbBackup: DatabaseConfig? = null
+
+    /**
+     * 数据库配置信息类
+     */
+    class DatabaseConfig {
+        //备份文件存放位置
+        var filepath: String? = null
+    }
+}

+ 28 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/SystemResController.kt

@@ -0,0 +1,28 @@
+package llh.svs.core.services.sys
+
+import llh.svs.core.services.sys.domain.SystemResInfo
+import llh.svs.core.services.sys.service.ServerResService
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+
+/**
+ * 服务器硬件资源信息
+ */
+@RestController
+@RequestMapping(path = ["/svs/system/res"])
+class SystemResController {
+
+    @Autowired
+    lateinit var serverResService: ServerResService
+
+    /**
+     * 获取服务器硬件占用信息
+     */
+    @GetMapping(path = ["/info"])
+    fun getSystemResInfo(): SystemResInfo {
+        return serverResService.getSystemResInfo()
+    }
+
+}

+ 6 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/AutoBackupStatus.kt

@@ -0,0 +1,6 @@
+package llh.svs.core.services.sys.domain
+
+class AutoBackupStatus {
+    var flag: Boolean? = null
+    var day: Int? = null
+}

+ 6 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/BackupFileResult.kt

@@ -0,0 +1,6 @@
+package llh.svs.core.services.sys.domain
+
+class BackupFileResult {
+    var filename: String? = null
+    var createtime: String? = null
+}

+ 5 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/ServerDate.kt

@@ -0,0 +1,5 @@
+package llh.svs.core.services.sys.domain
+
+class ServerDate {
+    var time: String? = null
+}

+ 15 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/domain/SystemResInfo.kt

@@ -0,0 +1,15 @@
+package llh.svs.core.services.sys.domain
+
+import jit.xms.core.services.util.domain.CpuInfo
+import jit.xms.core.services.util.domain.DiskInfo
+import jit.xms.core.services.util.domain.MemInfo
+
+class SystemResInfo {
+
+    var cpuInfo: CpuInfo? = null
+
+    var memInfo: MemInfo? = null
+
+    var diskInfo: List<DiskInfo> = mutableListOf()
+
+}

+ 180 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/service/DBBackupService.kt

@@ -0,0 +1,180 @@
+package llh.svs.core.services.sys.service
+
+import gaf3.core.data.PagedData
+import gaf3.core.exception.BusinessError
+import llh.svs.core.services.sys.SystemConfiguration
+import llh.svs.core.services.sys.domain.BackupFileResult
+import llh.svs.core.services.task.entity.SvsTaskLog
+import llh.svs.core.services.task.service.SvsTaskLogService
+import llh.svs.core.services.task.support.TaskStatus
+import llh.svs.core.services.task.support.TaskType
+import llh.svs.core.util.LinuxCmdExecutor
+import org.slf4j.LoggerFactory
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.scheduling.annotation.Async
+import org.springframework.stereotype.Service
+import org.springframework.util.Assert
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.attribute.BasicFileAttributes
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+import java.time.format.DateTimeFormatter
+import java.util.*
+
+/**
+ * 数据库备份回复相关操作
+ */
+@Service
+class DBBackupService(val config: SystemConfiguration, val logService: SvsTaskLogService) {
+
+    @Value("\${spring.datasource.url}")
+    lateinit var url: String
+
+    @Value("\${spring.datasource.username}")
+    lateinit var username: String
+
+    @Value("\${spring.datasource.password}")
+    lateinit var password: String
+
+    /**
+     * 手动备份数据库
+     */
+    fun backupDatabase(file: String?) {
+        if (config.dbBackup == null) throw BusinessError(BusinessError.ERR_BUSINESS, "数据库备份设置未配置")
+        val filename = file ?: LocalDateTime.now().format(formatter)
+        Assert.hasText(config.dbBackup!!.filepath, "数据库文件存放位置未配置")
+        val database = url.substring(0, url.indexOf('?')).let {
+            it.substring(it.lastIndexOf('/') + 1)
+        }
+        val dir = File(config.dbBackup!!.filepath!!)
+        if (!dir.isDirectory) dir.mkdirs()
+        val cmdString =
+            "mysqldump -u$username -p$password --databases $database --lock-all-tables --result-file=${config.dbBackup!!.filepath}/${filename}.sql"
+        runCatching {
+            LinuxCmdExecutor.execute(cmdString)
+        }.getOrElse {
+            log.error("数据库备份出错")
+            LinuxCmdExecutor.execute("rm -rf ${config.dbBackup!!.filepath}/${filename}.sql")
+            throw BusinessError(BusinessError.ERR_BUSINESS, "数据库备份执行失败")
+        }
+    }
+
+    /**
+     * 数据库恢复,根据服务器的备份文件名
+     */
+    fun recovery(filename: String) {
+        if (config.dbBackup == null) throw BusinessError(BusinessError.ERR_BUSINESS, "数据库备份设置未配置")
+        Assert.hasText(config.dbBackup!!.filepath, "数据库文件存放位置未配置")
+        val cmdString = "mysql -u$username -p$password < ${config.dbBackup!!.filepath}/${filename}"
+        runCatching {
+            LinuxCmdExecutor.execute(cmdString)
+        }.getOrElse {
+            log.error("数据库恢复出错")
+            throw BusinessError(BusinessError.ERR_BUSINESS, "数据库恢复执行失败")
+        }
+    }
+
+    /**
+     * 恢复数据库并创建任务
+     */
+    fun createTask(file: File): SvsTaskLog {
+        val acsTaskLog = SvsTaskLog().apply {
+            this.taskType = TaskType.RECOVERYDB.type
+            this.taskId = UUID.randomUUID().toString()
+            this.status = TaskStatus.PENDING.status
+            this.startTime = LocalDateTime.now()
+            this.endTime = null
+            this.progress = 0
+            this.summary = null
+        }
+        //执行数据库恢复任务
+        recovery(file, acsTaskLog)
+        return acsTaskLog
+    }
+
+    /**
+     * 根据用户上传的数据库脚本来进行数据库恢复
+     */
+    @Async
+    fun recovery(file: File, acsTaskLog: SvsTaskLog) {
+        if (!file.exists()) throw BusinessError(BusinessError.ERR_BUSINESS, "数据库备份临时文件不存在")
+        val cmdString = "mysql -u$username -p$password < ${file.absoluteFile}"
+        runCatching {
+            LinuxCmdExecutor.execute(cmdString)
+            logService.create(acsTaskLog)
+        }.getOrElse {
+            log.error("数据库恢复出错")
+            logService.progress(
+                taskId = acsTaskLog.taskId!!,
+                status = TaskStatus.ERROR.status,
+                summary = "数据库恢复失败:${it.message}"
+            )
+            throw BusinessError(BusinessError.ERR_BUSINESS, "数据库恢复执行失败")
+        }
+        //任务执行完成
+        logService.progress(taskId = acsTaskLog.taskId!!, progress = 100, summary = "数据库恢复完成")
+    }
+
+    /**
+     * 获取所有备份文件列表
+     * @param skip 跳过记录数,从0开始
+     * @param limit 每页条数
+     */
+    fun getAllBackupFile(skip: Int, limit: Int): PagedData<BackupFileResult> {
+        if (config.dbBackup == null) throw BusinessError(BusinessError.ERR_BUSINESS, "数据库备份设置未配置")
+        Assert.hasText(config.dbBackup!!.filepath, "备份文件存放路径未配置")
+        val backupDir = File(config.dbBackup!!.filepath!!)
+        if (!backupDir.isDirectory) backupDir.mkdirs()
+        val list = backupDir.listFiles()?.filter { !it.name.contains(".cron") }?.map {
+            BackupFileResult().apply {
+                this.filename = it.name
+                this.createtime = filenameFormatter.format(
+                    LocalDateTime.ofInstant(
+                        Files.readAttributes(
+                            it.toPath(),
+                            BasicFileAttributes::class.java
+                        ).creationTime().toInstant(), ZoneOffset.of("+8")
+                    )
+                )
+            }
+        } ?: mutableListOf()
+        val data = when {
+            list.size < skip -> mutableListOf()
+            list.size >= skip && list.size < skip + limit -> list.subList(skip, list.size)
+            else -> list.subList(skip, skip + limit)
+        }
+        return PagedData(data = data, total = list.size)
+    }
+
+    /**
+     * 根据文件名下载备份文件
+     */
+    fun downloadBackupFile(filename: String?): File {
+        if (config.dbBackup == null) throw BusinessError(BusinessError.ERR_BUSINESS, "数据库备份设置未配置")
+        Assert.hasText(config.dbBackup!!.filepath, "备份文件存放路径未配置")
+        Assert.hasText(filename, "备份文件名不可为空")
+        val file = File("${config.dbBackup!!.filepath!!}/${filename}")
+        if (file.exists()) return file
+        throw BusinessError(BusinessError.ERR_BUSINESS, "指定下载的备份文件不存在")
+    }
+
+    /**
+     * 根据文件名删除备份文件
+     */
+    fun deleteBackupFile(filename: String?) {
+        if (config.dbBackup == null) throw BusinessError(BusinessError.ERR_BUSINESS, "数据库备份设置未配置")
+        Assert.hasText(config.dbBackup!!.filepath, "备份文件存放路径未配置")
+        Assert.hasText(filename, "备份文件名不可为空")
+        val file = File("${config.dbBackup!!.filepath!!}/${filename}")
+        if (file.exists()) {
+            file.delete()
+        }
+    }
+
+    companion object {
+        private val log = LoggerFactory.getLogger(DBBackupService::class.java)
+        private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm:ss")
+        private val filenameFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+    }
+}

+ 57 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/service/ServerConfigService.kt

@@ -0,0 +1,57 @@
+package llh.svs.core.services.sys.service
+
+import gaf3.core.exception.BusinessError
+import llh.svs.core.services.sys.domain.ServerDate
+import llh.svs.core.util.LinuxCmdExecutor
+import org.slf4j.LoggerFactory
+import org.springframework.stereotype.Service
+import org.springframework.util.Assert
+
+/**
+ * 服务器硬件相关配置
+ */
+@Service
+class ServerConfigService {
+
+    /**
+     * 获取系统时间
+     */
+    fun getServerTime(): ServerDate {
+        val datetime = runCatching {
+            val cmdString = "date '+%Y-%m-%d %H:%M:%S'"
+            LinuxCmdExecutor.execute(cmdString).replace("\n", "")
+        }.getOrElse {
+            log.error("获取系统时间失败,原因:${it.message}")
+            throw BusinessError(BusinessError.ERR_SERVICE_FAULT, "获取系统时间失败")
+        }
+        return ServerDate().apply {
+            this.time = datetime
+        }
+    }
+
+    /**
+     * 设置系统时间
+     */
+    fun setServerTime(date: ServerDate) {
+        Assert.hasText(date.time, "设置时间不可为空")
+        val cmdString = "timedatectl set-ntp no && timedatectl set-time \"${date.time}\""
+        runCatching {
+            LinuxCmdExecutor.execute(cmdString)
+        }.getOrElse {
+            log.error("设置系统时间失败,原因:${it.message}")
+            throw BusinessError(BusinessError.ERR_SERVICE_FAULT, "设置系统时间失败")
+        }
+    }
+
+    /**
+     * 服务器重启
+     */
+    fun reboot() {
+        val cmdString = "reboot"
+        LinuxCmdExecutor.execute(cmdString)
+    }
+
+    companion object {
+        private val log = LoggerFactory.getLogger(ServerConfigService::class.java)
+    }
+}

+ 23 - 0
services/service-system/src/main/kotlin/llh/svs/core/services/sys/service/ServerResService.kt

@@ -0,0 +1,23 @@
+package llh.svs.core.services.sys.service
+
+import llh.svs.core.services.sys.domain.SystemResInfo
+import llh.svs.core.util.SysHWInfoUtil
+import org.springframework.stereotype.Service
+
+/**
+ * 系统硬件资源信息获取服务
+ */
+@Service
+class ServerResService {
+
+    /**
+     * 采集服务器CPU、磁盘、内存占用情况
+     */
+    fun getSystemResInfo(): SystemResInfo {
+        return SystemResInfo().apply {
+            this.cpuInfo = SysHWInfoUtil.getCpuInfo()
+            this.diskInfo = SysHWInfoUtil.getDiskInfo()
+            this.memInfo = SysHWInfoUtil.getMemInfo()
+        }
+    }
+}

+ 5 - 0
services/service-system/src/main/resources/application-service.yml

@@ -0,0 +1,5 @@
+svs:
+  service:
+    system:
+      db-backup:
+        filepath: /usr/backup

+ 11 - 0
services/service-task/src/main/kotlin/llh/svs/core/services/task/TaskApplication.kt

@@ -0,0 +1,11 @@
+package llh.svs.core.services.task
+
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.runApplication
+
+@SpringBootApplication
+class TaskApplication
+
+fun main(args: Array<String>) {
+    runApplication<TaskApplication>(*args)
+}

+ 42 - 0
services/service-task/src/main/kotlin/llh/svs/core/services/task/TaskController.kt

@@ -0,0 +1,42 @@
+package llh.svs.core.services.task
+
+import gaf3.core.data.PagedData
+import gaf3.core.exception.BusinessError
+import llh.svs.core.services.task.entity.SvsTaskLog
+import llh.svs.core.services.task.service.SvsTaskLogService
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RequestParam
+import org.springframework.web.bind.annotation.RestController
+
+@RestController
+@RequestMapping(path = ["/svs/task"])
+class TaskController {
+
+    @Autowired
+    lateinit var service: SvsTaskLogService
+
+    /**
+     * 按ID查询任务信息
+     * @param id 任务id
+     * @return 查询成功返回任务信息
+     * @throws BusinessError 查询不成功,描述异常情况。如:任务不存在
+     */
+    @GetMapping
+    fun findById(@RequestParam("id") id: String): SvsTaskLog {
+        return service.findById(id)
+    }
+
+    /**
+     * 按条件查询列表(分页)
+     * @param filter 任务信息
+     * @param skip 当前页数
+     * @param limit 每页条数
+     * @return 成功返回任务列表
+     */
+    @GetMapping(path = ["/items"])
+    fun find(filter: SvsTaskLog, skip: Int = 0, limit: Int = 20): PagedData<SvsTaskLog> {
+        return service.find(filter, skip, limit)
+    }
+}

+ 7 - 0
services/service-task/src/main/kotlin/llh/svs/core/services/task/dao/SvsTaskLogDAO.kt

@@ -0,0 +1,7 @@
+package llh.svs.core.services.task.dao
+
+import llh.svs.core.services.task.entity.SvsTaskLog
+import org.springframework.data.jpa.repository.JpaRepository
+
+interface SvsTaskLogDAO : JpaRepository<SvsTaskLog, String> {
+}

+ 83 - 0
services/service-task/src/main/kotlin/llh/svs/core/services/task/entity/SvsTaskLog.kt

@@ -0,0 +1,83 @@
+package llh.svs.core.services.task.entity
+
+import com.fasterxml.jackson.annotation.JsonIgnore
+import gaf3.core.jpa.GafTimestamp
+import java.time.LocalDateTime
+import javax.persistence.Column
+import javax.persistence.Entity
+import javax.persistence.Id
+import javax.persistence.Table
+
+@Entity
+@Table(name = "SVS_TASK_LOG")
+class SvsTaskLog : GafTimestamp() {
+
+    @Id
+    @Column(name = "TASK_ID", length = 48)
+    var taskId: String? = null
+
+    /**
+     * 任务类型: 由TaskStatus定义
+     */
+    @Column(name = "TASK_TYPE", length = 48)
+    var taskType: String? = null
+
+    /**
+     * 数据类型
+     */
+    @Column(name = "DATA_TYPE", length = 48)
+    var dataType: String? = null
+
+    /**
+     * 任务状态: pending - 准备中, running - 执行中, completed - 已完成, error  - 发生错误
+     */
+    @Column(name = "STATUS", length = 48)
+    var status: String? = null
+
+    /**
+     * 任务进度: 0-100
+     */
+    @Column(name = "PROGRESS")
+    var progress: Int? = null
+
+    /**
+     * 任务结果汇总
+     */
+    @Column(name = "SUMMARY")
+    var summary: String? = null
+
+    /**
+     * 任务开始时间
+     */
+    @Column(name = "START_TIME")
+    var startTime: LocalDateTime? = null
+
+    /**
+     * 任务结束时间
+     */
+    @Column(name = "END_TIME")
+    var endTime: LocalDateTime? = null
+
+    /**
+     * 导入/导出数据文件路径
+     */
+    @JsonIgnore
+    @Column(name = "FILE_PATH", length = 500)
+    var filePath: String? = null
+
+    /**
+     * 导入/导出数据文件类型(扩展名)
+     */
+    @JsonIgnore
+    @Column(name = "FILE_TYPE", length = 48)
+    var fileType: String? = null
+
+    /**
+     * 查询参数,json格式
+     */
+    @Column(name = "EXTRA")
+    var extra: String? = null
+
+    @Column(name = "REMARK")
+    var remark: String? = null
+}

+ 88 - 0
services/service-task/src/main/kotlin/llh/svs/core/services/task/service/SvsTaskLogService.kt

@@ -0,0 +1,88 @@
+package llh.svs.core.services.task.service
+
+import gaf3.core.data.PagedData
+import gaf3.core.exception.BusinessError
+import llh.svs.core.services.task.dao.SvsTaskLogDAO
+import llh.svs.core.services.task.entity.SvsTaskLog
+import llh.svs.core.services.task.support.TaskStatus
+import llh.svs.core.services.task.support.TaskType
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.data.domain.Example
+import org.springframework.data.domain.PageRequest
+import org.springframework.data.domain.Sort
+import org.springframework.data.repository.findByIdOrNull
+import org.springframework.stereotype.Service
+import org.springframework.util.Assert
+import java.time.LocalDateTime
+import java.util.*
+import javax.transaction.Transactional
+
+@Service
+class SvsTaskLogService {
+
+    @Autowired
+    lateinit var svsTaskLogDao: SvsTaskLogDAO
+
+    /**
+     * 根据id查找
+     */
+    fun findById(id: String): SvsTaskLog {
+        return svsTaskLogDao.findByIdOrNull(id) ?: throw BusinessError(BusinessError.ERR_DATA_NOTEXIST, "任务不存在")
+    }
+
+    /**
+     * 分页查询
+     */
+    fun find(filter: SvsTaskLog, skip: Int = 0, limit: Int = 20): PagedData<SvsTaskLog> {
+        val page: Int = skip / limit
+        val paged =
+            svsTaskLogDao.findAll(Example.of(filter), PageRequest.of(page, limit, Sort.Direction.ASC, "startTime"))
+        return PagedData(paged.content, paged.totalElements.toInt())
+    }
+
+    /**
+     * 创建任务记录,表示任务已提交
+     */
+    fun create(data: SvsTaskLog): SvsTaskLog {
+        Assert.hasText(data.taskType, "taskType不能为空")
+        if (data.taskType.equals(TaskType.IMPORT.type, true) || data.taskType.equals(TaskType.EXPORT.type, true)) {
+            Assert.hasText(data.dataType, "dataType不能为空")
+            Assert.hasText(data.fileType, "fileType不能为空")
+            Assert.hasText(data.filePath, "filePath不能为空")
+        }
+        data.taskId = data.taskId ?: UUID.randomUUID().toString()
+        data.status = TaskStatus.PENDING.status
+        data.startTime = LocalDateTime.now()
+        data.endTime = null
+        data.progress = 0
+        data.summary = null
+        return svsTaskLogDao.save(data)
+    }
+
+    /**
+     * 修改任务进度
+     */
+    @Transactional(Transactional.TxType.REQUIRES_NEW)
+    fun progress(taskId: String, progress: Int? = null, status: String? = null, summary: String? = null): SvsTaskLog {
+        // 检查任务状态
+        val task = svsTaskLogDao.findByIdOrNull(taskId) ?: throw BusinessError(BusinessError.ERR_DATA_NOTEXIST, "任务不存在")
+        progress?.let {
+            task.progress = progress
+            task.status = if (progress == 100) TaskStatus.COMPLETED.status else TaskStatus.RUNNING.status
+        }
+        status?.let {
+            task.status = status
+        }
+        summary?.let {
+            task.summary = summary
+        }
+
+        if (task.status != TaskStatus.RUNNING.status) {
+            task.endTime = LocalDateTime.now()
+        }
+        if (task.startTime == null) {
+            task.startTime = LocalDateTime.now()
+        }
+        return svsTaskLogDao.save(task)
+    }
+}

+ 9 - 0
services/service-task/src/main/kotlin/llh/svs/core/services/task/support/TaskStatus.kt

@@ -0,0 +1,9 @@
+package llh.svs.core.services.task.support
+
+enum class TaskStatus(val status: String) {
+
+    PENDING("pending"),
+    RUNNING("running"),
+    COMPLETED("completed"),
+    ERROR("error")
+}

+ 7 - 0
services/service-task/src/main/kotlin/llh/svs/core/services/task/support/TaskType.kt

@@ -0,0 +1,7 @@
+package llh.svs.core.services.task.support
+
+enum class TaskType(val type: String) {
+    IMPORT("import"),
+    EXPORT("export"),
+    RECOVERYDB("recoverydb")
+}

+ 5 - 0
settings.gradle.kts

@@ -0,0 +1,5 @@
+rootProject.name = "svs-core"
+include("apps:svs-init", "apps:svs-all-in-one")
+include("services", "shared", "platform")
+include("services:service-system")
+include("services:service-task")

+ 67 - 0
shared/build.gradle.kts

@@ -0,0 +1,67 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * This is a general purpose Gradle build.
+ * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds
+ */
+group = "llh.svs"
+version = rootProject.version
+
+plugins {
+    id("java-library")
+    id("maven-publish")
+    id("io.spring.dependency-management")
+    kotlin("jvm")
+    kotlin("plugin.spring")
+    kotlin("plugin.jpa")
+}
+
+dependencies {
+    compileOnly(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
+    compileOnly(platform(project(":platform")))
+    compileOnly("org.bouncycastle:bcprov-jdk15on")
+    compileOnly(fileTree("$rootDir/libs") { include("*.jar") })
+    compileOnly(kotlin("reflect"))
+    compileOnly(kotlin("stdlib-jdk8"))
+    compileOnly("cc-lotus.gaf3:gaf-core-shared:${property("gafVersion")}")
+    compileOnly("com.github.oshi:oshi-core:6.1.4")
+    compileOnly("com.alibaba:fastjson:${property("fastjsonVersion")}")
+    compileOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
+    compileOnly("org.springframework.cloud:spring-cloud-starter-openfeign")
+    compileOnly("org.springframework.boot:spring-boot-starter-webflux")
+    compileOnly("org.hibernate:hibernate-core")
+}
+dependencyManagement {
+    imports {
+        // mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
+        mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
+    }
+}
+
+tasks.named<Jar>("jar") {
+    archiveBaseName.set("svs-core-${project.name}")
+}
+
+tasks.register<Jar>(name = "libJar") {
+    archiveBaseName.set("svs-core-${project.name}-lib")
+    from(sourceSets["main"].output)
+}
+tasks.build { dependsOn(tasks.named("libJar")) }
+
+configurations {
+    create("lib")
+}
+
+artifacts {
+    add("lib", tasks["libJar"])
+}
+
+
+publishing {
+    publications {
+        create<MavenPublication>("maven") {
+            artifactId = "xms-core-shared"
+            from(components["java"])
+        }
+    }
+}

+ 41 - 0
shared/src/main/kotlin/llh/svs/core/util/FileDealTool.kt

@@ -0,0 +1,41 @@
+package llh.svs.core.util
+
+import org.springframework.core.io.FileSystemResource
+import org.springframework.core.io.Resource
+import org.springframework.http.HttpHeaders
+import org.springframework.http.ResponseEntity
+import org.springframework.http.codec.multipart.FilePart
+import org.springframework.util.Assert
+import java.io.File
+
+/**
+ * 上传下载文件通用处理
+ */
+class FileDealTool {
+
+    companion object {
+
+        fun dealMultiFile(file: FilePart): File {
+            val filename = file.filename()
+            val separatorIndex = filename.lastIndexOf('.')
+            Assert.isTrue(separatorIndex != -1, "文件名不合法")
+            val tempFile = File.createTempFile("tempbuckup", filename.substring(separatorIndex))
+            tempFile.deleteOnExit()
+            file.transferTo(tempFile)
+            return tempFile
+        }
+
+        fun getDownFileResponseEntity(file: File, name: String = "backup"): ResponseEntity<Resource> {
+            val httpHeaders = HttpHeaders()
+            httpHeaders.add(HttpHeaders.CACHE_CONTROL, "no-cache no-store must-revalidate")
+            httpHeaders.add(HttpHeaders.PRAGMA, "no-cache")
+            httpHeaders.add(HttpHeaders.EXPIRES, "0")
+            val filename = String(name.toByteArray(charset("GBK")), charset("ISO_8859_1"))
+            httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"${filename}.${file.extension}\"")
+            return ResponseEntity.ok()
+                .contentLength(file.length())
+                .headers(httpHeaders)
+                .body(FileSystemResource(file))
+        }
+    }
+}

+ 38 - 0
shared/src/main/kotlin/llh/svs/core/util/LinuxCmdExecutor.kt

@@ -0,0 +1,38 @@
+package llh.svs.core.util
+
+import gaf3.core.exception.BusinessError
+import org.slf4j.LoggerFactory
+import java.io.BufferedReader
+import java.io.InputStreamReader
+import java.lang.StringBuilder
+
+class LinuxCmdExecutor {
+    companion object {
+        fun execute(cmd: String): String {
+            runCatching {
+                var line: String?
+                val process = Runtime.getRuntime().exec(arrayOf("/bin/sh", "-c", cmd))
+                log.debug("执行的命令为:$cmd")
+                val waitFor = process.waitFor()
+                if (waitFor != 0) {
+                    throw BusinessError(BusinessError.ERR_BUSINESS, "bash命令执行返回异常, error=${waitFor}")
+                }
+
+                val reader = BufferedReader(InputStreamReader(process.inputStream))
+                val result = StringBuilder()
+                do {
+                    line = reader.readLine()
+                    if (line != null) {
+                        result.append(line + "\n")
+                    }
+                } while (line != null)
+                return result.toString()
+            }.getOrElse {
+                log.error("执行指定bash命令出现异常,原因:${it.message}")
+                throw it
+            }
+        }
+
+        private val log = LoggerFactory.getLogger(LinuxCmdExecutor::class.java)
+    }
+}

+ 59 - 0
shared/src/main/kotlin/llh/svs/core/util/SysHWInfoUtil.kt

@@ -0,0 +1,59 @@
+package llh.svs.core.util
+
+import jit.xms.core.services.util.domain.CpuInfo
+import jit.xms.core.services.util.domain.DiskInfo
+import jit.xms.core.services.util.domain.MemInfo
+import oshi.SystemInfo
+import oshi.util.Util
+
+/**
+ * 获取硬件信息工具类
+ */
+object SysHWInfoUtil {
+
+    /**
+     * 获取系统信息
+     */
+    private val systemInfo = SystemInfo()
+
+    /**
+     * 获取系统硬件信息
+     */
+    private val hardwareInfo = systemInfo.hardware
+
+    /**
+     * 获取操作系统信息
+     */
+    private val operationSystemInfo = systemInfo.operatingSystem
+
+    /**
+     * 获取CPU占用信息
+     */
+    fun getCpuInfo(): CpuInfo {
+        val processor = hardwareInfo.processor
+        val preSystemCpuLoadTicks = processor.systemCpuLoadTicks
+        Util.sleep(300)
+        return CpuInfo(
+            cpuNum = processor.logicalProcessorCount,
+            load = processor.getSystemCpuLoadBetweenTicks(preSystemCpuLoadTicks)
+        )
+    }
+
+    /**
+     * 获取内存信息
+     */
+    fun getMemInfo(): MemInfo {
+        val memory = hardwareInfo.memory
+        return MemInfo(total = memory.total, used = memory.total - memory.available, free = memory.available)
+    }
+
+    /**
+     * 获取磁盘信息
+     */
+    fun getDiskInfo(): List<DiskInfo> {
+        val fileSystem = operationSystemInfo.fileSystem
+        return fileSystem.fileStores.map {
+            DiskInfo(name = it.name, typeName = it.type, total = it.totalSpace, free = it.freeSpace, volume = it.volume)
+        }
+    }
+}

+ 3 - 0
shared/src/main/kotlin/llh/svs/core/util/domain/CpuInfo.kt

@@ -0,0 +1,3 @@
+package jit.xms.core.services.util.domain
+
+data class CpuInfo(val cpuNum: Int, val load: Double)

+ 3 - 0
shared/src/main/kotlin/llh/svs/core/util/domain/DiskInfo.kt

@@ -0,0 +1,3 @@
+package jit.xms.core.services.util.domain
+
+data class DiskInfo(val name: String, val typeName: String, val total: Long, val free: Long, val volume: String)

+ 3 - 0
shared/src/main/kotlin/llh/svs/core/util/domain/MemInfo.kt

@@ -0,0 +1,3 @@
+package jit.xms.core.services.util.domain
+
+data class MemInfo(val total: Long, val used: Long, val free: Long)

+ 11 - 0
src/main/kotlin/com/llh/svscore/SvsCoreApplication.kt

@@ -0,0 +1,11 @@
+package com.llh.svscore
+
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.runApplication
+
+@SpringBootApplication
+class SvsCoreApplication
+
+fun main(args: Array<String>) {
+    runApplication<SvsCoreApplication>(*args)
+}

+ 1 - 0
src/main/resources/application.properties

@@ -0,0 +1 @@
+

+ 13 - 0
src/test/kotlin/com/llh/svscore/SvsCoreApplicationTests.kt

@@ -0,0 +1,13 @@
+package com.llh.svscore
+
+import org.junit.jupiter.api.Test
+import org.springframework.boot.test.context.SpringBootTest
+
+@SpringBootTest
+class SvsCoreApplicationTests {
+
+    @Test
+    fun contextLoads() {
+    }
+
+}