fix(mobile): support Android system file picker
This commit is contained in:
@@ -11,6 +11,8 @@ import type {
|
||||
import { apiRequest, apiUrl, authHeaders, readTextPayload } from './api';
|
||||
import { getSelectedPosition } from './auth';
|
||||
import { fileSelectionFailure } from '../utils/file-selection';
|
||||
import { withPlatformFileSelection } from './file-selection-lifecycle';
|
||||
import { isAndroidAppRuntime } from './local-file-picker';
|
||||
|
||||
type RawKnowledgeSnippet = KnowledgeSnippet & {
|
||||
title?: string;
|
||||
@@ -20,7 +22,44 @@ type RawKnowledgeSnippet = KnowledgeSnippet & {
|
||||
const mediaExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.mp4', '.mov', '.avi', '.mkv', '.webm', '.m4v'];
|
||||
const videoExtensions = new Set(['.mp4', '.mov', '.avi', '.mkv', '.webm', '.m4v']);
|
||||
|
||||
export const chooseKnowledgeMedia = () =>
|
||||
interface AppMediaFile {
|
||||
tempFilePath?: string;
|
||||
path?: string;
|
||||
size?: number;
|
||||
fileType?: 'image' | 'video';
|
||||
}
|
||||
|
||||
interface AppChooseMediaResult {
|
||||
tempFiles?: AppMediaFile[];
|
||||
}
|
||||
|
||||
type UniWithChooseMedia = {
|
||||
chooseMedia?: (options: {
|
||||
count: number;
|
||||
mediaType: Array<'image' | 'video'>;
|
||||
sourceType: Array<'album'>;
|
||||
success: (result: AppChooseMediaResult) => void;
|
||||
fail: (error: unknown) => void;
|
||||
}) => void;
|
||||
};
|
||||
|
||||
const validateKnowledgeMedia = (
|
||||
path: string,
|
||||
name: string,
|
||||
size: number,
|
||||
declaredKind?: 'image' | 'video'
|
||||
): KnowledgeMediaSelectedFile => {
|
||||
if (!path) throw new Error('未获取到附件文件');
|
||||
const extension = `.${name.split('.').pop()?.toLowerCase() || ''}`;
|
||||
const kind = declaredKind || (videoExtensions.has(extension) ? 'video' : 'image');
|
||||
const maxSize = kind === 'video' ? 100 * 1024 * 1024 : 10 * 1024 * 1024;
|
||||
if (size > maxSize) {
|
||||
throw new Error(kind === 'video' ? '视频不能超过 100MB' : '图片不能超过 10MB');
|
||||
}
|
||||
return { path, name, size, kind };
|
||||
};
|
||||
|
||||
const chooseKnowledgeMediaWithFileInput = () =>
|
||||
new Promise<KnowledgeMediaSelectedFile>((resolve, reject) => {
|
||||
uni.chooseFile({
|
||||
count: 1,
|
||||
@@ -31,24 +70,49 @@ export const chooseKnowledgeMedia = () =>
|
||||
const file = (tempFiles[0] || {}) as { path?: string; name?: string; size?: number };
|
||||
const path = file.path || result.tempFilePaths?.[0] || '';
|
||||
const name = file.name || path.split('/').pop() || '现场附件';
|
||||
const extension = `.${name.split('.').pop()?.toLowerCase() || ''}`;
|
||||
const kind = videoExtensions.has(extension) ? 'video' : 'image';
|
||||
const size = Number(file.size || 0);
|
||||
const maxSize = kind === 'video' ? 100 * 1024 * 1024 : 10 * 1024 * 1024;
|
||||
if (!path) {
|
||||
reject(new Error('未获取到附件文件'));
|
||||
return;
|
||||
try {
|
||||
resolve(validateKnowledgeMedia(path, name, size));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
if (size > maxSize) {
|
||||
reject(new Error(kind === 'video' ? '视频不能超过 100MB' : '图片不能超过 10MB'));
|
||||
return;
|
||||
}
|
||||
resolve({ path, name, size, kind });
|
||||
},
|
||||
fail: (error) => reject(fileSelectionFailure(error, '附件'))
|
||||
});
|
||||
});
|
||||
|
||||
const chooseKnowledgeMediaWithAppPicker = () =>
|
||||
new Promise<KnowledgeMediaSelectedFile>((resolve, reject) => {
|
||||
const chooseMedia = (uni as unknown as UniWithChooseMedia).chooseMedia;
|
||||
if (!chooseMedia) {
|
||||
reject(new Error('当前 App 版本无法选择图片或视频'));
|
||||
return;
|
||||
}
|
||||
chooseMedia({
|
||||
count: 1,
|
||||
mediaType: ['image', 'video'],
|
||||
sourceType: ['album'],
|
||||
success: (result) => {
|
||||
const file = result.tempFiles?.[0] || {};
|
||||
const path = file.tempFilePath || file.path || '';
|
||||
const name = path.split('/').pop() || (file.fileType === 'video' ? '现场视频.mp4' : '现场图片.jpg');
|
||||
// App chooseMedia reports the selected file size in KiB.
|
||||
const size = Math.max(0, Number(file.size || 0)) * 1024;
|
||||
try {
|
||||
resolve(validateKnowledgeMedia(path, name, size, file.fileType));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
fail: (error) => reject(fileSelectionFailure(error, '附件'))
|
||||
});
|
||||
});
|
||||
|
||||
export const chooseKnowledgeMedia = () =>
|
||||
isAndroidAppRuntime()
|
||||
? withPlatformFileSelection(chooseKnowledgeMediaWithAppPicker)
|
||||
: chooseKnowledgeMediaWithFileInput();
|
||||
|
||||
const normalizeSnippet = (snippet: RawKnowledgeSnippet): KnowledgeSnippet => ({
|
||||
...snippet,
|
||||
docTitle: snippet.docTitle || snippet.title || '',
|
||||
|
||||
Reference in New Issue
Block a user