新增数字人版本管理
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package com.nanri.aiimage.modules.digitalhuman.controller;
|
||||
|
||||
import com.nanri.aiimage.common.api.ApiResponse;
|
||||
import com.nanri.aiimage.modules.digitalhuman.model.dto.UploadVersionRequest;
|
||||
import com.nanri.aiimage.modules.digitalhuman.model.vo.DigitalHumanVersionVo;
|
||||
import com.nanri.aiimage.modules.digitalhuman.service.DigitalHumanVersionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/digital-human/versions")
|
||||
@Tag(name = "数字人版本管理", description = "数字人程序版本管理接口,包括上传、查询、发布、删除等功能")
|
||||
public class DigitalHumanVersionController {
|
||||
|
||||
private final DigitalHumanVersionService versionService;
|
||||
|
||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@Operation(summary = "上传新版本", description = "上传数字人程序新版本到 OSS,并记录版本信息")
|
||||
public ApiResponse<DigitalHumanVersionVo> uploadVersion(@Valid @ModelAttribute UploadVersionRequest request) {
|
||||
DigitalHumanVersionVo vo = versionService.uploadVersion(
|
||||
request.getVersion(),
|
||||
request.getFile(),
|
||||
request.getChangelog(),
|
||||
request.getMinClientVersion(),
|
||||
request.getCreatedBy()
|
||||
);
|
||||
return ApiResponse.success(vo);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "查询版本列表", description = "查询所有数字人版本,按创建时间倒序")
|
||||
public ApiResponse<List<DigitalHumanVersionVo>> listVersions() {
|
||||
return ApiResponse.success(versionService.listVersions());
|
||||
}
|
||||
|
||||
@GetMapping("/latest")
|
||||
@Operation(summary = "获取最新版本", description = "获取当前标记为最新且已发布的版本")
|
||||
public ApiResponse<DigitalHumanVersionVo> getLatestVersion() {
|
||||
return ApiResponse.success(versionService.getLatestVersion());
|
||||
}
|
||||
|
||||
@GetMapping("/{version}")
|
||||
@Operation(summary = "获取版本详情", description = "根据版本号获取版本详细信息")
|
||||
public ApiResponse<DigitalHumanVersionVo> getVersionByVersion(
|
||||
@Parameter(description = "版本号", example = "1.0.0") @PathVariable String version) {
|
||||
return ApiResponse.success(versionService.getVersionByVersion(version));
|
||||
}
|
||||
|
||||
@PostMapping("/{version}/release")
|
||||
@Operation(summary = "发布版本", description = "将草稿状态的版本发布,状态变更为 RELEASED")
|
||||
public ApiResponse<DigitalHumanVersionVo> releaseVersion(
|
||||
@Parameter(description = "版本号", example = "1.0.0") @PathVariable String version) {
|
||||
return ApiResponse.success(versionService.releaseVersion(version));
|
||||
}
|
||||
|
||||
@PostMapping("/{version}/set-latest")
|
||||
@Operation(summary = "设为最新版本", description = "将指定已发布版本设置为最新版本,清除其他版本的最新标记")
|
||||
public ApiResponse<DigitalHumanVersionVo> setLatest(
|
||||
@Parameter(description = "版本号", example = "1.0.0") @PathVariable String version) {
|
||||
return ApiResponse.success(versionService.setLatest(version));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{version}")
|
||||
@Operation(summary = "删除版本", description = "删除指定版本,同时删除 OSS 上的文件。最新版本不允许删除")
|
||||
public ApiResponse<Void> deleteVersion(
|
||||
@Parameter(description = "版本号", example = "1.0.0") @PathVariable String version) {
|
||||
versionService.deleteVersion(version);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@GetMapping("/{version}/download-url")
|
||||
@Operation(summary = "获取下载链接", description = "获取指定版本的 OSS 下载链接")
|
||||
public ApiResponse<String> getDownloadUrl(
|
||||
@Parameter(description = "版本号", example = "1.0.0") @PathVariable String version) {
|
||||
return ApiResponse.success(versionService.getDownloadUrl(version));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.nanri.aiimage.modules.digitalhuman.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.nanri.aiimage.modules.digitalhuman.model.entity.DigitalHumanVersionEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface DigitalHumanVersionMapper extends BaseMapper<DigitalHumanVersionEntity> {
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.nanri.aiimage.modules.digitalhuman.model.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Data
|
||||
@Schema(description = "上传数字人版本请求")
|
||||
public class UploadVersionRequest {
|
||||
|
||||
@NotBlank(message = "版本号不能为空")
|
||||
@Schema(description = "版本号", example = "1.0.0", required = true)
|
||||
private String version;
|
||||
|
||||
@NotNull(message = "文件不能为空")
|
||||
@Schema(description = "数字人程序压缩包", required = true)
|
||||
private MultipartFile file;
|
||||
|
||||
@Schema(description = "更新日志")
|
||||
private String changelog;
|
||||
|
||||
@Schema(description = "最低客户端版本要求", example = "1.0.0")
|
||||
private String minClientVersion;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String createdBy;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.nanri.aiimage.modules.digitalhuman.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("biz_digital_human_version")
|
||||
public class DigitalHumanVersionEntity {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String version;
|
||||
private String ossObjectKey;
|
||||
private Long fileSize;
|
||||
private String md5;
|
||||
private String changelog;
|
||||
private String minClientVersion;
|
||||
private Boolean isLatest;
|
||||
private String status;
|
||||
private String createdBy;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime releasedAt;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.nanri.aiimage.modules.digitalhuman.model.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Schema(description = "数字人版本信息")
|
||||
public class DigitalHumanVersionVo {
|
||||
|
||||
@Schema(description = "版本ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "版本号", example = "1.0.0")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "文件大小(字节)")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "文件MD5")
|
||||
private String md5;
|
||||
|
||||
@Schema(description = "更新日志")
|
||||
private String changelog;
|
||||
|
||||
@Schema(description = "最低客户端版本要求", example = "1.0.0")
|
||||
private String minClientVersion;
|
||||
|
||||
@Schema(description = "是否最新版本")
|
||||
private Boolean isLatest;
|
||||
|
||||
@Schema(description = "状态:DRAFT/RELEASED")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "下载链接")
|
||||
private String downloadUrl;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String createdBy;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Schema(description = "发布时间")
|
||||
private LocalDateTime releasedAt;
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
package com.nanri.aiimage.modules.digitalhuman.service;
|
||||
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.nanri.aiimage.common.exception.BusinessException;
|
||||
import com.nanri.aiimage.config.OssProperties;
|
||||
import com.nanri.aiimage.modules.digitalhuman.mapper.DigitalHumanVersionMapper;
|
||||
import com.nanri.aiimage.modules.digitalhuman.model.entity.DigitalHumanVersionEntity;
|
||||
import com.nanri.aiimage.modules.digitalhuman.model.vo.DigitalHumanVersionVo;
|
||||
import com.nanri.aiimage.modules.file.service.oss.OssStorageService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.Files;
|
||||
import java.security.MessageDigest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DigitalHumanVersionService {
|
||||
|
||||
private static final String STATUS_DRAFT = "DRAFT";
|
||||
private static final String STATUS_RELEASED = "RELEASED";
|
||||
private static final String OSS_PATH_PREFIX = "digital-human/versions/";
|
||||
|
||||
private final DigitalHumanVersionMapper versionMapper;
|
||||
private final OssStorageService ossStorageService;
|
||||
private final OssProperties ossProperties;
|
||||
|
||||
@Transactional
|
||||
public DigitalHumanVersionVo uploadVersion(String version, MultipartFile file, String changelog,
|
||||
String minClientVersion, String createdBy) {
|
||||
// 检查版本号是否已存在
|
||||
DigitalHumanVersionEntity existing = versionMapper.selectOne(new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.eq(DigitalHumanVersionEntity::getVersion, version));
|
||||
if (existing != null) {
|
||||
throw new BusinessException("版本号已存在:" + version);
|
||||
}
|
||||
|
||||
// 保存临时文件
|
||||
File tempFile = null;
|
||||
try {
|
||||
tempFile = Files.createTempFile("digital-human-", ".zip").toFile();
|
||||
file.transferTo(tempFile);
|
||||
|
||||
// 计算 MD5
|
||||
String md5 = calculateMd5(tempFile);
|
||||
|
||||
// 构建 OSS 路径
|
||||
String ossObjectKey = OSS_PATH_PREFIX + "v" + version + "/ShuFuDigitalHuman.zip";
|
||||
|
||||
// 上传到 OSS
|
||||
OSS ossClient = buildOssClient();
|
||||
try {
|
||||
ossClient.putObject(ossProperties.getBucket(), ossObjectKey, tempFile);
|
||||
} finally {
|
||||
ossClient.shutdown();
|
||||
}
|
||||
|
||||
// 保存数据库记录
|
||||
DigitalHumanVersionEntity entity = new DigitalHumanVersionEntity();
|
||||
entity.setVersion(version);
|
||||
entity.setOssObjectKey(ossObjectKey);
|
||||
entity.setFileSize(tempFile.length());
|
||||
entity.setMd5(md5);
|
||||
entity.setChangelog(changelog);
|
||||
entity.setMinClientVersion(minClientVersion);
|
||||
entity.setIsLatest(false);
|
||||
entity.setStatus(STATUS_DRAFT);
|
||||
entity.setCreatedBy(createdBy);
|
||||
entity.setCreatedAt(LocalDateTime.now());
|
||||
|
||||
versionMapper.insert(entity);
|
||||
|
||||
return toVo(entity);
|
||||
} catch (IOException e) {
|
||||
log.error("上传数字人版本失败", e);
|
||||
throw new BusinessException("文件处理失败:" + e.getMessage());
|
||||
} finally {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
tempFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<DigitalHumanVersionVo> listVersions() {
|
||||
List<DigitalHumanVersionEntity> entities = versionMapper.selectList(
|
||||
new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.orderByDesc(DigitalHumanVersionEntity::getCreatedAt)
|
||||
);
|
||||
return entities.stream().map(this::toVo).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public DigitalHumanVersionVo getLatestVersion() {
|
||||
DigitalHumanVersionEntity entity = versionMapper.selectOne(new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.eq(DigitalHumanVersionEntity::getIsLatest, true)
|
||||
.eq(DigitalHumanVersionEntity::getStatus, STATUS_RELEASED)
|
||||
.last("limit 1"));
|
||||
if (entity == null) {
|
||||
throw new BusinessException("暂无已发布的版本");
|
||||
}
|
||||
return toVo(entity);
|
||||
}
|
||||
|
||||
public DigitalHumanVersionVo getVersionByVersion(String version) {
|
||||
DigitalHumanVersionEntity entity = versionMapper.selectOne(new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.eq(DigitalHumanVersionEntity::getVersion, version));
|
||||
if (entity == null) {
|
||||
throw new BusinessException("版本不存在:" + version);
|
||||
}
|
||||
return toVo(entity);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public DigitalHumanVersionVo releaseVersion(String version) {
|
||||
DigitalHumanVersionEntity entity = versionMapper.selectOne(new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.eq(DigitalHumanVersionEntity::getVersion, version));
|
||||
if (entity == null) {
|
||||
throw new BusinessException("版本不存在:" + version);
|
||||
}
|
||||
if (STATUS_RELEASED.equals(entity.getStatus())) {
|
||||
throw new BusinessException("版本已发布");
|
||||
}
|
||||
|
||||
entity.setStatus(STATUS_RELEASED);
|
||||
entity.setReleasedAt(LocalDateTime.now());
|
||||
versionMapper.updateById(entity);
|
||||
|
||||
return toVo(entity);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public DigitalHumanVersionVo setLatest(String version) {
|
||||
DigitalHumanVersionEntity entity = versionMapper.selectOne(new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.eq(DigitalHumanVersionEntity::getVersion, version));
|
||||
if (entity == null) {
|
||||
throw new BusinessException("版本不存在:" + version);
|
||||
}
|
||||
if (!STATUS_RELEASED.equals(entity.getStatus())) {
|
||||
throw new BusinessException("只有已发布的版本才能设为最新");
|
||||
}
|
||||
|
||||
// 清除其他版本的 is_latest 标记
|
||||
versionMapper.update(null, new LambdaUpdateWrapper<DigitalHumanVersionEntity>()
|
||||
.set(DigitalHumanVersionEntity::getIsLatest, false)
|
||||
.eq(DigitalHumanVersionEntity::getIsLatest, true));
|
||||
|
||||
// 设置当前版本为最新
|
||||
entity.setIsLatest(true);
|
||||
versionMapper.updateById(entity);
|
||||
|
||||
return toVo(entity);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteVersion(String version) {
|
||||
DigitalHumanVersionEntity entity = versionMapper.selectOne(new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.eq(DigitalHumanVersionEntity::getVersion, version));
|
||||
if (entity == null) {
|
||||
throw new BusinessException("版本不存在:" + version);
|
||||
}
|
||||
if (Boolean.TRUE.equals(entity.getIsLatest())) {
|
||||
throw new BusinessException("最新版本不能删除");
|
||||
}
|
||||
|
||||
// 删除 OSS 文件
|
||||
try {
|
||||
ossStorageService.deleteObject(entity.getOssObjectKey());
|
||||
} catch (Exception e) {
|
||||
log.warn("删除 OSS 文件失败:{}", entity.getOssObjectKey(), e);
|
||||
}
|
||||
|
||||
// 删除数据库记录
|
||||
versionMapper.deleteById(entity.getId());
|
||||
}
|
||||
|
||||
public String getDownloadUrl(String version) {
|
||||
DigitalHumanVersionEntity entity = versionMapper.selectOne(new LambdaQueryWrapper<DigitalHumanVersionEntity>()
|
||||
.eq(DigitalHumanVersionEntity::getVersion, version));
|
||||
if (entity == null) {
|
||||
throw new BusinessException("版本不存在:" + version);
|
||||
}
|
||||
return ossStorageService.generateDownloadUrl(entity.getOssObjectKey());
|
||||
}
|
||||
|
||||
private DigitalHumanVersionVo toVo(DigitalHumanVersionEntity entity) {
|
||||
DigitalHumanVersionVo vo = new DigitalHumanVersionVo();
|
||||
vo.setId(entity.getId());
|
||||
vo.setVersion(entity.getVersion());
|
||||
vo.setFileSize(entity.getFileSize());
|
||||
vo.setMd5(entity.getMd5());
|
||||
vo.setChangelog(entity.getChangelog());
|
||||
vo.setMinClientVersion(entity.getMinClientVersion());
|
||||
vo.setIsLatest(Boolean.TRUE.equals(entity.getIsLatest()));
|
||||
vo.setStatus(entity.getStatus());
|
||||
vo.setDownloadUrl(ossStorageService.generateDownloadUrl(entity.getOssObjectKey()));
|
||||
vo.setCreatedBy(entity.getCreatedBy());
|
||||
vo.setCreatedAt(entity.getCreatedAt());
|
||||
vo.setReleasedAt(entity.getReleasedAt());
|
||||
return vo;
|
||||
}
|
||||
|
||||
private String calculateMd5(File file) {
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||
md.update(buffer, 0, bytesRead);
|
||||
}
|
||||
byte[] digest = md.digest();
|
||||
BigInteger bigInt = new BigInteger(1, digest);
|
||||
return bigInt.toString(16).toLowerCase();
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("计算 MD5 失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private OSS buildOssClient() {
|
||||
return new OSSClientBuilder().build(
|
||||
"https://" + ossProperties.getEndpoint(),
|
||||
ossProperties.getAccessKeyId(),
|
||||
ossProperties.getAccessKeySecret()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ spring:
|
||||
name: aiimage-backend
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 200MB
|
||||
max-request-size: 500MB
|
||||
max-file-size: 2GB
|
||||
max-request-size: 2GB
|
||||
jackson:
|
||||
time-zone: Asia/Shanghai
|
||||
datasource:
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE `biz_digital_human_version` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`version` VARCHAR(32) NOT NULL COMMENT '版本号',
|
||||
`oss_object_key` VARCHAR(512) NOT NULL COMMENT 'OSS 路径',
|
||||
`file_size` BIGINT NOT NULL COMMENT '文件大小(字节)',
|
||||
`md5` VARCHAR(64) NOT NULL COMMENT '文件MD5',
|
||||
`changelog` TEXT COMMENT '更新日志',
|
||||
`min_client_version` VARCHAR(32) COMMENT '最低客户端版本要求',
|
||||
`is_latest` TINYINT(1) DEFAULT 0 COMMENT '是否最新版本',
|
||||
`status` VARCHAR(32) DEFAULT 'DRAFT' COMMENT '状态:DRAFT/RELEASED',
|
||||
`created_by` VARCHAR(128) COMMENT '创建人',
|
||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`released_at` DATETIME COMMENT '发布时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_version` (`version`),
|
||||
KEY `idx_status_is_latest` (`status`, `is_latest`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数字人版本管理表';
|
||||
@@ -0,0 +1,47 @@
|
||||
-- 插入现有的数字人版本记录(OSS 上已存在的版本)
|
||||
INSERT INTO `biz_digital_human_version` (
|
||||
`version`,
|
||||
`oss_object_key`,
|
||||
`file_size`,
|
||||
`md5`,
|
||||
`changelog`,
|
||||
`min_client_version`,
|
||||
`is_latest`,
|
||||
`status`,
|
||||
`created_by`,
|
||||
`created_at`,
|
||||
`released_at`
|
||||
) VALUES (
|
||||
'1.0.0',
|
||||
'ShuFuDigitalHuman.zip',
|
||||
0,
|
||||
'unknown',
|
||||
'初始版本(已存在于 OSS)',
|
||||
NULL,
|
||||
1,
|
||||
'RELEASED',
|
||||
'system',
|
||||
NOW(),
|
||||
NOW()
|
||||
);
|
||||
|
||||
-- 插入菜单权限配置(数字人版本管理)
|
||||
-- 注意:需要根据实际的 biz_permission_menu 表结构调整
|
||||
-- 如果表名或字段不同,请手动执行对应的 INSERT 语句
|
||||
INSERT INTO `biz_permission_menu` (
|
||||
`name`,
|
||||
`column_key`,
|
||||
`route_path`,
|
||||
`menu_type`,
|
||||
`sort_order`,
|
||||
`created_at`
|
||||
) VALUES (
|
||||
'数字人版本管理',
|
||||
'digital_human_version',
|
||||
'version',
|
||||
'admin',
|
||||
100,
|
||||
NOW()
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
`name` = '数字人版本管理',
|
||||
`route_path` = 'version';
|
||||
@@ -21,6 +21,8 @@ app = Flask(__name__, template_folder=BASE_DIR, static_folder=BASE_DIR)
|
||||
CORS(app)
|
||||
app.secret_key = os.environ.get('SECRET_KEY', secrets.token_hex(32))
|
||||
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
|
||||
# 文件上传大小限制:2GB(数字人 ZIP 包等大文件)
|
||||
app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024 * 1024
|
||||
|
||||
# 注册蓝图
|
||||
app.register_blueprint(auth)
|
||||
|
||||
@@ -1430,6 +1430,134 @@ def list_versions():
|
||||
return jsonify({'success': False, 'error': str(e)})
|
||||
|
||||
|
||||
# ========== 数字人版本管理(代理到 Java 后端)==========
|
||||
|
||||
@admin_api.route('/digital-human-versions')
|
||||
@admin_required
|
||||
def list_digital_human_versions():
|
||||
"""代理:查询数字人版本列表"""
|
||||
_, _, denied = _ensure_admin_menu_access('version')
|
||||
if denied:
|
||||
return denied
|
||||
page = request.args.get('page', '1')
|
||||
page_size = request.args.get('pageSize', '20')
|
||||
status = request.args.get('status', '')
|
||||
params = {'page': page, 'pageSize': page_size}
|
||||
if status:
|
||||
params['status'] = status
|
||||
result, error_response, status_code = _proxy_backend_java(
|
||||
'GET',
|
||||
'/api/digital-human/versions',
|
||||
params=params,
|
||||
timeout=30
|
||||
)
|
||||
if error_response:
|
||||
return error_response, status_code
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@admin_api.route('/digital-human-versions/latest')
|
||||
@admin_required
|
||||
def get_latest_digital_human_version():
|
||||
"""代理:获取最新数字人版本"""
|
||||
result, error_response, status_code = _proxy_backend_java(
|
||||
'GET',
|
||||
'/api/digital-human/versions/latest',
|
||||
timeout=10
|
||||
)
|
||||
if error_response:
|
||||
return error_response, status_code
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@admin_api.route('/digital-human-versions/upload', methods=['POST'])
|
||||
@admin_required
|
||||
def upload_digital_human_version():
|
||||
"""代理:上传数字人版本"""
|
||||
_, _, denied = _ensure_admin_menu_access('version')
|
||||
if denied:
|
||||
return denied
|
||||
|
||||
version = request.form.get('version', '').strip()
|
||||
changelog = request.form.get('changelog', '').strip()
|
||||
min_client_version = request.form.get('minClientVersion', '').strip()
|
||||
file_storage = request.files.get('file')
|
||||
|
||||
if not version:
|
||||
return jsonify({'success': False, 'message': '请填写版本号'}), 400
|
||||
if not file_storage:
|
||||
return jsonify({'success': False, 'message': '请选择文件'}), 400
|
||||
|
||||
files = {'file': (file_storage.filename, file_storage.stream, file_storage.content_type)}
|
||||
data = {'version': version}
|
||||
if changelog:
|
||||
data['changelog'] = changelog
|
||||
if min_client_version:
|
||||
data['minClientVersion'] = min_client_version
|
||||
|
||||
result, error_response, status_code = _proxy_backend_java(
|
||||
'POST',
|
||||
'/api/digital-human/versions/upload',
|
||||
files=files,
|
||||
data=data,
|
||||
timeout=300
|
||||
)
|
||||
if error_response:
|
||||
return error_response, status_code
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@admin_api.route('/digital-human-versions/<version>/release', methods=['POST'])
|
||||
@admin_required
|
||||
def release_digital_human_version(version):
|
||||
"""代理:发布数字人版本"""
|
||||
_, _, denied = _ensure_admin_menu_access('version')
|
||||
if denied:
|
||||
return denied
|
||||
result, error_response, status_code = _proxy_backend_java(
|
||||
'POST',
|
||||
f'/api/digital-human/versions/{version}/release',
|
||||
timeout=10
|
||||
)
|
||||
if error_response:
|
||||
return error_response, status_code
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@admin_api.route('/digital-human-versions/<version>/set-latest', methods=['POST'])
|
||||
@admin_required
|
||||
def set_latest_digital_human_version(version):
|
||||
"""代理:设为最新数字人版本"""
|
||||
_, _, denied = _ensure_admin_menu_access('version')
|
||||
if denied:
|
||||
return denied
|
||||
result, error_response, status_code = _proxy_backend_java(
|
||||
'POST',
|
||||
f'/api/digital-human/versions/{version}/set-latest',
|
||||
timeout=10
|
||||
)
|
||||
if error_response:
|
||||
return error_response, status_code
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@admin_api.route('/digital-human-versions/<version>', methods=['DELETE'])
|
||||
@admin_required
|
||||
def delete_digital_human_version(version):
|
||||
"""代理:删除数字人版本"""
|
||||
_, _, denied = _ensure_admin_menu_access('version')
|
||||
if denied:
|
||||
return denied
|
||||
result, error_response, status_code = _proxy_backend_java(
|
||||
'DELETE',
|
||||
f'/api/digital-human/versions/{version}',
|
||||
timeout=30
|
||||
)
|
||||
if error_response:
|
||||
return error_response, status_code
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@admin_api.route('/version', methods=['POST'])
|
||||
@admin_required
|
||||
def upload_version():
|
||||
|
||||
@@ -59,8 +59,8 @@ file_url_pre = f"https://{bucket}.oss-cn-hangzhou.aliyuncs.com/"
|
||||
backend_java_base_url, backend_java_base_url_source = _get_env(
|
||||
"java_api_base",
|
||||
"BACKEND_JAVA_BASE_URL",
|
||||
default="http://api.aishufu.top:18080/",
|
||||
# default="http://127.0.0.1:18080/",
|
||||
# default="http://api.aishufu.top:18080/",
|
||||
default="http://127.0.0.1:18080/",
|
||||
)
|
||||
backend_java_base_url = backend_java_base_url.rstrip("/")
|
||||
os.environ["OSS_ACCESS_KEY_ID"] = accessKeyId
|
||||
|
||||
@@ -3519,35 +3519,98 @@
|
||||
});
|
||||
};
|
||||
|
||||
function loadVersions() {
|
||||
fetch('/api/admin/versions')
|
||||
function loadVersions(page) {
|
||||
page = page || 1;
|
||||
fetch('/api/admin/digital-human-versions?page=' + page + '&pageSize=20')
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
var tbody = document.getElementById('versionListBody');
|
||||
if (!res.success) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="empty-tip">加载失败: ' + (res.error || '') + '</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="empty-tip">加载失败: ' + (res.message || res.error || '') + '</td></tr>';
|
||||
return;
|
||||
}
|
||||
var items = res.items || [];
|
||||
// 兼容两种返回格式:直接数组 或 分页对象
|
||||
var data = res.data;
|
||||
var items = [];
|
||||
var pages = 1;
|
||||
var current = 1;
|
||||
if (Array.isArray(data)) {
|
||||
items = data;
|
||||
} else if (data && Array.isArray(data.records)) {
|
||||
items = data.records;
|
||||
pages = data.pages || 1;
|
||||
current = data.current || 1;
|
||||
} else if (data && Array.isArray(data.items)) {
|
||||
items = data.items;
|
||||
}
|
||||
if (items.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="empty-tip">暂无版本记录</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="empty-tip">暂无版本记录</td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = items.map(function (v) {
|
||||
var url = (v.file_url || '').replace(/"/g, '"');
|
||||
return '<tr><td>' + (v.version || '') + '</td><td><a href="' + url + '" target="_blank" rel="noopener">' + url + '</a></td><td>' + (v.created_at || '') + '</td><td><a href="' + url + '" download class="btn btn-sm">下载</a></td></tr>';
|
||||
var statusText = v.status === 'DRAFT' ? '草稿' : (v.status === 'RELEASED' ? '已发布' : '已废弃');
|
||||
var statusColor = v.status === 'DRAFT' ? '#999' : (v.status === 'RELEASED' ? '#52c41a' : '#ff4d4f');
|
||||
var isLatestBadge = v.isLatest ? '<span style="color:#ff4d4f;font-weight:600;">★</span>' : '';
|
||||
var fileSize = v.fileSize ? (v.fileSize / 1024 / 1024).toFixed(2) + ' MB' : '-';
|
||||
var md5Short = (v.md5 || 'unknown').substring(0, 12) + '...';
|
||||
var changelog = (v.changelog || '-').substring(0, 50);
|
||||
if ((v.changelog || '').length > 50) changelog += '...';
|
||||
var releasedAt = v.releasedAt || '-';
|
||||
var downloadUrl = v.downloadUrl || '';
|
||||
|
||||
var actions = '';
|
||||
if (v.status === 'DRAFT') {
|
||||
actions += '<button class="btn btn-sm" onclick="releaseVersion(\'' + v.version + '\')">发布</button> ';
|
||||
}
|
||||
if (v.status === 'RELEASED' && !v.isLatest) {
|
||||
actions += '<button class="btn btn-sm" onclick="setLatestVersion(\'' + v.version + '\')">设为最新</button> ';
|
||||
}
|
||||
if (downloadUrl) {
|
||||
actions += '<a href="' + downloadUrl + '" class="btn btn-sm" download>下载</a> ';
|
||||
}
|
||||
if (!v.isLatest) {
|
||||
actions += '<button class="btn btn-sm btn-danger" onclick="deleteVersion(\'' + v.version + '\')">删除</button>';
|
||||
}
|
||||
|
||||
return '<tr>' +
|
||||
'<td>' + (v.version || '') + '</td>' +
|
||||
'<td style="color:' + statusColor + ';">' + statusText + '</td>' +
|
||||
'<td>' + isLatestBadge + '</td>' +
|
||||
'<td>' + fileSize + '</td>' +
|
||||
'<td title="' + (v.md5 || '') + '">' + md5Short + '</td>' +
|
||||
'<td>' + changelog + '</td>' +
|
||||
'<td>' + releasedAt + '</td>' +
|
||||
'<td>' + actions + '</td>' +
|
||||
'</tr>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// 分页
|
||||
var pagination = document.getElementById('versionPagination');
|
||||
if (pages > 1) {
|
||||
var html = '';
|
||||
for (var i = 1; i <= pages; i++) {
|
||||
var active = i === current ? ' active' : '';
|
||||
html += '<span class="page-item' + active + '" onclick="loadVersions(' + i + ')">' + i + '</span>';
|
||||
}
|
||||
pagination.innerHTML = html;
|
||||
} else {
|
||||
pagination.innerHTML = '';
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById('versionListBody').innerHTML = '<tr><td colspan="4" class="empty-tip">请求失败</td></tr>';
|
||||
.catch(function (err) {
|
||||
document.getElementById('versionListBody').innerHTML = '<tr><td colspan="8" class="empty-tip">请求失败: ' + (err.message || '') + '</td></tr>';
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('btnUploadVersion').onclick = function () {
|
||||
var version = (document.getElementById('versionNumber').value || '').trim();
|
||||
var minClientVersion = (document.getElementById('versionMinClientVersion').value || '').trim();
|
||||
var changelog = (document.getElementById('versionChangelog').value || '').trim();
|
||||
var fileInput = document.getElementById('versionZip');
|
||||
var msgEl = document.getElementById('msgVersion');
|
||||
msgEl.textContent = '';
|
||||
msgEl.className = 'msg';
|
||||
|
||||
if (!version) {
|
||||
msgEl.textContent = '请填写版本号';
|
||||
msgEl.classList.add('err');
|
||||
@@ -3564,34 +3627,99 @@
|
||||
msgEl.classList.add('err');
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('version', version);
|
||||
formData.append('file', file);
|
||||
msgEl.textContent = '上传中...';
|
||||
formData.append('version', version);
|
||||
if (minClientVersion) formData.append('minClientVersion', minClientVersion);
|
||||
if (changelog) formData.append('changelog', changelog);
|
||||
|
||||
msgEl.textContent = '上传中,请稍候...';
|
||||
msgEl.classList.remove('err', 'ok');
|
||||
fetch('/api/admin/version', {
|
||||
|
||||
fetch('/api/admin/digital-human-versions/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) {
|
||||
msgEl.textContent = '发布成功。版本:' + res.version + ',链接:' + (res.file_url || '');
|
||||
if (res.success && res.data) {
|
||||
msgEl.textContent = '上传成功!版本:' + res.data.version + '(状态:草稿,请在列表中点击"发布"按钮)';
|
||||
msgEl.classList.add('ok');
|
||||
document.getElementById('versionNumber').value = '';
|
||||
document.getElementById('versionMinClientVersion').value = '';
|
||||
document.getElementById('versionChangelog').value = '';
|
||||
fileInput.value = '';
|
||||
loadVersions();
|
||||
} else {
|
||||
msgEl.textContent = res.error || '上传失败';
|
||||
msgEl.textContent = res.message || res.error || '上传失败';
|
||||
msgEl.classList.add('err');
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
msgEl.textContent = '请求失败';
|
||||
.catch(function (err) {
|
||||
msgEl.textContent = '请求失败: ' + (err.message || '');
|
||||
msgEl.classList.add('err');
|
||||
});
|
||||
};
|
||||
|
||||
window.releaseVersion = function(version) {
|
||||
if (!confirm('确认发布版本 ' + version + ' 吗?')) return;
|
||||
fetch('/api/admin/digital-human-versions/' + version + '/release', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) {
|
||||
alert('发布成功!');
|
||||
loadVersions();
|
||||
} else {
|
||||
alert('发布失败:' + (res.message || res.error || ''));
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
alert('请求失败:' + (err.message || ''));
|
||||
});
|
||||
};
|
||||
|
||||
window.setLatestVersion = function(version) {
|
||||
if (!confirm('确认将版本 ' + version + ' 设为最新吗?客户端将自动检测并更新到此版本。')) return;
|
||||
fetch('/api/admin/digital-human-versions/' + version + '/set-latest', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) {
|
||||
alert('设置成功!版本 ' + version + ' 已标记为最新。');
|
||||
loadVersions();
|
||||
} else {
|
||||
alert('设置失败:' + (res.message || res.error || ''));
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
alert('请求失败:' + (err.message || ''));
|
||||
});
|
||||
};
|
||||
|
||||
window.deleteVersion = function(version) {
|
||||
if (!confirm('确认删除版本 ' + version + ' 吗?此操作将删除 OSS 文件,不可恢复!')) return;
|
||||
fetch('/api/admin/digital-human-versions/' + version, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) {
|
||||
alert('删除成功!');
|
||||
loadVersions();
|
||||
} else {
|
||||
alert('删除失败:' + (res.message || res.error || ''));
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
alert('请求失败:' + (err.message || ''));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// ========== 栏目权限配置 ==========
|
||||
function loadColumns() {
|
||||
fetch('/api/admin/columns')
|
||||
|
||||
@@ -916,19 +916,33 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 版本管理 -->
|
||||
<!-- 数字人版本管理 -->
|
||||
<div id="panel-version" class="tab-panel">
|
||||
<div class="form-box">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">发布新版本</h3>
|
||||
<div class="form-group">
|
||||
<label>版本号</label>
|
||||
<input type="text" id="versionNumber" placeholder="例如:1.0.0">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">上传新版本</h3>
|
||||
<p style="margin-bottom:16px;font-size:13px;color:#666;">
|
||||
上传数字人程序 ZIP 包,系统会自动计算 MD5 并存储到 OSS。上传后状态为草稿,需要手动发布。
|
||||
</p>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:200px;">
|
||||
<label>版本号 *</label>
|
||||
<input type="text" id="versionNumber" placeholder="例如:1.0.0">
|
||||
</div>
|
||||
<div class="form-group" style="min-width:200px;">
|
||||
<label>最低客户端版本</label>
|
||||
<input type="text" id="versionMinClientVersion" placeholder="例如:2.0.0(可选)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>ZIP 压缩包</label>
|
||||
<label>更新日志</label>
|
||||
<textarea id="versionChangelog" rows="3" placeholder="例如:修复数字人口型同步问题,优化启动速度" style="width:100%;padding:10px;border:1px solid #ddd;border-radius:6px;resize:vertical;"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>ZIP 压缩包 *</label>
|
||||
<input type="file" id="versionZip" accept=".zip">
|
||||
<p style="font-size:12px;color:#999;margin-top:4px;">仅支持 .zip 格式,文件名:ShuFuDigitalHuman.zip</p>
|
||||
</div>
|
||||
<button class="btn" id="btnUploadVersion">上传并发布</button>
|
||||
<button class="btn" id="btnUploadVersion">上传(草稿状态)</button>
|
||||
<p class="msg" id="msgVersion"></p>
|
||||
</div>
|
||||
<div class="panel-box">
|
||||
@@ -936,14 +950,19 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>版本号</th>
|
||||
<th>下载链接</th>
|
||||
<th>发布时间</th>
|
||||
<th>操作</th>
|
||||
<th style="width:80px;">版本号</th>
|
||||
<th style="width:60px;">状态</th>
|
||||
<th style="width:60px;">最新</th>
|
||||
<th style="width:80px;">文件大小</th>
|
||||
<th style="width:120px;">MD5</th>
|
||||
<th>更新日志</th>
|
||||
<th style="width:140px;">发布时间</th>
|
||||
<th style="width:240px;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="versionListBody"></tbody>
|
||||
</table>
|
||||
<div class="pagination" id="versionPagination"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
157
frontend-vue/src/shared/api/digital-human.ts
Normal file
157
frontend-vue/src/shared/api/digital-human.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { get, post, del, type JavaApiResponse, unwrapJavaResponse } from '@/shared/api/http'
|
||||
|
||||
const JAVA_API_PREFIX = '/newApi/api/digital-human/versions'
|
||||
|
||||
/**
|
||||
* 数字人版本信息
|
||||
*/
|
||||
export interface DigitalHumanVersion {
|
||||
id: number
|
||||
version: string
|
||||
ossObjectKey: string
|
||||
fileSize: number
|
||||
md5: string
|
||||
changelog: string | null
|
||||
minClientVersion: string | null
|
||||
isLatest: boolean
|
||||
status: 'DRAFT' | 'RELEASED' | 'DEPRECATED'
|
||||
createdBy: string | null
|
||||
createdAt: string
|
||||
releasedAt: string | null
|
||||
downloadUrl?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载链接信息
|
||||
*/
|
||||
export interface DownloadUrlVo {
|
||||
version: string
|
||||
downloadUrl: string
|
||||
expiresIn: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询参数
|
||||
*/
|
||||
export interface VersionListParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
status?: 'DRAFT' | 'RELEASED' | 'DEPRECATED'
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页结果
|
||||
*/
|
||||
export interface PageResult<T> {
|
||||
records: T[]
|
||||
total: number
|
||||
size: number
|
||||
current: number
|
||||
pages: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传新版本
|
||||
*/
|
||||
export function uploadDigitalHumanVersion(
|
||||
file: File,
|
||||
version: string,
|
||||
changelog?: string,
|
||||
minClientVersion?: string,
|
||||
) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('version', version)
|
||||
if (changelog) formData.append('changelog', changelog)
|
||||
if (minClientVersion) formData.append('minClientVersion', minClientVersion)
|
||||
|
||||
return unwrapJavaResponse(
|
||||
post<JavaApiResponse<DigitalHumanVersion>>(
|
||||
`${JAVA_API_PREFIX}/upload`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询版本列表
|
||||
*/
|
||||
export function getDigitalHumanVersions(params?: VersionListParams) {
|
||||
return unwrapJavaResponse(
|
||||
get<JavaApiResponse<PageResult<DigitalHumanVersion>>>(
|
||||
JAVA_API_PREFIX,
|
||||
{ params },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新版本
|
||||
*/
|
||||
export function getLatestDigitalHumanVersion() {
|
||||
return unwrapJavaResponse(
|
||||
get<JavaApiResponse<DigitalHumanVersion>>(
|
||||
`${JAVA_API_PREFIX}/latest`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定版本详情
|
||||
*/
|
||||
export function getDigitalHumanVersion(version: string) {
|
||||
return unwrapJavaResponse(
|
||||
get<JavaApiResponse<DigitalHumanVersion>>(
|
||||
`${JAVA_API_PREFIX}/${version}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布版本
|
||||
*/
|
||||
export function releaseDigitalHumanVersion(version: string) {
|
||||
return unwrapJavaResponse(
|
||||
post<JavaApiResponse<void>>(
|
||||
`${JAVA_API_PREFIX}/${version}/release`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设为最新版本
|
||||
*/
|
||||
export function setLatestDigitalHumanVersion(version: string) {
|
||||
return unwrapJavaResponse(
|
||||
post<JavaApiResponse<void>>(
|
||||
`${JAVA_API_PREFIX}/${version}/set-latest`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除版本
|
||||
*/
|
||||
export function deleteDigitalHumanVersion(version: string) {
|
||||
return unwrapJavaResponse(
|
||||
del<JavaApiResponse<void>>(
|
||||
`${JAVA_API_PREFIX}/${version}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载链接
|
||||
*/
|
||||
export function getDigitalHumanVersionDownloadUrl(version: string) {
|
||||
return unwrapJavaResponse(
|
||||
get<JavaApiResponse<DownloadUrlVo>>(
|
||||
`${JAVA_API_PREFIX}/${version}/download-url`,
|
||||
),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user