|
|
@@ -1,12 +1,13 @@
|
|
|
|
|
|
import UIButton from "@/components/ui/UIButton";
|
|
|
import { Colors } from "@/constants/theme";
|
|
|
-import { ActivityIndicator, Icon, Modal, Toast } from "@ant-design/react-native";
|
|
|
+import { ActionSheet, ActivityIndicator, Icon, Modal, Toast } from "@ant-design/react-native";
|
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
|
import { Platform, Pressable, Text, View } from "react-native";
|
|
|
|
|
|
import api from "@/utils/api";
|
|
|
import { openSystemSettings } from "@/utils/os";
|
|
|
+import clsx from "clsx";
|
|
|
import { DocumentPickerAsset, getDocumentAsync } from 'expo-document-picker';
|
|
|
import { File } from 'expo-file-system';
|
|
|
import { ImagePickerAsset, launchCameraAsync, launchImageLibraryAsync, requestCameraPermissionsAsync, requestMediaLibraryPermissionsAsync } from 'expo-image-picker';
|
|
|
@@ -14,7 +15,123 @@ import { Link } from "expo-router";
|
|
|
import { useCallback, useEffect, useState } from "react";
|
|
|
|
|
|
|
|
|
-export default function UploadScreen({ visible, onClose }: { visible: boolean, onClose: () => void }) {
|
|
|
+
|
|
|
+const takePhoto = async (upload: (assets: ImagePickerAsset[] | DocumentPickerAsset[]) => void) => {
|
|
|
+ const permission = await requestCameraPermissionsAsync();
|
|
|
+
|
|
|
+ if (!permission.granted) {
|
|
|
+ Modal.alert("请允许相册权限", "如果点击“确认“按钮后没有跳转,请自己前往系统设置开启相关权限", [
|
|
|
+ {
|
|
|
+ text: "确认",
|
|
|
+ onPress: openSystemSettings,
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+ // 跳转到 ios/android 相关设置页面
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const l = Toast.loading('正在打开相机...');
|
|
|
+ try {
|
|
|
+ const result = await launchCameraAsync({
|
|
|
+ allowsEditing: false, // 是否允许裁剪
|
|
|
+ quality: 0.9, // 照片质量
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!result.canceled) {
|
|
|
+ upload(result.assets);
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.warn(err);
|
|
|
+ Toast.fail('打开相机失败,请重试');
|
|
|
+ }
|
|
|
+ finally {
|
|
|
+ Toast.remove(l);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const picImg = async (upload: (assets: ImagePickerAsset[] | DocumentPickerAsset[]) => void) => {
|
|
|
+ const permission = await requestMediaLibraryPermissionsAsync();
|
|
|
+
|
|
|
+ if (!permission.granted) {
|
|
|
+ Modal.alert("请允许相册权限", "如果点击“确认“按钮后没有跳转,请自己前往系统设置开启相关权限", [
|
|
|
+ {
|
|
|
+ text: "确认",
|
|
|
+ onPress: openSystemSettings,
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+ // 跳转到 ios/android 相关设置页面
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const l = Toast.loading('正在打开相册...');
|
|
|
+ try {
|
|
|
+ let result = await launchImageLibraryAsync({
|
|
|
+ mediaTypes: ['images'], // 只选图片
|
|
|
+ allowsEditing: false,
|
|
|
+ quality: .9, // 质量 0~1
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!result.canceled) {
|
|
|
+ upload(result.assets);
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.warn(err);
|
|
|
+ Toast.fail('打开相册失败,请重试');
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ Toast.remove(l);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const pickDoc = async (upload: (assets: ImagePickerAsset[] | DocumentPickerAsset[]) => void) => {
|
|
|
+ const l = Toast.loading('正在打开相册...');
|
|
|
+
|
|
|
+ try {
|
|
|
+ let result = await getDocumentAsync({
|
|
|
+ type: [
|
|
|
+ // PDF
|
|
|
+ 'application/pdf',
|
|
|
+
|
|
|
+ // Word 文档
|
|
|
+ 'application/msword',
|
|
|
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
+
|
|
|
+ // Excel 表格
|
|
|
+ 'application/vnd.ms-excel',
|
|
|
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
|
+
|
|
|
+ // WPS 文字 / WPS 表格
|
|
|
+ 'application/wps-office.doc',
|
|
|
+ 'application/wps-office.docx',
|
|
|
+ 'application/wps-office.xls',
|
|
|
+ 'application/wps-office.xlsx',
|
|
|
+ 'application/wps-office.et',
|
|
|
+ 'application/wps-office.wps',
|
|
|
+
|
|
|
+ // 纯文本
|
|
|
+ 'text/plain',
|
|
|
+
|
|
|
+ // HTML
|
|
|
+ 'text/html',
|
|
|
+
|
|
|
+ // 全部图片(jpg/png/gif/webp 等)
|
|
|
+ 'image/*'
|
|
|
+ ],
|
|
|
+ copyToCacheDirectory: true, // 复制到应用缓存目录
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!result.canceled) {
|
|
|
+ upload(result.assets);
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.warn(err);
|
|
|
+ Toast.fail('打开文件失败,请重试');
|
|
|
+ }
|
|
|
+ finally {
|
|
|
+ Toast.remove(l);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+export function UploadScreen({ visible, onClose }: { visible: boolean, onClose: () => void }) {
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
@@ -51,120 +168,6 @@ export default function UploadScreen({ visible, onClose }: { visible: boolean, o
|
|
|
}
|
|
|
}, []);
|
|
|
|
|
|
- const takePhoto = useCallback(async () => {
|
|
|
- const permission = await requestCameraPermissionsAsync();
|
|
|
-
|
|
|
- if (!permission.granted) {
|
|
|
- Modal.alert("请允许相册权限", "如果点击“确认“按钮后没有跳转,请自己前往系统设置开启相关权限", [
|
|
|
- {
|
|
|
- text: "确认",
|
|
|
- onPress: openSystemSettings,
|
|
|
- }
|
|
|
- ]);
|
|
|
- // 跳转到 ios/android 相关设置页面
|
|
|
- return;
|
|
|
- }
|
|
|
- const l = Toast.loading('正在打开相机...');
|
|
|
- try {
|
|
|
- const result = await launchCameraAsync({
|
|
|
- allowsEditing: false, // 是否允许裁剪
|
|
|
- quality: 0.9, // 照片质量
|
|
|
- });
|
|
|
-
|
|
|
- if (!result.canceled) {
|
|
|
- upload(result.assets);
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- console.warn(err);
|
|
|
- Toast.fail('打开相机失败,请重试');
|
|
|
- }
|
|
|
- finally {
|
|
|
- Toast.remove(l);
|
|
|
- }
|
|
|
- }, [upload]);
|
|
|
-
|
|
|
- const picImg = useCallback(async () => {
|
|
|
- const permission = await requestMediaLibraryPermissionsAsync();
|
|
|
-
|
|
|
- if (!permission.granted) {
|
|
|
- Modal.alert("请允许相册权限", "如果点击“确认“按钮后没有跳转,请自己前往系统设置开启相关权限", [
|
|
|
- {
|
|
|
- text: "确认",
|
|
|
- onPress: openSystemSettings,
|
|
|
- }
|
|
|
- ]);
|
|
|
- // 跳转到 ios/android 相关设置页面
|
|
|
- return;
|
|
|
- }
|
|
|
- const l = Toast.loading('正在打开相册...');
|
|
|
- try {
|
|
|
- let result = await launchImageLibraryAsync({
|
|
|
- mediaTypes: ['images'], // 只选图片
|
|
|
- allowsEditing: false,
|
|
|
- quality: .9, // 质量 0~1
|
|
|
- });
|
|
|
-
|
|
|
- if (!result.canceled) {
|
|
|
- upload(result.assets);
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- console.warn(err);
|
|
|
- Toast.fail('打开相册失败,请重试');
|
|
|
- } finally {
|
|
|
-
|
|
|
- Toast.remove(l);
|
|
|
- }
|
|
|
- }, [upload]);
|
|
|
-
|
|
|
- const pickDoc = useCallback(async () => {
|
|
|
- const l = Toast.loading('正在打开相册...');
|
|
|
-
|
|
|
- try {
|
|
|
- let result = await getDocumentAsync({
|
|
|
- type: [
|
|
|
- // PDF
|
|
|
- 'application/pdf',
|
|
|
-
|
|
|
- // Word 文档
|
|
|
- 'application/msword',
|
|
|
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
-
|
|
|
- // Excel 表格
|
|
|
- 'application/vnd.ms-excel',
|
|
|
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
|
-
|
|
|
- // WPS 文字 / WPS 表格
|
|
|
- 'application/wps-office.doc',
|
|
|
- 'application/wps-office.docx',
|
|
|
- 'application/wps-office.xls',
|
|
|
- 'application/wps-office.xlsx',
|
|
|
- 'application/wps-office.et',
|
|
|
- 'application/wps-office.wps',
|
|
|
-
|
|
|
- // 纯文本
|
|
|
- 'text/plain',
|
|
|
-
|
|
|
- // HTML
|
|
|
- 'text/html',
|
|
|
-
|
|
|
- // 全部图片(jpg/png/gif/webp 等)
|
|
|
- 'image/*'
|
|
|
- ],
|
|
|
- copyToCacheDirectory: true, // 复制到应用缓存目录
|
|
|
- });
|
|
|
-
|
|
|
- if (!result.canceled) {
|
|
|
- upload(result.assets);
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- console.warn(err);
|
|
|
- Toast.fail('打开文件失败,请重试');
|
|
|
- }
|
|
|
- finally {
|
|
|
- Toast.remove(l);
|
|
|
- }
|
|
|
- }, [upload]);
|
|
|
-
|
|
|
return (
|
|
|
<Modal visible={visible} transparent={true} animationType="slide">
|
|
|
<View className="flex-row items-center">
|
|
|
@@ -175,10 +178,10 @@ export default function UploadScreen({ visible, onClose }: { visible: boolean, o
|
|
|
<View className="w-72 h-auto px-6">
|
|
|
|
|
|
<Text className="mt-2 text-2xl">请选择征信上传方式</Text>
|
|
|
- <UIButton title="从本机文件" icon="folder" onPress={pickDoc} className="mt-8" />
|
|
|
- {Platform.OS === 'ios' && <UIButton title="从本地相册" icon="picture" onPress={picImg} className="mt-4" />}
|
|
|
+ <UIButton title="从本机文件" icon="folder" onPress={() => pickDoc(upload)} className="mt-8" />
|
|
|
+ {Platform.OS === 'ios' && <UIButton title="从手机相册" icon="picture" onPress={() => picImg(upload)} className="mt-4" />}
|
|
|
|
|
|
- <UIButton title="拍照上传" icon="camera" onPress={takePhoto} className="mt-4" />
|
|
|
+ <UIButton title="拍照上传" icon="camera" onPress={() => takePhoto(upload)} className="mt-4" />
|
|
|
</View>)}
|
|
|
{
|
|
|
state === 1 && (
|
|
|
@@ -204,10 +207,106 @@ export default function UploadScreen({ visible, onClose }: { visible: boolean, o
|
|
|
)
|
|
|
}
|
|
|
<View className="h-8" />
|
|
|
- <Pressable hitSlop={8} className="absolute top-0 right-4" onPress={() => { onClose(); }}>
|
|
|
+ {state != 1 && <Pressable hitSlop={8} className="absolute top-0 right-4" onPress={() => { onClose(); }}>
|
|
|
<Icon name="close" size={32} />
|
|
|
- </Pressable>
|
|
|
+ </Pressable>}
|
|
|
</Modal >
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+export function UploadComponent({ onCompolete }: { onCompolete: () => void }) {
|
|
|
+
|
|
|
+
|
|
|
+ const [state, setState] = useState(0);
|
|
|
+
|
|
|
+ const upload = useCallback(async (assets: ImagePickerAsset[] | DocumentPickerAsset[]) => {
|
|
|
+ setState(1);
|
|
|
+ let att: { url: string, fullurl: string, attid: any } = null!;
|
|
|
+ try {
|
|
|
+ const file = new File(assets[0].uri);
|
|
|
+ // file.type = item.mimeType || 'application/octet-stream';
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('file', file);
|
|
|
+ att = await api.uploadFile<{ url: string, fullurl: string, attid: any }>('common/upload', { body: formData });
|
|
|
+
|
|
|
+ } catch (err) {
|
|
|
+ setState(0);
|
|
|
+ console.warn(err);
|
|
|
+ Toast.fail('上传失败,请重试');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await api.post('/credit/create', {
|
|
|
+ att: JSON.stringify(att),
|
|
|
+ });
|
|
|
+ setState(2);
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
+ } catch (err) {
|
|
|
+ setState(0);
|
|
|
+ Toast.fail('添加分析到队列失败,请重试');
|
|
|
+ }
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const onSelect = useCallback((index: number) => {
|
|
|
+ if (Platform.OS == 'android' && index == 2) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (Platform.OS == 'ios' && index == 3) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (index == 0) {
|
|
|
+ pickDoc(upload);
|
|
|
+ }
|
|
|
+ if (index == 1) {
|
|
|
+ if (Platform.OS == 'ios') {
|
|
|
+ picImg(upload);
|
|
|
+ } else {
|
|
|
+ takePhoto(upload);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (index == 2) {
|
|
|
+ takePhoto(upload);
|
|
|
+ }
|
|
|
+
|
|
|
+ }, []);
|
|
|
+ const selectFile = useCallback(() => {
|
|
|
+ ActionSheet.showActionSheetWithOptions({
|
|
|
+ title: "请选择征信上传方式",
|
|
|
+ cancelButtonIndex: 3,
|
|
|
+ options: Platform.OS == 'ios' ? ['从本机文件', '从手机相册', '拍照上传', '取消'] : ['从本机文件', '拍照上传', '取消']
|
|
|
+ }, onSelect);
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <View className="mb-3 rounded-2xl border border-outline-variant bg-surface-container-lowest p-4">
|
|
|
+ <Text className="mb-3 text-xs font-bold uppercase tracking-widest text-outline">
|
|
|
+ 上传征信文件
|
|
|
+ </Text>
|
|
|
+ <Pressable
|
|
|
+ onPress={selectFile}
|
|
|
+ disabled={state == 1}
|
|
|
+ className="items-center rounded-2xl border-2 border-dashed border-outline-variant/40 bg-surface-container-low/50 px-6 py-8 disabled:opacity-50"
|
|
|
+
|
|
|
+ >
|
|
|
+ <View className="mb-3 h-14 w-14 items-center justify-center rounded-full bg-primary-fixed">
|
|
|
+ <Ionicons name="cloud-upload-outline" size={30} color="#004ac6" />
|
|
|
+ </View>
|
|
|
+ <Text className="mb-1 text-base font-bold text-on-surface">{state == 1 ? '正在上传文档' : '点击上传征信报告'}</Text>
|
|
|
+ <Text className={clsx("text-sm leading-6 text-on-surface-variant", {
|
|
|
+ 'opacity-50': state == 1
|
|
|
+ })}>
|
|
|
+ 支持 PDF、图片格式,最大 20MB
|
|
|
+ </Text>
|
|
|
+ </Pressable>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <UIButton loading={state === 1} disabled={state === 1} type="primary">开始分析</UIButton>
|
|
|
+ </>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|