Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit43c7fa3

Browse files
committed
#1720 add dragger image capture modal + custom dragger styling
1 parent5db3f5a commit43c7fa3

File tree

3 files changed

+344
-221
lines changed

3 files changed

+344
-221
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
importReact,{Suspense,useCallback,useEffect,useRef,useState}from"react";
2+
import{defaultasButton}from"antd/es/button";
3+
importDropdownfrom"antd/es/dropdown";
4+
importtype{ItemType}from"antd/es/menu/interface";
5+
importSkeletonfrom"antd/es/skeleton";
6+
importMenufrom"antd/es/menu";
7+
importFlexfrom"antd/es/flex";
8+
importstyledfrom"styled-components";
9+
import{trans}from"i18n";
10+
import{CustomModal}from"lowcoder-design";
11+
12+
constCustomModalStyled=styled(CustomModal)`
13+
top: 10vh;
14+
.react-draggable {
15+
max-width: 100%;
16+
width: 500px;
17+
18+
video {
19+
width: 100%;
20+
}
21+
}
22+
`;
23+
24+
constError=styled.div`
25+
color: #f5222d;
26+
height: 100px;
27+
width: 100%;
28+
display: flex;
29+
align-items: center;
30+
justify-content: center;
31+
`;
32+
33+
constWrapper=styled.div`
34+
img,
35+
video,
36+
.ant-skeleton {
37+
width: 100%;
38+
height: 400px;
39+
max-height: 70vh;
40+
position: relative;
41+
object-fit: cover;
42+
background-color: #000;
43+
}
44+
.ant-skeleton {
45+
h3,
46+
li {
47+
background-color: transparent;
48+
}
49+
}
50+
`;
51+
52+
constReactWebcam=React.lazy(()=>import("react-webcam"));
53+
54+
exportconstImageCaptureModal=(props:{
55+
showModal:boolean;
56+
onModalClose:()=>void;
57+
onImageCapture:(image:string)=>void;
58+
})=>{
59+
const[errMessage,setErrMessage]=useState("");
60+
const[videoConstraints,setVideoConstraints]=useState<MediaTrackConstraints>({
61+
facingMode:"environment",
62+
});
63+
const[modeList,setModeList]=useState<ItemType[]>([]);
64+
const[dropdownShow,setDropdownShow]=useState(false);
65+
const[imgSrc,setImgSrc]=useState<string>();
66+
constwebcamRef=useRef<any>(null);
67+
68+
useEffect(()=>{
69+
if(props.showModal){
70+
setImgSrc("");
71+
setErrMessage("");
72+
}
73+
},[props.showModal]);
74+
75+
consthandleMediaErr=(err:any)=>{
76+
if(typeoferr==="string"){
77+
setErrMessage(err);
78+
}else{
79+
if(err.message==="getUserMedia is not implemented in this browser"){
80+
setErrMessage(trans("scanner.errTip"));
81+
}else{
82+
setErrMessage(err.message);
83+
}
84+
}
85+
};
86+
87+
consthandleCapture=useCallback(()=>{
88+
constimageSrc=webcamRef.current?.getScreenshot?.();
89+
setImgSrc(imageSrc);
90+
},[webcamRef]);
91+
92+
constgetModeList=()=>{
93+
navigator.mediaDevices.enumerateDevices().then((data)=>{
94+
constvideoData=data.filter((item)=>item.kind==="videoinput");
95+
constfaceModeList=videoData.map((item,index)=>({
96+
label:item.label||trans("scanner.camera",{index:index+1}),
97+
key:item.deviceId,
98+
}));
99+
setModeList(faceModeList);
100+
});
101+
};
102+
103+
return(
104+
<CustomModalStyled
105+
showOkButton={false}
106+
showCancelButton={false}
107+
open={props.showModal}
108+
maskClosable={true}
109+
destroyOnHidden
110+
onCancel={props.onModalClose}
111+
>
112+
{!!errMessage ?(
113+
<Error>{errMessage}</Error>
114+
) :(
115+
props.showModal&&(
116+
<Wrapper>
117+
{imgSrc ?(
118+
<imgsrc={imgSrc}alt="webcam"/>
119+
) :(
120+
<Suspensefallback={<Skeleton/>}>
121+
<ReactWebcam
122+
ref={webcamRef}
123+
onUserMediaError={handleMediaErr}
124+
screenshotFormat="image/jpeg"
125+
/>
126+
</Suspense>
127+
)}
128+
{imgSrc ?(
129+
<Flexjustify="center"gap={10}>
130+
<Button
131+
type="primary"
132+
style={{float:"right",marginTop:"10px"}}
133+
onClick={(e)=>{
134+
e.stopPropagation();
135+
if(imgSrc)props.onImageCapture(imgSrc);
136+
}}
137+
>
138+
{trans("file.usePhoto")}
139+
</Button>
140+
<Button
141+
style={{float:"right",marginTop:"10px"}}
142+
onClick={(e)=>{
143+
e.stopPropagation();
144+
setImgSrc("");
145+
}}
146+
>
147+
{trans("file.retakePhoto")}
148+
</Button>
149+
</Flex>
150+
) :(
151+
<Flexjustify="center"gap={10}>
152+
<Button
153+
type="primary"
154+
style={{float:"right",marginTop:"10px"}}
155+
onClick={(e)=>{
156+
e.stopPropagation();
157+
handleCapture();
158+
}}
159+
>
160+
{trans("file.capture")}
161+
</Button>
162+
<Dropdown
163+
placement="bottomRight"
164+
trigger={["click"]}
165+
open={dropdownShow}
166+
onOpenChange={(value)=>setDropdownShow(value)}
167+
popupRender={()=>(
168+
<Menu
169+
items={modeList}
170+
onClick={(value)=>
171+
setVideoConstraints({ ...videoConstraints,deviceId:value.key})
172+
}
173+
/>
174+
)}
175+
>
176+
<Button
177+
style={{float:"right",marginTop:"10px"}}
178+
onClick={(e)=>{
179+
e.stopPropagation();
180+
getModeList();
181+
}}
182+
>
183+
{trans("scanner.changeCamera")}
184+
</Button>
185+
</Dropdown>
186+
</Flex>
187+
)}
188+
</Wrapper>
189+
)
190+
)}
191+
</CustomModalStyled>
192+
);
193+
};
194+
195+
exportdefaultImageCaptureModal;
196+
197+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp