test(KYC页): 测试图片上传方式

This commit is contained in:
hzj 2025-11-12 16:46:32 +08:00
parent c5fa3992a3
commit c865a8783a
2 changed files with 202 additions and 21 deletions

121
src/utils/uploadFiles.js Normal file
View File

@ -0,0 +1,121 @@
/**
* 上传图片
* @param {Function} renderFun 回调函数接收APP传递的access参数
*/
export function uploadImgFile(renderFun) {
window.renderData = renderFun
// 兼容历史版本
window.getIosAccessOriginParam = renderFun
try {
if (android()) {
console.debug('Flutter Android WebView 检测')
console.debug('window.app 对象:', window.app)
// 检查Flutter注入的接口
if (window.app) {
console.debug('window.app 的所有方法:')
console.debug(Object.keys(window.app))
// 检查具体的方法
console.debug('uploadImgFile 方法存在?', typeof window.app.uploadImgFile)
console.debug('uploadImgFile 是函数?', typeof window.app.uploadImgFile === 'function')
}
// 等待Flutter注入完成
const waitForFlutterInterface = () => {
let attempts = 0
const maxAttempts = 50 // 最多等待5秒
// 循环检测Flutter接口
const checkInterface = () => {
attempts++
console.debug(`尝试第 ${attempts} 次检查Flutter接口...`)
if (
window.app &&
window.app.uploadImgFile &&
typeof window.app.uploadImgFile === 'function'
) {
console.debug('Flutter接口检测成功调用 uploadImgFile')
try {
const result = window.app.uploadImgFile()
console.debug('uploadImgFile 返回结果:', result)
renderFun(result)
} catch (error) {
console.error('调用 uploadImgFile 出错:', error)
}
} else if (attempts < maxAttempts) {
// 继续等待
setTimeout(checkInterface, 100)
} else {
console.error('Flutter接口注入超时使用默认数据')
// 使用默认的开发数据
const mockAccess = JSON.stringify('')
renderFun(mockAccess)
}
}
checkInterface()
}
// 如果window.app已存在直接检查否则等待
if (window.app) {
waitForFlutterInterface()
} else {
console.debug('等待Flutter注入window.app...')
// 监听window.app的创建
let checkCount = 0
const checkApp = () => {
checkCount++
if (window.app) {
console.debug('检测到window.app开始连接')
waitForFlutterInterface()
} else if (checkCount < 50) {
setTimeout(checkApp, 100)
} else {
console.error('等待window.app超时')
// 手动通知Flutter注入接口
if (window.FlutterApp && window.FlutterApp.postMessage) {
window.FlutterApp.postMessage('uploadImgFile')
}
}
}
checkApp()
}
} else {
console.debug('非移动设备环境')
// 非APP环境可能是浏览器调试
console.warn('Not in APP environment, using mock data for development')
// 开发环境可以提供模拟数据
if (process.env.NODE_ENV === 'development') {
const mockAccess = ''
setTimeout(() => renderFun(mockAccess), 100)
}
}
} catch (error) {
console.error('Failed to connect to APP:', error)
}
}
/**
* 解析APP传递的访问参数
* @param {string} access JSON字符串格式的访问参数
* @returns {Object} 解析后的参数对象
*/
export function parseAccessOrigin(access) {
try {
const accessParam = JSON.parse(access)
return {
success: true,
data: accessParam,
}
} catch (error) {
console.error('Failed to parse access origin:', error)
return {
success: false,
error: 'accessOrigin Error.',
data: null,
}
}
}

View File

@ -61,7 +61,22 @@
alt=""
style="display: block; width: 15vw; aspect-ratio: 1/1; object-fit: cover"
/>
<button
v-if="isInAppEnvironment"
@click="callNativeImagePicker"
style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
border: none;
"
></button>
<input
v-else
type="file"
accept="image/*"
@click="onFileInputClick"
@ -78,25 +93,6 @@
/>
</div>
<!-- 可见的备用文件选择按钮 -->
<label
style="
display: inline-flex;
align-items: center;
padding: 8px 16px;
background: linear-gradient(135deg, #8b45ff, #bb92ff);
color: white;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
"
>
<span>📁</span>
<span style="margin-left: 8px">{{ t('select_image') }}</span>
<input type="file" accept="image/*" @change="handleFileChange" style="display: none" />
</label>
<img
src="/src/assets/icon/direction.png"
alt=""
@ -195,6 +191,7 @@
</template>
<script setup>
import { isInApp } from '@/utils/appBridge.js'
import { useI18n } from 'vue-i18n'
import GeneralHeader from '@/components/GeneralHeader.vue'
import { ref, onMounted, computed } from 'vue'
@ -203,6 +200,7 @@ import { useRouter } from 'vue-router'
import { uploadImg } from '@/api/upload.js'
import { setDocumentDirection } from '@/locales/i18n'
import { getWithdrawInfoList, addWithdrawInfo, updateWithdrawInfo } from '@/api/wallet'
import { uploadImgFile, parseAccessOrigin } from '@/utils/uploadFiles.js'
const { t, locale } = useI18n()
const router = useRouter()
@ -217,6 +215,7 @@ const previewUrls = ref([]) //预览图片数组
const resImgUrls = ref([]) //
const updateStatus = ref(false) //
const isInAppEnvironment = ref(false)
const applyInfo = ref({
id: '', //ID
@ -232,10 +231,70 @@ const checkStatus = computed(() => {
return applyInfo.value.contactNumber != '' && previewUrls.value.length > 0
})
//
const callNativeImagePicker = () => {
console.log('调用原生图片选择器')
// 3
if (previewUrls.value.length >= 3) {
showWarning(t('max_images_warning'))
return Promise.resolve() // rejected Promise
}
return new Promise((resolve, reject) => {
try {
uploadImgFile((access) => {
try {
//
if (!access || access === '""' || access === '') {
console.warn('接收到空的图片数据')
showWarning(t('no_image_selected'))
reject(new Error('No image selected'))
return
}
const result = parseAccessOrigin(access)
if (result.success && result.data) {
const file = result.data
console.log('接收到原生图片数据:', file)
//
if (typeof file === 'string' && (file.startsWith('http') || file.startsWith('data:'))) {
// URLbase64
previewUrls.value.push(file)
tempFiles.value.push(file) //
} else {
//
previewUrls.value.push(file)
tempFiles.value.push(file)
}
showSuccess(t('image_selected_success'))
resolve()
} else {
const errorMsg = result.error || t('file_selection_failed')
console.error('图片选择失败:', errorMsg)
showError(errorMsg)
reject(new Error(errorMsg))
}
} catch (error) {
console.error('处理原生图片选择结果失败:', error)
showError(t('file_processing_failed'))
reject(error)
}
})
} catch (error) {
console.error('调用原生图片选择器失败:', error)
showError(t('native_image_picker_failed'))
reject(error)
}
})
}
//
const onFileInputClick = (event) => {
const onFileInputClick = () => {
console.log('=== 点击文件选择按钮 ===')
showInfo('Please select a file')
}
// ()
@ -383,6 +442,7 @@ const updateWithdrawInfoData = async () => {
}
onMounted(() => {
isInAppEnvironment.value = isInApp()
getWithdrawInfoListData() //
})
</script>