需求: 某知名化妆品牌,要做个在线问卷调查。需要试用着自拍上传
注:使用navigator.mediaDevices.getUserMedia 需要使用https请求协议否者视为不安全,无法访问,开发阶段需要将启动改为https 在package.json中
前端开发环境启动项目将http协议改为https协议
授权,默认前置,切换后置
注意切换摄像头时要注意,一定要像关闭摄像头不然会有问题在部分手机上
import {
Button,
Dialog,
ImageUploader,
Modal,
Popup,
Toast,
} from 'antd-mobile';
import React, { useEffect, useState } from 'react';
import { useRef } from 'react';
import { history } from 'umi';
import {
uploadFile,
getProjectInfo,
saveUploadFile,
deleteFile,
getQuestionsByResultId,
} from '@/app/request/requestApi'; // 接口
import { ImageUploadItem } from 'antd-mobile/es/components/image-uploader';
import { CameraOutline, ExclamationCircleFill } from 'antd-mobile-icons';
import './style.less';
const index = (props: any) => {
const [fileList, setFileList] = useState([]);
const [projectInfo, setProjectInfo] = useState({});
const [visible, setVisible] = useState(false);
const [rotvisible, setRotVisible] = useState(false);
const [direction, setDirection] = useState(0);
const [language, setLanguage] = useState('ZH');
useEffect(() => {
setLanguage(localStorage.getItem('language') ?? 'ZH');
}, []);
useEffect(() => {
setTimeout(() => {
document.getElementsByTagName('title')[0].text = '上传图片';
}, 500);
getProjectInfo().then((res) => {
if (res.success) {
localStorage.setItem('projectInfo', JSON.stringify(res.data));
setProjectInfo(res.data);
} else {
Dialog.alert({
content: res.msg,
onConfirm: () => {
history.push('../');
},
});
}
});
}, []);
useEffect(() => {
if (!visible) {
// 关闭
if (document.getElementById('video')?.srcObject) {
document.getElementById('video').srcObject.getTracks()[0].stop();
}
return;
}
if (
//@ts-ignore
// 开启
navigator.mediaDevices.getUserMedia ||
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
navigator.oGetUserMedia
) {
var facingMode: any = null;
if (direction == 1) {
facingMode = { exact: 'environment' };
} else {
facingMode = { exact: 'user' };
}
// 切换摄像头需先关闭再打开
if (document.getElementById('video')?.srcObject) {
document.getElementById('video').srcObject.getTracks()[0].stop();
}
//调用用户媒体设备, 访问摄像头
getUserMedia(
{ video: { width: 480, height: 320, facingMode: facingMode } }, // user 前置
success,
error,
);
} else {
alert('不支持访问用户媒体');
}
}, [visible, direction]);
let model: any = localStorage.getItem('model');
const onUpload = async (file: any) => {
let formData = new FormData();
formData.append('projectId', projectInfo.projectId);
formData.append('projectTimeId', projectInfo.timeId);
formData.append('phone', model);
formData.append('fileInfos', file);
var res = await uploadFile(formData);
if (res.success) {
return {
url: res.data[0].imageUrl,
} as ImageUploadItem;
} else {
Dialog.alert({
content: res.msg,
onConfirm: () => {
//history.push("../");
},
});
return {
url: URL.createObjectURL(file),
} as ImageUploadItem;
}
};
const getUserMedia = (constraints: any, success: any, error: any) => {
if (navigator.mediaDevices.getUserMedia) {
//最新的标准API
navigator.mediaDevices
.getUserMedia(constraints)
.then(success)
.catch(error);
} else if (navigator.webkitGetUserMedia) {
//webkit核心浏览器
navigator.webkitGetUserMedia(constraints, success, error);
} else if (navigator.mozGetUserMedia) {
//firfox浏览器
navigator.mozGetUserMedia(constraints, success, error);
} else if (navigator.getUserMedia) {
//旧版API
navigator.getUserMedia(constraints, success, error);
}
};
const success = (stream: any) => {
//兼容webkit核心浏览器
let CompatibleURL = window.URL || window.webkitURL;
//将视频流设置为video元素的源
let videoElement = document.getElementById('video');
//@ts-ignore
videoElement.srcObject = stream;
//@ts-ignore
videoElement.play();
};
const error = (error: any) => {
alert(`访问用户媒体设备失败${error.name}, ${error.message}`);
console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
};
return (
<>
{projectInfo.projectName}
{
console.log(item);
return Dialog.confirm({
content: '是否确认删除',
}).then((res) => {
if (!res) {
return false;
} else {
return deleteFile({
id: item.id,
}).then((res) => {
if (res.success) {
return true;
} else {
Dialog.alert({
content: res.msg,
onConfirm: () => {
//history.push('../');
},
});
return false;
}
});
}
});
}}
onChange={(files) => {
setFileList(files);
}}
disableUpload={true}
upload={onUpload}
children={
{
Dialog.alert({
content:
language == 'ZH'
? '请摘掉眼镜,露出额头和耳朵,在光线明亮的地方,原地旋转每30度左右拍一张,共6张'
: 'Please take off your glasses, expose your forehead and ears, and take a picture every 60 degrees or so in a bright place. A total of 6 pictures',
onConfirm: () => {
setVisible(true);
},
});
}}
style={{ fontSize: 32 }}
/>
}
/>
{language == 'ZH'
? '上传图片需最少六张图片才可进入下一步'
: 'A minimum of six images are required to upload images to proceed to the next step'}
{
setVisible(false);
}}
forceRender={true}
position="top"
bodyStyle={{
minWidth: '100%',
minHeight: '100%',
backgroundColor: 'black',
}}
>
// 切换摄像头
{
setDirection(direction == 1 ? 0 : 1);
console.log('切换摄像头');
}}
style={{ fontSize: '30px', lineHeight: '60px', color: 'white' }}
/>
// video 视频
// 拍照截取当前帧绘制到画布上
// 主要是获取摄像头的视频流并显示在Video 签中
{
var canvas = document.getElementById('canvas');
canvas.width = document.getElementById('video')?.offsetWidth;
canvas.height = document.getElementById('video')?.offsetHeight;
//@ts-ignore
canvas
?.getContext('2d')
?.drawImage(
document.getElementById('video'),
0,
0,
document.getElementById('video')?.offsetWidth,
document.getElementById('video')?.offsetHeight,
);
canvas.getContext('2d')?.canvas.toBlob(
(blob: any) => {
let files = new window.File(
[blob],
new Date().getTime() + '.jpg',
);
let formData = new FormData();
formData.append('projectId', projectInfo.projectId);
formData.append('projectTimeId', projectInfo.timeId);
formData.append(
'phone',
model,
// navigator.userAgent.split('AppleWebKit')[0],
);
formData.append('fileInfos', files);
setVisible(false);
uploadFile(formData).then((res) => {
if (res.success) {
setFileList([
...fileList,
{
key: new Date().getTime(),
url: URL.createObjectURL(files),
id: res.data[0].id,
},
]);
} else {
Dialog.alert({
content: res.msg,
onConfirm: () => {},
});
}
});
},
'image/jpeg',
0.7,
);
//@ts-ignore
var cutAvater = canvas.getContext('2d')?.canvas.toDataURL(0.7);
var arr = cutAvater?.split(',');
//@ts-ignore
var data = window.atob(arr[1]);
//@ts-ignore
var mime = arr[0].match(/:(.*?);/)[1];
var ia = new Uint8Array(data.length);
for (var i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i);
}
var blob = new Blob([ia], { type: 'image/jpeg' });
}}
className="camerBtn"
/>
>
);
};
export default index;
main {
padding: 24px 24px 16px;
display: flex;
}
video {
margin-right: 16px;
box-sizing: content-box;
//border: 4px solid #ffaabb;
}
canvas {
box-sizing: content-box;
border: 4px solid #aabbff;
}
.actions {
padding: 0 24px;
}
.actions button {
margin-right: 16px;
}
.imgSuccess {
width: 142px;
height: 119px;
background: url('../../../assets/images/success.png') no-repeat;
background-size: 100%;
border: 1px dashed gray;
}
.projectTitle {
display: block;
font-size: 26px;
color: #b18b35;
font-weight: bold;
font-family: 'MicrosoftYaHei-Bold';
margin: 20px 0 21px 20px;
}
.adm-image-uploader .adm-space-item {
width: 100px;
height: 100px;
border: 1px dashed black;
padding-bottom: 0px !important;
margin-top: 10px;
}
.adm-image-uploader {
margin-bottom: 40px;
}
.adm-image-uploader {
margin-left: 20px;
}
.adm-text-area-element {
background-color: #ffffff !important;
}
.btnNext {
color: white;
font-size: 12px;
font-weight: bold;
background-color: #b18b34;
border: none;
width: 236px;
height: 39px;
border-radius: 18px;
}
.adm-image-img {
// width: auto;
// height: 100%;
// margin:0 auto;
}
.camerBtn {
font-size: 60px;
color: white;
}
.divBtn {
position: absolute;
bottom: 0px;
width: 100%;
height: 80px;
text-align: center;
}