199 行
4.8 KiB
Plaintext
199 行
4.8 KiB
Plaintext
/**
|
|
* OmniCard AI (CRMmp) - 跨端统一图片上传核心业务驱动层 (UTS)
|
|
* 严格遵循 uts 强类型、零 emoji 与 AGENTS.md 约束
|
|
* 支持单图/多图上传、大图预览 (uni.previewImage)、独立删除与上限拦截
|
|
*/
|
|
|
|
export type ImageUploaderState = {
|
|
images: string[];
|
|
uploading: boolean;
|
|
errorMessage: string;
|
|
};
|
|
|
|
export type ChooseImageCallbackRes = {
|
|
tempFilePaths: string[];
|
|
};
|
|
|
|
export type ChooseImageOptions = {
|
|
count?: number;
|
|
sizeType?: string[];
|
|
sourceType?: string[];
|
|
success?: (res: ChooseImageCallbackRes) => void;
|
|
fail?: (err: unknown) => void;
|
|
};
|
|
|
|
export type ImageUploaderOptions = {
|
|
multiple?: boolean;
|
|
maxCount?: number;
|
|
sourceType?: string[];
|
|
chooseImageFn?: (options: ChooseImageOptions) => void;
|
|
};
|
|
|
|
/**
|
|
* 创建上传状态
|
|
*/
|
|
export function createImageUploaderState(initialImages?: string[]): ImageUploaderState {
|
|
return {
|
|
images: initialImages != null ? initialImages.slice() : [],
|
|
uploading: false,
|
|
errorMessage: '',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 追加图片 URL,并严格按 maxCount 截断
|
|
*/
|
|
export function addImageUrls(
|
|
state: ImageUploaderState,
|
|
urls: string[],
|
|
maxCount: number = 9
|
|
): void {
|
|
const nextList: string[] = [];
|
|
for (let i = 0; i < state.images.length; i++) {
|
|
nextList.push(state.images[i]);
|
|
}
|
|
for (let j = 0; j < urls.length; j++) {
|
|
const url = urls[j].trim();
|
|
if (url !== '') {
|
|
nextList.push(url);
|
|
}
|
|
}
|
|
state.images = nextList.slice(0, maxCount);
|
|
}
|
|
|
|
/**
|
|
* 依据索引删除单张图片
|
|
*/
|
|
export function removeImageByIndex(
|
|
state: ImageUploaderState,
|
|
index: number
|
|
): void {
|
|
if (index < 0 || index >= state.images.length) {
|
|
return;
|
|
}
|
|
const nextList: string[] = [];
|
|
for (let i = 0; i < state.images.length; i++) {
|
|
if (i !== index) {
|
|
nextList.push(state.images[i]);
|
|
}
|
|
}
|
|
state.images = nextList;
|
|
}
|
|
|
|
/**
|
|
* 清空所有图片
|
|
*/
|
|
export function clearAllImages(state: ImageUploaderState): void {
|
|
state.images = [];
|
|
}
|
|
|
|
/**
|
|
* 获取可用于全屏大图预览的 URL 数组
|
|
*/
|
|
export function resolvePreviewUrls(state: ImageUploaderState): string[] {
|
|
return state.images.slice();
|
|
}
|
|
|
|
/**
|
|
* 触发调用系统原生全屏大图放大预览
|
|
*/
|
|
export function previewImageAt(
|
|
state: ImageUploaderState,
|
|
currentUrlOrIndex: string | number
|
|
): void {
|
|
const urls = resolvePreviewUrls(state);
|
|
if (urls.length === 0) {
|
|
return;
|
|
}
|
|
let current = '';
|
|
if (typeof currentUrlOrIndex === 'number') {
|
|
if (currentUrlOrIndex >= 0 && currentUrlOrIndex < urls.length) {
|
|
current = urls[currentUrlOrIndex];
|
|
} else {
|
|
current = urls[0];
|
|
}
|
|
} else {
|
|
current = currentUrlOrIndex;
|
|
}
|
|
|
|
// #ifndef UNI-APP-X-TEST
|
|
try {
|
|
if (typeof uni !== 'undefined' && typeof uni.previewImage === 'function') {
|
|
uni.previewImage({
|
|
urls,
|
|
current,
|
|
});
|
|
}
|
|
} catch (_e) {}
|
|
// #endif
|
|
}
|
|
|
|
/**
|
|
* 选择图片并执行上传流程
|
|
*/
|
|
export async function chooseAndUploadImages(
|
|
state: ImageUploaderState,
|
|
options?: ImageUploaderOptions
|
|
): Promise<boolean> {
|
|
const opt = options != null ? options : {};
|
|
const multiple = opt.multiple !== undefined ? opt.multiple : false;
|
|
const maxCount = opt.maxCount !== undefined ? opt.maxCount : (multiple ? 9 : 1);
|
|
const remainingCount = maxCount - state.images.length;
|
|
|
|
if (remainingCount <= 0) {
|
|
state.errorMessage = '已达到上传上限';
|
|
return false;
|
|
}
|
|
|
|
const selectCount = multiple ? remainingCount : 1;
|
|
const sourceTypes = opt.sourceType != null && opt.sourceType.length > 0
|
|
? opt.sourceType
|
|
: ['album', 'camera'];
|
|
|
|
state.uploading = true;
|
|
state.errorMessage = '';
|
|
|
|
return new Promise<boolean>((resolve) => {
|
|
const chooseFn = opt.chooseImageFn != null
|
|
? opt.chooseImageFn
|
|
: (typeof uni !== 'undefined' && typeof uni.chooseImage === 'function' ? uni.chooseImage : null);
|
|
|
|
if (!chooseFn) {
|
|
state.uploading = false;
|
|
state.errorMessage = 'chooseImage 不可用';
|
|
resolve(false);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
chooseFn({
|
|
count: selectCount,
|
|
sourceType: sourceTypes,
|
|
success: (res: ChooseImageCallbackRes) => {
|
|
if (res.tempFilePaths != null && res.tempFilePaths.length > 0) {
|
|
addImageUrls(state, res.tempFilePaths, maxCount);
|
|
state.uploading = false;
|
|
resolve(true);
|
|
} else {
|
|
state.uploading = false;
|
|
resolve(false);
|
|
}
|
|
},
|
|
fail: (err: unknown) => {
|
|
state.uploading = false;
|
|
let msg = '取消选择图片';
|
|
if (err instanceof Error) {
|
|
msg = err.message;
|
|
}
|
|
state.errorMessage = msg;
|
|
resolve(false);
|
|
},
|
|
});
|
|
} catch (e) {
|
|
state.uploading = false;
|
|
state.errorMessage = e instanceof Error ? e.message : '选择异常';
|
|
resolve(false);
|
|
}
|
|
});
|
|
}
|