feat(software-version): 安装包改浏览器直传 MinIO,支持批量删除
- 后端新增 /api/admin/version/presign、confirm、delete 端点;直传后服务端校验对象并写 web_config - OSS 层新增软件版本对象 presign PUT/大小校验/删除与 client 桶 URL 识别 - 后台前端上传改 presign→PUT→confirm 三段式直传,带进度条;成功提示精简为"发布成功" - 版本列表加勾选/表头全选、批量删除与单行删除;操作按钮样式对齐其他子菜单
This commit is contained in:
@@ -1,21 +1,83 @@
|
||||
/** 软件版本列表加载适配(任务 127):GET /api/admin/versions。 */
|
||||
import { http } from '@/api/http'
|
||||
import axios from 'axios'
|
||||
import { http, unwrap } from '@/api/http'
|
||||
import { parseSoftwareVersionList, parseSoftwareVersionUpload } from './version-model.ts'
|
||||
import type { SoftwareVersionItem, SoftwareVersionList } from './version-dto.ts'
|
||||
|
||||
export const SOFTWARE_VERSIONS_ENDPOINT = '/api/admin/versions'
|
||||
export const SOFTWARE_VERSION_UPLOAD_ENDPOINT = '/api/admin/version'
|
||||
export const SOFTWARE_VERSION_PRESIGN_ENDPOINT = `${SOFTWARE_VERSION_UPLOAD_ENDPOINT}/presign`
|
||||
export const SOFTWARE_VERSION_CONFIRM_ENDPOINT = `${SOFTWARE_VERSION_UPLOAD_ENDPOINT}/confirm`
|
||||
export const SOFTWARE_VERSION_DELETE_ENDPOINT = `${SOFTWARE_VERSION_UPLOAD_ENDPOINT}/delete`
|
||||
|
||||
/** MinIO 直传专用实例:不带 cookie、不挂 401 跳登录拦截器(预签名过期/签名失败不能误判会话过期);大 zip 给足超时。 */
|
||||
const directPut = axios.create({ timeout: 600_000, withCredentials: false })
|
||||
|
||||
export async function fetchSoftwareVersions(): Promise<SoftwareVersionList> {
|
||||
const { data } = await http.get<unknown>(SOFTWARE_VERSIONS_ENDPOINT)
|
||||
return parseSoftwareVersionList(data)
|
||||
}
|
||||
|
||||
/** 上传客户端软件版本(multipart version + file);返回新版本行(含下载链接)。 */
|
||||
export async function uploadSoftwareVersion(version: string, file: Blob, filename = ''): Promise<SoftwareVersionItem | null> {
|
||||
const form = new FormData()
|
||||
form.append('version', version)
|
||||
form.append('file', file, filename || (file instanceof File ? file.name : 'version.zip'))
|
||||
const { data } = await http.post<unknown>(SOFTWARE_VERSION_UPLOAD_ENDPOINT, form)
|
||||
export interface SoftwareVersionUploadTarget {
|
||||
uploadUrl: string
|
||||
fileUrl: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export interface SoftwareVersionUploadResult {
|
||||
version: string
|
||||
fileUrl: string
|
||||
item: SoftwareVersionItem | null
|
||||
}
|
||||
|
||||
/** 第一步:向后端申请直传 PUT 预签名地址与公开下载 URL(登录会话签发,3 分钟有效)。 */
|
||||
export async function requestSoftwareVersionPresign(version: string): Promise<SoftwareVersionUploadTarget> {
|
||||
const { data } = await http.post<unknown>(SOFTWARE_VERSION_PRESIGN_ENDPOINT, null, { params: { version } })
|
||||
const core = (unwrap(data) ?? {}) as Record<string, unknown>
|
||||
const uploadUrl = typeof core.upload_url === 'string' ? core.upload_url : ''
|
||||
if (!uploadUrl) {
|
||||
throw new Error('后端未返回直传地址,请重试')
|
||||
}
|
||||
return {
|
||||
uploadUrl,
|
||||
fileUrl: typeof core.file_url === 'string' ? core.file_url : '',
|
||||
version: typeof core.version === 'string' ? core.version : version.trim(),
|
||||
}
|
||||
}
|
||||
|
||||
/** 第三步:直传完成后通知后端校验对象并写入版本记录(data.item 为新版本行)。 */
|
||||
export async function confirmSoftwareVersion(version: string): Promise<SoftwareVersionItem | null> {
|
||||
const { data } = await http.post<unknown>(SOFTWARE_VERSION_CONFIRM_ENDPOINT, null, { params: { version } })
|
||||
return parseSoftwareVersionUpload(data)
|
||||
}
|
||||
|
||||
/** 按 id 批量删除版本(后端会顺带清理无引用对象的 MinIO 安装包);返回实际删除行数。 */
|
||||
export async function deleteSoftwareVersions(ids: number[]): Promise<number> {
|
||||
if (!ids.length) return 0
|
||||
const { data } = await http.post<unknown>(SOFTWARE_VERSION_DELETE_ENDPOINT, ids)
|
||||
const core = (unwrap(data) ?? {}) as Record<string, unknown>
|
||||
return typeof core.deleted === 'number' ? core.deleted : ids.length
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传客户端软件版本(浏览器直传):presign 申请 → 直接 PUT 到 MinIO client 桶(不走 Java 中转)
|
||||
* → confirm 校验落库。onProgress 回传 0-100 上传进度。
|
||||
*/
|
||||
export async function uploadSoftwareVersion(
|
||||
version: string,
|
||||
file: Blob,
|
||||
_filename = '',
|
||||
onProgress?: (percent: number) => void,
|
||||
): Promise<SoftwareVersionUploadResult> {
|
||||
const target = await requestSoftwareVersionPresign(version)
|
||||
await directPut.put(target.uploadUrl, file, {
|
||||
headers: { 'Content-Type': 'application/octet-stream' },
|
||||
onUploadProgress: (event) => {
|
||||
if (!onProgress) return
|
||||
const total = event.total || 0
|
||||
onProgress(total > 0 ? Math.min(Math.round((event.loaded / total) * 100), 100) : 0)
|
||||
},
|
||||
})
|
||||
const item = await confirmSoftwareVersion(target.version)
|
||||
return { version: target.version, fileUrl: item?.fileUrl || target.fileUrl, item }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user