feat(mobile): track mobile app scaffold

This commit is contained in:
caoxiaozhu
2026-05-22 12:41:45 +08:00
parent 222ba0bfdc
commit 1f15699013
79 changed files with 16854 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
import * as ImagePicker from 'expo-image-picker';
export type CapturedReceipt = {
uri: string;
fileName: string;
mimeType?: string;
source: 'camera' | 'library';
};
function toReceipt(asset: ImagePicker.ImagePickerAsset, source: CapturedReceipt['source']): CapturedReceipt {
return {
uri: asset.uri,
fileName: asset.fileName || `receipt-${Date.now()}.jpg`,
mimeType: asset.mimeType,
source,
};
}
export async function captureReceiptFromCamera(): Promise<CapturedReceipt | null> {
const permission = await ImagePicker.requestCameraPermissionsAsync();
if (!permission.granted) {
throw new Error('需要相机权限才能拍摄票据。');
}
const result = await ImagePicker.launchCameraAsync({
allowsEditing: false,
quality: 0.84,
mediaTypes: ['images'],
});
if (result.canceled || !result.assets[0]) {
return null;
}
return toReceipt(result.assets[0], 'camera');
}
export async function pickReceiptFromLibrary(): Promise<CapturedReceipt | null> {
const permission = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (!permission.granted) {
throw new Error('需要相册权限才能选择票据图片。');
}
const result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: false,
quality: 0.88,
mediaTypes: ['images'],
});
if (result.canceled || !result.assets[0]) {
return null;
}
return toReceipt(result.assets[0], 'library');
}