dev_hjm
hjm 6 years ago
parent 2abd97a217
commit 702b471d0b

@ -217,6 +217,10 @@ const UsersInfo = Loadable({
loader: () => import('./modules/user/usersInfo/Infos'),
loading: Loading,
})
const InfosIndex = Loadable({
loader: () => import('./modules/user/usersInfo/InfosIndex'),
loading: Loading,
})
// 教学案例
const MoopCases = Loadable({
@ -327,7 +331,10 @@ class App extends Component {
/>
<Route path="/users/:username"
render={
(props) => (<UsersInfo {...this.props} {...props} {...this.state} />)
(props) => {
return (<InfosIndex {...this.props} {...props} {...this.state} />)
}
}></Route>
<Route

@ -69,7 +69,7 @@ export function initAxiosInterceptors(props) {
// proxy = 'http://localhost:3000'
// }
// ---------------------------------------------
if (config.url.indexOf(proxy) != -1) {
if (config.url.indexOf(proxy) != -1 || config.url.indexOf(':') != -1) {
return config
}
requestProxy(config)

@ -190,7 +190,7 @@ function AliyunUploader(props) {
}
// 首先调用 uploader.addFile(event.target.files[i], null, null, null, userData)
console.log(uploader)
uploader.addFile(file, null, null, null, userData)
let result = uploader.addFile(file, null, null, null, userData)
$('#authUpload').attr('disabled', false)
// $('#pauseUpload').attr('disabled', true)
// $('#resumeUpload').attr('disabled', true)

@ -17,7 +17,7 @@ class ActionBtn extends Component {
to==undefined ?
<a href="javascript:void(0)" onClick={this.props.onClick}
{...others}
className={"Actionbtn "+`${map[style]} ${this.props.className}`}
className={"Actionbtn "+`${map[style || 'blue']} ${this.props.className}`}
>{children}</a>
:
<Link to={to} className={"btn "+`${map[this.props.style]} ${this.props.className}`}>{this.props.children}</Link>

@ -10,7 +10,7 @@ class CBreadcrumb extends Component{
render(){
let { items, className, separator }=this.props;
return(
<p className={`clearfix mb10 ${className}`}>
<p className={`clearfix mb10 ${className} cBreadcrumb`}>
{ items && items.map( (item, index) => {
if (!item.name) {
return ''

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { SnackbarHOC } from 'educoder';
import {Link} from 'react-router-dom';
import {Tooltip,Menu} from 'antd';
import Loadable from 'react-loadable';
@ -8,8 +8,7 @@ import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import UpgradeModals from '../../modals/UpgradeModals';
import axios from 'axios';
import {getImageUrl} from 'educoder';
import { TPMIndexHOC } from '../../tpm/TPMIndexHOC';
import { CNotificationHOC } from '../../courses/common/CNotificationHOC'
import "./usersInfo.css"
import "../../courses/css/members.css"
import "../../courses/css/Courses.css"
@ -462,4 +461,5 @@ class Infos extends Component{
)
}
}
export default CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(Infos) ));
// CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC))
export default (Infos) ;

@ -0,0 +1,68 @@
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import { SnackbarHOC } from 'educoder';
import { TPMIndexHOC } from '../../tpm/TPMIndexHOC';
import { CNotificationHOC } from '../../courses/common/CNotificationHOC'
import Loadable from 'react-loadable';
import Loading from '../../../Loading';
const UsersInfo = Loadable({
loader: () => import('./Infos'),
loading: Loading,
})
const VideoUploadList = Loadable({
loader: () => import('./video/VideoUploadList'),
loading: Loading,
})
const $ = window.$;
class InfosIndex extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
}
}
componentDidMount =()=>{
}
//判断是否看的是当前用户的个人主页
componentDidUpdate =(prevProps)=> {
}
render(){
let {
data ,
}=this.state;
return(
<Switch {...this.props}>
{/* --------------------------------------------------------------------- */}
{/* 视频发布 */}
<Route exact path="/users/:username/videoes/upload"
render={
(props) => (<VideoUploadList {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/users/:username"
render={
(props) => (<UsersInfo {...this.props} {...props} {...this.state} />)
}
></Route>
</Switch>
)
}
}
export default CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(InfosIndex) ));

@ -0,0 +1,162 @@
import { getUrl2, isDev } from 'educoder'
import axios from 'axios'
let _url_origin = getUrl2()
let _path = _isDev ? 'public' : 'build'
let _testHost = 'http://192.168.2.63:3001/api' ; // '' ;
let login = 'innov'
let uploader;
let $ = window.$
function loadLib(callback) {
$.getScript(
`${_url_origin}/react/${_path}/js/aliyun-upload/lib/es6-promise.min.js`,
(data, textStatus, jqxhr) => {
$.getScript(
`${_url_origin}/react/${_path}/js/aliyun-upload/lib/aliyun-oss-sdk-5.3.1.min.js`,
(data, textStatus, jqxhr) => {
$.getScript(
`${_url_origin}/react/${_path}/js/aliyun-upload/aliyun-upload-sdk-1.5.0.min.js`,
(data, textStatus, jqxhr) => {
callback && callback()
});
});
});
}
function createUploader(options) {
if (window.AliyunUpload && window.AliyunUpload.Vod) {
doCreateUploader(options)
} else {
loadLib(() => {
doCreateUploader(options)
})
}
}
function doCreateUploader (options) {
uploader = new AliyunUpload.Vod({
timeout: $('#timeout').val() || 60000,
partSize: $('#partSize').val() || 1048576,
parallel: $('#parallel').val() || 5,
retryCount: $('#retryCount').val() || 3,
retryDuration: $('#retryDuration').val() || 2,
region: $('#region').val() || 'ap-southeast-1',
userId: $('#userId').val() || 1202060945918292, // 1303984639806000,
// 添加文件成功
addFileSuccess: function (uploadInfo) {
options.addFileSuccess && options.addFileSuccess(uploadInfo)
console.log("addFileSuccess: " + uploadInfo.file.name)
uploader.startUpload()
},
// 开始上传
onUploadstarted: function (uploadInfo) {
// 如果是 UploadAuth 上传方式, 需要调用 uploader.setUploadAuthAndAddress 方法
// 如果是 UploadAuth 上传方式, 需要根据 uploadInfo.videoId是否有值调用点播的不同接口获取uploadauth和uploadAddress
// 如果 uploadInfo.videoId 有值,调用刷新视频上传凭证接口,否则调用创建视频上传凭证接口
// 注意: 这里是测试 demo 所以直接调用了获取 UploadAuth 的测试接口, 用户在使用时需要判断 uploadInfo.videoId 存在与否从而调用 openApi
// 如果 uploadInfo.videoId 存在, 调用 刷新视频上传凭证接口(https://help.aliyun.com/document_detail/55408.html)
// 如果 uploadInfo.videoId 不存在,调用 获取视频上传地址和凭证接口(https://help.aliyun.com/document_detail/55407.html)
const fileName = uploadInfo.file.name
if (!uploadInfo.videoId) {
var createUrl = `${_testHost}/users/${login}/video_auths.json?debug=true`
axios.post(createUrl, {
title: fileName,
file_name: fileName
}).then((response) => {
// if (response.data.status == )
const data = response.data.data
var uploadAuth = data.UploadAuth
var uploadAddress = data.UploadAddress
var videoId = data.VideoId
uploader.setUploadAuthAndAddress(uploadInfo, uploadAuth, uploadAddress, videoId)
}).catch((error) => {
console.log(error)
})
$('#status').text('文件开始上传...')
console.log("onUploadStarted:" + uploadInfo.file.name + ", endpoint:" + uploadInfo.endpoint + ", bucket:" + uploadInfo.bucket + ", object:" + uploadInfo.object)
} else {
// 如果videoId有值根据videoId刷新上传凭证
var refreshUrl = `${_testHost}/users/${login}/video_auths.json?debug=true`
axios.put(refreshUrl, {
video_id: uploadInfo.videoId,
}).then((response) => {
const data = response.data.data
var uploadAuth = data.UploadAuth
var uploadAddress = data.UploadAddress
var videoId = data.VideoId
uploader.setUploadAuthAndAddress(uploadInfo, uploadAuth, uploadAddress, videoId)
}).catch((error) => {
console.log(error)
})
}
},
// 文件上传成功
onUploadSucceed: function (uploadInfo) {
options.onUploadSucceed && options.onUploadSucceed(uploadInfo)
console.log("onUploadSucceed: " + uploadInfo.file.name + ", endpoint:" + uploadInfo.endpoint + ", bucket:" + uploadInfo.bucket + ", object:" + uploadInfo.object)
$('#status').text('文件上传成功!')
},
// 文件上传失败
onUploadFailed: function (uploadInfo, code, message) {
console.log("onUploadFailed: file:" + uploadInfo.file.name + ",code:" + code + ", message:" + message)
$('#status').text('文件上传失败!')
},
// 取消文件上传
onUploadCanceled: function (uploadInfo, code, message) {
console.log("Canceled file: " + uploadInfo.file.name + ", code: " + code + ", message:" + message)
$('#status').text('文件上传已暂停!')
},
// 文件上传进度,单位:字节, 可以在这个函数中拿到上传进度并显示在页面上
onUploadProgress: function (uploadInfo, totalSize, progress) {
options.onUploadProgress && options.onUploadProgress(uploadInfo, totalSize, progress)
console.log("onUploadProgress:file:" + uploadInfo.file.name + ", fileSize:" + totalSize + ", percent:" + Math.ceil(progress * 100) + "%")
var progressPercent = Math.ceil(progress * 100)
$('#auth-progress').text(progressPercent)
$('#status').text('文件上传中...')
},
// 上传凭证超时
onUploadTokenExpired: function (uploadInfo) {
// 上传大文件超时, 如果是上传方式一即根据 UploadAuth 上传时
// 需要根据 uploadInfo.videoId 调用刷新视频上传凭证接口(https://help.aliyun.com/document_detail/55408.html)重新获取 UploadAuth
// 然后调用 resumeUploadWithAuth 方法, 这里是测试接口, 所以我直接获取了 UploadAuth
$('#status').text('文件上传超时!')
var refreshUrl = `${_testHost}/users/${login}/video_auths.json?debug=true`
axios.put(refreshUrl, {
video_id: uploadInfo.videoId,
}).then((response) => {
const data = response.data.data
var uploadAuth = data.UploadAuth
uploader.resumeUploadWithAuth(uploadAuth)
}).catch((error) => {
console.log(error)
})
},
// 全部文件上传结束
onUploadEnd: function (uploadInfo) {
options.onUploadEnd && options.onUploadEnd(uploadInfo)
$('#status').text('文件上传完毕!')
console.log("onUploadEnd: uploaded all the files")
}
})
if (options.gotUploader) {
options.gotUploader(uploader)
}
}
export function getUploader (_login, options) {
_login && (login = _login)
if (!uploader) {
uploader = createUploader(options)
}
return uploader;
}

@ -1,12 +1,17 @@
import React, { useState, useEffect, memo } from 'react';
import {Link} from 'react-router-dom';
import { getUrl2, isDev } from 'educoder'
import axios from 'axios'
function InfoVideo (props) {
const username = props.match.params.username
return (
<div>123</div>
<div>123
<Link to={`/users/${username}/videoes/upload`}>to upload</Link>
</div>
)
}

@ -0,0 +1,36 @@
import update from 'immutability-helper'
export function reducer(state, action) {
switch (action.type) {
case 'addVideo':
const uploadInfo = action.uploadInfo
return {videoes: [...state.videoes, {
name: uploadInfo.file.name,
size: uploadInfo.file.size,
type: uploadInfo.file.type,
fileHash: uploadInfo.fileHash, // "ba1bbc53fdecd9eaaae479fbd9518442"
state: uploadInfo.state, // "Uploading" "Ready" "Success"
videoId: uploadInfo.videoId, // "719b82c875c34ac39f94feb145d25ad2"
loaded: 0
}]};
case 'updateProgress':
let _index = -1;
state.videoes.some((item, index) => {
// addFileSuccess的时候没有fileHash
// if (uploadInfo.fileHash == item.fileHash) {
if (action.uploadInfo.fileHash == item.fileHash || action.uploadInfo.file.name == item.name) {
_index = index
return true;
}
})
return {videoes: update(state.videoes, {[_index]: {
loaded: {$set: action.progressPercent},
fileHash: {$set: action.uploadInfo.fileHash}
}})};
default:
throw new Error();
}
}
export const initialState = {videoes: []};

@ -0,0 +1,45 @@
import React, { useState, useEffect, memo } from 'react';
import { Progress, Input } from 'antd'
import { getUrl2, isDev, CBreadcrumb, ActionBtn } from 'educoder'
import axios from 'axios'
const MAX_LENGTH = 60
/**
name: file.name,
size: file.size,
type: file.type,
fileHash: uploadInfo.fileHash, // "ba1bbc53fdecd9eaaae479fbd9518442"
state: uploadInfo.state, // "Uploading"
videoId: uploadInfo.videoId, // "719b82c875c34ac39f94feb145d25ad2"
loaded: 0
*/
function VideoUpload (props) {
const { className, index, name, loaded, state, cancelUpload } = props;
const [title, setTitle] = useState('')
const username = props.match.params.username
function titleChange () {
setTitle(e.target.value)
}
return (
<div className={`videoUpload ${className}`}>
<div className="filename">{index+1}. {name}</div>
<div className="progress df">
<Progress percent={loaded}
status={state == "Uploading" ? "active" : ''}
/>
<ActionBtn className="cancelUpload" onClick={() => cancelUpload(index)}>取消上传</ActionBtn>
</div>
<Input placeholder={`标题支持最多${MAX_LENGTH}个字符`} onInput={titleChange} maxLength={MAX_LENGTH} suffix ={
<span className="color-grey-6 font-13">{String(title.length)}/{MAX_LENGTH}</span>
}></Input>
</div>
)
}
export default VideoUpload

@ -0,0 +1,208 @@
import React, { useState, useEffect, useReducer, memo } from 'react';
import { getUrl2, isDev, CBreadcrumb } from 'educoder'
import axios from 'axios'
import VideoUpload from './VideoUpload'
import { Button } from 'antd'
import { getUploader } from './AliyunUploaderManager'
import { reducer, initialState } from './VideoReducer'
let uploader
const files = []
function VideoUploadList (props) {
const [videoes, setVideoes] = useState([]);
const [state, dispatch] = useReducer(reducer, initialState);
const uploaderOptions = {
}
function onUploadChange (e) {
var file = e.target.files[0]
if (!file) {
alert("请先选择需要上传的文件!")
return
}
// TODO 判断文件类型
var Title = file.name
file.type
var userData = '{"Vod":{}}'
if (!uploader) {
getUploader(username,
// Object.assign(uploaderOptions,
{
addFileSuccess: (uploadInfo) => {
const file = uploadInfo.file
console.log('addFileSuccess', uploadInfo)
// const newVideoes = [...videoes, {
// name: file.name,
// size: file.size,
// type: file.type,
// fileHash: uploadInfo.fileHash, // "ba1bbc53fdecd9eaaae479fbd9518442"
// state: uploadInfo.state, // "Uploading" "Ready"
// videoId: uploadInfo.videoId, // "719b82c875c34ac39f94feb145d25ad2"
// loaded: 0
// }]
// setVideoes(newVideoes)
files.push(file)
dispatch({type: 'addVideo', uploadInfo})
},
onUploadProgress: (uploadInfo, totalSize, progress) => {
var progressPercent = Math.ceil(progress * 100)
let _index = -1;
videoes.some((item, index) => {
// addFileSuccess的时候没有fileHash
// if (uploadInfo.fileHash == item.fileHash) {
if (uploadInfo.file.name == item.name) {
_index = index
return true;
}
})
// TODO 这里不用reducer会出现state被重置的问题
// if (_index == -1) {
// const newVideoes = [...videoes, {
// name: file.name,
// size: file.size,
// type: file.type,
// fileHash: uploadInfo.fileHash, // "ba1bbc53fdecd9eaaae479fbd9518442"
// state: uploadInfo.state, // "Uploading" "Ready"
// videoId: uploadInfo.videoId, // "719b82c875c34ac39f94feb145d25ad2"
// loaded: progressPercent
// }]
// setVideoes(newVideoes)
// return;
// }
// // exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: false}}})
// setVideoes(update(videoes, {[_index]: { loaded: {$set: progressPercent}}}))
dispatch({type: 'updateProgress', uploadInfo, progressPercent})
},
onUploadEnd: (uploadInfo) => {
console.log('onUploadEnd', uploadInfo)
},
onUploadSucceed: (uploadInfo) => {
console.log('onUploadSucceed', uploadInfo)
},
// 可能需要等lib加载完毕才能执行
gotUploader: (_uploader) => {
// 首先调用 uploader.addFile(event.target.files[i], null, null, null, userData)
console.log(_uploader)
let result = _uploader.addFile(file, null, null, null, userData)
uploader = _uploader;
window.uploader = uploader;
}
}
// )
)
} else {
let result = uploader.addFile(file, null, null, null, userData)
}
}
// uploader.deleteFile(index);
function cancelUpload(index) {
// 确定取消?
setVideoes([...videoes.splice(index, 1)])
const file = files[index]
uploader.cancelFile(file)
files.splice(index, 1)
}
// login
const username = props.match.params.username
return (
<div className="educontent videoUploadList">
<style>{`
.videoUploadList .section {
background: #fff;
padding: 16px 20px;
margin-top: 20px;
}
/* item */
.videoUploadList .cancelUpload {
flex: 0 0 92px;
}
`}</style>
<CBreadcrumb
separator=" > "
items={[
{ to: `users/${username}/videoes`, name: '视频'},
{ name: '上传'}
]}
></CBreadcrumb>
<div className="title section">上传视频</div>
{state.videoes.map((item, vIndex) => {
return (
<VideoUpload {...props} {...item} className="section"
cancelUpload={cancelUpload}
index={vIndex}
></VideoUpload>
)
})}
<div className="description section">
<div className="">视频大小不支持断点续传单个视频文件最大200M单次最多支持3个视频文件上传 </div>
<div className="">视频规格aviflvf4vm4vmovmp4rmvbswfwebm </div>
<div className="">温馨提示请勿上传违法视频平台将为每一个视频分配一个地址您可以通过引用改地址将视频使用在开发社区等模块</div>
</div>
<Button type="primary" icon="plus-square" onClick={() => { document.getElementById('fileUpload').click()}}>
添加更多视频
</Button>
<input type="file" id="fileUpload" style={{display: 'none'}} onChange={onUploadChange}></input>
</div>
)
}
export default VideoUploadList
/**
bucket: "outin-396971199eed11e991a100163e1c7426"
checkpoint: {file: File, name: "sv/2d0fd065-16c7a62fcc5/2d0fd065-16c7a62fcc5.mp4", fileSize: 491511493, partSize: 1048576, uploadId: "A8DB0663F44C44F58F3F7F45892ED08B", }
endpoint: "https://oss-cn-shanghai.aliyuncs.com"
file: File {name: "[阳光电影-www.ygdy8.com]金秘书为何这样-02.mp4", lastModified: 1532441562000, lastModifiedDate: Tue Jul 24 2018 22:12:42 GMT+0800 (China Standard Time), webkitRelativePath: "", size: 491511493, }
fileHash: "ba1bbc53fdecd9eaaae479fbd9518442"
isImage: false
loaded: 0.5927505330490405
object: "sv/2d0fd065-16c7a62fcc5/2d0fd065-16c7a62fcc5.mp4"
region: "cn-shanghai"
retry: false
ri: "F0FDC11A-9A92-4A50-882A-423C3EA499F3"
state: "Uploading"
userData: "eyJWb2QiOnt9fQ=="
videoId: "719b82c875c34ac39f94feb145d25ad2"
file
lastModified: 1532441562000
lastModifiedDate: Tue Jul 24 2018 22:12:42 GMT+0800 (China Standard Time) {}
name: "[阳光电影-www.ygdy8.com]金秘书为何这样-02.mp4"
size: 491511493
type: "video/mp4"
webkitRelativePath: ""
*/
Loading…
Cancel
Save