feat(wordcloud): 前端 R4 类型/api/词云页真实接口 + stickerEdit 线稿真实地址
This commit is contained in:
+102
-5
@@ -1,7 +1,104 @@
|
||||
import Taro from '@tarojs/taro'
|
||||
import http, { BASE_URL, getToken } from '../request'
|
||||
import type {
|
||||
CosCredentials,
|
||||
SketchResult,
|
||||
WordCloudJob,
|
||||
WordCloudStatus,
|
||||
} from '../../types'
|
||||
|
||||
/**
|
||||
* R4 上传接口归属文件。
|
||||
* 后端 COS/wordcloud 适配器就绪后,在这里补充:
|
||||
* getUploadCredentials / uploadImage / generateWordCloud / getWordCloudJob / sketchImage
|
||||
* 词云任务使用“创建任务 -> 轮询状态 -> 取结果链接”的异步模型。
|
||||
* R4 上传 / 词云 / 线稿接口。
|
||||
* 契约:前端与后端见 docs 里 api-contract-v1.md §8;后端与 wordcloud 见 wordcloud-contract.md。
|
||||
* multipart 上传经 Taro.uploadFile 统一带 Bearer token、解析后端 { code, message, data } 信封;
|
||||
* 与 request.ts 的 JSON 封装保持一致的成功/失败语义。
|
||||
*/
|
||||
export {}
|
||||
|
||||
interface Envelope<T> {
|
||||
code: number
|
||||
message: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
/** multipart 上传封装:带 token、解析统一信封;业务失败抛 Error(message) */
|
||||
async function uploadMultipart<T>(
|
||||
path: string,
|
||||
filePath: string,
|
||||
name: string,
|
||||
formData?: Record<string, string>,
|
||||
): Promise<T> {
|
||||
const res = await Taro.uploadFile({
|
||||
url: `${BASE_URL}${path}`,
|
||||
filePath,
|
||||
name,
|
||||
formData,
|
||||
header: { Authorization: `Bearer ${getToken()}` },
|
||||
})
|
||||
|
||||
let body: Envelope<T>
|
||||
try {
|
||||
body = JSON.parse(res.data)
|
||||
} catch {
|
||||
throw new Error('网络异常,请稍后重试')
|
||||
}
|
||||
if (body && typeof body.code === 'number' && body.code !== 0) {
|
||||
throw new Error(body.message || '请求失败')
|
||||
}
|
||||
return (body && typeof body.code === 'number' ? body.data : body) as T
|
||||
}
|
||||
|
||||
/** 获取 COS 直传凭证(STS 临时凭证或预签名 URL;小程序不持有永久密钥) */
|
||||
export function getUploadCredentials(key: string): Promise<CosCredentials> {
|
||||
return http.get<CosCredentials>(`/api/upload/credentials?key=${encodeURIComponent(key)}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 直传 COS:服务端下发预签名 URL 时用 PUT 提交文件字节;否则返回凭证由调用方决定。
|
||||
* 注:COS 直传的最终语义以联调阶段服务端 upload 模块实现为准(当前后端为占位)。
|
||||
*/
|
||||
export async function uploadToCos(localPath: string, credentials: CosCredentials): Promise<string> {
|
||||
if (!credentials.presignedUrl) {
|
||||
throw new Error('获取 COS 直传地址失败')
|
||||
}
|
||||
const fileSystem = Taro.getFileSystemManager()
|
||||
const data = fileSystem.readFileSync(localPath)
|
||||
await Taro.request({
|
||||
url: credentials.presignedUrl,
|
||||
method: 'PUT',
|
||||
data,
|
||||
header: { 'Content-Type': 'application/octet-stream' },
|
||||
})
|
||||
// 直传成功后返回去掉签名参数的对象地址
|
||||
return credentials.presignedUrl.split('?')[0]
|
||||
}
|
||||
|
||||
/** 线稿:图片 → 处理后图片 URL(失败由调用方降级本地灰度) */
|
||||
export function sketchImage(localPath: string): Promise<SketchResult> {
|
||||
return uploadMultipart<SketchResult>('/api/sketch', localPath, 'image')
|
||||
}
|
||||
|
||||
/** 创建词云任务:底图 + 名单 → jobId(异步模型,随后轮询) */
|
||||
export function createWordCloudJob(
|
||||
imagePath: string,
|
||||
names: string,
|
||||
params?: Record<string, unknown>,
|
||||
): Promise<{ jobId: string }> {
|
||||
return uploadMultipart<{ jobId: string }>(
|
||||
'/api/wordcloud/generate',
|
||||
imagePath,
|
||||
'image',
|
||||
{ names, ...(params ? { params: JSON.stringify(params) } : {}) },
|
||||
)
|
||||
}
|
||||
|
||||
/** 轮询词云任务状态;success 后 WordCloudJob.imageUrl 为结果图 COS 链接 */
|
||||
export function getWordCloudJob(jobId: string): Promise<WordCloudJob> {
|
||||
return http.get<WordCloudJob>(`/api/wordcloud/jobs/${jobId}`)
|
||||
}
|
||||
|
||||
/** 取词云任务结果(后端将 wordcloud 产物转存 COS 后返回) */
|
||||
export function getWordCloudResult(jobId: string): Promise<{ imageUrl: string; svgUrl?: string }> {
|
||||
return http.get<{ imageUrl: string; svgUrl?: string }>(`/api/wordcloud/jobs/${jobId}/result`)
|
||||
}
|
||||
|
||||
export type { WordCloudStatus }
|
||||
|
||||
Reference in New Issue
Block a user