zjk
2026-08-31 13eb6604dd95dea5fca4b81bf6b4455c2bcbf416
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/system/service/AppVersionSettingsAppService.java
@@ -45,13 +45,18 @@
    @Transactional
    public AppVersionDetailVO create(AppVersionCreateRequest request) {
        AppVersionConfig latest = latest();
        String androidFileUrl = normalizeOptionalText(request.getAndroidFileUrl());
        String androidFileName = normalizeOptionalText(request.getAndroidFileName());
        String iosFileUrl = normalizeOptionalText(request.getIosFileUrl());
        String iosFileName = normalizeOptionalText(request.getIosFileName());
        validatePackageFields(androidFileUrl, androidFileName, iosFileUrl, iosFileName);
        AppVersionConfig item = new AppVersionConfig();
        item.setVersionNo(request.getVersionNo().trim());
        item.setVersionCode(latest == null ? 1 : defaultNumber(latest.getVersionCode()) + 1);
        item.setAndroidFileUrl(request.getAndroidFileUrl().trim());
        item.setAndroidFileName(request.getAndroidFileName().trim());
        item.setIosFileUrl(request.getIosFileUrl().trim());
        item.setIosFileName(request.getIosFileName().trim());
        item.setAndroidFileUrl(androidFileUrl);
        item.setAndroidFileName(androidFileName);
        item.setIosFileUrl(iosFileUrl);
        item.setIosFileName(iosFileName);
        item.setForceUpdate(booleanToInteger(request.getForceUpdate()));
        item.setUpdateNotice(request.getUpdateNotice().trim());
        item.setDeleted(0);
@@ -60,6 +65,10 @@
    }
    public AppVersionCheckVO checkUpdate(String platform, Integer currentVersionCode) {
        return checkUpdate(platform, currentVersionCode, null);
    }
    public AppVersionCheckVO checkUpdate(String platform, Integer currentVersionCode, String currentVersionNo) {
        if (currentVersionCode == null) {
            throw new IllegalArgumentException("当前版本号不能为空");
        }
@@ -74,16 +83,100 @@
            return vo;
        }
        boolean hasUpdate = defaultNumber(latest.getVersionCode()) > currentVersionCode;
        String downloadUrl = AppVersionConfig.PLATFORM_ANDROID.equals(normalizedPlatform)
                ? normalizeOptionalText(latest.getAndroidFileUrl())
                : normalizeOptionalText(latest.getIosFileUrl());
        boolean hasUpdate = downloadUrl != null && isNewerVersion(latest, currentVersionCode, currentVersionNo);
        vo.setHasUpdate(hasUpdate);
        if (!hasUpdate) {
            return vo;
        }
        vo.setLatestVersionNo(latest.getVersionNo());
        vo.setLatestVersionCode(defaultNumber(latest.getVersionCode()));
        vo.setForceUpdate(integerToBoolean(latest.getForceUpdate()));
        vo.setUpdateNotice(latest.getUpdateNotice());
        vo.setDownloadUrl(AppVersionConfig.PLATFORM_ANDROID.equals(normalizedPlatform)
                ? latest.getAndroidFileUrl()
                : latest.getIosFileUrl());
        vo.setDownloadUrl(downloadUrl);
        return vo;
    }
    public AppVersionCheckVO checkUpdateNew(String platform) {
        String normalizedPlatform = normalizePlatform(platform);
        AppVersionConfig latest = latest();
        AppVersionCheckVO vo = new AppVersionCheckVO();
        if (latest == null) {
            vo.setHasUpdate(Boolean.FALSE);
            return vo;
        }
        String downloadUrl = AppVersionConfig.PLATFORM_ANDROID.equals(normalizedPlatform)
                ? normalizeOptionalText(latest.getAndroidFileUrl())
                : normalizeOptionalText(latest.getIosFileUrl());
        boolean hasUpdate = downloadUrl != null;
        vo.setHasUpdate(hasUpdate);
        if (!hasUpdate) {
            return vo;
        }
        vo.setLatestVersionNo(latest.getVersionNo());
        vo.setLatestVersionCode(defaultNumber(latest.getVersionCode()));
        vo.setForceUpdate(integerToBoolean(latest.getForceUpdate()));
        vo.setUpdateNotice(latest.getUpdateNotice());
        vo.setDownloadUrl(downloadUrl);
        return vo;
    }
    /**
     * 判断后台最新版本是否高于当前 APP,兼容原生 versionCode 与展示 versionNo 不一致的历史包。
     */
    private boolean isNewerVersion(AppVersionConfig latest, Integer currentVersionCode, String currentVersionNo) {
        if (defaultNumber(latest.getVersionCode()) > currentVersionCode) {
            return true;
        }
        return compareVersionNo(latest.getVersionNo(), currentVersionNo) > 0;
    }
    /**
     * 比较数字点号版本号,无法解析的版本号不参与兜底判断。
     */
    private int compareVersionNo(String latestVersionNo, String currentVersionNo) {
        String latest = normalizeOptionalText(latestVersionNo);
        String current = normalizeOptionalText(currentVersionNo);
        if (latest == null || current == null) {
            return 0;
        }
        String[] latestParts = latest.split("\\.");
        String[] currentParts = current.split("\\.");
        int maxLength = Math.max(latestParts.length, currentParts.length);
        for (int i = 0; i < maxLength; i++) {
            Integer latestNumber = parseVersionNumber(latestParts, i);
            Integer currentNumber = parseVersionNumber(currentParts, i);
            if (latestNumber == null || currentNumber == null) {
                return 0;
            }
            int compareResult = latestNumber.compareTo(currentNumber);
            if (compareResult != 0) {
                return compareResult;
            }
        }
        return 0;
    }
    /**
     * 解析指定版本号片段,缺失片段按 0 处理。
     */
    private Integer parseVersionNumber(String[] parts, int index) {
        if (index >= parts.length) {
            return 0;
        }
        String value = parts[index] == null ? "" : parts[index].trim();
        if (!value.matches("\\d+")) {
            return null;
        }
        try {
            return Integer.valueOf(value);
        } catch (NumberFormatException ex) {
            return null;
        }
    }
    private AppVersionConfig latest() {
@@ -151,4 +244,31 @@
    private Boolean integerToBoolean(Integer value) {
        return value != null && value == 1;
    }
    private void validatePackageFields(String androidFileUrl, String androidFileName, String iosFileUrl, String iosFileName) {
        boolean hasAndroidFileUrl = androidFileUrl != null;
        boolean hasAndroidFileName = androidFileName != null;
        boolean hasIosFileUrl = iosFileUrl != null;
        boolean hasIosFileName = iosFileName != null;
        boolean hasAndroidPackage = hasAndroidFileUrl || hasAndroidFileName;
        boolean hasIosPackage = hasIosFileUrl || hasIosFileName;
        if (hasAndroidPackage && (!hasAndroidFileUrl || !hasAndroidFileName)) {
            throw new IllegalArgumentException("安卓文件地址和名称必须同时填写");
        }
        if (hasIosPackage && (!hasIosFileUrl || !hasIosFileName)) {
            throw new IllegalArgumentException("iOS文件地址和名称必须同时填写");
        }
        if (!hasAndroidPackage && !hasIosPackage) {
            throw new IllegalArgumentException("请至少上传一个安装包");
        }
    }
    private String normalizeOptionalText(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }
}