|
|
@@ -109,147 +109,131 @@ const uploading = ref(false)
|
|
|
const uploaderRef = ref(null)
|
|
|
|
|
|
// 打开相机
|
|
|
-const openCamera = async () => {
|
|
|
+const openCamera = () => {
|
|
|
+ // 检查是否在App环境中
|
|
|
+ if (window.android && window.android.openCamera) {
|
|
|
+ // 调用App原生相机
|
|
|
+ window.android.openCamera()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否在iOS环境中
|
|
|
+ if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.openCamera) {
|
|
|
+ // 调用iOS原生相机
|
|
|
+ window.webkit.messageHandlers.openCamera.postMessage({})
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 移动端浏览器:使用兼容性最好的方法
|
|
|
+ if (/Android|iPhone|iPad|iPod/i.test(navigator.userAgent)) {
|
|
|
+ // 移动设备:使用input file的capture属性
|
|
|
+ const input = document.createElement('input')
|
|
|
+ input.type = 'file'
|
|
|
+ input.accept = 'image/*'
|
|
|
+ input.capture = 'camera' // 强制使用相机
|
|
|
+
|
|
|
+ input.onchange = (e) => {
|
|
|
+ const file = e.target.files[0]
|
|
|
+ if (file) {
|
|
|
+ handleCameraPhoto(file)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 触发点击
|
|
|
+ input.click()
|
|
|
+ } else {
|
|
|
+ // PC端:使用getUserMedia
|
|
|
+ openCameraForPC()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// PC端打开相机
|
|
|
+const openCameraForPC = async () => {
|
|
|
try {
|
|
|
- // 检查浏览器是否支持getUserMedia
|
|
|
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
|
showFailToast('您的浏览器不支持相机功能')
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- // 请求相机权限
|
|
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
|
- video: {
|
|
|
- facingMode: 'environment' // 使用后置摄像头
|
|
|
- }
|
|
|
+ video: { facingMode: 'environment' }
|
|
|
})
|
|
|
-
|
|
|
- // 创建相机预览界面
|
|
|
showCameraPreview(stream)
|
|
|
} catch (error) {
|
|
|
console.error('打开相机失败:', error)
|
|
|
- if (error.name === 'NotAllowedError') {
|
|
|
- showFailToast('相机权限被拒绝,请在浏览器设置中允许相机访问')
|
|
|
- } else if (error.name === 'NotFoundError') {
|
|
|
- showFailToast('未找到可用的相机设备')
|
|
|
- } else {
|
|
|
- showFailToast('打开相机失败: ' + error.message)
|
|
|
- }
|
|
|
+ showFailToast('打开相机失败,请检查权限设置')
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 显示相机预览界面
|
|
|
+// 显示相机预览界面(仅PC端使用)
|
|
|
const showCameraPreview = (stream) => {
|
|
|
- // 创建预览弹窗
|
|
|
const previewDiv = document.createElement('div')
|
|
|
previewDiv.style.cssText = `
|
|
|
- position: fixed;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- background: black;
|
|
|
- z-index: 9999;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
|
|
+ background: black; z-index: 9999; display: flex; flex-direction: column;
|
|
|
+ align-items: center; justify-content: center;
|
|
|
`
|
|
|
|
|
|
- // 创建视频元素
|
|
|
const video = document.createElement('video')
|
|
|
- video.style.cssText = `
|
|
|
- width: 100%;
|
|
|
- height: 80%;
|
|
|
- object-fit: cover;
|
|
|
- `
|
|
|
+ video.style.cssText = `width: 100%; height: 80%; object-fit: cover;`
|
|
|
video.srcObject = stream
|
|
|
video.autoplay = true
|
|
|
video.playsInline = true
|
|
|
|
|
|
- // 创建拍照按钮
|
|
|
const captureBtn = document.createElement('button')
|
|
|
captureBtn.style.cssText = `
|
|
|
- width: 80px;
|
|
|
- height: 80px;
|
|
|
- border-radius: 50%;
|
|
|
- background: #fff;
|
|
|
- border: 4px solid #1989fa;
|
|
|
- margin-top: 20px;
|
|
|
- cursor: pointer;
|
|
|
- font-size: 16px;
|
|
|
- color: #1989fa;
|
|
|
+ width: 80px; height: 80px; border-radius: 50%; background: #fff;
|
|
|
+ border: 4px solid #1989fa; margin-top: 20px; cursor: pointer;
|
|
|
+ font-size: 16px; color: #1989fa;
|
|
|
`
|
|
|
captureBtn.textContent = '拍照'
|
|
|
|
|
|
- // 创建关闭按钮
|
|
|
const closeBtn = document.createElement('button')
|
|
|
closeBtn.style.cssText = `
|
|
|
- position: absolute;
|
|
|
- top: 20px;
|
|
|
- right: 20px;
|
|
|
- background: rgba(255,255,255,0.3);
|
|
|
- border: none;
|
|
|
- color: white;
|
|
|
- font-size: 24px;
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- border-radius: 50%;
|
|
|
- cursor: pointer;
|
|
|
+ position: absolute; top: 20px; right: 20px; background: rgba(255,255,255,0.3);
|
|
|
+ border: none; color: white; font-size: 24px; width: 40px; height: 40px;
|
|
|
+ border-radius: 50%; cursor: pointer;
|
|
|
`
|
|
|
closeBtn.textContent = '×'
|
|
|
|
|
|
- // 拍照功能
|
|
|
captureBtn.onclick = () => {
|
|
|
- // 创建canvas来捕获照片
|
|
|
const canvas = document.createElement('canvas')
|
|
|
const context = canvas.getContext('2d')
|
|
|
canvas.width = video.videoWidth
|
|
|
canvas.height = video.videoHeight
|
|
|
context.drawImage(video, 0, 0)
|
|
|
|
|
|
- // 将canvas转换为blob
|
|
|
canvas.toBlob(async (blob) => {
|
|
|
- // 停止相机流
|
|
|
stream.getTracks().forEach(track => track.stop())
|
|
|
-
|
|
|
- // 移除预览界面
|
|
|
document.body.removeChild(previewDiv)
|
|
|
-
|
|
|
- // 创建文件对象
|
|
|
const file = new File([blob], 'camera-photo.jpg', { type: 'image/jpeg' })
|
|
|
-
|
|
|
- // 创建文件项
|
|
|
- const fileItem = {
|
|
|
- file: file,
|
|
|
- content: URL.createObjectURL(blob),
|
|
|
- status: 'uploading'
|
|
|
- }
|
|
|
- uploadImages.value = [fileItem]
|
|
|
-
|
|
|
- // 触发图片处理
|
|
|
- await afterReadImage(fileItem)
|
|
|
+ handleCameraPhoto(file)
|
|
|
}, 'image/jpeg', 0.9)
|
|
|
}
|
|
|
|
|
|
- // 关闭功能
|
|
|
closeBtn.onclick = () => {
|
|
|
- // 停止相机流
|
|
|
stream.getTracks().forEach(track => track.stop())
|
|
|
- // 移除预览界面
|
|
|
document.body.removeChild(previewDiv)
|
|
|
}
|
|
|
|
|
|
- // 添加到界面
|
|
|
previewDiv.appendChild(video)
|
|
|
previewDiv.appendChild(captureBtn)
|
|
|
previewDiv.appendChild(closeBtn)
|
|
|
document.body.appendChild(previewDiv)
|
|
|
-
|
|
|
- // 播放视频
|
|
|
video.play()
|
|
|
}
|
|
|
|
|
|
+// 处理相机拍摄的照片
|
|
|
+const handleCameraPhoto = async (file) => {
|
|
|
+ const fileItem = {
|
|
|
+ file: file,
|
|
|
+ content: URL.createObjectURL(file),
|
|
|
+ status: 'uploading'
|
|
|
+ }
|
|
|
+ uploadImages.value = [fileItem]
|
|
|
+ await afterReadImage(fileItem)
|
|
|
+}
|
|
|
+
|
|
|
// 移除图片
|
|
|
const removeImage = () => {
|
|
|
uploadImages.value = []
|