import { Button } from '@tarojs/components'; import Taro, { UploadTask, useDidHide, useLoad, useUnload } from '@tarojs/taro'; import { isEqual } from 'lodash-es'; import { useCallback, useEffect, useRef, useState } from 'react'; import MaterialVideoCard from '@/components/material-video-card'; import SafeBottomPadding from '@/components/safe-bottom-padding'; import { EventName, OpenSource, PageUrl } from '@/constants/app'; import { CollectEventName, ReportEventId } from '@/constants/event'; import { MaterialVideoInfo } from '@/types/material'; import { logWithPrefix } from '@/utils/common'; import { collectEvent, reportEvent } from '@/utils/event'; import { chooseMedia, postVideos, requestVideoList } from '@/utils/material'; import { getPageQuery, navigateBack, navigateTo } from '@/utils/route'; import Toast from '@/utils/toast'; import { uploadVideo } from '@/utils/video'; import './index.less'; // 限制 500M const MAX_FILE_SIZE_LIMIT = 1024 * 1024 * 1000; const PREFIX = 'page-material-upload-video'; const log = logWithPrefix(PREFIX); const TEMP_DATA: MaterialVideoInfo = { url: '', coverUrl: '', title: '', type: 'image', isDefault: false }; export default function MaterialUploadVideo() { const [source, setSource] = useState(OpenSource.None); const [videoList, setVideoList] = useState([]); const saveRef = useRef<(videos: MaterialVideoInfo[]) => Promise>(); const lastSaveVideosRef = useRef([]); const initVideoList = useCallback(async () => { try { const res = await requestVideoList(); lastSaveVideosRef.current = res; setVideoList(res); } catch (e) { console.error(e); Toast.error('加载失败请重试'); } }, []); const handleClickDelete = useCallback( (video: MaterialVideoInfo) => { log('handleClickDelete', video); const newVideoList = videoList.filter(v => v.coverUrl !== video.coverUrl); setVideoList(newVideoList); }, [videoList] ); const handleDefaultChange = useCallback( (video: MaterialVideoInfo) => { log('handleDefaultChange', video); const newVideoList = videoList.map(v => ({ ...v, isDefault: v.coverUrl === video.coverUrl })); setVideoList(newVideoList); }, [videoList] ); const handleTitleChange = useCallback( (video: MaterialVideoInfo, newTitle: string) => { // log('handleTitleChange', video, newTitle); const newVideoList = [...videoList]; const index = newVideoList.findIndex(v => v.coverUrl === video.coverUrl); if (index < 0) { return; } newVideoList.splice(index, 1, { ...video, title: newTitle }); setVideoList(newVideoList); }, [videoList] ); const handleClickUpload = useCallback(async () => { log('click upload'); let showLoading = false; try { reportEvent(ReportEventId.CLICK_UPLOAD_VIDEO); const media = await chooseMedia(); if (!media) { return; } const { type, tempFiles } = media; log('upload result', type, tempFiles); const tempFile = tempFiles[0]; if (!tempFile) { throw new Error('tempFile is not exist'); } if (tempFile.size > MAX_FILE_SIZE_LIMIT) { Toast.info('视频超过1000m,请更换', 3000); collectEvent(CollectEventName.VIDEO_EXCEEDING_LIMITS); return; } showLoading = true; Taro.showLoading({ title: '准备上传' }); const onProgress: UploadTask.OnProgressUpdateCallback = res => { log('上传视频进度', res.progress, '总长度', res.totalBytesExpectedToSend, '已上传的长度', res.totalBytesSent); Taro.showLoading({ title: `上传${res.progress}%` }); }; const { url, coverUrl } = await uploadVideo(tempFile.tempFilePath, tempFile.fileType, onProgress); const newVideo: MaterialVideoInfo = { title: '', isDefault: false, url: url, coverUrl: coverUrl, type: tempFile.fileType === 'video' ? 'video' : 'image', }; setVideoList([...videoList, newVideo]); } catch (e) { console.error('upload fail', e); Toast.error('上传失败'); collectEvent(CollectEventName.UPLOAD_VIDEO_FAILED, e); } finally { showLoading && Taro.hideLoading(); } }, [videoList]); const handleClickSubmit = useCallback(async () => { log('handleClickSubmit', videoList); reportEvent(ReportEventId.CLICK_SAVE_VIDEOS); if (videoList.length < 2) { Toast.info('请至少上传 2 个录屏'); return; } try { Taro.showLoading(); await saveRef.current?.(videoList); Taro.eventCenter.trigger(EventName.CREATE_PROFILE); if (source === OpenSource.None) { navigateTo(PageUrl.MaterialCreateProfile); } else { navigateBack(); } } catch (e) { Toast.error('保存失败请重试'); collectEvent(CollectEventName.SAVE_VIDEO_LIST_FAILED, e); } finally { Taro.hideLoading(); } }, [videoList, source]); useEffect(() => { saveRef.current = async (videos: MaterialVideoInfo[]) => { if (!videos.length) { log('长度为空不保存'); return; } if (isEqual(lastSaveVideosRef.current, videos)) { log('没变化不保存'); return; } lastSaveVideosRef.current = videos; await postVideos(videos); }; }, []); useLoad(() => { const query = getPageQuery<{ source: OpenSource }>(); log('query', query); const { source: openSource } = query; openSource && setSource(openSource); initVideoList(); }); useDidHide(() => { log('didHide', videoList); saveRef.current?.(videoList); }); useUnload(() => { log('unload', videoList); saveRef.current?.(videoList); }); return (
上传录屏更易获得企业青睐
录屏是企业最关注的资料,建议提供多个风格和品类
{videoList.map(video => ( handleClickDelete(video)} onClickSetDefault={() => handleDefaultChange(video)} onTitleChange={(newTitle: string) => handleTitleChange(video, newTitle)} /> ))} {videoList.length < 6 && }
); }