feat:脚本文件预览

This commit is contained in:
xiaozhu
2026-08-31 18:48:19 +08:00
parent 4ff0f344af
commit 690de643ad
12 changed files with 1138 additions and 65 deletions
+117 -4
View File
@@ -556,6 +556,109 @@ export async function deleteResource(
);
}
/** 同源流式下载数据资源字节,供 Excel 等预览器使用。 */
export async function fetchResourceContentFile(
workspaceId: string,
resourceId: string,
fileName: string,
signal?: AbortSignal,
): Promise<File> {
const response = await fetch(
`/api/v1/data-resources/${encodeURIComponent(resourceId)}/content?workspace_id=${encodeURIComponent(workspaceId)}`,
{
credentials: "same-origin",
signal,
headers: {
"X-Request-ID": createUuid().replaceAll("-", ""),
},
},
);
if (response.status === 401 && typeof window !== "undefined") {
const here = window.location.pathname;
if (here !== "/login") {
window.location.assign("/login");
}
throw new ApiRequestError("未登录或登录已过期", 401);
}
if (!response.ok) {
let message = `请求失败(HTTP ${response.status}`;
try {
const payload = (await response.json()) as ApiErrorEnvelope;
const detailMessage =
typeof payload.detail === "string"
? payload.detail
: payload.detail?.message;
if (detailMessage) message = detailMessage;
} catch {
/* ignore non-JSON error bodies */
}
throw new ApiRequestError(message, response.status);
}
const blob = await response.blob();
return new File([blob], fileName, {
type: blob.type || "application/octet-stream",
});
}
export type ResourcePreviewPayload = {
kind: "table";
columns: string[];
rows: string[][];
row_count: number;
truncated: boolean;
delimiter: string;
};
/** 表格类数据资源抽样预览(csv / tsv)。 */
export async function fetchResourcePreview(
workspaceId: string,
resourceId: string,
input: { limit?: number } = {},
signal?: AbortSignal,
): Promise<ResourcePreviewPayload> {
const parameters = new URLSearchParams();
parameters.set("workspace_id", workspaceId);
if (input.limit != null) parameters.set("limit", String(input.limit));
const response = await fetch(
`/api/v1/data-resources/${encodeURIComponent(resourceId)}/preview?${parameters.toString()}`,
{
credentials: "same-origin",
signal,
headers: {
"X-Request-ID": createUuid().replaceAll("-", ""),
},
},
);
if (response.status === 401 && typeof window !== "undefined") {
const here = window.location.pathname;
if (here !== "/login") {
window.location.assign("/login");
}
throw new ApiRequestError("未登录或登录已过期", 401);
}
const payload = await response.json();
if (!response.ok) {
const error = payload as ApiErrorEnvelope;
const detailMessage =
typeof error.detail === "string" ? error.detail : error.detail?.message;
throw new ApiRequestError(
detailMessage ?? `请求失败(HTTP ${response.status}`,
response.status,
);
}
const data = (payload as { data: ResourcePreviewPayload }).data;
if (!data || data.kind !== "table" || !Array.isArray(data.columns)) {
throw new ApiRequestError("响应数据格式错误", response.status);
}
return data;
}
export async function createResourceUpload(
workspaceId: string,
body: {
@@ -1667,10 +1770,20 @@ export type WorkspaceBoundApi = {
uploadId: string,
body: Parameters<typeof bindResourceUpload>[2],
) => Promise<ResourceItem>;
deleteResource: (
resourceId: string,
) => Promise<{ resource_id: string; status: string }>;
updateScript: (
deleteResource: (
resourceId: string,
) => Promise<{ resource_id: string; status: string }>;
fetchResourceContentFile: (
resourceId: string,
fileName: string,
signal?: AbortSignal,
) => Promise<File>;
fetchResourcePreview: (
resourceId: string,
input?: { limit?: number },
signal?: AbortSignal,
) => Promise<ResourcePreviewPayload>;
updateScript: (
scriptId: string,
input: Parameters<typeof updateScript>[2],
) => Promise<ScriptItem>;