feat(app-versions): 新增App版本管理功能模块
This commit is contained in:
@@ -0,0 +1,104 @@
|
|||||||
|
package com.yolo.keyboard.controller.admin.appversions;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
import jakarta.validation.*;
|
||||||
|
import jakarta.servlet.http.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageParam;
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageResult;
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.CommonResult;
|
||||||
|
import com.yolo.keyboard.framework.common.util.object.BeanUtils;
|
||||||
|
import static com.yolo.keyboard.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
import com.yolo.keyboard.framework.excel.core.util.ExcelUtils;
|
||||||
|
|
||||||
|
import com.yolo.keyboard.framework.apilog.core.annotation.ApiAccessLog;
|
||||||
|
import static com.yolo.keyboard.framework.apilog.core.enums.OperateTypeEnum.*;
|
||||||
|
|
||||||
|
import com.yolo.keyboard.controller.admin.appversions.vo.*;
|
||||||
|
import com.yolo.keyboard.dal.dataobject.appversions.AppVersionsDO;
|
||||||
|
import com.yolo.keyboard.service.appversions.AppVersionsService;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/keyboard/app-versions")
|
||||||
|
@Validated
|
||||||
|
public class AppVersionsController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppVersionsService appVersionsService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。")
|
||||||
|
@PreAuthorize("@ss.hasPermission('keyboard:app-versions:create')")
|
||||||
|
public CommonResult<Long> createAppVersions(@RequestBody AppVersionsSaveReqVO createReqVO) {
|
||||||
|
return success(appVersionsService.createAppVersions(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@Operation(summary = "更新App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。")
|
||||||
|
@PreAuthorize("@ss.hasPermission('keyboard:app-versions:update')")
|
||||||
|
public CommonResult<Boolean> updateAppVersions(@RequestBody AppVersionsSaveReqVO updateReqVO) {
|
||||||
|
appVersionsService.updateAppVersions(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('keyboard:app-versions:delete')")
|
||||||
|
public CommonResult<Boolean> deleteAppVersions(@RequestParam("id") Long id) {
|
||||||
|
appVersionsService.deleteAppVersions(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete-list")
|
||||||
|
@Parameter(name = "ids", description = "编号", required = true)
|
||||||
|
@Operation(summary = "批量删除App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。")
|
||||||
|
@PreAuthorize("@ss.hasPermission('keyboard:app-versions:delete')")
|
||||||
|
public CommonResult<Boolean> deleteAppVersionsList(@RequestParam("ids") List<Long> ids) {
|
||||||
|
appVersionsService.deleteAppVersionsListByIds(ids);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
|
@PreAuthorize("@ss.hasPermission('keyboard:app-versions:query')")
|
||||||
|
public CommonResult<AppVersionsRespVO> getAppVersions(@RequestParam("id") Long id) {
|
||||||
|
AppVersionsDO appVersions = appVersionsService.getAppVersions(id);
|
||||||
|
return success(BeanUtils.toBean(appVersions, AppVersionsRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('keyboard:app-versions:query')")
|
||||||
|
public CommonResult<PageResult<AppVersionsRespVO>> getAppVersionsPage(@Valid AppVersionsPageReqVO pageReqVO) {
|
||||||
|
PageResult<AppVersionsDO> pageResult = appVersionsService.getAppVersionsPage(pageReqVO);
|
||||||
|
return success(BeanUtils.toBean(pageResult, AppVersionsRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/export-excel")
|
||||||
|
@Operation(summary = "导出App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。 Excel")
|
||||||
|
@PreAuthorize("@ss.hasPermission('keyboard:app-versions:export')")
|
||||||
|
@ApiAccessLog(operateType = EXPORT)
|
||||||
|
public void exportAppVersionsExcel(@Valid AppVersionsPageReqVO pageReqVO,
|
||||||
|
HttpServletResponse response) throws IOException {
|
||||||
|
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||||
|
List<AppVersionsDO> list = appVersionsService.getAppVersionsPage(pageReqVO).getList();
|
||||||
|
// 导出 Excel
|
||||||
|
ExcelUtils.write(response, "App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。.xls", "数据", AppVersionsRespVO.class,
|
||||||
|
BeanUtils.toBean(list, AppVersionsRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.yolo.keyboard.controller.admin.appversions.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageParam;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static com.yolo.keyboard.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。分页 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AppVersionsPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "应用标识(支持多App/多包名场景);单App可固定为 main。", example = "10064")
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
@Schema(description = "平台:android 或 ios(用 CHECK 约束限制取值)。")
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
@Schema(description = "渠道标识:如 official / huawei / xiaomi / testflight 等,用于区分不同分发包。")
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
@Schema(description = "展示用版本号(语义版本字符串),如 1.2.3。", example = "芋艿")
|
||||||
|
private String versionName;
|
||||||
|
|
||||||
|
@Schema(description = "比较用版本号(整数递增):Android 对应 versionCode;iOS 建议维护同样的递增值以便比较。")
|
||||||
|
private Long versionCode;
|
||||||
|
|
||||||
|
@Schema(description = "iOS 可选构建号(例如 CFBundleVersion),通常为字符串;用于追溯构建或与CI编号对齐。")
|
||||||
|
private String buildNumber;
|
||||||
|
|
||||||
|
@Schema(description = "最低支持版本号(整数):客户端 version_code 低于该值必须更新/可拒绝继续使用。")
|
||||||
|
private Long minSupportedCode;
|
||||||
|
|
||||||
|
@Schema(description = "是否强制更新:当客户端未达到最新版本且此字段为 true,可要求强更(即使 >= min_supported_code)。")
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
private Boolean[] isForceUpdate;
|
||||||
|
|
||||||
|
@Schema(description = "是否生效:true 表示该版本记录可用于对外更新检查;false 用于下架/撤回。")
|
||||||
|
private Boolean isActive;
|
||||||
|
|
||||||
|
@Schema(description = "更新说明(展示给用户的版本更新内容)。")
|
||||||
|
private String releaseNotes;
|
||||||
|
|
||||||
|
@Schema(description = "下载链接:Android 可为 apk 直链/市场 scheme;iOS 通常为 App Store 链接或统一跳转页。", example = "https://www.iocoder.cn")
|
||||||
|
private String downloadUrl;
|
||||||
|
|
||||||
|
@Schema(description = "应用市场/商店页面链接(可选,若 download_url 已覆盖可不填)。", example = "https://www.iocoder.cn")
|
||||||
|
private String storeUrl;
|
||||||
|
|
||||||
|
@Schema(description = "扩展元数据(JSON):如包大小、md5、签名信息、最低系统版本等。")
|
||||||
|
private Object metadata;
|
||||||
|
|
||||||
|
@Schema(description = "发布时间(对外宣布/上线时间),用于展示与排序。")
|
||||||
|
private LocalDateTime releasedAt;
|
||||||
|
|
||||||
|
@Schema(description = "记录创建时间。")
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Schema(description = "记录更新时间(建议配合触发器自动维护)。")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.yolo.keyboard.controller.admin.appversions.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import cn.idev.excel.annotation.*;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。 Response VO")
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
public class AppVersionsRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键,自增版本记录ID。", requiredMode = Schema.RequiredMode.REQUIRED, example = "25012")
|
||||||
|
@ExcelProperty("主键,自增版本记录ID。")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "应用标识(支持多App/多包名场景);单App可固定为 main。", requiredMode = Schema.RequiredMode.REQUIRED, example = "10064")
|
||||||
|
@ExcelProperty("应用标识(支持多App/多包名场景);单App可固定为 main。")
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
@Schema(description = "平台:android 或 ios(用 CHECK 约束限制取值)。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("平台:android 或 ios(用 CHECK 约束限制取值)。")
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
@Schema(description = "渠道标识:如 official / huawei / xiaomi / testflight 等,用于区分不同分发包。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("渠道标识:如 official / huawei / xiaomi / testflight 等,用于区分不同分发包。")
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
@Schema(description = "展示用版本号(语义版本字符串),如 1.2.3。", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
|
||||||
|
@ExcelProperty("展示用版本号(语义版本字符串),如 1.2.3。")
|
||||||
|
private String versionName;
|
||||||
|
|
||||||
|
@Schema(description = "比较用版本号(整数递增):Android 对应 versionCode;iOS 建议维护同样的递增值以便比较。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("比较用版本号(整数递增):Android 对应 versionCode;iOS 建议维护同样的递增值以便比较。")
|
||||||
|
private Long versionCode;
|
||||||
|
|
||||||
|
@Schema(description = "iOS 可选构建号(例如 CFBundleVersion),通常为字符串;用于追溯构建或与CI编号对齐。")
|
||||||
|
@ExcelProperty("iOS 可选构建号(例如 CFBundleVersion),通常为字符串;用于追溯构建或与CI编号对齐。")
|
||||||
|
private String buildNumber;
|
||||||
|
|
||||||
|
@Schema(description = "最低支持版本号(整数):客户端 version_code 低于该值必须更新/可拒绝继续使用。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("最低支持版本号(整数):客户端 version_code 低于该值必须更新/可拒绝继续使用。")
|
||||||
|
private Long minSupportedCode;
|
||||||
|
|
||||||
|
@Schema(description = "是否强制更新:当客户端未达到最新版本且此字段为 true,可要求强更(即使 >= min_supported_code)。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("是否强制更新:当客户端未达到最新版本且此字段为 true,可要求强更(即使 >= min_supported_code)。")
|
||||||
|
private Boolean isForceUpdate;
|
||||||
|
|
||||||
|
@Schema(description = "是否生效:true 表示该版本记录可用于对外更新检查;false 用于下架/撤回。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("是否生效:true 表示该版本记录可用于对外更新检查;false 用于下架/撤回。")
|
||||||
|
private Boolean isActive;
|
||||||
|
|
||||||
|
@Schema(description = "更新说明(展示给用户的版本更新内容)。")
|
||||||
|
@ExcelProperty("更新说明(展示给用户的版本更新内容)。")
|
||||||
|
private String releaseNotes;
|
||||||
|
|
||||||
|
@Schema(description = "下载链接:Android 可为 apk 直链/市场 scheme;iOS 通常为 App Store 链接或统一跳转页。", example = "https://www.iocoder.cn")
|
||||||
|
@ExcelProperty("下载链接:Android 可为 apk 直链/市场 scheme;iOS 通常为 App Store 链接或统一跳转页。")
|
||||||
|
private String downloadUrl;
|
||||||
|
|
||||||
|
@Schema(description = "应用市场/商店页面链接(可选,若 download_url 已覆盖可不填)。", example = "https://www.iocoder.cn")
|
||||||
|
@ExcelProperty("应用市场/商店页面链接(可选,若 download_url 已覆盖可不填)。")
|
||||||
|
private String storeUrl;
|
||||||
|
|
||||||
|
@Schema(description = "扩展元数据(JSON):如包大小、md5、签名信息、最低系统版本等。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("扩展元数据(JSON):如包大小、md5、签名信息、最低系统版本等。")
|
||||||
|
private Object metadata;
|
||||||
|
|
||||||
|
@Schema(description = "发布时间(对外宣布/上线时间),用于展示与排序。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("发布时间(对外宣布/上线时间),用于展示与排序。")
|
||||||
|
private LocalDateTime releasedAt;
|
||||||
|
|
||||||
|
@Schema(description = "记录创建时间。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("记录创建时间。")
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Schema(description = "记录更新时间(建议配合触发器自动维护)。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("记录更新时间(建议配合触发器自动维护)。")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.yolo.keyboard.controller.admin.appversions.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。新增/修改 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AppVersionsSaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键,自增版本记录ID。", requiredMode = Schema.RequiredMode.REQUIRED, example = "25012")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "应用标识(支持多App/多包名场景);单App可固定为 main。", requiredMode = Schema.RequiredMode.REQUIRED, example = "10064")
|
||||||
|
@NotEmpty(message = "应用标识(支持多App/多包名场景);单App可固定为 main。不能为空")
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
@Schema(description = "平台:android 或 ios(用 CHECK 约束限制取值)。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotEmpty(message = "平台:android 或 ios(用 CHECK 约束限制取值)。不能为空")
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
@Schema(description = "渠道标识:如 official / huawei / xiaomi / testflight 等,用于区分不同分发包。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotEmpty(message = "渠道标识:如 official / huawei / xiaomi / testflight 等,用于区分不同分发包。不能为空")
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
@Schema(description = "展示用版本号(语义版本字符串),如 1.2.3。", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
|
||||||
|
@NotEmpty(message = "展示用版本号(语义版本字符串),如 1.2.3。不能为空")
|
||||||
|
private String versionName;
|
||||||
|
|
||||||
|
@Schema(description = "比较用版本号(整数递增):Android 对应 versionCode;iOS 建议维护同样的递增值以便比较。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "比较用版本号(整数递增):Android 对应 versionCode;iOS 建议维护同样的递增值以便比较。不能为空")
|
||||||
|
private Long versionCode;
|
||||||
|
|
||||||
|
@Schema(description = "iOS 可选构建号(例如 CFBundleVersion),通常为字符串;用于追溯构建或与CI编号对齐。")
|
||||||
|
private String buildNumber;
|
||||||
|
|
||||||
|
@Schema(description = "最低支持版本号(整数):客户端 version_code 低于该值必须更新/可拒绝继续使用。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "最低支持版本号(整数):客户端 version_code 低于该值必须更新/可拒绝继续使用。不能为空")
|
||||||
|
private Long minSupportedCode;
|
||||||
|
|
||||||
|
@Schema(description = "是否强制更新:当客户端未达到最新版本且此字段为 true,可要求强更(即使 >= min_supported_code)。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "是否强制更新:当客户端未达到最新版本且此字段为 true,可要求强更(即使 >= min_supported_code)。不能为空")
|
||||||
|
private Boolean isForceUpdate;
|
||||||
|
|
||||||
|
@Schema(description = "是否生效:true 表示该版本记录可用于对外更新检查;false 用于下架/撤回。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "是否生效:true 表示该版本记录可用于对外更新检查;false 用于下架/撤回。不能为空")
|
||||||
|
private Boolean isActive;
|
||||||
|
|
||||||
|
@Schema(description = "更新说明(展示给用户的版本更新内容)。")
|
||||||
|
private String releaseNotes;
|
||||||
|
|
||||||
|
@Schema(description = "下载链接:Android 可为 apk 直链/市场 scheme;iOS 通常为 App Store 链接或统一跳转页。", example = "https://www.iocoder.cn")
|
||||||
|
private String downloadUrl;
|
||||||
|
|
||||||
|
@Schema(description = "应用市场/商店页面链接(可选,若 download_url 已覆盖可不填)。", example = "https://www.iocoder.cn")
|
||||||
|
private String storeUrl;
|
||||||
|
|
||||||
|
@Schema(description = "扩展元数据(JSON):如包大小、md5、签名信息、最低系统版本等。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Object metadata;
|
||||||
|
|
||||||
|
@Schema(description = "发布时间(对外宣布/上线时间),用于展示与排序。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "发布时间(对外宣布/上线时间),用于展示与排序。不能为空")
|
||||||
|
private LocalDateTime releasedAt;
|
||||||
|
|
||||||
|
@Schema(description = "记录创建时间。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Schema(description = "记录更新时间(建议配合触发器自动维护)。", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.yolo.keyboard.dal.dataobject.appversions;
|
||||||
|
|
||||||
|
import com.yolo.keyboard.framework.tenant.core.aop.TenantIgnore;import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import com.yolo.keyboard.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。 DO
|
||||||
|
*
|
||||||
|
* @author ziin
|
||||||
|
*/
|
||||||
|
@TableName("keyboard_app_versions")
|
||||||
|
@KeySequence("keyboard_app_versions_id_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@TenantIgnore
|
||||||
|
public class AppVersionsDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键,自增版本记录ID。
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 应用标识(支持多App/多包名场景);单App可固定为 main。
|
||||||
|
*/
|
||||||
|
private String appId;
|
||||||
|
/**
|
||||||
|
* 平台:android 或 ios(用 CHECK 约束限制取值)。
|
||||||
|
*/
|
||||||
|
private String platform;
|
||||||
|
/**
|
||||||
|
* 渠道标识:如 official / huawei / xiaomi / testflight 等,用于区分不同分发包。
|
||||||
|
*/
|
||||||
|
private String channel;
|
||||||
|
/**
|
||||||
|
* 展示用版本号(语义版本字符串),如 1.2.3。
|
||||||
|
*/
|
||||||
|
private String versionName;
|
||||||
|
/**
|
||||||
|
* 比较用版本号(整数递增):Android 对应 versionCode;iOS 建议维护同样的递增值以便比较。
|
||||||
|
*/
|
||||||
|
private Long versionCode;
|
||||||
|
/**
|
||||||
|
* iOS 可选构建号(例如 CFBundleVersion),通常为字符串;用于追溯构建或与CI编号对齐。
|
||||||
|
*/
|
||||||
|
private String buildNumber;
|
||||||
|
/**
|
||||||
|
* 最低支持版本号(整数):客户端 version_code 低于该值必须更新/可拒绝继续使用。
|
||||||
|
*/
|
||||||
|
private Long minSupportedCode;
|
||||||
|
/**
|
||||||
|
* 是否强制更新:当客户端未达到最新版本且此字段为 true,可要求强更(即使 >= min_supported_code)。
|
||||||
|
*/
|
||||||
|
private Boolean isForceUpdate;
|
||||||
|
/**
|
||||||
|
* 是否生效:true 表示该版本记录可用于对外更新检查;false 用于下架/撤回。
|
||||||
|
*/
|
||||||
|
private Boolean isActive;
|
||||||
|
/**
|
||||||
|
* 更新说明(展示给用户的版本更新内容)。
|
||||||
|
*/
|
||||||
|
private String releaseNotes;
|
||||||
|
/**
|
||||||
|
* 下载链接:Android 可为 apk 直链/市场 scheme;iOS 通常为 App Store 链接或统一跳转页。
|
||||||
|
*/
|
||||||
|
private String downloadUrl;
|
||||||
|
/**
|
||||||
|
* 应用市场/商店页面链接(可选,若 download_url 已覆盖可不填)。
|
||||||
|
*/
|
||||||
|
private String storeUrl;
|
||||||
|
/**
|
||||||
|
* 扩展元数据(JSON):如包大小、md5、签名信息、最低系统版本等。
|
||||||
|
*/
|
||||||
|
private Object metadata;
|
||||||
|
/**
|
||||||
|
* 发布时间(对外宣布/上线时间),用于展示与排序。
|
||||||
|
*/
|
||||||
|
private LocalDateTime releasedAt;
|
||||||
|
/**
|
||||||
|
* 记录创建时间。
|
||||||
|
*/
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
/**
|
||||||
|
* 记录更新时间(建议配合触发器自动维护)。
|
||||||
|
*/
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.yolo.keyboard.dal.mysql.appversions;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageResult;
|
||||||
|
import com.yolo.keyboard.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import com.yolo.keyboard.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.yolo.keyboard.dal.dataobject.appversions.AppVersionsDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import com.yolo.keyboard.controller.admin.appversions.vo.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。 Mapper
|
||||||
|
*
|
||||||
|
* @author ziin
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface AppVersionsMapper extends BaseMapperX<AppVersionsDO> {
|
||||||
|
|
||||||
|
default PageResult<AppVersionsDO> selectPage(AppVersionsPageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<AppVersionsDO>()
|
||||||
|
.eqIfPresent(AppVersionsDO::getAppId, reqVO.getAppId())
|
||||||
|
.eqIfPresent(AppVersionsDO::getPlatform, reqVO.getPlatform())
|
||||||
|
.eqIfPresent(AppVersionsDO::getChannel, reqVO.getChannel())
|
||||||
|
.likeIfPresent(AppVersionsDO::getVersionName, reqVO.getVersionName())
|
||||||
|
.eqIfPresent(AppVersionsDO::getVersionCode, reqVO.getVersionCode())
|
||||||
|
.eqIfPresent(AppVersionsDO::getBuildNumber, reqVO.getBuildNumber())
|
||||||
|
.eqIfPresent(AppVersionsDO::getMinSupportedCode, reqVO.getMinSupportedCode())
|
||||||
|
.betweenIfPresent(AppVersionsDO::getIsForceUpdate, reqVO.getIsForceUpdate())
|
||||||
|
.eqIfPresent(AppVersionsDO::getIsActive, reqVO.getIsActive())
|
||||||
|
.eqIfPresent(AppVersionsDO::getReleaseNotes, reqVO.getReleaseNotes())
|
||||||
|
.eqIfPresent(AppVersionsDO::getDownloadUrl, reqVO.getDownloadUrl())
|
||||||
|
.eqIfPresent(AppVersionsDO::getStoreUrl, reqVO.getStoreUrl())
|
||||||
|
.eqIfPresent(AppVersionsDO::getMetadata, reqVO.getMetadata())
|
||||||
|
.eqIfPresent(AppVersionsDO::getReleasedAt, reqVO.getReleasedAt())
|
||||||
|
.eqIfPresent(AppVersionsDO::getCreatedAt, reqVO.getCreatedAt())
|
||||||
|
.eqIfPresent(AppVersionsDO::getUpdatedAt, reqVO.getUpdatedAt())
|
||||||
|
.orderByDesc(AppVersionsDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.yolo.keyboard.service.appversions;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import jakarta.validation.*;
|
||||||
|
import com.yolo.keyboard.controller.admin.appversions.vo.*;
|
||||||
|
import com.yolo.keyboard.dal.dataobject.appversions.AppVersionsDO;
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageResult;
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。 Service 接口
|
||||||
|
*
|
||||||
|
* @author ziin
|
||||||
|
*/
|
||||||
|
public interface AppVersionsService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。
|
||||||
|
*
|
||||||
|
* @param createReqVO 创建信息
|
||||||
|
* @return 编号
|
||||||
|
*/
|
||||||
|
Long createAppVersions(@Valid AppVersionsSaveReqVO createReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。
|
||||||
|
*
|
||||||
|
* @param updateReqVO 更新信息
|
||||||
|
*/
|
||||||
|
void updateAppVersions(@Valid AppVersionsSaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void deleteAppVersions(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。
|
||||||
|
*
|
||||||
|
* @param ids 编号
|
||||||
|
*/
|
||||||
|
void deleteAppVersionsListByIds(List<Long> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。
|
||||||
|
*/
|
||||||
|
AppVersionsDO getAppVersions(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。分页
|
||||||
|
*/
|
||||||
|
PageResult<AppVersionsDO> getAppVersionsPage(AppVersionsPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.yolo.keyboard.service.appversions;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import com.yolo.keyboard.controller.admin.appversions.vo.*;
|
||||||
|
import com.yolo.keyboard.dal.dataobject.appversions.AppVersionsDO;
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageResult;
|
||||||
|
import com.yolo.keyboard.framework.common.pojo.PageParam;
|
||||||
|
import com.yolo.keyboard.framework.common.util.object.BeanUtils;
|
||||||
|
|
||||||
|
import com.yolo.keyboard.dal.mysql.appversions.AppVersionsMapper;
|
||||||
|
|
||||||
|
import static com.yolo.keyboard.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static com.yolo.keyboard.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
|
import static com.yolo.keyboard.framework.common.util.collection.CollectionUtils.diffList;import static com.yolo.keyboard.module.infra.enums.ErrorCodeConstants.APP_VERSIONS_NOT_EXISTS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App 版本发布与更新检查表:区分 Android/iOS、渠道,支持最低支持版本与强更策略。 Service 实现类
|
||||||
|
*
|
||||||
|
* @author ziin
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class AppVersionsServiceImpl implements AppVersionsService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppVersionsMapper appVersionsMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long createAppVersions(AppVersionsSaveReqVO createReqVO) {
|
||||||
|
// 插入
|
||||||
|
AppVersionsDO appVersions = BeanUtils.toBean(createReqVO, AppVersionsDO.class);
|
||||||
|
appVersionsMapper.insert(appVersions);
|
||||||
|
|
||||||
|
// 返回
|
||||||
|
return appVersions.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAppVersions(AppVersionsSaveReqVO updateReqVO) {
|
||||||
|
// 校验存在
|
||||||
|
validateAppVersionsExists(updateReqVO.getId());
|
||||||
|
// 更新
|
||||||
|
AppVersionsDO updateObj = BeanUtils.toBean(updateReqVO, AppVersionsDO.class);
|
||||||
|
appVersionsMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAppVersions(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
validateAppVersionsExists(id);
|
||||||
|
// 删除
|
||||||
|
appVersionsMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAppVersionsListByIds(List<Long> ids) {
|
||||||
|
// 删除
|
||||||
|
appVersionsMapper.deleteByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void validateAppVersionsExists(Long id) {
|
||||||
|
if (appVersionsMapper.selectById(id) == null) {
|
||||||
|
throw exception(APP_VERSIONS_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppVersionsDO getAppVersions(Long id) {
|
||||||
|
return appVersionsMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<AppVersionsDO> getAppVersionsPage(AppVersionsPageReqVO pageReqVO) {
|
||||||
|
return appVersionsMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?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.yolo.keyboard.module.keyboard.dal.mysql.appversions.AppVersionsMapper">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||||
|
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||||
|
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||||
|
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||||
|
-->
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -96,4 +96,5 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode TENANT_COMMISSION_NOT_EXISTS = new ErrorCode(1_001_202_022, "租户内购分成记录不存在");
|
ErrorCode TENANT_COMMISSION_NOT_EXISTS = new ErrorCode(1_001_202_022, "租户内购分成记录不存在");
|
||||||
ErrorCode AI_COMPANION_NOT_EXISTS = new ErrorCode(1_001_202_023, "AI陪聊角色表,用于定义恋爱/陪伴型虚拟角色的基础信息与人设不存在");
|
ErrorCode AI_COMPANION_NOT_EXISTS = new ErrorCode(1_001_202_023, "AI陪聊角色表,用于定义恋爱/陪伴型虚拟角色的基础信息与人设不存在");
|
||||||
ErrorCode WARNING_MESSAGE_NOT_EXISTS = new ErrorCode(1_001_202_024, "用户注销提示信息不存在");
|
ErrorCode WARNING_MESSAGE_NOT_EXISTS = new ErrorCode(1_001_202_024, "用户注销提示信息不存在");
|
||||||
|
ErrorCode APP_VERSIONS_NOT_EXISTS = new ErrorCode(1_001_202_025, "App 版本发布与更新检查表信息不存在");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user