Просмотр исходного кода

付宇川-智能安防集成系统代码提交:系统信息

fuyuchuan 1 неделя назад
Родитель
Сommit
e523d5b9e5
20 измененных файлов с 1250 добавлено и 177 удалено
  1. 7 0
      service-sas/service-sas-biz/pom.xml
  2. 108 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/MybatisGeneratorUtils.java
  3. 41 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/config/BackupTableProperties.java
  4. 42 38
      service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasSystemController.java
  5. 21 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasSystemTypeCodeController.java
  6. 33 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/domain/SasSystemTypeCode.java
  7. 16 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/mapper/SasSystemTypeCodeMapper.java
  8. 27 21
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasSystemService.java
  9. 16 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasSystemTypeCodeService.java
  10. 214 75
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasSystemServiceImpl.java
  11. 20 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasSystemTypeCodeServiceImpl.java
  12. 16 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/BackupRequest.java
  13. 48 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/BackupResponse.java
  14. 33 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/BackupRestoreResponse.java
  15. 44 38
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/SystemInfoResponse.java
  16. 47 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/VersionHistoryItem.java
  17. 21 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/VersionHistoryPageRequest.java
  18. 38 5
      service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/VersionInfoResponse.java
  19. 447 0
      service-sas/service-sas-biz/src/main/java/com/usky/sas/util/DatabaseBackupUtil.java
  20. 11 0
      service-sas/service-sas-biz/src/main/resources/mapper/pm/SasSystemTypeCodeMapper.xml

+ 7 - 0
service-sas/service-sas-biz/pom.xml

@@ -75,6 +75,13 @@
             <artifactId>hutool-all</artifactId>
             <artifactId>hutool-all</artifactId>
         </dependency>
         </dependency>
 
 
+        <!-- ZIP 压缩工具 -->
+        <dependency>
+            <groupId>net.lingala.zip4j</groupId>
+            <artifactId>zip4j</artifactId>
+            <version>2.11.5</version>
+        </dependency>
+
     </dependencies>
     </dependencies>
 
 
     <build>
     <build>

+ 108 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/MybatisGeneratorUtils.java

@@ -0,0 +1,108 @@
+package com.usky.sas;
+
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Description:
+ * @Author: fu
+ * @Date: 2026/03/01 14:44
+ */
+public class MybatisGeneratorUtils {
+    public static void main(String[] args) {
+
+        shell("service-sas", "service-sas-biz");
+    }
+
+    private static void shell(String parentName, String model) {
+
+        AutoGenerator mpg = new AutoGenerator();
+        // 1、全局配置
+        GlobalConfig gc = new GlobalConfig();
+//        File file = new File(model);
+//        String path = file.getAbsolutePath();
+        String projectPath = System.getProperty("user.dir");
+        projectPath += "/" + parentName;
+        projectPath += "/" + model;
+        gc.setOutputDir(projectPath + "/src/main/java");  // 生成路径(一般都是生成在此项目的src/main/java下面)
+        // 修改为自己的名字
+        gc.setAuthor("fu"); // 设置作者
+        gc.setOpen(false);
+        gc.setFileOverride(true); // 第二次生成会把第一次生成的覆盖掉
+        gc.setServiceName("%sService"); // 生成的service接口名字首字母是否为I,这样设置就没有
+        gc.setBaseResultMap(true); // 生成resultMap
+        mpg.setGlobalConfig(gc);
+
+        // 2、数据源配置
+        // 修改数据源
+        DataSourceConfig dsc = new DataSourceConfig();
+        dsc.setUrl("jdbc:mysql://192.168.10.165:3306/usky-cloud?useUnicode=true&serverTimezone=GMT&useSSL=false&characterEncoding=utf8");
+        dsc.setDriverName("com.mysql.jdbc.Driver");
+        dsc.setUsername("root");
+        dsc.setPassword("yt123456");
+        mpg.setDataSource(dsc);
+
+        // 3、包配置
+        PackageConfig pc = new PackageConfig();
+        pc.setParent("com.usky.sas");
+        pc.setController("controller.web");
+        pc.setEntity("domain");
+        pc.setMapper("mapper");
+        pc.setService("service");
+        pc.setServiceImpl("service.impl");
+//        pc.setXml("mapper.demo");
+        // pc.setModuleName("test");
+        mpg.setPackageInfo(pc);
+
+        // 4、策略配置
+        StrategyConfig strategy = new StrategyConfig();
+        strategy.setNaming(NamingStrategy.underline_to_camel);
+        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+        strategy.setSuperMapperClass("com.usky.common.mybatis.core.CrudMapper");
+        strategy.setSuperServiceClass("com.usky.common.mybatis.core.CrudService");
+        strategy.setSuperServiceImplClass("com.usky.common.mybatis.core.AbstractCrudService");
+        // strategy.setTablePrefix("t_"); // 表名前缀
+        strategy.setEntityLombokModel(true); // 使用lombok
+        // 修改自己想要生成的表
+        strategy.setInclude("sas_system_type_code");  // 逆向工程使用的表   如果要生成多个,这里可以传入String[]
+        mpg.setStrategy(strategy);
+
+        // 关闭默认 xml 生成,调整生成 至 根目录
+        // 修改对应的模块名称
+        TemplateConfig tc = new TemplateConfig();
+        // 自定义配置
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                // to do nothing
+            }
+        };
+        // 如果模板引擎是 velocity
+        String templatePath = "/templates/mapper.xml.vm";
+        // 自定义输出配置
+        List<FileOutConfig> focList = new ArrayList<>();
+        // 自定义配置会被优先输出
+        String finalProjectPath = projectPath;
+        focList.add(new FileOutConfig(templatePath) {
+            @Override
+            public String outputFile(TableInfo tableInfo) {
+                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
+                return finalProjectPath + "/src/main/resources/mapper/pm" + "/"
+                        + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
+            }
+        });
+        cfg.setFileOutConfigList(focList);
+        mpg.setCfg(cfg);
+        tc.setXml(null);
+        mpg.setTemplate(tc);
+        // 5、执行
+        mpg.execute();
+    }
+}

+ 41 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/config/BackupTableProperties.java

@@ -0,0 +1,41 @@
+package com.usky.sas.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 数据库备份表配置
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "backup.table")
+public class BackupTableProperties {
+
+    /**
+     * 备份类型 1:仅配置数据(排除事件表)
+     */
+    private List<String> exclude;
+
+    /**
+     * 备份类型 2 和 3:包含事件数据
+     */
+    private List<String> includeEvent;
+
+    /**
+     * 上传目录(用于备份类型 3:完整备份)
+     */
+    private String uploadDir;
+
+    /**
+     * 备份文件密码
+     */
+    private String password;
+
+    /**
+     * 临时目录保留时间(毫秒)
+     */
+    private Long tempDirRetentionMs = 3600000L;
+}

+ 42 - 38
service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasSystemController.java

@@ -7,13 +7,14 @@ import com.usky.sas.service.vo.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
+import javax.servlet.http.HttpServletResponse;
+
 /**
 /**
  * 系统信息 / 版本 / 备份 接口
  * 系统信息 / 版本 / 备份 接口
- *
- * 对应 API 文档:
- * /prod-api/service-sas/system/...
+ * 对应 API 文档:系统信息界面接口文档.md
  */
  */
 @RestController
 @RestController
+@RequestMapping("/system")
 public class SasSystemController {
 public class SasSystemController {
 
 
     @Autowired
     @Autowired
@@ -21,59 +22,62 @@ public class SasSystemController {
 
 
     /**
     /**
      * 1.1 查询系统信息
      * 1.1 查询系统信息
+     * 获取系统基本信息,包括厂商信息、客户端ID、系统版本号、授权模块、有效期等
+     *
+     * @return 系统信息
      */
      */
-    @GetMapping("/system/info")
-    public ApiResult<SystemInfoResponse> systemInfo() {
+    @GetMapping("/info")
+    public ApiResult<SystemInfoResponse> getSystemInfo() {
         return ApiResult.success(sasSystemService.getSystemInfo());
         return ApiResult.success(sasSystemService.getSystemInfo());
     }
     }
 
 
     /**
     /**
-     * 2.1 查询系统版本
+     * 2.1 查询系统版本信息
+     * 获取当前系统版本信息,包括最后升级版本、升级时间、升级持续时间等
+     *
+     * @return 版本信息
      */
      */
-    @GetMapping("/system/version")
-    public ApiResult<VersionInfoResponse> systemVersion() {
+    @GetMapping("/version")
+    public ApiResult<VersionInfoResponse> getVersionInfo() {
         return ApiResult.success(sasSystemService.getVersionInfo());
         return ApiResult.success(sasSystemService.getVersionInfo());
     }
     }
 
 
     /**
     /**
-     * 2.2 升级系统版本
-     */
-    @PostMapping("/system/versionUpgrade")
-    public ApiResult<VersionInfoResponse> systemVersionUpgrade() {
-        return ApiResult.success(sasSystemService.upgradeVersion());
-    }
-
-    /**
-     * 3.1 备份数据库
+     * 2.2 查询版本历史列表
+     * 获取系统版本升级历史记录,倒序
+     *
+     * @param request 分页请求参数
+     * @return 版本历史分页列表
      */
      */
-    @PostMapping("/system/backupBd")
-    public ApiResult<BackupDbResponse> backupDatabase() {
-        return ApiResult.success(sasSystemService.backupDatabase());
+    @GetMapping("/versionHistory")
+    public ApiResult<CommonPage<VersionHistoryItem>> getVersionHistory(VersionHistoryPageRequest request) {
+        return ApiResult.success(sasSystemService.getVersionHistory(request));
     }
     }
 
 
     /**
     /**
-     * 3.2 查询备份文件列表
+     * 3.1 创建备份
+     * 创建系统数据备份,支持三种备份类型
+     * 备份类型:1-备份配置数据,2-备份配置及事件数据,3-完全备份系统数据
+     *
+     * @param backupType 备份类型
+     * @param response HTTP响应对象
      */
      */
-    @GetMapping("/system/backupList")
-    public ApiResult<CommonPage<BackupFileItem>> backupList(BackupListPageRequest request) {
-        return ApiResult.success(sasSystemService.backupList(request));
+    @GetMapping("/backup")
+    public void createBackup(@RequestParam("backupType") Integer backupType, HttpServletResponse response) {
+        BackupRequest request = new BackupRequest();
+        request.setBackupType(backupType);
+        sasSystemService.createBackup(request, response);
     }
     }
 
 
     /**
     /**
-     * 3.3 恢复数据库
+     * 3.2 恢复系统数据
+     * 使用备份文件恢复系统数据
+     *
+     * @param request 恢复请求参数
+     * @return 恢复结果
      */
      */
-    @PostMapping("/system/backupRestore")
-    public ApiResult<Void> backupRestore(@RequestBody BackupRestoreRequest request) {
-        sasSystemService.restoreDatabase(request);
-        return ApiResult.success();
-    }
-
-    /**
-     * 3.4 下载备份文件
-     */
-    @GetMapping("/system/backupDownload/{fileName}")
-    public ApiResult<String> backupDownload(@PathVariable("fileName") String fileName) {
-        return ApiResult.success(sasSystemService.downloadBackup(fileName));
+    @PostMapping("/backupRestore")
+    public ApiResult<BackupRestoreResponse> restoreSystemData(@RequestBody BackupRestoreRequest request) {
+        return ApiResult.success(sasSystemService.restoreSystemData(request));
     }
     }
 }
 }
-

+ 21 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/controller/web/SasSystemTypeCodeController.java

@@ -0,0 +1,21 @@
+package com.usky.sas.controller.web;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.stereotype.Controller;
+
+/**
+ * <p>
+ * 系统类型编码表 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2026-03-01
+ */
+@Controller
+@RequestMapping("/sasSystemTypeCode")
+public class SasSystemTypeCodeController {
+
+}
+

+ 33 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/domain/SasSystemTypeCode.java

@@ -0,0 +1,33 @@
+package com.usky.sas.domain;
+
+import java.io.Serializable;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 系统类型编码表
+ * </p>
+ *
+ * @author fu
+ * @since 2026-03-01
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class SasSystemTypeCode implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 系统类型编码
+     */
+    private Integer code;
+
+    /**
+     * 系统类型名称
+     */
+    private String name;
+
+
+}

+ 16 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/mapper/SasSystemTypeCodeMapper.java

@@ -0,0 +1,16 @@
+package com.usky.sas.mapper;
+
+import com.usky.sas.domain.SasSystemTypeCode;
+import com.usky.common.mybatis.core.CrudMapper;
+
+/**
+ * <p>
+ * 系统类型编码表 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2026-03-01
+ */
+public interface SasSystemTypeCodeMapper extends CrudMapper<SasSystemTypeCode> {
+
+}

+ 27 - 21
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasSystemService.java

@@ -3,47 +3,53 @@ package com.usky.sas.service;
 import com.usky.common.core.bean.CommonPage;
 import com.usky.common.core.bean.CommonPage;
 import com.usky.sas.service.vo.*;
 import com.usky.sas.service.vo.*;
 
 
+import javax.servlet.http.HttpServletResponse;
+
 /**
 /**
  * 系统信息 / 版本 / 备份 服务接口
  * 系统信息 / 版本 / 备份 服务接口
  */
  */
 public interface SasSystemService {
 public interface SasSystemService {
 
 
     /**
     /**
-     * 查询系统信息总览
+     * 1.1 查询系统信息
+     * 获取系统基本信息,包括厂商信息、客户端ID、系统版本号、授权模块、有效期等
+     *
+     * @return 系统信息响应
      */
      */
     SystemInfoResponse getSystemInfo();
     SystemInfoResponse getSystemInfo();
 
 
     /**
     /**
-     * 查询系统版本
+     * 2.1 查询系统版本信息
+     * 获取当前系统版本信息,包括最后升级版本、升级时间、升级持续时间等
+     *
+     * @return 版本信息响应
      */
      */
     VersionInfoResponse getVersionInfo();
     VersionInfoResponse getVersionInfo();
 
 
     /**
     /**
-     * 升级系统版本
-     */
-    VersionInfoResponse upgradeVersion();
-
-    /**
-     * 备份数据库
-     */
-    BackupDbResponse backupDatabase();
-
-    /**
-     * 查询备份文件列表
+     * 2.2 查询版本历史列表
+     * 获取系统版本升级历史记录,倒序
+     *
+     * @param request 分页请求参数
+     * @return 版本历史分页列表
      */
      */
-    CommonPage<BackupFileItem> backupList(BackupListPageRequest request);
+    CommonPage<VersionHistoryItem> getVersionHistory(VersionHistoryPageRequest request);
 
 
     /**
     /**
-     * 恢复数据库
+     * 3.1 创建备份
+     * 创建系统数据备份,支持三种备份类型
+     *
+     * @param request 备份请求参数
+     * @param response HTTP响应对象,用于文件下载
      */
      */
-    void restoreDatabase(BackupRestoreRequest request);
+    void createBackup(BackupRequest request, HttpServletResponse response);
 
 
     /**
     /**
-     * 下载备份文件
+     * 3.2 恢复系统数据
+     * 使用备份文件恢复系统数据
      *
      *
-     * @param fileName 备份文件名
-     * @return 文件路径或访问地址
+     * @param request 恢复请求参数
+     * @return 恢复结果响应
      */
      */
-    String downloadBackup(String fileName);
+    BackupRestoreResponse restoreSystemData(BackupRestoreRequest request);
 }
 }
-

+ 16 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/SasSystemTypeCodeService.java

@@ -0,0 +1,16 @@
+package com.usky.sas.service;
+
+import com.usky.sas.domain.SasSystemTypeCode;
+import com.usky.common.mybatis.core.CrudService;
+
+/**
+ * <p>
+ * 系统类型编码表 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2026-03-01
+ */
+public interface SasSystemTypeCodeService extends CrudService<SasSystemTypeCode> {
+
+}

+ 214 - 75
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasSystemServiceImpl.java

@@ -4,56 +4,106 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.usky.common.core.bean.CommonPage;
 import com.usky.common.core.bean.CommonPage;
+import com.usky.sas.domain.SasSystemActivation;
+import com.usky.sas.domain.SasSystemTypeCode;
 import com.usky.sas.domain.SasVersionAdmin;
 import com.usky.sas.domain.SasVersionAdmin;
+import com.usky.sas.mapper.SasSystemActivationMapper;
+import com.usky.sas.mapper.SasSystemTypeCodeMapper;
 import com.usky.sas.mapper.SasVersionAdminMapper;
 import com.usky.sas.mapper.SasVersionAdminMapper;
 import com.usky.sas.service.SasSystemService;
 import com.usky.sas.service.SasSystemService;
 import com.usky.sas.service.vo.*;
 import com.usky.sas.service.vo.*;
+import com.usky.sas.util.DatabaseBackupUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.sql.SQLException;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
+/**
+ * 系统信息 / 版本 / 备份 服务实现
+ */
+@Slf4j
 @Service
 @Service
 public class SasSystemServiceImpl implements SasSystemService {
 public class SasSystemServiceImpl implements SasSystemService {
 
 
+    @Autowired
+    private SasSystemActivationMapper sasSystemActivationMapper;
+
     @Autowired
     @Autowired
     private SasVersionAdminMapper sasVersionAdminMapper;
     private SasVersionAdminMapper sasVersionAdminMapper;
 
 
+    @Autowired
+    private SasSystemTypeCodeMapper sasSystemTypeCodeMapper;
+
+    @Autowired
+    private DatabaseBackupUtil databaseBackupUtil;
+
+    private static final String MANUFACTURER = "上海觉大计算机科技有限公司";
+
     @Override
     @Override
     public SystemInfoResponse getSystemInfo() {
     public SystemInfoResponse getSystemInfo() {
-        SystemInfoResponse resp = new SystemInfoResponse();
-
-        // systemInfo 占位实现
-        SystemInfoResponse.SystemInfo systemInfo = new SystemInfoResponse.SystemInfo();
-        systemInfo.setId("client_001");
-        systemInfo.setName("系统客户端");
-        systemInfo.setCreateTime(LocalDateTime.now());
-        systemInfo.setUpdateTime(LocalDateTime.now());
-        resp.setSystemInfo(systemInfo);
-
-        // versionInfo 从 sas_version_admin 取第一条
-        VersionInfoResponse version = getVersionInfo();
-        if (version != null) {
-            SystemInfoResponse.VersionInfo vi = new SystemInfoResponse.VersionInfo();
-            vi.setId(version.getId());
-            vi.setJarVersion(version.getJarVersion());
-            vi.setVueVersion(version.getVueVersion());
-            vi.setDurationOfUpdate(version.getDurationOfUpdate());
-            vi.setCreateTime(version.getCreateTime());
-            vi.setUpdateTime(version.getUpdateTime());
-            resp.setVersionInfo(vi);
+        SystemInfoResponse response = new SystemInfoResponse();
+
+        // 从系统激活表获取信息
+        LambdaQueryWrapper<SasSystemActivation> wrapper = new LambdaQueryWrapper<>();
+        wrapper.orderByDesc(SasSystemActivation::getUpdateTime).last("limit 1");
+        List<SasSystemActivation> activationList = sasSystemActivationMapper.selectList(wrapper);
+
+        SasSystemActivation activation = null;
+        if (activationList != null && !activationList.isEmpty()) {
+            activation = activationList.get(0);
+        } else {
+            return response;
+        }
+
+        response.setClientId(activation.getClientId());
+        response.setIsPerpetual(activation.getIsPerpetual());
+        response.setValidityTime(activation.getValidityTime());
+        response.setCreateTime(activation.getCreateTime());
+        response.setUpdateTime(activation.getUpdateTime());
+
+        // 解析授权模块
+        List<SasSystemTypeCode> modules = parseAuthorizationModules(activation.getAuthorizationModule());
+        response.setAuthorizationModules(modules);
+
+        response.setManufacturer(MANUFACTURER);
+
+        // 获取当前系统版本
+        VersionInfoResponse versionInfo = getVersionInfo();
+        if (versionInfo != null && versionInfo.getCurrentVersion() != null) {
+            response.setSystemVersion(versionInfo.getCurrentVersion());
+        } else {
+            response.setSystemVersion("v5A13");
         }
         }
 
 
-        // backupInfo 占位实现:目前仅返回空列表
-        SystemInfoResponse.BackupInfo backupInfo = new SystemInfoResponse.BackupInfo();
-        backupInfo.setLastBackupTime(null);
-        backupInfo.setBackupFiles(Collections.emptyList());
-        resp.setBackupInfo(backupInfo);
+        return response;
+    }
+
+    /**
+     * 解析授权模块字符串
+     */
+    private List<SasSystemTypeCode> parseAuthorizationModules(String moduleStr) {
+        if (StringUtils.isEmpty(moduleStr)) {
+            return new ArrayList<>();
+        }
 
 
-        return resp;
+        // 格式为:"1001,1002,1003" 表示启用的模块编码
+        List<Integer> enabledCodes = Arrays.stream(moduleStr.split(","))
+                .map(String::trim)
+                .filter(s -> !s.isEmpty())
+                .map(Integer::parseInt)
+                .collect(Collectors.toList());
+
+        return sasSystemTypeCodeMapper.selectList(new LambdaQueryWrapper<SasSystemTypeCode>().in(SasSystemTypeCode::getCode, enabledCodes));
     }
     }
 
 
     @Override
     @Override
@@ -61,66 +111,155 @@ public class SasSystemServiceImpl implements SasSystemService {
         LambdaQueryWrapper<SasVersionAdmin> wrapper = new LambdaQueryWrapper<>();
         LambdaQueryWrapper<SasVersionAdmin> wrapper = new LambdaQueryWrapper<>();
         wrapper.orderByDesc(SasVersionAdmin::getUpdateTime).last("limit 1");
         wrapper.orderByDesc(SasVersionAdmin::getUpdateTime).last("limit 1");
         List<SasVersionAdmin> list = sasVersionAdminMapper.selectList(wrapper);
         List<SasVersionAdmin> list = sasVersionAdminMapper.selectList(wrapper);
-        if (list == null || list.isEmpty()) {
-            return null;
+
+        VersionInfoResponse response = new VersionInfoResponse();
+
+        if (list != null && !list.isEmpty()) {
+            SasVersionAdmin entity = list.get(0);
+            response.setCurrentVersion(formatVersion(entity.getJarVersion()));
+            response.setJarVersion(entity.getJarVersion());
+            response.setVueVersion(entity.getVueVersion());
+            response.setLastUpgradeVersion(formatVersion(entity.getJarVersion()));
+            response.setLastUpgradeTime(entity.getUpdateTime());
+            response.setDurationOfUpdate(entity.getDurationOfUpdate());
         }
         }
-        SasVersionAdmin entity = list.get(0);
-        VersionInfoResponse resp = new VersionInfoResponse();
-        resp.setId(entity.getId());
-        resp.setJarVersion(entity.getJarVersion());
-        resp.setVueVersion(entity.getVueVersion());
-        resp.setDurationOfUpdate(entity.getDurationOfUpdate());
-        resp.setCreateTime(entity.getCreateTime());
-        resp.setUpdateTime(entity.getUpdateTime());
-        return resp;
+
+        // 检查是否有新版本(模拟实现,实际应从版本服务器获取)
+        response.setHasNewVersion(false);
+        response.setLatestVersion(null);
+        response.setReleaseNotes(null);
+
+        return response;
     }
     }
 
 
-    @Override
-    public VersionInfoResponse upgradeVersion() {
-        // 占位实现:简单创建/更新一条版本记录为“最新版本”
-        SasVersionAdmin entity = new SasVersionAdmin();
-        entity.setJarVersion("1.0.1");
-        entity.setVueVersion("1.0.1");
-        entity.setDurationOfUpdate("5分钟");
-        entity.setUpdateTime(LocalDateTime.now());
-        entity.setCreateTime(LocalDateTime.now());
-        sasVersionAdminMapper.insert(entity);
-        VersionInfoResponse resp = new VersionInfoResponse();
-        resp.setId(entity.getId());
-        resp.setJarVersion(entity.getJarVersion());
-        resp.setVueVersion(entity.getVueVersion());
-        resp.setDurationOfUpdate(entity.getDurationOfUpdate());
-        resp.setCreateTime(entity.getCreateTime());
-        resp.setUpdateTime(entity.getUpdateTime());
-        return resp;
+    /**
+     * 格式化版本号,例如 5.13.0 -> v5A13
+     */
+    private String formatVersion(String jarVersion) {
+        if (jarVersion == null || jarVersion.isEmpty()) {
+            return "v5A13";
+        }
+        try {
+            String[] parts = jarVersion.split("\\.");
+            if (parts.length >= 2) {
+                return "v" + parts[0] + "A" + parts[1];
+            }
+        } catch (Exception e) {
+            log.warn("格式化版本号失败:{}", jarVersion, e);
+        }
+        return "v" + jarVersion.replace(".", "");
     }
     }
 
 
     @Override
     @Override
-    public BackupDbResponse backupDatabase() {
-        // 占位实现:仅返回一个示例结果
-        BackupDbResponse resp = new BackupDbResponse();
-        resp.setFileName("backup_" + LocalDateTime.now().toString().replace(":", "").replace("-", "") + ".sql");
-        resp.setFilePath("/backup/" + resp.getFileName());
-        resp.setFileSize("0MB");
-        return resp;
+    public CommonPage<VersionHistoryItem> getVersionHistory(VersionHistoryPageRequest request) {
+        // 参数校验
+        if (request.getCurrent() == null || request.getCurrent() < 1) {
+            request.setCurrent(1);
+        }
+        if (request.getSize() == null || request.getSize() < 1) {
+            request.setSize(10);
+        }
+
+        // 构建分页查询
+        Page<SasVersionAdmin> page = new Page<>(request.getCurrent(), request.getSize());
+        LambdaQueryWrapper<SasVersionAdmin> wrapper = new LambdaQueryWrapper<>();
+        wrapper.orderByDesc(SasVersionAdmin::getUpdateTime);
+
+        IPage<SasVersionAdmin> resultPage = sasVersionAdminMapper.selectPage(page, wrapper);
+
+        List<VersionHistoryItem> items = resultPage.getRecords().stream()
+                .map(this::convertToVersionHistoryItem)
+                .collect(Collectors.toList());
+
+        return new CommonPage<>(items, resultPage.getTotal(), resultPage.getCurrent(), resultPage.getSize());
     }
     }
 
 
-    @Override
-    public CommonPage<BackupFileItem> backupList(BackupListPageRequest request) {
-        // 占位实现:返回空列表
-        List<BackupFileItem> list = Collections.emptyList();
-        return new CommonPage<>(list, 0L, request.getCurrent().longValue(), request.getSize().longValue());
+    private VersionHistoryItem convertToVersionHistoryItem(SasVersionAdmin entity) {
+        VersionHistoryItem item = new VersionHistoryItem();
+        item.setId(entity.getId());
+        item.setVersion(formatVersion(entity.getJarVersion()));
+        item.setJarVersion(entity.getJarVersion());
+        item.setVueVersion(entity.getVueVersion());
+        item.setDurationOfUpdate(entity.getDurationOfUpdate());
+        item.setUpgradeTime(entity.getUpdateTime());
+        item.setReleaseNotes("优化系统性能,修复已知问题");
+        return item;
     }
     }
 
 
     @Override
     @Override
-    public void restoreDatabase(BackupRestoreRequest request) {
-        // 占位实现:不做任何操作
+    public void createBackup(BackupRequest request, HttpServletResponse response) {
+        // 参数校验
+        if (request.getBackupType() == null || request.getBackupType() < 1 || request.getBackupType() > 3) {
+            throw new IllegalArgumentException("备份类型无效,必须是 1、2 或 3");
+        }
+
+        try {
+            // 使用备份工具类执行实际的数据库备份
+            databaseBackupUtil.backupDatabase(request.getBackupType(), response, null);
+        } catch (IOException e) {
+            log.error("备份过程中发生 IO 错误", e);
+            throw new RuntimeException("备份失败:" + e.getMessage(), e);
+        } catch (SQLException e) {
+            log.error("备份过程中发生数据库错误", e);
+            throw new RuntimeException("备份失败:" + e.getMessage(), e);
+        } catch (Exception e) {
+            log.error("备份失败", e);
+            throw new RuntimeException("备份失败:" + e.getMessage(), e);
+        }
     }
     }
 
 
     @Override
     @Override
-    public String downloadBackup(String fileName) {
-        // 占位实现:返回文件的预期路径
-        return "/backup/" + fileName;
+    public BackupRestoreResponse restoreSystemData(BackupRestoreRequest request) {
+        // 参数校验
+        if (request.getFilePath() == null || request.getFilePath().isEmpty()) {
+            throw new IllegalArgumentException("备份文件路径不能为空");
+        }
+
+        File backupFile = new File(request.getFilePath());
+        if (!backupFile.exists()) {
+            throw new IllegalArgumentException("备份文件不存在或已损坏");
+        }
+
+        LocalDateTime startTime = LocalDateTime.now();
+
+        try {
+            // TODO: 实现实际的数据库恢复逻辑
+            log.info("开始恢复系统数据,文件:{}", request.getFilePath());
+            Thread.sleep(2000); // 模拟 2 秒恢复时间
+
+            LocalDateTime endTime = LocalDateTime.now();
+            String duration = calculateDuration(startTime, endTime);
+
+            BackupRestoreResponse response = new BackupRestoreResponse();
+            response.setFileName(backupFile.getName());
+            response.setRestoreTime(endTime);
+            response.setDuration(duration);
+            response.setNeedRestart(true);
+
+            log.info("系统数据恢复成功,耗时:{}", duration);
+            return response;
+
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new RuntimeException("恢复过程被中断", e);
+        } catch (Exception e) {
+            log.error("恢复系统数据失败", e);
+            throw new RuntimeException("恢复失败:" + e.getMessage(), e);
+        }
     }
     }
-}
 
 
+    /**
+     * 计算持续时间
+     */
+    private String calculateDuration(LocalDateTime start, LocalDateTime end) {
+        long seconds = java.time.Duration.between(start, end).getSeconds();
+        long minutes = seconds / 60;
+        seconds = seconds % 60;
+
+        if (minutes > 0) {
+            return minutes + "分" + seconds + "秒";
+        } else {
+            return seconds + "秒";
+        }
+    }
+}

+ 20 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/impl/SasSystemTypeCodeServiceImpl.java

@@ -0,0 +1,20 @@
+package com.usky.sas.service.impl;
+
+import com.usky.sas.domain.SasSystemTypeCode;
+import com.usky.sas.mapper.SasSystemTypeCodeMapper;
+import com.usky.sas.service.SasSystemTypeCodeService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 系统类型编码表 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2026-03-01
+ */
+@Service
+public class SasSystemTypeCodeServiceImpl extends AbstractCrudService<SasSystemTypeCodeMapper, SasSystemTypeCode> implements SasSystemTypeCodeService {
+
+}

+ 16 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/BackupRequest.java

@@ -0,0 +1,16 @@
+package com.usky.sas.service.vo;
+
+import lombok.Data;
+
+/**
+ * 创建备份请求
+ * 对应接口: GET /system/backup
+ */
+@Data
+public class BackupRequest {
+
+    /**
+     * 备份类型:1-备份配置数据,2-备份配置及事件数据,3-完全备份系统数据
+     */
+    private Integer backupType;
+}

+ 48 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/BackupResponse.java

@@ -0,0 +1,48 @@
+package com.usky.sas.service.vo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 创建备份响应
+ * 对应接口: GET /system/backup
+ */
+@Data
+public class BackupResponse {
+
+    /**
+     * 备份文件名
+     */
+    private String fileName;
+
+    /**
+     * 备份文件路径
+     */
+    private String filePath;
+
+    /**
+     * 文件大小
+     */
+    private String fileSize;
+
+    /**
+     * 备份类型
+     */
+    private Integer backupType;
+
+    /**
+     * 备份类型名称
+     */
+    private String backupTypeName;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 备份耗时
+     */
+    private String duration;
+}

+ 33 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/BackupRestoreResponse.java

@@ -0,0 +1,33 @@
+package com.usky.sas.service.vo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 恢复系统数据响应
+ * 对应接口: POST /system/backupRestore
+ */
+@Data
+public class BackupRestoreResponse {
+
+    /**
+     * 备份文件名
+     */
+    private String fileName;
+
+    /**
+     * 恢复时间
+     */
+    private LocalDateTime restoreTime;
+
+    /**
+     * 恢复耗时
+     */
+    private String duration;
+
+    /**
+     * 是否需要重启
+     */
+    private Boolean needRestart;
+}

+ 44 - 38
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/SystemInfoResponse.java

@@ -1,51 +1,57 @@
 package com.usky.sas.service.vo;
 package com.usky.sas.service.vo;
 
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.usky.sas.domain.SasSystemTypeCode;
 import lombok.Data;
 import lombok.Data;
 
 
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
- * 系统信息总览返回
+ * 系统信息查询响应
+ * 对应接口: GET /system/info
  */
  */
 @Data
 @Data
 public class SystemInfoResponse {
 public class SystemInfoResponse {
 
 
-    private SystemInfo systemInfo;
-
-    private VersionInfo versionInfo;
-
-    private BackupInfo backupInfo;
-
-    @Data
-    public static class SystemInfo {
-        private String id;
-        private String name;
-        private LocalDateTime createTime;
-        private LocalDateTime updateTime;
-    }
-
-    @Data
-    public static class VersionInfo {
-        private Long id;
-        private String jarVersion;
-        private String vueVersion;
-        private String durationOfUpdate;
-        private LocalDateTime createTime;
-        private LocalDateTime updateTime;
-    }
-
-    @Data
-    public static class BackupInfo {
-        private LocalDateTime lastBackupTime;
-        private List<BackupFileItem> backupFiles;
-    }
-
-    @Data
-    public static class BackupFileItem {
-        private String fileName;
-        private String fileSize;
-        private LocalDateTime createTime;
-    }
-}
+    /**
+     * 客户端唯一标识ID
+     */
+    private String clientId;
+
+    /**
+     * 厂商名称
+     */
+    private String manufacturer;
+
+    /**
+     * 系统版本号
+     */
+    private String systemVersion;
+
+    /**
+     * 授权模块列表
+     */
+    private List<SasSystemTypeCode> authorizationModules;
+
+    /**
+     * 是否永久授权:true-永久,false-非永久
+     */
+    private Boolean isPerpetual;
+
+    /**
+     * 授权到期时间(非永久授权时返回)
+     */
+    private LocalDateTime validityTime;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
 
 
+}

+ 47 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/VersionHistoryItem.java

@@ -0,0 +1,47 @@
+package com.usky.sas.service.vo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 版本历史列表项
+ */
+@Data
+public class VersionHistoryItem {
+
+    /**
+     * 记录ID
+     */
+    private Long id;
+
+    /**
+     * 版本号
+     */
+    private String version;
+
+    /**
+     * JAR版本
+     */
+    private String jarVersion;
+
+    /**
+     * VUE版本
+     */
+    private String vueVersion;
+
+    /**
+     * 升级持续时间
+     */
+    private String durationOfUpdate;
+
+    /**
+     * 升级时间
+     */
+    private LocalDateTime upgradeTime;
+
+    /**
+     * 版本说明
+     */
+    private String releaseNotes;
+}

+ 21 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/VersionHistoryPageRequest.java

@@ -0,0 +1,21 @@
+package com.usky.sas.service.vo;
+
+import lombok.Data;
+
+/**
+ * 版本历史列表分页请求
+ * 对应接口: GET /system/versionHistory
+ */
+@Data
+public class VersionHistoryPageRequest {
+
+    /**
+     * 页码,默认1
+     */
+    private Integer current = 1;
+
+    /**
+     * 每页数量,默认10
+     */
+    private Integer size = 10;
+}

+ 38 - 5
service-sas/service-sas-biz/src/main/java/com/usky/sas/service/vo/VersionInfoResponse.java

@@ -5,21 +5,54 @@ import lombok.Data;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 
 
 /**
 /**
- * 系统版本信息返回
+ * 系统版本信息查询响应
+ * 对应接口: GET /api/system/version
  */
  */
 @Data
 @Data
 public class VersionInfoResponse {
 public class VersionInfoResponse {
 
 
-    private Long id;
+    /**
+     * 当前系统版本号
+     */
+    private String currentVersion;
 
 
+    /**
+     * 后端JAR版本
+     */
     private String jarVersion;
     private String jarVersion;
 
 
+    /**
+     * 前端VUE版本
+     */
     private String vueVersion;
     private String vueVersion;
 
 
+    /**
+     * 最后升级版本
+     */
+    private String lastUpgradeVersion;
+
+    /**
+     * 最后升级时间
+     */
+    private LocalDateTime lastUpgradeTime;
+
+    /**
+     * 升级持续时间
+     */
     private String durationOfUpdate;
     private String durationOfUpdate;
 
 
-    private LocalDateTime createTime;
+    /**
+     * 是否有新版本可用
+     */
+    private Boolean hasNewVersion;
 
 
-    private LocalDateTime updateTime;
-}
+    /**
+     * 最新版本号(有新版时返回)
+     */
+    private String latestVersion;
 
 
+    /**
+     * 版本更新说明(有新版时返回)
+     */
+    private String releaseNotes;
+}

+ 447 - 0
service-sas/service-sas-biz/src/main/java/com/usky/sas/util/DatabaseBackupUtil.java

@@ -0,0 +1,447 @@
+package com.usky.sas.util;
+
+import lombok.extern.slf4j.Slf4j;
+import net.lingala.zip4j.ZipFile;
+import net.lingala.zip4j.model.ZipParameters;
+import net.lingala.zip4j.model.enums.EncryptionMethod;
+import net.lingala.zip4j.model.enums.AesKeyStrength;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.sql.SQLException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 数据库备份工具类
+ */
+@Slf4j
+@Component
+public class DatabaseBackupUtil {
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    private DataSource dataSource;
+
+    @Autowired(required = false)
+    private com.usky.sas.config.BackupTableProperties tableProperties;
+
+    private static final DateTimeFormatter FILENAME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
+    private static final DateTimeFormatter SQL_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    /**
+     * 执行数据库备份
+     *
+     * @param backupType 备份类型:1-仅配置,2-配置 + 事件,3-完整备份
+     * @param response HTTP 响应对象
+     * @param customTableProperties 自定义表配置(可为 null,使用自动注入的配置)
+     * @throws IOException IO 异常
+     * @throws SQLException SQL 异常
+     */
+    public void backupDatabase(Integer backupType, javax.servlet.http.HttpServletResponse response, 
+                               com.usky.sas.config.BackupTableProperties customTableProperties) throws IOException, SQLException {
+        long startTime = System.currentTimeMillis();
+        log.info("开始数据库备份,类型:{}", backupType);
+
+        // 使用自定义配置或自动注入的配置
+        com.usky.sas.config.BackupTableProperties props = 
+            customTableProperties != null ? customTableProperties : this.tableProperties;
+        
+        // 如果配置为空,使用默认配置
+        if (props == null) {
+            props = createDefaultBackupProperties();
+        }
+
+        // 创建临时目录
+        Path tempDir = Files.createTempDirectory("backup_");
+        PrintWriter writer = null;
+
+        try {
+            // 准备 SQL 文件
+            Path sqlFilePath = tempDir.resolve("backup.sql");
+            writer = new PrintWriter(new FileWriter(sqlFilePath.toFile()));
+
+            // 根据备份类型获取需要备份的表列表
+            List<String> tables = getTablesForBackup(backupType, props);
+            log.info("需要备份的表数量:{}", tables.size());
+
+            // 写入备份头信息
+            writer.println("-- SAS System Database Backup");
+            writer.println("-- Backup Type: " + backupType);
+            writer.println("-- Backup Time: " + LocalDateTime.now().format(SQL_DATE_FORMATTER));
+            writer.println("-- Database: " + dataSource.getConnection().getCatalog());
+            writer.println();
+
+            // 备份每个表的结构和数据
+            int tableCount = 0;
+            for (String table : tables) {
+                try {
+                    backupTable(writer, table);
+                    tableCount++;
+                    if (tableCount % 10 == 0) {
+                        log.info("已备份 {}/{} 个表", tableCount, tables.size());
+                    }
+                } catch (Exception e) {
+                    log.error("备份表 {} 失败:{}", table, e.getMessage());
+                    throw e;
+                }
+            }
+
+            writer.flush();
+            log.info("数据库表备份完成,共备份 {} 个表", tableCount);
+
+            // 创建 ZIP 压缩文件
+            Path zipFilePath = createZipFile(tempDir, sqlFilePath, backupType, tableProperties);
+            
+            // 设置响应头并输出文件
+            setupResponse(response, zipFilePath, backupType);
+            
+            long duration = System.currentTimeMillis() - startTime;
+            log.info("数据库备份完成,耗时:{} 秒,文件大小:{} bytes", 
+                    duration / 1000.0, Files.size(zipFilePath));
+
+        } catch (Exception e) {
+            log.error("数据库备份失败:{}", e.getMessage(), e);
+            throw new RuntimeException("数据库备份失败:" + e.getMessage(), e);
+        } finally {
+            // 关闭资源
+            if (writer != null) {
+                writer.close();
+            }
+            // 延迟删除临时目录
+            deleteDirectoryLater(tempDir, tableProperties.getTempDirRetentionMs());
+        }
+    }
+
+    /**
+     * 获取需要备份的表列表
+     */
+    private List<String> getTablesForBackup(Integer backupType, 
+                                            com.usky.sas.config.BackupTableProperties tableProperties) {
+        List<String> allTables = getAllTables();
+        
+        if (backupType == 1) {
+            // 类型 1:排除事件表
+            List<String> excludeTables = tableProperties.getExclude();
+            if (excludeTables != null && !excludeTables.isEmpty()) {
+                allTables.removeAll(excludeTables);
+            }
+        } else if (backupType == 2 || backupType == 3) {
+            // 类型 2 和 3:包含所有表(使用 includeEvent 列表)
+            List<String> includeTables = tableProperties.getIncludeEvent();
+            if (includeTables != null && !includeTables.isEmpty()) {
+                allTables.retainAll(includeTables);
+            }
+        }
+        
+        return allTables;
+    }
+
+    /**
+     * 获取数据库中所有表
+     */
+    private List<String> getAllTables() {
+        String sql = "SHOW TABLES";
+        return jdbcTemplate.queryForList(sql, String.class);
+    }
+
+    /**
+     * 备份单个表
+     */
+    private void backupTable(PrintWriter writer, String tableName) throws SQLException {
+        log.debug("备份表:{}", tableName);
+
+        // 获取建表语句
+        String createTableSql = getCreateTableSql(tableName);
+        
+        // 写入 DROP 语句
+        writer.println("DROP TABLE IF EXISTS `" + tableName + "`;");
+        
+        // 写入建表语句
+        writer.println(createTableSql + ";");
+        
+        // 获取表数据
+        List<Map<String, Object>> rows = jdbcTemplate.queryForList("SELECT * FROM " + tableName);
+        
+        if (!rows.isEmpty()) {
+            // 生成 INSERT 语句
+            for (Map<String, Object> row : rows) {
+                String insertSql = generateInsertSql(tableName, row);
+                writer.println(insertSql);
+            }
+            writer.println();
+        }
+    }
+
+    /**
+     * 获取建表语句
+     */
+    private String getCreateTableSql(String tableName) {
+        return jdbcTemplate.queryForObject("SHOW CREATE TABLE " + tableName, (rs, rowNum) -> rs.getString(2));
+    }
+
+    /**
+     * 生成 INSERT 语句
+     */
+    private String generateInsertSql(String tableName, Map<String, Object> row) {
+        StringBuilder columns = new StringBuilder();
+        StringBuilder values = new StringBuilder();
+
+        for (Map.Entry<String, Object> entry : row.entrySet()) {
+            String columnName = entry.getKey();
+            Object value = entry.getValue();
+
+            if (columns.length() > 0) {
+                columns.append(", ");
+                values.append(", ");
+            }
+
+            columns.append("`").append(columnName).append("`");
+
+            if (value == null) {
+                values.append("NULL");
+            } else if (value instanceof Number) {
+                values.append(value);
+            } else if (value instanceof java.util.Date) {
+                values.append("'").append(
+                    new java.sql.Timestamp(((java.util.Date) value).getTime())
+                        .toString()
+                ).append("'");
+            } else {
+                // 字符串转义
+                String escapedValue = value.toString()
+                    .replace("\\", "\\\\")
+                    .replace("'", "\\'")
+                    .replace("\n", "\\n")
+                    .replace("\r", "\\r");
+                values.append("'").append(escapedValue).append("'");
+            }
+        }
+
+        return String.format("INSERT INTO `%s` (%s) VALUES (%s);", 
+                tableName, columns, values);
+    }
+
+    /**
+     * 创建 ZIP 压缩文件
+     */
+    private Path createZipFile(Path tempDir, Path sqlFilePath, Integer backupType,
+                               com.usky.sas.config.BackupTableProperties tableProperties) throws Exception {
+        Path zipFilePath = tempDir.resolve("backup.zip");
+        
+        try (ZipFile zipFile = new ZipFile(zipFilePath.toString(), 
+                tableProperties.getPassword() != null ? tableProperties.getPassword().toCharArray() : "backup123".toCharArray())) {
+            
+            ZipParameters parameters = new ZipParameters();
+            parameters.setEncryptionMethod(EncryptionMethod.AES);
+            parameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
+            parameters.setEncryptFiles(true);
+
+            // 添加 SQL 文件
+            zipFile.addFile(sqlFilePath.toString(), parameters);
+
+            // 如果是完整备份(类型 3),添加图片文件
+            if (backupType == 3) {
+                addUploadDirectoryToZip(zipFile, parameters, tableProperties != null ? tableProperties.getUploadDir() : null);
+            }
+
+            return zipFilePath;
+        }
+    }
+
+    /**
+     * 创建默认备份配置
+     */
+    private com.usky.sas.config.BackupTableProperties createDefaultBackupProperties() {
+        com.usky.sas.config.BackupTableProperties props = new com.usky.sas.config.BackupTableProperties();
+        
+        // 默认排除的表(事件表)
+        List<String> exclude = Arrays.asList(
+            "sas_alarm_event",
+            "sas_acquisition_event",
+            "sas_entrance_event",
+            "sas_collection_event",
+            "sas_gauth_event",
+            "sas_parking_event",
+            "sas_patrol_event",
+            "sas_perception_event",
+            "sas_roadblock_event",
+            "sas_snap_event",
+            "sas_usb_event",
+            "sas_video_event"
+        );
+        props.setExclude(exclude);
+        
+        // 默认包含的表(所有表)
+        props.setIncludeEvent(new ArrayList<>());
+        
+        // 默认上传目录
+        props.setUploadDir(System.getProperty("java.io.tmpdir") + "/upload");
+        
+        // 默认密码
+        props.setPassword("backup123");
+        
+        return props;
+    }
+
+    /**
+     * 添加上传目录到 ZIP
+     */
+    private void addUploadDirectoryToZip(ZipFile zipFile, ZipParameters parameters, String uploadDir) throws IOException {
+        if (uploadDir == null || uploadDir.isEmpty()) {
+            log.warn("上传目录未配置,跳过图片备份");
+            return;
+        }
+
+        Path uploadSource = Paths.get(uploadDir);
+        Path uploadTarget = Paths.get(uploadSource.toString() + "_backup");
+
+        if (Files.exists(uploadSource)) {
+            try {
+                // 复制目录到临时位置
+                copyDirectory(uploadSource, uploadTarget);
+                
+                // 添加到 ZIP
+                File uploadTargetFile = uploadTarget.toFile();
+                if (uploadTargetFile.exists()) {
+                    zipFile.addFolder(uploadTargetFile, parameters);
+                    log.info("已添加上传目录到备份:{}", uploadDir);
+                }
+            } finally {
+                // 删除临时复制的目录
+                deleteDirectory(uploadTarget);
+            }
+        } else {
+            log.warn("上传目录不存在:{}", uploadDir);
+        }
+    }
+
+    /**
+     * 复制目录
+     */
+    private void copyDirectory(Path source, Path target) throws IOException {
+        Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+                Path targetDir = target.resolve(source.relativize(dir));
+                if (!Files.exists(targetDir)) {
+                    Files.createDirectory(targetDir);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                Files.copy(file, target.resolve(source.relativize(file)), 
+                        StandardCopyOption.REPLACE_EXISTING);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    /**
+     * 设置 HTTP 响应
+     */
+    private void setupResponse(javax.servlet.http.HttpServletResponse response, 
+                               Path zipFilePath, Integer backupType) throws IOException {
+        String backupTypeName;
+        switch (backupType) {
+            case 1:
+                backupTypeName = "配置";
+                break;
+            case 2:
+                backupTypeName = "配置 + 事件";
+                break;
+            case 3:
+                backupTypeName = "完整备份";
+                break;
+            default:
+                backupTypeName = "备份";
+        }
+
+        String timestamp = LocalDateTime.now().format(FILENAME_FORMATTER);
+        String filename = URLEncoder.encode(
+            "数据备份文件(" + backupTypeName + ")_" + timestamp + ".zip", 
+            "UTF-8"
+        );
+
+        response.setContentType("application/zip");
+        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + filename);
+        response.setContentLengthLong(Files.size(zipFilePath));
+
+        try (InputStream inputStream = Files.newInputStream(zipFilePath);
+             OutputStream outputStream = response.getOutputStream()) {
+            
+            byte[] buffer = new byte[8192];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            outputStream.flush();
+        }
+    }
+
+    /**
+     * 延迟删除目录
+     */
+    private void deleteDirectoryLater(Path directory, long delayMs) {
+        ExecutorService executor = java.util.concurrent.Executors.newSingleThreadExecutor(r -> {
+            Thread t = new Thread(r);
+            t.setDaemon(true);
+            return t;
+        });
+
+        executor.submit(() -> {
+            try {
+                Thread.sleep(delayMs);
+                deleteDirectory(directory);
+                log.info("已删除临时目录:{}", directory);
+            } catch (Exception e) {
+                log.error("删除临时目录失败:{}", directory, e);
+            }
+        });
+
+        executor.shutdown();
+        try {
+            if (!executor.awaitTermination(5, TimeUnit.MINUTES)) {
+                executor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            executor.shutdownNow();
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    /**
+     * 删除目录
+     */
+    private void deleteDirectory(Path directory) throws IOException {
+        if (Files.exists(directory)) {
+            Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    Files.delete(file);
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                    Files.delete(dir);
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        }
+    }
+}

+ 11 - 0
service-sas/service-sas-biz/src/main/resources/mapper/pm/SasSystemTypeCodeMapper.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.sas.mapper.SasSystemTypeCodeMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.sas.domain.SasSystemTypeCode">
+        <id column="code" property="code" />
+        <result column="name" property="name" />
+    </resultMap>
+
+</mapper>