Commit a478bc19 by guomingpang

fix:替换新建培训计划是封面默认图地址

parent 132fb94f
/* /*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:45:51 * @Date: 2021-02-20 16:45:51
* @LastEditors: wufan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-05-13 16:36:26 * @LastEditTime: 2021-06-01 15:20:33
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react';
import { Button,Input,Switch,Radio,Row,Col,Modal,message,Tooltip} from 'antd'; import { Button, Input, Switch, Radio, Row, Col, Modal, message, Tooltip } from 'antd';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import SelectOperatorModal from '../modal/SelectOperatorModal'; import SelectOperatorModal from '../modal/SelectOperatorModal';
import { ImgCutModalNew } from '@/components';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal'; import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import Upload from '@/core/upload'; import Upload from '@/core/upload';
// import PhotoClip from 'photoclip' // import PhotoClip from 'photoclip'
import './BasicInfo.less'; import './BasicInfo.less';
const { TextArea } = Input; const { TextArea } = Input;
const defaultCover = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'; const defaultCover = 'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png';
let cutFlag = false; let cutFlag = false;
let timer = null class BasicInfo extends React.Component {
class BasicInfo extends React.Component{
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
operatorModalVisible: false, operatorModalVisible: false,
showSelectFileModal:false, showSelectFileModal: false,
cutImageBlob: null cutImageBlob: null,
}; };
} }
handleShowSelectOperatorModal = () => {
handleShowSelectOperatorModal = () =>{
this.setState({ this.setState({
operatorModalVisible:true operatorModalVisible: true,
}) });
} };
handleCloseSelectOperatorMOdal = ()=>{ handleCloseSelectOperatorMOdal = () => {
this.setState({ this.setState({
operatorModalVisible:false operatorModalVisible: false,
}) });
} };
handleConfirmSelectOperator = (selectOperatorList)=> { handleConfirmSelectOperator = (selectOperatorList) => {
if(selectOperatorList.length === 0){ if (selectOperatorList.length === 0) {
message.warning('请选择运营师') message.warning('请选择运营师');
return; return;
} }
this.props.onChange('selectOperatorList',selectOperatorList); this.props.onChange('selectOperatorList', selectOperatorList);
this.setState({ this.setState({
operatorModalVisible:false operatorModalVisible: false,
}) });
} };
enableStateChange = ()=> { enableStateChange = () => {
if(this.props.data.enableState==="NO"){ if (this.props.data.enableState === 'NO') {
this.props.onChange('enableState','YES') this.props.onChange('enableState', 'YES');
}else{ } else {
this.props.onChange('enableState','NO') this.props.onChange('enableState', 'NO');
}
} }
};
// 使用默认封面图 // 使用默认封面图
handleResetCoverUrl = ()=> { handleResetCoverUrl = () => {
const { data: { coverUrl } } = this.props; const {
data: { coverUrl },
} = this.props;
const isDefaultCover = coverUrl === defaultCover; const isDefaultCover = coverUrl === defaultCover;
// 如果已经是默认图的话,不做任何任何处理 // 如果已经是默认图的话,不做任何任何处理
if (isDefaultCover) return; if (isDefaultCover) return;
message.success('已替换为默认图'); message.success('已替换为默认图');
this.props.onChange('coverUrl',defaultCover); this.props.onChange('coverUrl', defaultCover);
setTimeout(()=>{ setTimeout(() => {
this.props.onChange('coverId', null); this.props.onChange('coverId', null);
},1000) }, 1000);
} };
handleSelectCover = (file)=> { handleSelectCover = (file) => {
this.uploadImage(file); this.uploadImage(file);
} };
//上传图片 //上传图片
uploadImage = (imageFile) => { uploadImage = (imageFile) => {
const { folderName } = imageFile;
const fileName = window.random_string(16) + folderName.slice(folderName.lastIndexOf("."));
const self = this; const self = this;
this.setState( this.setState(
{ {
...@@ -87,57 +83,55 @@ class BasicInfo extends React.Component{ ...@@ -87,57 +83,55 @@ class BasicInfo extends React.Component{
}, },
() => { () => {
setTimeout(() => { setTimeout(() => {
const okBtnDom = document.querySelector("#headPicModal"); const okBtnDom = document.querySelector('#headPicModal');
const options = { const options = {
size: [500, 282], size: [500, 282],
ok: okBtnDom, ok: okBtnDom,
maxZoom: 3, maxZoom: 3,
style: { style: {
jpgFillColor: "transparent", jpgFillColor: 'transparent',
}, },
done: function (dataUrl) { done: function (dataUrl) {
clearTimeout(self.timer); clearTimeout(self.timer);
self.timer = setTimeout(() => { self.timer = setTimeout(() => {
if ((self.state.rotate != this.rotate()) || (self.state.scale != this.scale())) { if (self.state.rotate !== this.rotate() || self.state.scale !== this.scale()) {
console.log(this.scale(), 'scale') console.log(this.scale(), 'scale');
const _dataUrl = this.clip() const _dataUrl = this.clip();
const cutImageBlob = self.convertBase64UrlToBlob(_dataUrl); const cutImageBlob = self.convertBase64UrlToBlob(_dataUrl);
self.setState({ self.setState({
cutImageBlob, cutImageBlob,
dataUrl: _dataUrl, dataUrl: _dataUrl,
rotate: this.rotate(), rotate: this.rotate(),
scale: this.scale() scale: this.scale(),
}) });
} }
}, 500);
}, 500)
const cutImageBlob = self.convertBase64UrlToBlob(dataUrl); const cutImageBlob = self.convertBase64UrlToBlob(dataUrl);
self.setState({ self.setState({
cutImageBlob, cutImageBlob,
dataUrl dataUrl,
}) });
setTimeout(() => { setTimeout(() => {
cutFlag = false; cutFlag = false;
}, 2000); }, 2000);
}, },
fail: (failInfo) => { fail: (failInfo) => {
message.error("图片上传失败了,请重新上传"); message.error('图片上传失败了,请重新上传');
}, },
loadComplete: function (img) { loadComplete: function (img) {
setTimeout(() => { setTimeout(() => {
const _dataUrl = this.clip() const _dataUrl = this.clip();
self.setState({ self.setState({
dataUrl: _dataUrl, dataUrl: _dataUrl,
hasImgReady: true hasImgReady: true,
}) });
}, 100) }, 100);
}, },
}; };
const imgUrl = `${imageFile.ossUrl}?${new Date().getTime()}` const imgUrl = `${imageFile.ossUrl}?${new Date().getTime()}`;
if (!this.state.photoclip) { if (!this.state.photoclip) {
const _photoclip = new PhotoClip("#headPicModal", options); const _photoclip = new PhotoClip('#headPicModal', options);
_photoclip.load(imgUrl); _photoclip.load(imgUrl);
this.setState({ this.setState({
photoclip: _photoclip, photoclip: _photoclip,
...@@ -146,7 +140,6 @@ class BasicInfo extends React.Component{ ...@@ -146,7 +140,6 @@ class BasicInfo extends React.Component{
this.state.photoclip.clear(); this.state.photoclip.clear();
this.state.photoclip.load(imgUrl); this.state.photoclip.load(imgUrl);
} }
}, 200); }, 200);
} }
); );
...@@ -154,251 +147,283 @@ class BasicInfo extends React.Component{ ...@@ -154,251 +147,283 @@ class BasicInfo extends React.Component{
//获取resourceId //获取resourceId
getSignature = (blob, fileName) => { getSignature = (blob, fileName) => {
Upload.uploadBlobToOSS(blob, 'cover' + (new Date()).valueOf(),null,'signInfo').then((signInfo) => { Upload.uploadBlobToOSS(blob, 'cover' + new Date().valueOf(), null, 'signInfo').then((signInfo) => {
this.setState({ this.setState(
coverClicpPath:signInfo.fileUrl, {
coverId:signInfo.resourceId, coverClicpPath: signInfo.fileUrl,
visible: false coverId: signInfo.resourceId,
},()=>this.updateCover()) visible: false,
},
() => this.updateCover()
);
}); });
}; };
updateCover = () =>{ updateCover = () => {
const {coverClicpPath,coverId} = this.state const { coverClicpPath, coverId } = this.state;
this.setState({ this.setState({
showSelectFileModal: false showSelectFileModal: false,
}) });
this.props.onChange('coverUrl', coverClicpPath); this.props.onChange('coverUrl', coverClicpPath);
setTimeout(()=>{ setTimeout(() => {
this.props.onChange('coverId', coverId); this.props.onChange('coverId', coverId);
},1000) }, 1000);
} };
// base64转换成blob // base64转换成blob
convertBase64UrlToBlob = (urlData) => { convertBase64UrlToBlob = (urlData) => {
const bytes = window.atob(urlData.split(",")[1]); const bytes = window.atob(urlData.split(',')[1]);
const ab = new ArrayBuffer(bytes.length); const ab = new ArrayBuffer(bytes.length);
const ia = new Uint8Array(ab); const ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) { for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i); ia[i] = bytes.charCodeAt(i);
} }
return new Blob([ab], { type: "image/png" }); return new Blob([ab], { type: 'image/png' });
}; };
limitNumber = value => { limitNumber = (value) => {
if (typeof value === 'string') { if (typeof value === 'string') {
return !isNaN(Number(value)) ? value.replace(/^(0+)|[^\d]/g, '') : '' return !isNaN(Number(value)) ? value.replace(/^(0+)|[^\d]/g, '') : '';
} else if (typeof value === 'number') { } else if (typeof value === 'number') {
return !isNaN(value) ? String(value).replace(/^(0+)|[^\d]/g, '') : '' return !isNaN(value) ? String(value).replace(/^(0+)|[^\d]/g, '') : '';
} else { } else {
return '' return '';
}
} }
percentCompleteBlur = (e,field) =>{ };
percentCompleteBlur = (e, field) => {
let _percentCompleteLive; let _percentCompleteLive;
const { value } = e.target; const { value } = e.target;
if(value > 100){ if (value > 100) {
_percentCompleteLive = 100; _percentCompleteLive = 100;
}else{ } else {
if(value < 0){ if (value < 0) {
_percentCompleteLive = 0; _percentCompleteLive = 0;
}else{ } else {
_percentCompleteLive = value; _percentCompleteLive = value;
} }
} }
this.props.onChange(field,_percentCompleteLive) this.props.onChange(field, _percentCompleteLive);
} };
render(){ render() {
const { operatorModalVisible ,showSelectFileModal,visible,hasImgReady,cutImageBlob} = this.state; const { operatorModalVisible, showSelectFileModal, visible, hasImgReady, cutImageBlob } = this.state;
const { data} = this.props; const { data } = this.props;
const { planName,coverUrl,instro,enableState,operateType,selectOperatorList,percentCompleteLive,percentCompleteVideo,percentCompletePicture} = data; const { planName, coverUrl, instro, enableState, operateType, selectOperatorList, percentCompleteLive, percentCompleteVideo, percentCompletePicture } =
data;
// 当前是否使用的是默认图片 // 当前是否使用的是默认图片
const isDefaultCover = coverUrl === defaultCover; const isDefaultCover = coverUrl === defaultCover;
return ( return (
<div className="plan-basic-info"> <div className='plan-basic-info'>
<div className="plan-name"> <div className='plan-name'>
<span className="label"><span className="require">*</span>培训计划名称:</span> <span className='label'>
<span className='require'>*</span>培训计划名称:
</span>
<Input <Input
value={planName} value={planName}
placeholder="请输入培训计划名称(20字以内)" placeholder='请输入培训计划名称(20字以内)'
maxLength={20} maxLength={20}
style={{ width: 240 }} style={{ width: 240 }}
onChange={(e)=>this.props.onChange('planName', e.target.value)} onChange={(e) => this.props.onChange('planName', e.target.value)}
/> />
</div> </div>
<div className="cover"> <div className='cover'>
<span className="label">封面图:</span> <span className='label'>封面图:</span>
<div className="cover__wrap"> <div className='cover__wrap'>
<div className="img-content"> <div className='img-content'>
{ isDefaultCover && {isDefaultCover && <span className='tag'>默认图</span>}
<span className="tag">默认图</span> <img src={coverUrl} width='690' alt='' />
}
<img src={coverUrl} width="690"/>
</div> </div>
<div className="opt-btns"> <div className='opt-btns'>
<Button onClick={() => { <Button
onClick={() => {
this.setState({ this.setState({
showSelectFileModal:true showSelectFileModal: true,
}) });
}}>上传图片</Button> }}>
<span 上传图片
className={`default-btn ${isDefaultCover ? 'disabled' : ''}`} </Button>
onClick={this.handleResetCoverUrl} <span className={`default-btn ${isDefaultCover ? 'disabled' : ''}`} onClick={this.handleResetCoverUrl}>
>使用默认图</span> 使用默认图
<div className="tips">建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div> </span>
<div className='tips'>建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div>
</div> </div>
</div> </div>
</div> </div>
<div className="introduction"> <div className='introduction'>
<span className="label">简介:</span> <span className='label'>简介:</span>
<TextArea <TextArea
placeholder="请输入培训计划简介" placeholder='请输入培训计划简介'
maxLength={200} maxLength={200}
style={{ width: '552px',height:'110px'}} style={{ width: '552px', height: '110px' }}
className="instro-textarea" className='instro-textarea'
value={instro} value={instro}
onChange={(e)=>this.props.onChange('instro', e.target.value)} onChange={(e) => this.props.onChange('instro', e.target.value)}
/> />
</div> </div>
<div className="wether-use"> <div className='wether-use'>
<span className="label">是否启用:</span> <span className='label'>是否启用:</span>
<div className="content"> <div className='content'>
<div> <div>
<Switch checked={enableState==="YES"? true:false} onChange={()=> {this.enableStateChange()}}/> <Switch
checked={enableState === 'YES' ? true : false}
onChange={() => {
this.enableStateChange();
}}
/>
</div> </div>
<div> <div>
<div className="instro-text"> <div className='instro-text'>
<div>开启:此培训计划可以分享给学员进行学习</div> <div>开启:此培训计划可以分享给学员进行学习</div>
<div>关闭:此培训计划暂不可分享给学员进行学习,后续可开启</div> <div>关闭:此培训计划暂不可分享给学员进行学习,后续可开启</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="view-range" > <div className='view-range'>
<span className="label"> <span className='label'>
<span className="require">*</span> <span className='require'>*</span>
可见范围 可见范围
<Tooltip <Tooltip title='学院管理员、管理员默认都可见'>
title="学院管理员、管理员默认都可见"> <span className='iconfont'>&#xe61d;</span>
<span className="iconfont">&#xe61d;</span> </Tooltip>
</Tooltip></span>
<div className="content"> </span>
<Radio.Group value={operateType} onChange={(e) => { this.props.onChange('operateType', e.target.value) }}> <div className='content'>
<Radio.Group
value={operateType}
onChange={(e) => {
this.props.onChange('operateType', e.target.value);
}}>
<Row style={{ marginBottom: '5px' }}> <Row style={{ marginBottom: '5px' }}>
<Col span={24}> <Col span={24}>
<Radio value="All_Operate"> <Radio value='All_Operate'>
所有运营师 所有运营师
<span className="playback__text">后续新增的运营师都有权限可见</span> <span className='playback__text'>后续新增的运营师都有权限可见</span>
</Radio> </Radio>
</Col> </Col>
</Row> </Row>
<Row> <Row>
<Col span={24}> <Col span={24}>
<Radio value="Assign_Operate"> <Radio value='Assign_Operate'>
指定运营师 指定运营师
<span className="playback__text">仅被选择的运营师有权限可见</span> <span className='playback__text'>仅被选择的运营师有权限可见</span>
</Radio> </Radio>
</Col> </Col>
</Row> </Row>
</Radio.Group> </Radio.Group>
{operateType==="Assign_Operate" && {operateType === 'Assign_Operate' && (
<div className="choose-business"> <div className='choose-business'>
<Button onClick={()=>{this.handleShowSelectOperatorModal()}}>选择运营师</Button> <Button
<span>已选择<span>{selectOperatorList.length}</span>名运营师</span> onClick={() => {
this.handleShowSelectOperatorModal();
}}>
选择运营师
</Button>
<span>
已选择<span>{selectOperatorList.length}</span>名运营师
</span>
</div> </div>
} )}
</div> </div>
</div> </div>
<div className="done-standard"> <div className='done-standard'>
<span className="label standard-label"><span className="require">*</span>完成标准:</span> <span className='label standard-label'>
<span className='require'>*</span>完成标准:
</span>
<div> <div>
<div className="live-standard-info"> <div className='live-standard-info'>
<span className="icon iconfont">&#xe865;</span> <span className='icon iconfont'>&#xe865;</span>
<span className="instro">直播课单个课程,学员学习进度达到 <span className='instro'>
直播课单个课程,学员学习进度达到
<Input <Input
width="40" width='40'
value={percentCompleteLive} value={percentCompleteLive}
onChange={(e) => { this.props.onChange('percentCompleteLive', e.target.value.replace(/\D/g,'')) }} onChange={(e) => {
onBlur={(e)=>this.percentCompleteBlur(e,'percentCompleteLive')} this.props.onChange('percentCompleteLive', e.target.value.replace(/\D/g, ''));
className="input-box" }}
/>%,即视为"已完成"学习 onBlur={(e) => this.percentCompleteBlur(e, 'percentCompleteLive')}
className='input-box'
/>
%,即视为"已完成"学习
</span> </span>
</div> </div>
<div className="live-standard-info"> <div className='live-standard-info'>
<span className="icon iconfont">&#xe864;</span> <span className='icon iconfont'>&#xe864;</span>
<span className="instro">视频课单个课程,学员学习进度达到 <span className='instro'>
视频课单个课程,学员学习进度达到
<Input <Input
width="40" width='40'
value={percentCompleteVideo} value={percentCompleteVideo}
onChange={(e) => { this.props.onChange('percentCompleteVideo', e.target.value.replace(/\D/g,'')) }} onChange={(e) => {
onBlur={(e)=>this.percentCompleteBlur(e,'percentCompleteVideo')} this.props.onChange('percentCompleteVideo', e.target.value.replace(/\D/g, ''));
className="input-box" }}
onBlur={(e) => this.percentCompleteBlur(e, 'percentCompleteVideo')}
className='input-box'
/> />
%,即视为"已完成"学习 %,即视为"已完成"学习
</span> </span>
</div> </div>
<div className="live-standard-info"> <div className='live-standard-info'>
<span className="icon iconfont">&#xe601;</span> <span className='icon iconfont'>&#xe601;</span>
<span className="instro">图文课单个课程,学员学习进度达到 <span className='instro'>
图文课单个课程,学员学习进度达到
<Input <Input
width="40" width='40'
value={percentCompletePicture} value={percentCompletePicture}
onChange={(e) => { this.props.onChange('percentCompletePicture', e.target.value.replace(/\D/g,'')) }} onChange={(e) => {
onBlur={(e)=>this.percentCompleteBlur(e,'percentCompletePicture')} this.props.onChange('percentCompletePicture', e.target.value.replace(/\D/g, ''));
className="input-box" }}
onBlur={(e) => this.percentCompleteBlur(e, 'percentCompletePicture')}
className='input-box'
/> />
%,即视为"已完成"学习 %,即视为"已完成"学习
</span> </span>
</div> </div>
</div> </div>
</div> </div>
{ operatorModalVisible && {operatorModalVisible && (
<SelectOperatorModal <SelectOperatorModal
visible={operatorModalVisible} visible={operatorModalVisible}
onClose={this.handleCloseSelectOperatorMOdal} onClose={this.handleCloseSelectOperatorMOdal}
selectOperatorList={selectOperatorList} selectOperatorList={selectOperatorList}
onSelect={this.handleConfirmSelectOperator} onSelect={this.handleConfirmSelectOperator}
/> />
} )}
{showSelectFileModal && {showSelectFileModal && (
<SelectPrepareFileModal <SelectPrepareFileModal
key="basic" key='basic'
operateType="select" operateType='select'
multiple={false} multiple={false}
accept="image/jpeg,image/png,image/jpg" accept='image/jpeg,image/png,image/jpg'
selectTypeList={['JPG', 'JPEG', 'PNG']} selectTypeList={['JPG', 'JPEG', 'PNG']}
tooltip='支持文件类型:jpg、jpeg、png' tooltip='支持文件类型:jpg、jpeg、png'
isOpen={showSelectFileModal} isOpen={showSelectFileModal}
onClose={() => { onClose={() => {
this.setState({ this.setState({
showSelectFileModal:false showSelectFileModal: false,
}) });
}} }}
onSelect={this.handleSelectCover} onSelect={this.handleSelectCover}
/> />
} )}
<Modal <Modal
title="设置图片" title='设置图片'
width={1080} width={1080}
visible={visible} visible={visible}
maskClosable={false} maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>} closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
onCancel={() => { onCancel={() => {
this.setState({ visible: false }); this.setState({ visible: false });
}} }}
zIndex={10001} zIndex={10001}
footer={[ footer={[
<Button <Button
key="back" key='back'
onClick={() => { onClick={() => {
this.setState({ visible: false }); this.setState({ visible: false });
}} }}>
>
重新上传 重新上传
</Button>, </Button>,
<Button <Button
key="submit" key='submit'
type="primary" type='primary'
disabled={!hasImgReady} disabled={!hasImgReady}
onClick={() => { onClick={() => {
if (!cutFlag) { if (!cutFlag) {
...@@ -406,32 +431,29 @@ class BasicInfo extends React.Component{ ...@@ -406,32 +431,29 @@ class BasicInfo extends React.Component{
this.refs.hiddenBtn.click(); this.refs.hiddenBtn.click();
} }
this.getSignature(cutImageBlob); this.getSignature(cutImageBlob);
}} }}>
>
确定 确定
</Button>, </Button>,
]} ]}>
> <div className='clip-box'>
<div className="clip-box">
<div <div
id="headPicModal" id='headPicModal'
ref="headPicModal" ref='headPicModal'
style={{ style={{
width: "500px", width: '500px',
height: "430px", height: '430px',
marginBottom: 0, marginBottom: 0,
}} }}></div>
></div> <div id='clipBtn' style={{ display: 'none' }} ref='hiddenBtn'></div>
<div id="clipBtn" style={{ display: "none" }} ref="hiddenBtn"></div> <div className='preview-img'>
<div className="preview-img"> <div className='title'>效果预览</div>
<div className="title">效果预览</div> <div id='preview-url-box' style={{ width: 500, height: 282 }}>
<div id="preview-url-box" style={{width:500,height:282}}> <img src={this.state.dataUrl} style={{ width: '100%' }} alt='' />
<img src={this.state.dataUrl} style={{ width: '100%' }} alt="" />
</div> </div>
<div className="tip-box"> <div className='tip-box'>
<div className="tip">温馨提示</div> <div className='tip'>温馨提示</div>
<div className="tip">①预览效果图时可能存在延迟,单击左侧图片刷新即可</div> <div className='tip'>①预览效果图时可能存在延迟,单击左侧图片刷新即可</div>
<div className="tip">②设置图片时双击可旋转图片,滚动可放大或缩小图片</div> <div className='tip'>②设置图片时双击可旋转图片,滚动可放大或缩小图片</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -440,4 +462,4 @@ class BasicInfo extends React.Component{ ...@@ -440,4 +462,4 @@ class BasicInfo extends React.Component{
); );
} }
} }
export default withRouter(BasicInfo) export default withRouter(BasicInfo);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment