Commit 378b0dc2 authored by baixian's avatar baixian

优化

parent a679370e
......@@ -243,4 +243,9 @@ export default {
subjectDelete: `${dakaapi}member/website/subject/destroy`,
subjectSort: `${dakaapi}member/website/subject/subject_sort`,
},
liveClass: {
lives: `${dakaapi}member/lives`,
livesStatus: `${dakaapi}member/live/status`,
livesUrl: `${dakaapi}member/live/url`,
},
};
......@@ -210,5 +210,19 @@ export default {
},
],
},
{
id: '70',
name: '直播课堂',
key: 70,
isFather: false,
style: {
width: '20px',
height: '20px',
},
activeurl: `${__IMGCDN__}menu/crmactive.png`,
notactiveurl: `${__IMGCDN__}menu/crm.png`,
path: '/sjd/liveClass',
relativePath: ['/sjd/liveClass', '/sjd/addLive'],
},
],
};
......@@ -56,6 +56,7 @@ import addcrm from './addcrm';
import crmdetail from './crmdetail';
import holidays from './holidays';
import officialtheme from './officialtheme';
import liveclass from './liveclass';
export default {
loginModel,
indexstaicModel,
......@@ -106,4 +107,5 @@ export default {
crmdetail,
holidays,
officialtheme,
liveclass,
};
import { routerRedux } from 'dva/router';
import { message } from 'antd';
import { delay } from 'redux-saga';
import moment from 'moment';
import {
LocalStorage,
SessionStorage,
isExpired,
getRandomFilename,
} from '../utils/index';
import errorcode from '../common/errorcode';
import * as uploader from '../services/uploader';
import * as liveAjax from '../services/liveclass';
import * as themeAjax from '../services/createtheme';
export default {
namespace: 'liveclass',
state: {
liveList: [],
liveListTotal: 0,
liveListParams: {
title: '',
status: '',
page: 1,
perPage: 10,
},
addLiveObj: {
title: '',
remark: '',
secret: '',
cover: '',
live_start_time: '',
need_replay: 1,
pay_switch: 1,
status: 1,
content: [
{ type: 'editor', value: '' },
],
},
liveLoading: false,
downloadVisible: false,
liveUrlData: {},
},
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-line
},
},
effects: {
* queryinfo({ payload }, { call, put, select }) {
yield put({
type: 'queryList',
payload: {
params: {
},
},
});
},
* uEditorChange({ payload }, { call, put, select }) {
const { value } = payload;
const { addLiveObj } = yield select(state => state.liveclass);
addLiveObj.content = [{
type: 'editor',
value,
}];
yield put({
type: 'updateState',
payload: {
addLiveObj: { ...addLiveObj },
},
});
},
* queryList({ payload }, { call, put, select }) {
const { params } = payload;
const { sid } = yield select(state => state.webapp);
const { liveListParams, liveListTotal } = yield select(state => state.liveclass);
const loading = message.loading('数据加载中...', 0.5);
const newParams = Object.assign(liveListParams, params, {
school_id: sid,
});
let newTotal = liveListTotal;
const data = yield call(liveAjax.liveList, {
...newParams,
});
setTimeout(loading);
if (data.code == 200) {
if (data.data.total != undefined) {
newTotal = data.data.total;
}
yield put({
type: 'updateState',
payload: {
liveList: data.data && data.data.list,
liveListTotal: newTotal,
liveListParams: { ...newParams },
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* queryDetail({ payload }, { call, put, select }) {
const { id } = payload;
const data = yield call(liveAjax.liveDetail, {
id,
});
if (data.code == 200) {
yield put({
type: 'updateState',
payload: {
addLiveObj: {
title: data.data.title,
remark: data.data.remark,
secret: data.data.secret,
cover: data.data.cover,
live_start_time: data.data.live_start_time,
need_replay: data.data.need_replay,
pay_switch: data.data.pay_switch,
status: data.data.status,
content: JSON.parse(data.data.content),
id: data.data.id,
},
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* queryLiveUrl({ payload }, { call, put, select }) {
const { id } = payload;
const data = yield call(liveAjax.liveUrl, {
id,
});
if (data.code == 200) {
yield put({
type: 'updateState',
payload: {
liveUrlData: data.data,
downloadVisible: true,
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* deleteLive({ payload }, { call, put, select }) {
const { record } = payload;
const data = yield call(liveAjax.deleteLive, {
id: record.id,
});
if (data.code == 200) {
message.success('删除成功', 0.5);
yield put({
type: 'queryList',
payload: {
params: {
},
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* queryimagesignature({ payload }, { call, put, select }) {
const { userInfo, sid } = yield select(state => state.webapp);
const { files, uploadtype, contentSort } = payload;
const file = files.files ? files.files[0] : null;
const REGEXP_VIDEO = /^image\/\w+/;
const params = { type: 1, token: userInfo.token, schoolId: sid };
let signature = {};
if (file && (REGEXP_VIDEO.test(file.type) || file.type === '')) {
const uploaderLoading = message.loading('正在上传图片');
const uploadSignature = yield call(uploader.uploadImageSignature, params);
if (uploadSignature.code == 200) {
signature = uploadSignature.data;
yield put({
type: 'uploadimage',
payload: {
signature,
files,
uploaderLoading,
uploadtype,
contentSort,
},
});
} else {
setTimeout(uploaderLoading);
yield put({
type: 'webapp/errorrequestresolve',
payload: {
code: uploadSignature,
},
});
}
}
},
* uploadimage({ payload }, { call, put, select }) {
const {
signature, files, uploaderLoading, uploadtype,
} = payload;
const file = files.files ? files.files[0] : null;
const {
addLiveObj,
} = yield select(state => state.liveclass);
const filename = `${signature.dir}${getRandomFilename(file.name)}`;
const params = {
key: filename,
policy: signature.policy,
OSSAccessKeyId: signature.accessid,
signature: signature.signature,
file,
url: signature.host,
};
const uploadImg = yield call(uploader.uploadImg, params);
const imageUrl = filename;
if (uploadtype == 'quickCover') {
addLiveObj.cover = imageUrl;
yield put({
type: 'updateState',
payload: {
addLiveObj: { ...addLiveObj },
},
});
}
setTimeout(uploaderLoading);
},
* saveLive({ payload }, { call, put, select }) {
const { sid } = yield select(state => state.webapp);
const {
addLiveObj,
liveLoading,
} = yield select(state => state.liveclass);
if (liveLoading) {
return;
}
yield put({
type: 'updateState',
payload: {
liveLoading: true,
},
});
const newParams = { ...addLiveObj };
const {
title,
remark,
secret,
live_start_time,
need_replay,
pay_switch,
status,
callBack,
} = payload;
const loadmessage = message.loading('保存中...', 0);
const postFunction = (newParams.id != undefined) && newParams.id !== 0 ? liveAjax.editLive : liveAjax.addLive;
const data = yield call(postFunction, Object.assign(newParams,
{
school_id: sid,
title,
remark,
secret,
live_start_time,
status,
need_replay,
pay_switch,
content: JSON.stringify(newParams.content),
},
));
yield put({
type: 'updateState',
payload: {
liveLoading: false,
},
});
setTimeout(loadmessage);
if (data.code === 200) {
if (callBack && (typeof callBack == 'function')) {
callBack();
}
yield put({
type: 'updateState',
payload: {
addLiveObj: {
title: '',
remark: '',
secret: '',
cover: '',
live_start_time: '',
need_replay: 1,
pay_switch: 1,
status: 1,
content: [
{ type: 'editor', value: '' },
],
},
},
});
message.success('保存成功', 0.5);
yield delay(300);
yield put(routerRedux.goBack());
yield put({
type: 'queryLiveUrl',
payload: {
id: data.data.id,
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* changeStatus({ payload }, { call, put, select }) {
const { id, type } = payload;
const data = yield call(liveAjax.changeStatus, {
id,
status: type,
});
if (data.code == 200) {
message.success('修改成功', 0.5);
yield put({
type: 'queryList',
payload: {
params: {
},
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* goBack({ payload }, { call, put, select }) {
yield put(routerRedux.goBack());
},
* reset({ payload }, { call, put, select }) {
yield put({
type: 'queryList',
payload: {
params: {
title: '',
state: '',
page: 1,
perPage: 10,
},
},
});
},
* createLive({ payload }, { put, select }) {
yield put(routerRedux.push({
pathname: '/sjd/addLive',
}));
},
* goStartLive({ payload }, { put, select }) {
yield put({
type: 'updateState',
payload: {
downloadVisible: true,
},
});
},
* goEdit({ payload }, { put, select }) {
const { id } = payload;
yield put(routerRedux.push({
pathname: `/sjd/editLive/${id}`,
}));
},
* pageInit({ payload }, { call, put, select }) {
yield put({
type: 'updateState',
payload: {
liveList: [],
liveListTotal: 0,
liveLoading: false,
liveListParams: {
title: '',
status: '',
page: 1,
perPage: 10,
},
addLiveObj: {
title: '',
remark: '',
secret: '',
cover: '',
live_start_time: '',
need_replay: 1,
pay_switch: 1,
status: 1,
content: [
{ type: 'editor', value: '' },
],
},
downloadVisible: false,
liveUrlData: {},
},
});
},
},
reducers: {
save(state, action) {
return { ...state, ...action.payload };
},
updateState(state, action) {
return { ...state, ...action.payload };
},
},
};
......@@ -1298,6 +1298,61 @@ export default {
},
});
}
if (pathname === '/sjd/liveClass') {
dispatch({
type: 'liveclass/queryinfo',
});
dispatch({
type: 'updateState',
payload: {
breadcrumbList: [{
path: pathname,
name: '直播课堂',
}],
},
});
}
if (pathname === '/sjd/addLive') {
dispatch({
type: 'updateState',
payload: {
breadcrumbList: [
{
path: 'sjd/liveClass',
name: '直播课堂',
},
{
path: pathname,
name: '添加直播',
},
],
},
});
}
const editLiveclass = pathToRegexp('/sjd/editLive/:id').exec(pathname);
if (editLiveclass) {
dispatch({
type: 'liveclass/queryDetail',
payload: {
id: editLiveclass[1],
},
});
dispatch({
type: 'updateState',
payload: {
breadcrumbList: [
{
path: 'sjd/liveClass',
name: '直播课堂',
},
{
path: pathname,
name: '编辑直播',
},
],
},
});
}
if (pathname === '/sjd/record') {
dispatch({
type: 'classrecord/queryinfo',
......
import React from 'react';
import { connect } from 'dva';
import {
Button,
Row,
Col,
Modal,
Icon,
DatePicker,
Divider,
Form,
Input,
Card,
Select,
Table,
Pagination,
Tag,
Badge,
Tooltip,
message,
Radio, InputNumber,
} from 'antd';
import moment from 'moment';
import pageStyle from './AddLive.less';
import Editor from './components/Editor';
import { pageIn, hasBtnPower, DayCount, pricify, imagify } from '../../utils/index';
import ThemeEditor from '../onlineclasses/ThemeEditor';
const { Option } = Select;
const FormItem = Form.Item;
const { RangePicker } = DatePicker;
const { TextArea } = Input;
class AddCrmForm extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.editorref = React.createRef();
}
componentDidMount() { // 挂载
const { dispatch } = this.props;
pageIn('直播课堂');
dispatch({
type: 'webapp/querymemberinfo',
});
}
componentDidUpdate() {
}
componentWillUnmount() { // 卸载
}
save = (e) => {
const { dispatch, form } = this.props;
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
const {
title,
remark,
cover,
secret,
live_start_time,
need_replay,
pay_switch,
status,
} = values;
dispatch({
type: 'liveclass/saveLive',
payload: {
title,
remark,
cover,
secret: Number(pay_switch) == 1 ? secret : '',
live_start_time: live_start_time.format('YYYY-MM-DD HH:mm:ss'),
need_replay,
pay_switch,
status,
callBack: () => {
form.resetFields();
},
},
});
}
});
}
goBack = () => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/goBack',
});
}
uEditorChange = (value) => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/uEditorChange',
payload: {
value,
},
});
}
uploadCover = (e) => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/queryimagesignature',
payload: {
files: e.target,
uploadtype: 'quickCover',
},
});
}
render() {
const {
form: { getFieldDecorator, getFieldValue },
addLiveObj,
collapsed,
screenIsBig,
liveLoading,
} = this.props;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 3 },
md: { span: 3 },
lg: { span: 3 },
xl: { span: 2 },
xxl: { span: 2 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 21 },
md: { span: 21 },
lg: { span: 21 },
xl: { span: 22 },
xxl: { span: 21 },
},
};
const radioStyle = {
height: '30px',
lineHeight: '30px',
};
return (
<div className={pageStyle.container}>
<div className={pageStyle.topTip}>查看教程</div>
<div className={pageStyle.headerWrap}>
<div className={pageStyle.commonTitle}><span className={pageStyle.line} />基本信息</div>
<Form hideRequiredMark labelAlign="left" onSubmit={this.save}>
<FormItem {...formItemLayout} label="直播名称">
{getFieldDecorator('title', {
initialValue: addLiveObj.title,
rules: [
{ required: true, message: '请填写直播名称!' },
{ max: 40, message: '直播名称字数不能超过40位!' },
],
})(
<Input style={{ width: 490 }} placeholder="请输入直播名称" />,
)}
</FormItem>
<FormItem {...formItemLayout} label="直播简介">
{getFieldDecorator('remark', {
initialValue: addLiveObj.remark,
})(
<TextArea
style={{ width: 490 }}
placeholder="请填写直播简介"
rows={4}
/>,
)}
</FormItem>
<FormItem {...formItemLayout} label="直播时间">
<span className="ant-form-text">开始时间</span>
{getFieldDecorator('live_start_time', {
initialValue: addLiveObj.live_start_time ? moment(addLiveObj.live_start_time) : undefined,
rules: [
{ required: true, message: '请选择直播开始时间!' },
],
})(
<DatePicker disabled={addLiveObj.id != undefined && addLiveObj.id} showTime placeholder="请选择直播开始时间" />,
)}
</FormItem>
<FormItem {...formItemLayout} label="封面图">
<div className={pageStyle.imgWrap}>
<div className={pageStyle.imgLeft}>
{
addLiveObj.cover != '' ?
<img className={pageStyle.coverimg} src={imagify(addLiveObj.cover)} alt="" /> :
<div className={pageStyle.imgBox}>
<img className={pageStyle.defaultImg} src={`${__IMGCDN__}liveclass/defalutImg.png`} alt="" />
</div>
}
</div>
<div className={pageStyle.imgRight}>
<Button type="primary" ghost className={pageStyle.uploadImg}>
<input
type="file"
className={pageStyle.uploadInput}
accept="image/png, image/jpeg"
id="upload1"
onChange={(e) => { this.uploadCover(e); }}
/>
<span>选择文件</span>
</Button>
<div className={pageStyle.imgTip}>建议尺寸750*560px43JPGPNG 格式, 图片小于5M <span>查看示例</span></div>
</div>
</div>
</FormItem>
<FormItem {...formItemLayout} label="直播详情">
<Editor
ref={this.editorref.current}
uEditorCallback={this.uEditorCallback}
uEditorChange={this.uEditorChange}
commentParams={JSON.parse(JSON.stringify(addLiveObj))}
/>
</FormItem>
<div className={pageStyle.commonTitle}><span className={pageStyle.line} />售卖设置</div>
<FormItem {...formItemLayout} label="" className={pageStyle.radioWrap}>
{getFieldDecorator('pay_switch', {
initialValue: Number(addLiveObj.pay_switch),
})(
<Radio.Group>
<Radio style={radioStyle} value={1}>
<div className={pageStyle.radioList}>
<span className={pageStyle.radioName}>加密 </span>
{getFieldValue('pay_switch') === 1 ? (
<FormItem {...formItemLayout} label="">
<span className="ant-form-text">设置密码</span>
{getFieldDecorator('secret', {
initialValue: addLiveObj.secret,
rules: [
{ required: true, message: '密码不能为空' },
{
message: '请输入正整数',
pattern: new RegExp(/^[1-9]\d*$/, 'g'),
},
],
})(<Input maxLength={6} style={{ width: 144 }} placeholder="设置密码" />,
)}
</FormItem>
) : (
''
)}
</div>
</Radio>
<Radio style={radioStyle} value={2}><span className={pageStyle.radioName}>免费</span></Radio>
</Radio.Group>,
)}
</FormItem>
<div className={pageStyle.commonTitle}><span className={pageStyle.line} />直播回放设置</div>
<FormItem {...formItemLayout} label="" className={pageStyle.radioWrap}>
{getFieldDecorator('need_replay', {
initialValue: Number(addLiveObj.need_replay),
})(
<Radio.Group>
<Radio style={radioStyle} value={1}><span className={pageStyle.radioName}>开启回放</span><span className={pageStyle.radioTip}>开启回放,直播结束后直播间将播放回放视频</span></Radio>
<Radio style={radioStyle} value={2}><span className={pageStyle.radioName}>关闭回放</span><span className={pageStyle.radioTip}>关闭回放,直播结束后直播间不播放回放视频</span></Radio>
</Radio.Group>,
)}
</FormItem>
<div className={pageStyle.commonTitle}><span className={pageStyle.line} />上架设置</div>
<FormItem {...formItemLayout} label="" className={pageStyle.radioWrap}>
{getFieldDecorator('status', {
initialValue: Number(addLiveObj.status),
})(
<Radio.Group>
<Radio style={radioStyle} value={1}>
<span className={pageStyle.radioName}>暂不上架</span>
</Radio>
<Radio style={radioStyle} value={2}><span className={pageStyle.radioName}>立即上架</span></Radio>
</Radio.Group>,
)}
</FormItem>
<div
className={pageStyle.footerBox}
style={{
left: screenIsBig ? (!collapsed ? '193px' : '102px') : 0, // eslint-disable-line
width: screenIsBig ? (`calc(100% - ${!collapsed ? '214px' : '122px'})`) : '100%', // eslint-disable-line
}}
>
<div>
<Button style={{ marginRight: 10 }} onClick={this.goBack}>返回</Button>
<Button type="primary" loading={liveLoading} htmlType="submit">保存</Button>
</div>
</div>
</Form>
</div>
</div>
);
}
}
const AddCrm = Form.create()(AddCrmForm);
AddCrmForm.propTypes = {
};
function mapStateToProps(state) {
const {
addLiveObj,
liveLoading,
} = state.liveclass;
const { schoolUserInfo, collapsed, screenIsBig } = state.webapp;
return {
schoolUserInfo,
collapsed,
screenIsBig,
addLiveObj,
liveLoading,
};
}
export default connect(mapStateToProps)(AddCrm);
@import '../../less/variables.less';
.container {
background-color: #fff;
border-radius: 2px;
padding:20px;
padding-bottom: 50px;
}
.topTip {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(33,148,255,1);
padding-bottom: 20px;
}
.headerWrap {
.commonTitle {
font-size:16px;
font-family:PingFangSC-Medium,PingFang SC;
font-weight:600;
line-height: 24px;
color:rgba(0,0,0,0.85);
margin-bottom: 20px;
.line {
width: 3px;
height: 19px;
background-color: #1890FF;
display: inline-block;
vertical-align: -10%;
margin-right: 6px;
}
}
:global {
.ant-form-item {
margin-bottom: 20px;
}
}
}
.addMobile {
font-size:13px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(24,144,255,1);
line-height:18px;
cursor: pointer;
display: inline-block;
margin-left: 10px;
}
.mobileTip {
font-size:12px;
font-weight:400;
color:rgba(153,153,153,1);
line-height:17px;
margin-bottom: 0;
}
.imgWrap {
display: flex;
.imgLeft {
width: 200px;
height: 150px;
margin-right: 20px;
.coverimg {
width: 100%;
height: 100%;
}
.imgBox {
width: 200px;
height: 150px;
background-color: #F7F8F9;
border: 1px solid #E6E6E6;
border-radius: 6px;
text-align: center;
line-height: 150px;
.defaultImg {
width: 32px;
height: 28px;
}
}
}
.imgRight {
.uploadImg {
position: relative;
width: 100px;
height: 40px;
cursor: pointer;
.uploadInput {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
opacity: 0;
z-index: 5;
}
}
.imgTip {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(143,143,143,1);
width: 270px;
&>span {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(24,144,255,1);
cursor: pointer;
}
}
}
}
.radioWrap {
width: 100%;
:global {
.ant-form-item-children {
width: 100%;
}
.ant-radio-wrapper {
width: 100%;
display: flex;
align-items: center;
}
.ant-form-item {
margin-bottom: 0px;
}
}
.radioList {
display: flex;
align-items: center;
}
.radioName {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(51,51,51,1);
display: inline-block;
margin-right: 20px;
}
.radioTip {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(143,143,143,1);
}
}
.footerBox {
position: fixed;
bottom: 0;
background-color: #fff;
padding: 20px 20px 14px 20px;
width: 100%;
box-shadow:1px -6px 6px 0px rgba(0, 0, 0, 0.04);
transition: 0.2s left;
transition: 0.1s width;
z-index: 20;
text-align: left;
}
import { connect } from 'dva';
import React from 'react';
import PropTypes from 'prop-types';
import { message, Row, Col, Input, Select, Modal, Form, InputNumber, Checkbox, Radio, Tabs } from 'antd';
import ClipboardJS from 'clipboard';
import { imagify, pageIn } from '../../utils/index';
import pageStyle from './DownloadModal.less';
const FormItem = Form.Item;
const { TabPane } = Tabs;
class DownloadModal extends React.Component {
componentWillMount() {
}
componentDidUpdate() {
}
componentWillUpdate() {
}
componentDidMount() { // 挂载
pageIn('直播课堂');
this.clipboard = new ClipboardJS('#btnCopyLink1'); // 点击按钮复制到粘贴板
this.clipboard = new ClipboardJS('#btnCopyLink2');
this.clipboard = new ClipboardJS('#btnCopyLink3');
this.clipboard.on('success', () => {
message.success('复制成功', 0.5);
});
}
componentWillUnmount() { // 卸载
}
close = () => {
const { form, close } = this.props;
close();
}
render() {
const {
visible,
form: { getFieldDecorator, getFieldValue },
liveUrlData,
} = this.props;
return (
<Modal
className={pageStyle.modalWrap}
visible={visible}
onCancel={this.close}
maskClosable={false}
zIndex={110}
width={800}
bodyStyle={{ borderRadius: 8 }}
footer={
<div className={pageStyle.footerTip}>
*若上述下载失败或要下载最新版请到OBS软件官网进行下载:https://obsproject.com/
</div>
}
>
<div className={pageStyle.wrap}>
<div className={pageStyle.title}>直播间创建成功,快去OBS直播客户端开始学员讲课吧</div>
<div className={pageStyle.titleTip}>说明:OBS是讲师进行直播推流使用的第三方软件,助教可以配合网页/h5进行直播评论互动,详情操作 查看 <span>OBS直播使用教程</span></div>
<div className={pageStyle.stepOne}>
<span>1</span>OBS推
</div>
<div className={pageStyle.stepWrap}>
<div className={pageStyle.stepText}>(1) OBS推流工具下载</div>
<div className={pageStyle.downloadType}>
<div className={pageStyle.downloadItem}>
<img className={pageStyle.macImg} src={`${__IMGCDN__}liveclass/mac.png`} alt="" />
<div className={pageStyle.downloadItemRight}>
<span>Mac</span>
<span className={pageStyle.dowloadSize}>下载</span>
</div>
</div>
<div className={pageStyle.downloadItem}>
<img className={pageStyle.windowsImg} src={`${__IMGCDN__}liveclass/windows.png`} alt="" />
<div className={pageStyle.downloadItemRight}>
<span>Mac</span>
<span className={pageStyle.dowloadSize}>下载</span>
</div>
</div>
</div>
<div className={pageStyle.stepText}>(2) 推流信息 <span>OBS软件中输入以下URL与流名称,根据桌面共享直播使用教程配置开启直播</span></div>
<div className={pageStyle.copyWrap}>
<div className={pageStyle.copyRight}>URL</div>
<div className={pageStyle.copyBox} id="copy1">{liveUrlData.stream_url}</div>
<div className={pageStyle.copyButton} data-clipboard-target="#copy1" id="btnCopyLink1">复制</div>
</div>
<div className={pageStyle.copyWrap}>
<div className={pageStyle.copyRight}>流名称</div>
<div className={pageStyle.copyBox} id="copy2">{liveUrlData.stream_name}</div>
<div className={pageStyle.copyButton} data-clipboard-target="#copy2" id="btnCopyLink2">复制</div>
</div>
</div>
<div className={pageStyle.stepOne} style={{ marginTop: 16 }}>
<span>2</span>网页端地
<div className={pageStyle.copyWrap} style={{ marginTop: 0, marginLeft: 47 }}>
<div className={pageStyle.copyBox} id="copy3">https://www.baidu.com/</div>
<div className={pageStyle.copyButton} data-clipboard-target="#copy3" id="btnCopyLink3">复制</div>
</div>
</div>
<p className={pageStyle.webTip} >复制链接在网页直接打开</p>
</div>
</Modal>
);
}
}
const Download = Form.create()(DownloadModal);
export default Download;
.wrap {
.title {
font-size:16px;
font-family:PingFang SC;
font-weight:bold;
color:rgba(0,0,0,1);
position: relative;
text-align: center;
&:after {
position: absolute;
content: '';
display: block;
width: 34px;
height: 4px;
background-color: #1890FF;
border-radius: 2px;
left: 50%;
bottom: -10px;
}
}
.titleTip {
margin: 30px 0;
font-size: 14px;
color: #888;
&>span {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(128,128,128,1);
text-align: center;
}
}
}
.stepOne {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(0,0,0,1);
display: flex;
align-items: center;
&>span {
width: 19px;
height: 19px;
border-radius: 50%;
background-color: #3699FF;
display: inline-block;
line-height: 19px;
text-align: center;
color: #fff;
margin-right: 13px;
}
}
.stepWrap {
margin-left: 35px;
.stepText {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(0,0,0,1);
line-height:26px;
margin: 18px 0 20px;
&>span {
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(128,128,128,1);
}
}
.downloadType {
display: flex;
justify-content: center;
align-items: center;
.downloadItem {
display: flex;
&:first-child {
margin-right: 80px;
}
.macImg {
width: 47px;
height: 57px;
}
.windowsImg {
width: 52px;
height: 50px;
}
.downloadItemRight {
margin-left: 25px;
&>span {
display: block;
margin-bottom: 10px;
font-size:14px;
font-family:PingFang SC;
font-weight:400;
color:rgba(0,0,0,1);
}
.dowloadSize {
width: 41px;
height: 23px;
margin-bottom: 22px;
border: 1px solid #BFBFBF;
text-align: center;
line-height: 23px;
}
}
}
}
}
.copyWrap {
margin-top: 16px;
margin-left: 52px;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
.copyRight {
width: 42px;
margin-right: 20px;
height: 17px;
font-family: PingFangSC-Regular;
font-weight: 400;
color: #353535;
line-height: 17px;
}
.copyBox {
padding: 0 8px;
width: 388px;
background: #f5f7fa;
border-radius: 4px 0 0 4px;
border: 1px solid #9EAABA;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 36px;
font-size: 14px;
font-weight: 400;
color: #808080;
line-height: 34px;
}
.copyButton {
font-size: 14px;
width: 64px;
height: 36px;
background: #3699FF;
border-radius: 0px 4px 4px 0px;
color: white;
display: -webkit-flex;
display: flex;
-webkit-justify-content: center;
justify-content: center;
-webkit-align-items: center;
align-items: center;
cursor: pointer;
}
}
.modalWrap {
:global {
.ant-modal-footer {
padding: 0;
}
}
}
.footerTip {
background-color: #EFEFEF;
font-size:12px;
font-family:PingFang SC;
font-weight:400;
color:rgba(128,128,128,1);
line-height:35px;
height: 35px;
text-align: center;
}
.webTip {
margin-left: 150px;
margin-top: 15px;
}
import { connect } from 'dva';
import React from 'react';
import { Icon, Divider, Tabs, Select, Form, Upload, Row, Col, Input, Radio, Modal, message } from 'antd';
import pageStyle from './Editor.less';
import api from '../../../common/api';
import { pageIn, hasBtnPower, LocalStorage, imagify, ossVideofy, audioorigin } from '../../../utils/index';
const upImg = `${__IMGCDN__}subjectUp.png`;
const { TabPane } = Tabs;
const { TextArea } = Input;
class Editor extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
clearHtml = () => {
if (this.uEditor) {
this.uEditor.execCommand('cleardoc');
}
}
componentWillUnmount() {
if (this.uEditor) {
this.uEditor.destroy();
}
clearTimeout(this.timeout2);
clearTimeout(this.setTimeout3);
}
componentDidMount() { // 挂载
this.renderEditor();
}
renderEditor = () => {
const { sid, commentParams } = this.props;
const that = this;
if (UE && document.getElementById('editor_id')) {
that.uEditor = UE.getEditor('editor_id', {
autoHeightEnabled: false,
zIndex: 10,
allowDivTransToP: false,
// UEDITOR_HOME_URL: '../../js/ueeditor/',
materiaImgUrl: api.courseMateria.index,
materiaImgParams: {
school_id: LocalStorage.getItem('sid') || 0,
type: 1,
// page: 1
// perPage: 12
trans_status: 2,
},
elementPathEnabled: false,
requestUser: LocalStorage.getItem('user') || {},
serverUrl: api.editorUpload,
imageFieldName: 'file',
initialFrameHeight: 300,
removeFormatAttributes: 'class,style,lang,width,height,align,hspace,valign',
toolbars: [
[
'source', // 源代码
'undo', // 撤销
'redo', // 重做
'fontsize', // 字号
'forecolor', // 字体颜色
'bold', // 加粗
'italic', // 斜体
'underline', // 下划线
// 'strikethrough', // 删除线
// 'subscript', // 下标
// 'superscript', // 上标
// 'blockquote', // 引用
// 'pasteplain', // 纯文本粘贴模式
// 'horizontal', // 分隔线
// 'removeformat', // 清除格式
// 'unlink', // 取消链接
'inserttitle', // 插入标题
'simpleupload', // 单图上传
'insertimage', // 多图上传
// 'link', // 超链接
'emotion', // 表情
'spechars', // 特殊字符
'searchreplace', // 查询替换
// 'map', // Baidu地图
// 'insertvideo', // 视频
'justifyleft', // 居左对齐
'justifyright', // 居右对齐
'justifycenter', // 居中对齐
'justifyjustify', // 两端对齐
// 'fullscreen', // 全屏
'imagecenter', // 居中
'edittip ', // 编辑提示
// 'customstyle', // 自定义标题
// 'background', // 背景
// 'scrawl', // 涂鸦
// 'music', // 音乐
// 'inserttable', // 插入表格
// 'drafts', // 从草稿箱加载
// 'charts', // 图表
// 'fontfamily', // 字体
// 'insertcode', // 代码语言
'insertorderedlist', // 有序列表
// 'insertunorderedlist', // 无序列表
'lineheight', // 行间距
'rowspacingtop', // 段前距
'rowspacingbottom', // 段后距
'backcolor', // 背景色
// 'preview', // 预览
],
],
});
that.timeout2 = setTimeout(() => {
if (document.getElementById('editor_id')) {
const { sid, commentParams } = that.props;
if (commentParams.content && commentParams.content.length == 1) {
if (commentParams.content[0].type == 'editor' && commentParams.content[0].value != '') {
that.uEditor.ready(() => {
that.uEditor.setContent(commentParams.content[0].value);
});
}
}
}
that.uEditor.ready(() => {
that.uEditor.setHeight(600);
that.uEditor.addListener('contentChange', () => {
that.props.uEditorChange(this.uEditor.getContent());
});
});
}, 800);
} else {
that.setTimeout3 = setTimeout(() => {
that.renderEditor();
}, 200);
}
}
render() {
const {
commentParams,
} = this.props;
return (
<div className={pageStyle.container}>
<div className="clearfix">
<div className={pageStyle.editorwrap} style={{ float: 'left' }}>
{/* eslint-disable-next-line array-callback-return,consistent-return */}
{commentParams.content.map((item, index) => {
// eslint-disable-next-line default-case
switch (item.type) {
case 'editor':
return (
<div key={index} className={pageStyle.editorwrap}>
<textarea id="editor_id" name="content" style={{ width: '700px', height: '300px' }}>
</textarea>
<div className={pageStyle.extraoperatebox}>
<div className={pageStyle.extraoperateitem} onClick={this.clearHtml}>
<img alt="" className={pageStyle.del} src={`${__IMGCDN__}coursetemplate/del.png`} />
<span>清空内容</span>
</div>
{/* <div className={pageStyle.extraoperateitem} onClick={this.reviewHtml}> */}
{/* <img alt="" className={pageStyle.mobile} src={`${__IMGCDN__}coursetemplate/mobile.png`} /> */}
{/* <span>手机预览</span> */}
{/* </div> */}
</div>
</div>
);
}
},
)}
</div>
</div>
</div>
);
}
}
Editor.propTypes = {
};
export default connect()(Editor);
.textWrap {
height: auto;
position: relative;
margin-bottom:10px;
:global {
.ant-input {
padding: 6px 15px 20px;
}
}
.sizeNumber {
position: absolute;
bottom: 8px;
right: 10px;
}
}
.templatesbox {
line-height: initial;
width: 282px;
border:1px solid rgba(0,0,0,0.15);
.templatesheader {
background-color: #D9D9D9;
line-height: 37px;
color: #616161;
font-size: 16px;
text-align: center;
}
.templatesbody {
padding: 9px;
max-height: 550px;
overflow-y: scroll;
.templatesitem {
margin-bottom: 12px;
.imgbox {
width: 100%;
height: 135px;
border-radius: 6px;
overflow: hidden;
position: relative;
img {
height: 135px;
display: block;
width: 100%;
}
&:hover .templateoperate {
display: flex;
}
.templateoperate {
display: none;
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
left: 0;
top: 0;
z-index: 1;
// display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
.operateitem {
letter-spacing: 1px;
line-height: 40px;
color: #FFFFFF;
font-size: 14px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
.operateicon {
margin-right: 4px;
}
&.preview {
.operateicon {
width: 16px;
height: 12px;
}
}
&.use {
.operateicon {
width: 16px;
height: 16px;
}
}
cursor: pointer;
&:hover {
background-color: rgba(0,0,0,0.5);
}
}
}
}
.templatename {
color: #616161;
font-size: 12px;
text-align: center;
margin-top: 4px;
}
}
}
}
.editorwrap {
// width: 424px;
// margin-top: 15px;
position: relative;
.extraoperatebox {
line-height: initial;
position: absolute;
top: 0;
width: 105px;
right: -105px;
z-index: 5;
.extraoperateitem {
background: #404040;
-webkit-border-radius: 3px;
border-radius: 3px;
color: #fff;
padding: 6px 19px;
margin-bottom: 14px;
cursor: pointer;
font-size: 12px;
margin-bottom: 10px;
display: flex;
align-items: center;
.del {
width: 14px;
height: 16px;
display: block;
margin-right: 3px;
}
.mobile {
width: 10px;
height: 14px;
display: block;
margin-left: 2px;
margin-right: 5px;
}
}
}
.videowrap {
width: 100%;
height: 200px;
position: relative;
margin-bottom: 10px;
.videoPoster {
width: 100%;
height: 100%;
}
}
.videowrap:hover {
cursor: pointer;
.videohide {
opacity: 1;
background-color: rgba(0,0,0,0.5);
transition: all .3s;
z-index: 1;
color: #fff;
}
}
.videohide {
position: absolute;
width: 100%;
height: 100%;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
color: #fff;
z-index: -1;
a {
color: #fff;
}
}
.uploadimgbox {
display: flex;
align-items: flex-end;
margin-bottom: 18px;
flex-wrap: wrap;
.imgwrap {
width: 100%;
// height: 120px;
border-radius: 4px;
// margin-right: 6px;
position: relative;
.uploadimgwrap {
width: 100%;
// height: 120px;
overflow: hidden;
}
}
.imgwrap:hover {
cursor: pointer;
.imghide {
opacity: 1;
background-color: rgba(0,0,0,0.5);
transition: all .3s;
z-index: 1;
color: #fff;
}
}
.imghide {
position: absolute;
width: 100%;
height: 100%;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
color: #fff;
z-index: -1;
a {
color: #fff;
}
}
.teacheruploadimg {
object-fit: contain;
border-radius: 4px;
width: 100%;
}
.teacheruploadimg:nth-child(4n){
margin-right: 0;
}
}
}
.uploadflex {
display: flex;
align-items: center;
.uploadimg {
cursor: pointer;
width: 106px;
height: 32px;
line-height: 32px;
text-align: center;
border: 1px solid #D9D9D9;
border-radius: 4px;
color: rgba(0,0,0,0.65);
position: relative;
margin-right: 30px;
.fileuploadinput {
cursor: pointer;
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0;
left: 0;
top: 0;
}
}
}
.toolList {
position: absolute;
right: -30px;
top: 0;
width: 30px;
height: 90px;
display: flex;
flex-direction: column;
background-color: #D3D3D3;
opacity: 0;
border-radius: 2px;
z-index: -1;
div {
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 14px;
cursor: pointer;
}
div>img {
width: 14px;
height: 14px;
}
.up:hover {
background-color: #1890FF;
}
.down,.nodown {
transform: rotate(180deg);
}
.nodown,.noup {
cursor: not-allowed;
}
.down:hover {
background-color: #1890FF;
}
.delete:hover {
background-color: #FF6060;
}
}
.textWrap:hover,.imgwrap:hover,.videowrap:hover {
.toolList {
opacity: 1;
z-index: 1;
}
}
import { connect } from 'dva';
import React from 'react';
import {
Icon,
Button,
Row,
Col,
Input,
Select,
Checkbox,
Table,
Modal,
Form,
Alert,
Radio,
message,
Pagination,
Tooltip, DatePicker,
Divider,
} from 'antd';
import moment from 'moment';
import { routerRedux } from 'dva/router';
import pageStyle from './index.less';
import DownloadModal from './DownloadModal';
import { pageIn, hasBtnPower, btnPermission, translateType } from '../../utils/index';
import BtnPermission from '../../components/BtnPermission';
const { Option } = Select;
const { TextArea } = Input;
const { Search } = Input;
const { RangePicker } = DatePicker;
class LiveClass extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidMount() { // 挂载
pageIn('直播课堂');
}
disabledDate = (current) => {
return current && current > moment();
}
componentWillUnmount() { // 卸载
}
sizeChange = (page, perPage) => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/queryList',
payload: {
params: {
page: 1,
perPage,
},
},
});
}
changePagination = (page, perPage) => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/queryList',
payload: {
params: {
page,
perPage,
},
},
});
}
searchParamsChange = (e, type, key) => {
const { dispatch } = this.props;
let getvalue = '';
if (type == 'Input') {
getvalue = e;
} else if (type == 'Select') {
getvalue = e;
}
dispatch({
type: 'liveclass/queryList',
payload: {
params: {
page: 1,
[key]: getvalue || '',
},
},
});
}
reset = () => {
const { dispatch } = this.props;
// eslint-disable-next-line react/no-string-refs
this.refs.searchBar.input.state.value = '';
dispatch({
type: 'liveclass/reset',
});
}
createLive = () => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/createLive',
});
}
goEdit = (id) => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/goEdit',
payload: {
id,
},
});
}
deleteLive = (record) => {
const { dispatch } = this.props;
Modal.confirm({
title: '确定删除这个课程吗?',
content: '删除后不可恢复,请谨慎操作!',
okText: '确定',
cancelText: '取消',
icon: <Icon type="close-circle" style={{ color: 'red' }} />,
onOk() {
dispatch({
type: 'liveclass/deleteLive',
payload: {
record,
},
});
},
okButtonProps: {
type: 'danger',
style: {
color: '#fff',
backgroundColor: '#ff4d4f',
borderColor: '#ff4d4f',
},
},
});
}
goStartLive = (record) => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/queryLiveUrl',
payload: {
id: record.id,
},
});
}
closeDownload = () => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/updateState',
payload: {
downloadVisible: false,
},
});
}
changeStatus = (type, record) => {
const { dispatch } = this.props;
dispatch({
type: 'liveclass/changeStatus',
payload: {
type,
id: record.id,
},
});
}
render() {
const {
userPermission,
liveList,
liveListTotal,
liveListParams,
downloadVisible,
liveUrlData,
} = this.props;
const columns = [
{
title: '课程名称',
dataIndex: 'title',
key: 'title',
},
{
title: '创建时间',
dataIndex: 'created_at',
key: 'created_at',
},
{
title: '直播时间',
dataIndex: 'live_start_time',
key: 'live_start_time',
},
{
title: '直播状态',
dataIndex: 'live_status',
key: 'live_status',
render: (text, record) => {
return (
<div className={pageStyle.typeColor}>
{text == 1 && <div className={pageStyle.typeColor1}><span className={pageStyle.point}></span>待直播</div> }
{text == 2 && <div className={pageStyle.typeColor2}><span className={pageStyle.point}></span>直播中</div>}
{text == 3 && <div className={pageStyle.typeColor3}><span className={pageStyle.point}></span>直播中</div>}
{text == 4 && <div className={pageStyle.typeColor4}><span className={pageStyle.point}></span>已下架</div>}
</div>
);
},
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
render: (text, record) => {
return (
<div className={pageStyle.typeColor}>
{text == 1 && <div className={pageStyle.typeColor1}><span className={pageStyle.point}></span>待上架</div> }
{text == 2 && <div className={pageStyle.typeColor2}><span className={pageStyle.point}></span>已上架</div>}
{text == 3 && <div className={pageStyle.typeColor3}><span className={pageStyle.point}></span>已下架</div>}
</div>
);
},
},
{
title: '操作',
dataIndex: 'c',
key: 'c',
render: (text, record) => {
return (
<div className={pageStyle.tableoperatebox}>
<span className="hreflink" onClick={() => this.goEdit(record.id)}>编辑</span>
<Divider type="vertical" />
{
record.status == 1 && <span className="hreflink" onClick={() => this.changeStatus(2, record)}>上架</span>
}
{
record.status == 2 && <span className="hreflink" onClick={() => this.changeStatus(3, record)}>下架</span>
}
{
record.status == 3 && <span className="hreflink" onClick={() => this.changeStatus(2, record)}>上架</span>
}
<Divider type="vertical" />
<span className="hreflink">分享直播间</span>
{
record.status == 2 && <span className="hreflink" onClick={() => this.goStartLive(record)}><Divider type="vertical" />去直播</span>
}
{
record.replay_url != '' && <span className="hreflink">直播回放<Divider type="vertical" /></span>
}
<span className="hreflink" onClick={() => this.deleteLive(record)}><Divider type="vertical" />删除</span>
</div>
);
},
},
];
return (
<div className={pageStyle.container}>
<div className={pageStyle.headerbox}>
<Button size="small" style={{ marginRight: 20 }} type="primary" onClick={this.createLive}>创建直播</Button>
<span className={pageStyle.headerbtn}>查看直播教程</span>
</div>
<div className={pageStyle.searchbox}>
<Row
gutter={{
sm: 24, xs: 24, md: 24, lg: 24,
}}
className={pageStyle.searchrow}
>
<Col xs={{ span: 19 }} sm={{ span: 19 }} md={{ span: 19 }} lg={{ span: 19 }} xl={{ span: 19 }}>
<Row
gutter={{
sm: 24, xs: 24, md: 24, lg: 24,
}}
className={pageStyle.formList}
>
<Col className={pageStyle.formitem} xs={{ span: 12 }} sm={{ span: 12 }} md={{ span: 12 }} lg={{ span: 8 }} xl={{ span: 8 }}>
<div className={pageStyle.formitemlabel}>课程名称:</div>
{/* eslint-disable-next-line react/no-string-refs */}
<Search allowClear style={{ width: '100%' }} ref="searchBar" placeholder="请输入课程标题" onSearch={e => this.searchParamsChange(e, 'Input', 'title')} />
</Col>
<Col className={pageStyle.formitem} xs={{ span: 12 }} sm={{ span: 12 }} md={{ span: 12 }} lg={{ span: 8 }} xl={{ span: 8 }}>
<div className={pageStyle.formitemlabel} >全部状态:</div>
<Select allowClear style={{ width: '100%', overflow: 'hidden' }} className={pageStyle.selectitem} onChange={e => this.searchParamsChange(e, 'Select', 'status')} placeholder="全部">
<Option value="">全部</Option>
<Option value={1}>待上架</Option>
<Option value={2}>已上架</Option>
<Option value={3}>已下架</Option>
</Select>
</Col>
<Col className={pageStyle.formitem} xs={{ span: 12 }} sm={{ span: 12 }} md={{ span: 12 }} lg={{ span: 8 }} xl={{ span: 8 }}>
<div className={pageStyle.rightList}>
<Tooltip title="清空筛选">
<img onClick={this.reset} className={pageStyle.resetIcon} src={`${__IMGCDN__}common/reset.png`} alt="" />
</Tooltip>
</div>
</Col>
</Row>
</Col>
</Row>
</div>
<div className={pageStyle.tablebox}>
<Table
rowKey="id"
dataSource={liveList}
columns={columns}
scroll={{ x: 'max-content' }}
pagination={false}
bordered
footer={null}
/>
<div className={pageStyle.tablefooterbox}>
<span className={pageStyle.tablefooterstatic}>{liveListTotal}条数据</span>
<Pagination
showSizeChanger
showQuickJumper
onShowSizeChange={this.sizeChange}
total={Number(liveListTotal)}
onChange={this.changePagination}
current={Number(liveListParams.page) || 1}
pageSize={liveListParams.perPage}
/>
</div>
</div>
<DownloadModal
visible={downloadVisible}
close={this.closeDownload}
liveUrlData={liveUrlData}
/>
</div>
);
}
}
LiveClass.propTypes = {
};
const LiveClassForm = Form.create()(LiveClass);
function mapStateToProps(state) {
const {
liveList,
liveListTotal,
liveListParams,
downloadVisible,
liveUrlData,
} = state.liveclass;
const {
guideStep,
guideShow,
} = state.userguide;
const {
userPermission,
schoolUserInfo,
} = state.webapp;
return {
userPermission,
guideStep,
guideShow,
schoolUserInfo,
liveList,
liveListTotal,
liveListParams,
downloadVisible,
liveUrlData,
};
}
export default connect(mapStateToProps)(LiveClassForm);
@import '../../less/variables.less';
.container {
background-color: #fff;
border-radius: 2px;
padding: 20px;
}
.headerbox{
background-color: #fff;
.headerbtn {
color: #2194FF;
font-size: 14px;
cursor: pointer;
}
padding-bottom: 18px;
}
.searchrow {
.formitem {
display: flex;
align-items: center;
margin-bottom: 16px;
.formitemlabel {
color: #000000;
font-size: 14px;
line-height: 1;
min-width: 70px;
white-space: nowrap;
}
}
}
.selectitem {
display: block;
}
.searchbtnbox {
height: 54px;
display: flex;
align-items: flex-end;
}
.resetbtn {
margin-right: 16px;
}
.tablebox {
background: #fff;
:global {
.ant-table-fixed {
border-bottom: 1px solid #E8E8E8 !important;
}
.ant-table tbody tr:nth-child(2n) {
background-color: #FBFBFB;
}
.ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 11px 10px;
}
.ant-table-bordered .ant-table-tbody tr td {
border-bottom: none;
border-right: none!important;
}
.ant-table-bordered .ant-table-thead tr th {
border-bottom: none;
border-right: none!important;
}
.ant-table-bordered .ant-table-thead tr th:last-child {
border-right: 1px solid #e8e8e8!important;
}
.ant-table-bordered .ant-table-tbody tr td:last-child {
border-right: 1px solid #e8e8e8!important;
}
.ant-table-bordered .ant-table-tbody tr:last-child {
border-bottom: 1px solid #e8e8e8!important;
}
}
}
.divideline {
color: #E9E9E9;
padding: 0 8px;
}
.alink {
color: #1890FF;
}
.classNamebox {
max-width: 250px;
word-break: break-all;
color: #1890FF;
cursor: pointer;
}
.tableoperatebox {
min-width: 160px;
line-height: 30px;
}
.endsearchcol {
margin-bottom: 18px;
}
.endclassfooter {
display: flex;
align-items: center;
justify-content: space-between;
}
.classroomitem {
margin-bottom: 5px;
.classroom {
color:rgba(0,0,0,0.85);
}
.aLink {
color: #1890FF;
padding-left: 21px;
}
}
.rightList {
display: flex;
align-items: center;
height: 32px;
.resetIcon {
width: 14px;
height: 14px;
cursor: pointer;
margin-right: 15px;
}
.expend {
font-size:13px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(102,102,102,1);
display: inline-block;
cursor: pointer;
}
}
.tablefooterbox {
color: rgba(0,0,0,0.6);
font-size: 16px;
line-height: 50px;
display: flex;
background-color: #fff;
align-items: center;
justify-content: space-between;
padding-left: 14px;
padding-right: 14px;
margin-top: 10px;
.tablefooterstatic {
color:rgba(0,0,0,0.65);
font-size: 14px;
}
}
.typeColor {
.point {
width: 6px;
height: 6px;
border-radius: 50%;
display: inline-block;
margin-right: 5px;
}
.typeColor1 {
color: #3ADD60;
display: flex;
align-items: center;
.point {
background-color: #3ADD60;
}
}
.typeColor2 {
display: flex;
align-items: center;
color: #FFB97A;
.point {
background-color: #FFB97A;
}
}
.typeColor3 {
color: #65B8F4;
display: flex;
align-items: center;
.point {
background-color: #65B8F4;
}
}
.typeColor4 {
color: #FF6B6B;
display: flex;
align-items: center;
.point {
background-color: #FF6B6B;
}
}
}
......@@ -281,6 +281,16 @@ const ThemeClass = props => (
{ ThemeClass => (<ThemeClass {...props} />) }
</Bundle>
);
const LiveClass = props => (
<Bundle load={() => import(/* webpackChunkName:"LiveClass" */'./pages/liveclass/index')}>
{ LiveClass => (<LiveClass {...props} />) }
</Bundle>
);
const AddLive = props => (
<Bundle load={() => import(/* webpackChunkName:"AddLive" */'./pages/liveclass/AddLive')}>
{ AddLive => (<AddLive {...props} />) }
</Bundle>
);
function RouterConfig({ history }) {
return (
<ConfigProvider locale={zhCN}>
......@@ -334,6 +344,9 @@ function RouterConfig({ history }) {
<Route path="/sjd/addCustomsContent/:id" exact component={UnclockDetail} />
<Route path="/sjd/addStoreCount/:id" exact component={AddStoreCount} />
<Route path="/sjd/themeClass" exact component={ThemeClass} />
<Route path="/sjd/liveClass" exact component={LiveClass} />
<Route path="/sjd/addLive" exact component={AddLive} />
<Route path="/sjd/editLive/:id" exact component={AddLive} />
<Route component={Errorpage} />
</Switch>
</SjdIndex>
......
import qs from 'qs';
import request from '../utils/request';
import api from '../common/api';
export function liveList(params) {
const data = qs.stringify(params);
return request({
url: `${api.liveClass.lives}?${data}`,
method: 'GET',
});
}
export function addLive(params) {
const data = qs.stringify(params);
return request({
url: `${api.liveClass.lives}`,
method: 'POST',
data,
});
}
export function editLive(params) {
const data = qs.stringify(params);
return request({
url: `${api.liveClass.lives}/${params.id}`,
method: 'PUT',
data,
});
}
export function liveDetail(params) {
const data = qs.stringify(params);
return request({
url: `${api.liveClass.lives}/${params.id}`,
method: 'GET',
data,
});
}
export function deleteLive(parmas) {
const data = qs.stringify(parmas);
return request({
url: `${api.liveClass.lives}/${parmas.id}`,
method: 'DELETE',
data,
});
}
export function changeStatus(params) {
const data = qs.stringify(params);
return request({
url: `${api.liveClass.livesStatus}`,
method: 'POST',
data,
});
}
export function liveUrl(params) {
const data = qs.stringify(params);
return request({
url: `${api.liveClass.livesUrl}?${data}`,
method: 'GET',
});
}
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