import type { DmsPreviewResourceType } from '#/api/x/dms/preview';
|
import type { DmsWatermarkParameters } from '#/api/x/dms/watermarkParameters';
|
|
import { useGlobSetting } from '@jnpf/hooks';
|
import { createImgPreview } from '@jnpf/ui';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import { createDmsFilePreviewTicket } from '#/api/x/dms/preview';
|
import { watermarkParameters } from '#/api/x/dms/watermarkParameters';
|
import { onlineUtils } from '#/utils/jnpf';
|
|
const IMAGE_EXTENSIONS = new Set(['bmp', 'gif', 'jpeg', 'jpg', 'png', 'webp']);
|
const IMAGE_MIME_TYPES = new Set(['image/bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/webp', 'image/x-ms-bmp']);
|
const IMAGE_PREVIEW_OPENING_LOCK_MS = 500;
|
const ONLY_OFFICE_EXTENSIONS = new Set([
|
'csv',
|
'doc',
|
'docm',
|
'docx',
|
'dot',
|
'dotx',
|
'htm',
|
'html',
|
'odp',
|
'ods',
|
'odt',
|
'otp',
|
'ots',
|
'ott',
|
'pdf',
|
'pot',
|
'potx',
|
'pps',
|
'ppsx',
|
'ppt',
|
'pptm',
|
'pptx',
|
'rtf',
|
'txt',
|
'xls',
|
'xlsm',
|
'xlsx',
|
'xlt',
|
'xltx',
|
]);
|
const openingResources = new Set<string>();
|
|
export interface OpenDmsFilePreviewOptions extends DmsWatermarkParameters {
|
fileName: string;
|
mimeType?: string;
|
resourceId: string;
|
resourceType: DmsPreviewResourceType;
|
}
|
|
function fileExtension(fileName: string) {
|
const normalized = fileName.trim().toLowerCase();
|
return normalized.includes('.') ? normalized.split('.').pop() || '' : '';
|
}
|
|
export function supportsImagePreview(fileName: string, mimeType?: string) {
|
const normalizedMimeType = mimeType?.split(';')[0]?.trim().toLowerCase() || '';
|
return IMAGE_EXTENSIONS.has(fileExtension(fileName)) || IMAGE_MIME_TYPES.has(normalizedMimeType);
|
}
|
|
export function supportsOnlyOfficePreview(fileName: string) {
|
return ONLY_OFFICE_EXTENSIONS.has(fileExtension(fileName));
|
}
|
|
export function dmsPreviewStreamUrl(fileVersionId: string, accessTicket: string) {
|
const apiURL = (useGlobSetting().apiURL || '').replace(/\/+$/, '');
|
const query = new URLSearchParams({ ticket: accessTicket });
|
return `${apiURL}/api/file/Dms/OnlyOffice/${encodeURIComponent(fileVersionId)}?${query.toString()}`;
|
}
|
|
export async function openDmsFilePreview(options: OpenDmsFilePreviewOptions) {
|
if (!supportsImagePreview(options.fileName, options.mimeType) && !supportsOnlyOfficePreview(options.fileName)) {
|
throw new Error('OnlyOffice 不支持该文件格式');
|
}
|
const openingKey = JSON.stringify([options.resourceType, options.resourceId, watermarkParameters(options)]);
|
if (openingResources.has(openingKey)) return false;
|
openingResources.add(openingKey);
|
let releaseDelay = 0;
|
try {
|
const response = await createDmsFilePreviewTicket({
|
...watermarkParameters(options),
|
operationId: uuidv4(),
|
resourceId: options.resourceId,
|
resourceType: options.resourceType,
|
});
|
const ticket = response.data;
|
if (!ticket?.accessTicket || !ticket.fileVersionId || !ticket.fileName) {
|
throw new Error('后端返回的 DMS 预览票据不完整');
|
}
|
if (supportsImagePreview(ticket.fileName, ticket.mimeType)) {
|
createImgPreview({ imageList: [dmsPreviewStreamUrl(ticket.fileVersionId, ticket.accessTicket)] });
|
releaseDelay = IMAGE_PREVIEW_OPENING_LOCK_MS;
|
return true;
|
}
|
if (!supportsOnlyOfficePreview(ticket.fileName)) {
|
throw new Error('OnlyOffice 不支持该文件格式');
|
}
|
onlineUtils.openOfficeDocument({
|
dmsAccessTicket: ticket.accessTicket,
|
dmsPreviewExpiresAt: ticket.expiresAt,
|
refreshDmsPreviewTicket: async () => {
|
const refreshed = await createDmsFilePreviewTicket({
|
...watermarkParameters(options),
|
operationId: crypto.randomUUID(),
|
resourceId: ticket.fileVersionId,
|
resourceType: 'FILE_VERSION',
|
});
|
return refreshed.data;
|
},
|
file: {
|
fileId: ticket.fileVersionId,
|
fileSize: ticket.sizeBytes,
|
name: ticket.fileName,
|
},
|
fileType: 'dms',
|
mode: 'view',
|
title: ticket.fileName,
|
});
|
return true;
|
} finally {
|
if (releaseDelay) {
|
setTimeout(() => openingResources.delete(openingKey), releaseDelay);
|
} else {
|
openingResources.delete(openingKey);
|
}
|
}
|
}
|
|
export function dmsPreviewErrorMessage(error: unknown) {
|
return error instanceof Error && error.message ? error.message : '文件预览失败';
|
}
|