243 lines
7.8 KiB
JavaScript
243 lines
7.8 KiB
JavaScript
"use client";
|
|
|
|
import React, { useEffect, useState } from "react";
|
|
import { DotLoading, Image, List, ImageViewer, Modal } from "antd-mobile";
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
import { faAdd, faClose, faPlay } from "@fortawesome/free-solid-svg-icons";
|
|
import { getVideoBase64 } from "@/utils/tools";
|
|
import { DragDropContext, Draggable, Droppable } from "@hello-pangea/dnd";
|
|
export default function UploadImgs({
|
|
assets,
|
|
getImgs,
|
|
accept = "image/png, image/jpeg, image/jpg",
|
|
existImages = [],
|
|
type = 1,
|
|
videoSrc = null,
|
|
getVideoCover,
|
|
}) {
|
|
const maxCount = 6;
|
|
const [loading, setLoading] = useState(false);
|
|
const [filesUrls, setFilesUrls] = useState([]);
|
|
const [videoUrl, setVideoUrl] = useState(null);
|
|
const [frameImage, setFrameImage] = useState({ src: null, h: 0, w: 0 });
|
|
useEffect(() => {
|
|
if (existImages.length > 0) {
|
|
setFilesUrls(
|
|
existImages.map((it, index) => ({ url: it.url, id: `${index}` }))
|
|
);
|
|
}
|
|
if (videoSrc) {
|
|
setVideoUrl(videoSrc);
|
|
}
|
|
}, [existImages]);
|
|
useEffect(() => {
|
|
getVideoCover && getVideoCover(frameImage);
|
|
}, [frameImage]);
|
|
|
|
const handleUploadImage = async (e) => {
|
|
let file = e.target.files[0];
|
|
if (!file) return;
|
|
var videoUrl = URL.createObjectURL(file);
|
|
var videoObj = document.createElement("video");
|
|
const eles = Array.from(e.target.files);
|
|
if (type == 1) {
|
|
const newFils = eles.map((it, index) => ({
|
|
url: URL.createObjectURL(it),
|
|
id: "new" + index,
|
|
}));
|
|
setFilesUrls((old) => [...old, ...newFils]);
|
|
} else {
|
|
videoObj.onloadedmetadata = function (evt) {
|
|
URL.revokeObjectURL(videoUrl);
|
|
const target = evt.target;
|
|
setFrameImage({
|
|
src: videoUrl,
|
|
w: target.videoWidth,
|
|
h: target.videoHeight,
|
|
});
|
|
setLoading(true);
|
|
// let newFilesUrls = [...filesUrls];
|
|
|
|
if (type == 2) {
|
|
if (typeof window == "undefined") return;
|
|
// newFiles = [...assets, file];
|
|
// setFileList(newAssets);
|
|
creatVideoCanvas(file);
|
|
setVideoUrl(URL.createObjectURL(file));
|
|
}
|
|
// setFileList(newFiles);
|
|
setLoading(false);
|
|
};
|
|
|
|
videoObj.src = videoUrl;
|
|
videoObj.load();
|
|
}
|
|
getImgs([...assets, ...eles]);
|
|
};
|
|
const handleRemoveItem = (index) => {
|
|
let newArr = [...filesUrls];
|
|
let newAssets = [...assets];
|
|
newArr.splice(index, 1);
|
|
newAssets.splice(index, 1);
|
|
setFilesUrls(newArr);
|
|
getImgs(newAssets);
|
|
};
|
|
const showPhotos = (images, index) => {
|
|
const file = images[0];
|
|
const urls = type == 2 ? [frameImage.src] : images;
|
|
if (type == 1) {
|
|
ImageViewer.Multi.show({
|
|
images: urls,
|
|
defaultIndex: index,
|
|
});
|
|
} else {
|
|
Modal.show({
|
|
content: (
|
|
<video
|
|
autoPlay
|
|
playsInline
|
|
controls
|
|
muted={true}
|
|
controlslist="nodownload"
|
|
>
|
|
<source src={videoUrl} />
|
|
</video>
|
|
),
|
|
closeOnMaskClick: true,
|
|
bodyStyle: {
|
|
background: "none",
|
|
maxHeight: "100vh",
|
|
},
|
|
});
|
|
}
|
|
};
|
|
const creatVideoCanvas = (file) => {
|
|
if (typeof window == "undefined") return;
|
|
// const videoD = document.getElementById("video_upload");
|
|
const url = URL.createObjectURL(file);
|
|
// videoD.src = url;
|
|
getVideoBase64(url).then((src) => {
|
|
setFrameImage((old) => ({ ...old, src }));
|
|
setFilesUrls([{ url: src, id: "0" }]);
|
|
});
|
|
};
|
|
const reorder = (list, startIndex, endIndex) => {
|
|
const result = Array.from(list);
|
|
const [removed] = result.splice(startIndex, 1);
|
|
result.splice(endIndex, 0, removed);
|
|
|
|
return result;
|
|
};
|
|
const onDragEnd = (result) => {
|
|
if (!result.destination) return;
|
|
const newList = reorder(
|
|
assets,
|
|
result.source.index,
|
|
result.destination.index
|
|
);
|
|
getImgs([...newList]);
|
|
// const newArr=newList.map((it,index)=>({...it,url:it.url||URL.createObjectURL(it)}))
|
|
const newArr = newList.map((it, index) => {
|
|
if (it.url) {
|
|
return { url: it.url, id: `${index}` };
|
|
} else {
|
|
return { url: URL.createObjectURL(it), id: `${index}` };
|
|
}
|
|
});
|
|
setFilesUrls(newArr);
|
|
};
|
|
return (
|
|
<div>
|
|
<DragDropContext onDragEnd={onDragEnd}>
|
|
<Droppable direction="horizontal" droppableId="droppable">
|
|
{(droppableProvided) => (
|
|
<div
|
|
className="mb-2 grid grid-cols-4 gap-1"
|
|
ref={droppableProvided.innerRef}
|
|
>
|
|
{filesUrls.map((item, index) => (
|
|
<Draggable key={item.id} draggableId={item.id} index={index}>
|
|
{(provided, snapshot) => (
|
|
<div
|
|
ref={provided.innerRef}
|
|
{...provided.draggableProps}
|
|
{...provided.dragHandleProps}
|
|
style={{
|
|
...provided.draggableProps.style,
|
|
opacity: snapshot.isDragging ? 0.8 : 1,
|
|
}}
|
|
>
|
|
<div key={index} className="rounded relative">
|
|
<div
|
|
onClick={() => showPhotos(filesUrls, index)}
|
|
style={{ height: "calc(25vw - 0.75rem)" }}
|
|
>
|
|
<Image
|
|
src={item.url}
|
|
width="100%"
|
|
height="100%"
|
|
className="rounded"
|
|
fit="cover"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
className="h-6 w-6 bg-[#33333380] absolute top-0 right-0 flex justify-center items-center rounded-bl"
|
|
onClick={() => handleRemoveItem(index)}
|
|
>
|
|
<FontAwesomeIcon icon={faClose} size="xl" />
|
|
</div>
|
|
{type == 2 && (
|
|
<div
|
|
className="absolute top-1/2 left-1/2 flex justify-center items-center -mt-2 -ml-1"
|
|
onClick={() => showPhotos(filesUrls)}
|
|
>
|
|
<FontAwesomeIcon icon={faPlay} size="xl" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</Draggable>
|
|
))}
|
|
{droppableProvided.placeholder}
|
|
</div>
|
|
)}
|
|
</Droppable>
|
|
</DragDropContext>
|
|
{loading && (
|
|
<div className="rounded border-[#ffffff80] text-[#ffffff80] flex flex-col justify-center items-center">
|
|
<DotLoading />
|
|
<p>上传中</p>
|
|
</div>
|
|
)}
|
|
<div className="grid grid-cols-4 gap-1">
|
|
{type == 2 && filesUrls.length > 0 ? null : (
|
|
<>
|
|
<label htmlFor="uploadAvatarBtn">
|
|
<div
|
|
className="border-2 border-[#ffffff80] text-[#ffffff80] rounded border-dashed w-full h-full flex justify-center items-center"
|
|
style={{ minHeight: "calc(25vw - 0.75rem)" }}
|
|
>
|
|
<div style={{ maxWidth: "24px" }}>
|
|
<FontAwesomeIcon icon={faAdd} size="2xl" />
|
|
</div>
|
|
</div>
|
|
</label>
|
|
<input
|
|
type="file"
|
|
multiple={type == 1}
|
|
id="uploadAvatarBtn"
|
|
style={{ display: "none" }}
|
|
// accept="image/png, image/jpeg, video/*"
|
|
accept={accept}
|
|
// capture="camera"
|
|
onChange={handleUploadImage}
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|