Commit ae5b709a by wufan

Merge branch 'feature/wufan/20200109/work-weixin' into 'master'

Feature/wufan/20200109/work weixin

See merge request !2
parents f290316c 3ad07192
...@@ -64,6 +64,8 @@ module.exports = { ...@@ -64,6 +64,8 @@ module.exports = {
appPublic: resolveApp('public'), appPublic: resolveApp('public'),
appHtml: resolveApp('src/index.html'), appHtml: resolveApp('src/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'), appIndexJs: resolveModule(resolveApp, 'src/index'),
h5Html: resolveApp('src/h5.html'),
h5IndexJs: resolveModule(resolveApp, 'src/h5'),
appPackageJson: resolveApp('package.json'), appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'), appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'), appTsConfig: resolveApp('tsconfig.json'),
......
...@@ -20,6 +20,7 @@ const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); ...@@ -20,6 +20,7 @@ const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const paths = require('./paths'); const paths = require('./paths');
const modules = require('./modules'); const modules = require('./modules');
const vConsolePlugin = require('vconsole-webpack-plugin');
const getClientEnvironment = require('./env'); const getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin'); const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
...@@ -52,7 +53,7 @@ const lessModuleRegex = /\.module\.less$/; ...@@ -52,7 +53,7 @@ const lessModuleRegex = /\.module\.less$/;
// This is the production and development configuration. // This is the production and development configuration.
// It is focused on developer experience, fast rebuilds, and a minimal bundle. // It is focused on developer experience, fast rebuilds, and a minimal bundle.
module.exports = function(webpackEnv) { module.exports = function (webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development'; const isEnvDevelopment = webpackEnv === 'development';
const isEnvProduction = webpackEnv === 'production'; const isEnvProduction = webpackEnv === 'production';
...@@ -608,6 +609,9 @@ module.exports = function(webpackEnv) { ...@@ -608,6 +609,9 @@ module.exports = function(webpackEnv) {
}; };
}, },
}), }),
// Moment.js is an extremely popular library that bundles large locale files // Moment.js is an extremely popular library that bundles large locale files
// by default due to how webpack interprets its code. This is a practical // by default due to how webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales. // solution that requires the user to opt into importing specific locales.
...@@ -659,6 +663,9 @@ module.exports = function(webpackEnv) { ...@@ -659,6 +663,9 @@ module.exports = function(webpackEnv) {
// The formatter is invoked directly in WebpackDevServerUtils during development // The formatter is invoked directly in WebpackDevServerUtils during development
formatter: isEnvProduction ? typescriptFormatter : undefined, formatter: isEnvProduction ? typescriptFormatter : undefined,
}), }),
new vConsolePlugin({
enable: (process.env.DEPLOY_ENV === 'prod' || process.env.DEPLOY_ENV === 'beta') ? false : true
})
].filter(Boolean), ].filter(Boolean),
// Some libraries import Node modules but don't use them in the browser. // Some libraries import Node modules but don't use them in the browser.
// Tell webpack to provide empty mocks for them so importing them works. // Tell webpack to provide empty mocks for them so importing them works.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -133,6 +133,7 @@ ...@@ -133,6 +133,7 @@
"@types/ali-oss": "^6.0.5", "@types/ali-oss": "^6.0.5",
"@types/jquery": "^3.5.4", "@types/jquery": "^3.5.4",
"ali-oss": "^6.12.0", "ali-oss": "^6.12.0",
"react-sortable-hoc": "^1.11.0" "react-sortable-hoc": "^1.11.0",
"vconsole-webpack-plugin": "^1.5.2"
} }
} }
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditTime: 2021-01-09 11:18:27
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="icon" href="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> -->
<link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/KGSYFEpcHT.png">
<title>小麦企培</title>
<script type="text/javascript" charset="utf-8" src="./jquery.min.js"></script>
<style type="text/css">
.box {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: rgba(244, 246, 250, 1);
}
p {
font-size: 17px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 24px;
margin-top: 12px;
}
.hide {
display: none;
text-align: center;
}
</style>
</head>
<body>
<div class="box">
<div id='success' class='hide'>
<img src="https://image.xiaomaiketang.com/xm/iRkcMHPHba.png" style='width:60px' alt="">
<p>
扫码成功
</p>
</div>
<div id="error" class='hide'>
<img src="https://image.xiaomaiketang.com/xm/6kSAYFMm2r.png
" style='width:60px' alt="">
<p id='message'>
</p>
</div>
</div>
</body>
<script>
$(document).ready(function () {
var BASIC_HOST_MAP = {
dev: 'https://dev-heimdall.xiaomai5.com/',
dev1: 'https://dev1-heimdall.xiaomai5.com/',
rc: 'https://rc-heimdall.xiaomai5.com/',
gray: 'https://gray-heimdall.xiaomai5.com/',
prod: 'https://gateway-heimdall.xiaomai5.com/'
};
var APPID_MAP = {
dev: 'ww80fd6928a46cf33a',
dev1: 'ww80fd6928a46cf33a',
rc: 'ww2009937c82bc57bd',
gray: 'ww2009937c82bc57bd',
prod: 'ww2009937c82bc57bd'
};
function getParameterByName(name) {
name = name.replace(/[\\[]/, '\\[').replace(/[\]]/, '\\]')
const regex = new RegExp('[\\?&]' + name + '=([^&#]*)')
const results = regex.exec(window.location.href)
return results === null
? ''
: decodeURIComponent(results[1].replace(/\+/g, ' '))
}
const env = getParameterByName('env');
const appTermEnum = getParameterByName('appTermEnum');
const code = getParameterByName('code');
const ticket = getParameterByName('ticket');
if (!code) {
postJSON('hades/anon/hades/getCorpTrainSuiteId', {}, (res) => {
const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${res.result}&redirect_uri=${encodeURIComponent(location.href)}&response_type=code&scope=snsapi_privateinfo&state=STATE#wechat_redirect`
location.href = url
})
return
} else {
postJSON("hades/anon/hades/wXWorkUserTicketLogin", {
appTermEnum: appTermEnum,
code: code,
ticket: ticket
}, (res) => {
if (res.code == 200) {
$('#success').show()
} else {
$('#error').show();
var message = res.message.split(',').join('<br />')
$('#message').html(message)
}
})
}
function postJSON(url, data, callback) {
const ajaxOptions = {
data: JSON.stringify(data),
type: 'POST',
url: BASIC_HOST_MAP[env] + url,
contentType: 'application/json; charset=UTF-8',
timeout: 20000,
dataType: 'json',
success(res, status, xhr) {
callback(res)
},
};
$.ajax(ajaxOptions)
}
});
</script>
</html>
\ No newline at end of file
...@@ -77,6 +77,7 @@ checkBrowsers(paths.appPath, isInteractive) ...@@ -77,6 +77,7 @@ checkBrowsers(paths.appPath, isInteractive)
} }
const config = configFactory('development'); const config = configFactory('development');
console.log(config.entry)
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name; const appName = require(paths.appPackageJson).name;
const useTypeScript = fs.existsSync(paths.appTsConfig); const useTypeScript = fs.existsSync(paths.appTsConfig);
......
...@@ -117,7 +117,6 @@ class ShareLiveModal extends React.Component { ...@@ -117,7 +117,6 @@ class ShareLiveModal extends React.Component {
>{`【${courseName}】开课啦,快来学习!`}</div> >{`【${courseName}】开课啦,快来学习!`}</div>
<img <img
src={coverImgSrc} src={coverImgSrc}
crossOrigin="*"
className="course-cover" className="course-cover"
alt="course-cover" alt="course-cover"
/> />
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-31 09:34:31 * @Date: 2020-08-31 09:34:31
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-22 15:24:03 * @LastEditTime: 2021-01-09 14:39:46
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -27,7 +27,7 @@ interface HeadersType{ ...@@ -27,7 +27,7 @@ interface HeadersType{
storeId?:any, storeId?:any,
storeUserId?:any, storeUserId?:any,
userId?:any, userId?:any,
token?:any xmtoken?:any
} }
class Axios { class Axios {
static post( static post(
...@@ -49,7 +49,7 @@ class Axios { ...@@ -49,7 +49,7 @@ class Axios {
headerObject.userId = User.getUserId(); headerObject.userId = User.getUserId();
} }
if(User.getToken()){ if(User.getToken()){
headerObject.token = User.getToken(); headerObject.xmtoken = User.getToken();
} }
const instance: AxiosInstance = axios.create({ const instance: AxiosInstance = axios.create({
timeout: TIME_OUT, timeout: TIME_OUT,
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-31 09:34:51 * @Date: 2020-08-31 09:34:51
* @LastEditors: wufan * @LastEditors: wufan
* @LastEditTime: 2020-12-17 14:14:43 * @LastEditTime: 2021-01-06 20:18:46
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -23,7 +23,7 @@ class Service { ...@@ -23,7 +23,7 @@ class Service {
return Axios.post('POST', `hades/${url}`, params, option); return Axios.post('POST', `hades/${url}`, params, option);
} }
static Sales(url: string, params: any, option: any) { static Sales(url: string, params: any, option?: any) {
return Axios.post('POST', `sales/${url}`, params, option); return Axios.post('POST', `sales/${url}`, params, option);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-31 09:34:25 * @Date: 2020-08-31 09:34:25
* @LastEditors: wufan * @LastEditors: wufan
* @LastEditTime: 2020-12-26 14:19:23 * @LastEditTime: 2021-01-09 15:50:08
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -20,6 +20,10 @@ class User { ...@@ -20,6 +20,10 @@ class User {
return Storage.get(`${PREFIX}_storeName`) return Storage.get(`${PREFIX}_storeName`)
} }
getStoreType(){
return Storage.get(`${PREFIX}_storeType`)
}
getStoreUserId(){ getStoreUserId(){
return Storage.get(`${PREFIX}_storeUserId`) return Storage.get(`${PREFIX}_storeUserId`)
} }
...@@ -43,6 +47,10 @@ class User { ...@@ -43,6 +47,10 @@ class User {
return Storage.set(`${PREFIX}_storeName`,value) return Storage.set(`${PREFIX}_storeName`,value)
} }
setStoreType(value:any){
return Storage.set(`${PREFIX}_storeType`,value)
}
setStoreUserId(value:any){ setStoreUserId(value:any){
return Storage.set(`${PREFIX}_storeUserId`,value) return Storage.set(`${PREFIX}_storeUserId`,value)
} }
......
@font-face { @font-face {
font-family: 'iconfont'; /* project id 2223403 */ font-family: 'iconfont'; /* project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_w7su9rdwngo.eot'); src: url('//at.alicdn.com/t/font_2223403_qb6r10go4s.eot');
src: url('//at.alicdn.com/t/font_2223403_w7su9rdwngo.eot?#iefix') format('embedded-opentype'), src: url('//at.alicdn.com/t/font_2223403_qb6r10go4s.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_2223403_w7su9rdwngo.woff2') format('woff2'), url('//at.alicdn.com/t/font_2223403_qb6r10go4s.woff2') format('woff2'),
url('//at.alicdn.com/t/font_2223403_w7su9rdwngo.woff') format('woff'), url('//at.alicdn.com/t/font_2223403_qb6r10go4s.woff') format('woff'),
url('//at.alicdn.com/t/font_2223403_w7su9rdwngo.ttf') format('truetype'), url('//at.alicdn.com/t/font_2223403_qb6r10go4s.ttf') format('truetype'),
url('//at.alicdn.com/t/font_2223403_w7su9rdwngo.svg#iconfont') format('svg'); url('//at.alicdn.com/t/font_2223403_qb6r10go4s.svg#iconfont') format('svg');
} }
.iconfont{ .iconfont{
font-family:"iconfont" !important; font-family:"iconfont" !important;
......
...@@ -72,9 +72,7 @@ class CourseSelect extends React.Component { ...@@ -72,9 +72,7 @@ class CourseSelect extends React.Component {
loading: false, loading: false,
totalCount: Number(total), totalCount: Number(total),
}); });
}).finally((res) => { })
this.setState({ loading: false });
});
} }
handleCourseSelect = (course) => { handleCourseSelect = (course) => {
......
import React from 'react'
import React from 'react';
import { Modal, Button } from "antd"; import { Modal, Button } from "antd";
import "./DownloadLiveModal.less" import "./DownloadLiveModal.less"
...@@ -12,37 +13,12 @@ class DownloadLiveModal extends React.Component { ...@@ -12,37 +13,12 @@ class DownloadLiveModal extends React.Component {
type: 'pre', type: 'pre',
} }
} }
downloadLiveClient(){
if (type === 'pre') {
const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
if(isMac){
Modal.info({
title: "抱歉,暂不支持Mac版",
content: "Mac版正在开发中,敬请期待",
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
okText: '我知道了'
});
return;
}
url && window.open(url);
this.setState({
image: 'https://image.xiaomaiketang.com/xm/wPwRdaa7MM.png',
tip: '安装完成后,再次打开即可开始直播。',
text: '我知道了',
type: 'finish',
})
} else {
this.props.onCancel();
}
}
render() { render() {
const { url } = this.props; const { url } = this.props;
const { image, tip, text, type } = this.state; const { image, tip, text, type } = this.state;
return <Modal return <Modal
visible={true} visible={true}
maskClosable={false}
title="下载客户端" title="下载客户端"
className="download-live-modal" className="download-live-modal"
footer={null} footer={null}
...@@ -56,8 +32,17 @@ class DownloadLiveModal extends React.Component { ...@@ -56,8 +32,17 @@ class DownloadLiveModal extends React.Component {
type="primary" type="primary"
className="download-button" className="download-button"
onClick={() => { onClick={() => {
if (type === 'pre') {
url && window.open(url);
this.setState({
image: 'https://image.xiaomaiketang.com/xm/wPwRdaa7MM.png',
tip: '安装完成后,再次打开即可开始直播。',
text: '我知道了',
type: 'finish',
})
} else {
this.props.onCancel();
}
}} }}
>{text}</Button> >{text}</Button>
</Modal> </Modal>
......
...@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; ...@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { Modal, Button } from 'antd'; import { Modal, Button } from 'antd';
import Service from '@/common/js/service'; import Service from '@/common/js/service';
import User from '@/common/js/user'; import User from '@/common/js/user';
import PhotoClip from 'photoclip'
let cutFlag = false; let cutFlag = false;
class ImgCutModalNew extends React.Component { class ImgCutModalNew extends React.Component {
...@@ -30,10 +31,10 @@ class ImgCutModalNew extends React.Component { ...@@ -30,10 +31,10 @@ class ImgCutModalNew extends React.Component {
const fileName = window.random_string(16) + name.slice(name.lastIndexOf('.')); const fileName = window.random_string(16) + name.slice(name.lastIndexOf('.'));
const params = { const params = {
bizCode: bizCode, accessTypeEnum:"PUBLIC",
accessTypeEnum: 'PUBLIC', bizCode:'CLOUD_CLASS_COMMON',
instId: LS.get('instId'), instId:User.getStoreId(),
resourceName: fileName resourceName:name
} }
// 压缩 // 压缩
if (compress) { if (compress) {
...@@ -41,7 +42,7 @@ class ImgCutModalNew extends React.Component { ...@@ -41,7 +42,7 @@ class ImgCutModalNew extends React.Component {
dataUrl = this.getBase64Size(dataUrl) > compressSizeByte ? await this.handleCompressImg(dataUrl, compressSizeByte, cutWidth) : dataUrl; dataUrl = this.getBase64Size(dataUrl) > compressSizeByte ? await this.handleCompressImg(dataUrl, compressSizeByte, cutWidth) : dataUrl;
} }
const cutImage = this.convertBase64UrlToBlob(dataUrl); const cutImage = this.convertBase64UrlToBlob(dataUrl);
Service.Hades('public/hades/commonOssAuthority', param).then((res) => { Service.Hades('public/hades/commonOssAuthority', params).then((res) => {
const { resourceId, accessId, policy, callback, signature,key, host } = res.result; const { resourceId, accessId, policy, callback, signature,key, host } = res.result;
const localUrl = URL.createObjectURL(cutImage); const localUrl = URL.createObjectURL(cutImage);
// 构建上传的表单 // 构建上传的表单
...@@ -66,6 +67,7 @@ class ImgCutModalNew extends React.Component { ...@@ -66,6 +67,7 @@ class ImgCutModalNew extends React.Component {
}) })
} }
}; };
if (!photoclip) { if (!photoclip) {
const _photoclip = new PhotoClip('#imgCutModalNew', options); const _photoclip = new PhotoClip('#imgCutModalNew', options);
_photoclip.load(imageFile); _photoclip.load(imageFile);
......
...@@ -9,7 +9,6 @@ import React from 'react' ...@@ -9,7 +9,6 @@ import React from 'react'
import { message } from "antd"; import { message } from "antd";
import moment from 'moment'; import moment from 'moment';
require("./MultipleDatePicker.less"); require("./MultipleDatePicker.less");
class MultipleDatePicker extends React.Component { class MultipleDatePicker extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
...@@ -245,13 +244,14 @@ class MultipleDatePicker extends React.Component { ...@@ -245,13 +244,14 @@ class MultipleDatePicker extends React.Component {
</div> </div>
)} )}
<ul className="week"> <ul className="week">
<li></li>
<li></li> <li></li>
<li></li> <li></li>
<li></li> <li></li>
<li></li> <li></li>
<li></li> <li></li>
<li></li> <li></li>
<li></li>
</ul> </ul>
<ul className="calendar" id="multiCalendar"> <ul className="calendar" id="multiCalendar">
{this.state.calendar} {this.state.calendar}
......
'use strict';
var extend = require('extend');
var qrcodeAlgObjCache = [];
var QRCodeAlg = require('./qrcodealg');
/**
* 计算矩阵点的前景色
* @param {Obj} config
* @param {Number} config.row 点x坐标
* @param {Number} config.col 点y坐标
* @param {Number} config.count 矩阵大小
* @param {Number} config.options 组件的options
* @return {String}
*/
var getForeGround = function getForeGround(config) {
var options = config.options;
if (options.pdground && (config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5 || config.row > config.count - 6 && config.row < config.count - 2 && config.col > 1 && config.col < 5 || config.row > 1 && config.row < 5 && config.col > config.count - 6 && config.col < config.count - 2)) {
return options.pdground;
}
return options.foreground;
};
/**
* 点是否在Position Detection
* @param {row} 矩阵行
* @param {col} 矩阵列
* @param {count} 矩阵大小
* @return {Boolean}
*/
var inPositionDetection = function inPositionDetection(row, col, count) {
if (row < 7 && col < 7 || row > count - 8 && col < 7 || row < 7 && col > count - 8) {
return true;
}
return false;
};
/**
* 二维码构造函数,主要用于绘制
* @param {参数列表} opt 传递参数
* @return {}
*/
var qrcode = function qrcode(opt) {
if (typeof opt === 'string') {
// 只编码ASCII字符串
opt = {
text: opt
};
}
//设置默认参数
this.options = extend({}, {
text: '',
render: '',
size: 256,
correctLevel: 3,
background: '#ffffff',
foreground: '#000000',
image: '',
imageSize: 30
}, opt);
//使用QRCodeAlg创建二维码结构
var qrCodeAlg = null;
for (var i = 0, l = qrcodeAlgObjCache.length; i < l; i++) {
if (qrcodeAlgObjCache[i].text == this.options.text && qrcodeAlgObjCache[i].text.correctLevel == this.options.correctLevel) {
qrCodeAlg = qrcodeAlgObjCache[i].obj;
break;
}
}
if (i == l) {
qrCodeAlg = new QRCodeAlg(this.options.text, this.options.correctLevel);
qrcodeAlgObjCache.push({ text: this.options.text, correctLevel: this.options.correctLevel, obj: qrCodeAlg });
}
if (this.options.render) {
switch (this.options.render) {
case 'canvas':
return this.createCanvas(qrCodeAlg);
case 'table':
return this.createTable(qrCodeAlg);
case 'svg':
return this.createSVG(qrCodeAlg);
default:
return this.createDefault(qrCodeAlg);
}
}
return this.createDefault(qrCodeAlg);
};
extend(qrcode.prototype, {
// default create canvas -> svg -> table
createDefault: function createDefault(qrCodeAlg) {
var canvas = document.createElement('canvas');
if (canvas.getContext) {
return this.createCanvas(qrCodeAlg);
}
var SVG_NS = 'http://www.w3.org/2000/svg';
if (!!document.createElementNS && !!document.createElementNS(SVG_NS, 'svg').createSVGRect) {
return this.createSVG(qrCodeAlg);
}
return this.createTable(qrCodeAlg);
},
// canvas create
createCanvas: function createCanvas(qrCodeAlg) {
var options = this.options;
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var count = qrCodeAlg.getModuleCount();
// preload img
var loadImage = function loadImage(url, callback) {
var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;
img.onload = function () {
callback(this);
img.onload = null;
};
};
//计算每个点的长宽
var tileW = (options.size / count).toPrecision(4);
var tileH = (options.size / count).toPrecision(4);
canvas.width = options.size;
canvas.height = options.size;
//绘制
for (var row = 0; row < count; row++) {
for (var col = 0; col < count; col++) {
var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
var foreground = getForeGround({
row: row,
col: col,
count: count,
options: options
});
ctx.fillStyle = qrCodeAlg.modules[row][col] ? foreground : options.background;
ctx.fillRect(Math.round(col * tileW), Math.round(row * tileH), w, h);
}
}
if (options.image) {
loadImage(options.image, function (img) {
var x = ((options.size - options.imageSize) / 2).toFixed(2);
var y = ((options.size - options.imageSize) / 2).toFixed(2);
ctx.drawImage(img, x, y, options.imageSize, options.imageSize);
});
}
return canvas;
},
// table create
createTable: function createTable(qrCodeAlg) {
var options = this.options;
var count = qrCodeAlg.getModuleCount();
// 计算每个节点的长宽;取整,防止点之间出现分离
var tileW = Math.floor(options.size / count);
var tileH = Math.floor(options.size / count);
if (tileW <= 0) {
tileW = count < 80 ? 2 : 1;
}
if (tileH <= 0) {
tileH = count < 80 ? 2 : 1;
}
//创建table节点
//重算码大小
var s = [];
s.push('<table style="border:0px; margin:0px; padding:0px; border-collapse:collapse; background-color:' + options.background + ';">');
// 绘制二维码
for (var row = 0; row < count; row++) {
s.push('<tr style="border:0px; margin:0px; padding:0px; height:' + tileH + 'px">');
for (var col = 0; col < count; col++) {
var foreground = getForeGround({
row: row,
col: col,
count: count,
options: options
});
if (qrCodeAlg.modules[row][col]) {
s.push('<td style="border:0px; margin:0px; padding:0px; width:' + tileW + 'px; background-color:' + foreground + '"></td>');
} else {
s.push('<td style="border:0px; margin:0px; padding:0px; width:' + tileW + 'px; background-color:' + options.background + '"></td>');
}
}
s.push('</tr>');
}
s.push('</table>');
if (options.image) {
// 计算表格的总大小
var width = tileW * count;
var height = tileH * count;
var x = ((width - options.imageSize) / 2).toFixed(2);
var y = ((height - options.imageSize) / 2).toFixed(2);
s.unshift('<div style=\'position:relative; \n width:' + width + 'px; \n height:' + height + 'px;\'>');
s.push('<img src=\'' + options.image + '\' \n width=\'' + options.imageSize + '\' \n height=\'' + options.imageSize + '\' \n style=\'position:absolute;left:' + x + 'px; top:' + y + 'px;\'>');
s.push('</div>');
}
var span = document.createElement('span');
span.innerHTML = s.join('');
return span.firstChild;
},
// create svg
createSVG: function createSVG(qrCodeAlg) {
var options = this.options;
var count = qrCodeAlg.getModuleCount();
var scale = count / options.size;
// create svg
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('width', options.size);
svg.setAttribute('height', options.size);
svg.setAttribute('viewBox', '0 0 ' + count + ' ' + count);
for (var row = 0; row < count; row++) {
for (var col = 0; col < count; col++) {
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
var foreground = getForeGround({
row: row,
col: col,
count: count,
options: options
});
rect.setAttribute('x', col);
rect.setAttribute('y', row);
rect.setAttribute('width', 1);
rect.setAttribute('height', 1);
rect.setAttribute('stroke-width', 0);
if (qrCodeAlg.modules[row][col]) {
rect.setAttribute('fill', foreground);
} else {
rect.setAttribute('fill', options.background);
}
svg.appendChild(rect);
}
}
// create image
if (options.image) {
var img = document.createElementNS('http://www.w3.org/2000/svg', 'image');
img.setAttributeNS('http://www.w3.org/1999/xlink', 'href', options.image);
img.setAttribute('x', ((count - options.imageSize * scale) / 2).toFixed(2));
img.setAttribute('y', ((count - options.imageSize * scale) / 2).toFixed(2));
img.setAttribute('width', options.imageSize * scale);
img.setAttribute('height', options.imageSize * scale);
svg.appendChild(img);
}
return svg;
}
});
module.exports = qrcode;
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: wufan * @Author: wufan
* @Date: 2020-12-01 17:21:21 * @Date: 2020-12-01 17:21:21
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-22 15:39:00 * @LastEditTime: 2021-01-09 11:06:42
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -38,6 +38,9 @@ export function sendNewPhoneAuthCode(params: object) { ...@@ -38,6 +38,9 @@ export function sendNewPhoneAuthCode(params: object) {
export function editUserPhone(params: object) { export function editUserPhone(params: object) {
return Service.Hades("public/hades/editUserPhone", params); return Service.Hades("public/hades/editUserPhone", params);
} }
export function getLastedVersion(params: object) {
return Service.Hades("public/hades/getLastedVersion", params);
}
export const getOssClient = ( export const getOssClient = (
data: object, data: object,
instId: string, instId: string,
......
/* /*
* @Author: wufan * @Author: wufan
* @Date: 2020-12-12 11:57:10 * @Date: 2020-12-12 11:57:10
* @LastEditors: zhangleyuan * @LastEditors: wufan
* @LastEditTime: 2020-12-16 16:14:42 * @LastEditTime: 2021-01-06 20:18:16
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -12,6 +12,9 @@ import Service from "@/common/js/service"; ...@@ -12,6 +12,9 @@ import Service from "@/common/js/service";
export function fetchLecturerData(params: object) { export function fetchLecturerData(params: object) {
return Service.Hades("public/courseCloud/queryTeacherVisitData", params); return Service.Hades("public/courseCloud/queryTeacherVisitData", params);
} }
export function getQrcode(params: object) {
return Service.Sales("public/businessShow/convertShortUrls", params);
}
export function fetchUserData(params: object) { export function fetchUserData(params: object) {
return Service.Hades("public/courseCloud/queryStudentVisitData", params); return Service.Hades("public/courseCloud/queryStudentVisitData", params);
...@@ -49,3 +52,28 @@ export function turnOnOrOffLiveCloudCourse(params: object) { ...@@ -49,3 +52,28 @@ export function turnOnOrOffLiveCloudCourse(params: object) {
export function delLiveCloudCourse(params: object) { export function delLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/delLiveCloudCourse", params); return Service.Hades("public/courseCloud/delLiveCloudCourse", params);
} }
//视频课相关接口
export function changeVideoShelfState(params: object) {
return Service.Hades("public/hades/changeVideoShelfState", params);
}
export function createVideoSchedule(params: object) {
return Service.Hades("public/hades/createVideoSchedule", params);
}
export function delVideoSchedule(params: object) {
return Service.Hades("public/hades/delVideoSchedule", params);
}
export function editVideoSchedule(params: object) {
return Service.Hades("public/hades/editVideoSchedule", params);
}
export function userWatchInfo(params: object) {
return Service.Hades("public/hades/userWatchInfo", params);
}
export function videoScheduleDetail(params: object) {
return Service.Hades("public/hades/videoScheduleDetail", params);
}
export function videoSchedulePage(params: object) {
return Service.Hades("public/hades/videoSchedulePage", params);
}
export function videoWatchInfo(params: object) {
return Service.Hades("public/hades/videoWatchInfo", params);
}
\ No newline at end of file
/* /*
* @Author: wufan * @Author: wufan
* @Date: 2020-11-25 18:25:02 * @Date: 2020-11-25 18:25:02
* @LastEditors: zhangleyuan * @LastEditors: wufan
* @LastEditTime: 2020-12-23 16:52:56 * @LastEditTime: 2021-01-11 19:38:50
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -41,7 +41,7 @@ export function addEmployee(params: object) { ...@@ -41,7 +41,7 @@ export function addEmployee(params: object) {
} }
export function editEmployee(params: object) { export function editEmployee(params: object) {
return Service.Hades("public/hades/editStoreUser", params); return Service.Hades("public/hades/editOneselfMsg", params);
} }
export function deleteEmployee(params: object) { export function deleteEmployee(params: object) {
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
* @Author: wufan * @Author: wufan
* @Date: 2020-12-01 17:20:49 * @Date: 2020-12-01 17:20:49
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-11 11:36:19 * @LastEditTime: 2021-01-09 11:08:02
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import { getUserStore, getUserPermission ,logout,getStoreUser,sendBizAuthCode,editUserPhone,checkBizAuthCode,sendNewPhoneAuthCode,sendLoginAuthCode,login} from '@/data-source/base/request-apis'; import { getUserStore, getUserPermission ,logout,getStoreUser,sendBizAuthCode,editUserPhone,checkBizAuthCode,sendNewPhoneAuthCode,sendLoginAuthCode,login,getLastedVersion} from '@/data-source/base/request-apis';
export default class StoreService { export default class StoreService {
// 获取员工列表 // 获取员工列表
...@@ -46,4 +46,7 @@ export default class StoreService { ...@@ -46,4 +46,7 @@ export default class StoreService {
static login(params: any){ static login(params: any){
return login(params); return login(params);
} }
static getLastedVersion(params: any){
return getLastedVersion(params);
}
} }
\ No newline at end of file
/* /*
* @Author: 陈剑宇 * @Author: 陈剑宇
* @Date: 2020-05-07 14:43:01 * @Date: 2020-05-07 14:43:01
* @LastEditTime: 2021-01-04 20:14:06 * @LastEditTime: 2021-01-18 21:05:12
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @Description: * @Description:
* @FilePath: /wheat-web-demo/src/domains/basic-domain/constants.ts * @FilePath: /wheat-web-demo/src/domains/basic-domain/constants.ts
...@@ -25,5 +25,6 @@ export const USER_TYPE: string = 'B'; ...@@ -25,5 +25,6 @@ export const USER_TYPE: string = 'B';
export const PROJECT = 'xmzj-web-b'; export const PROJECT = 'xmzj-web-b';
export const VERSION = '5.4.8'; export const VERSION = '5.4.8';
export const PREFIX = 'cloud-class'; export const PREFIX = 'cloud-class';
// host // host
export const BASIC_HOST: string = BASIC_HOST_MAP[ENV]; export const BASIC_HOST: string = BASIC_HOST_MAP[ENV];
/* /*
* @Author: wufan * @Author: wufan
* @Date: 2020-11-25 18:25:02 * @Date: 2020-11-25 18:25:02
* @LastEditors: zhangleyuan * @LastEditors: wufan
* @LastEditTime: 2020-12-16 16:15:15 * @LastEditTime: 2021-01-06 20:17:40
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import { fetchLecturerData, fetchUserData, exportStudentCourseData,exportPlayBackCourseData, fetchPlaybackList,createLiveCloudCourse,getLiveCloudCoursePage,getLiveCloudCourseDetail,updateLiveCloudCourse,turnOnOrOffLiveCloudCourse,delLiveCloudCourse} from '@/data-source/course/request-api'; import {
fetchLecturerData, fetchUserData, exportStudentCourseData, exportPlayBackCourseData, fetchPlaybackList, createLiveCloudCourse, getLiveCloudCoursePage,
getLiveCloudCourseDetail, updateLiveCloudCourse, turnOnOrOffLiveCloudCourse, delLiveCloudCourse, changeVideoShelfState, createVideoSchedule, delVideoSchedule, editVideoSchedule, userWatchInfo, videoSchedulePage, videoScheduleDetail, videoWatchInfo, getQrcode
} from '@/data-source/course/request-api';
export default class courseService { export default class courseService {
// 获取讲师上课数据 // 获取讲师上课数据
...@@ -14,6 +17,11 @@ export default class courseService { ...@@ -14,6 +17,11 @@ export default class courseService {
return fetchLecturerData(params); return fetchLecturerData(params);
} }
// 生成二维码
static getQrcode(params: any) {
return getQrcode(params);
}
// 获取用户上课数据 // 获取用户上课数据
static fetchUserData(params: any) { static fetchUserData(params: any) {
return fetchUserData(params); return fetchUserData(params);
...@@ -52,4 +60,28 @@ export default class courseService { ...@@ -52,4 +60,28 @@ export default class courseService {
static delLiveCloudCourse(params: any) { static delLiveCloudCourse(params: any) {
return delLiveCloudCourse(params); return delLiveCloudCourse(params);
} }
static changeVideoShelfState(params: any) {
return changeVideoShelfState(params);
}
static createVideoSchedule(params: any) {
return createVideoSchedule(params);
}
static delVideoSchedule(params: any) {
return delVideoSchedule(params);
}
static editVideoSchedule(params: any) {
return editVideoSchedule(params);
}
static userWatchInfo(params: any) {
return userWatchInfo(params);
}
static videoSchedulePage(params: any) {
return videoSchedulePage(params);
}
static videoScheduleDetail(params: any) {
return videoScheduleDetail(params);
}
static videoWatchInfo(params: any) {
return videoWatchInfo(params);
}
} }
\ No newline at end of file
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-20 09:21:40 * @Date: 2020-08-20 09:21:40
* @LastEditors: wufan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-12 11:18:53 * @LastEditTime: 2021-01-18 21:05:31
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import { MapInterface } from '@/domains/basic-domain/interface' import { MapInterface } from '@/domains/basic-domain/interface'
const ENV: string = process.env.DEPLOY_ENV || 'dev'; const ENV: string = process.env.DEPLOY_ENV || 'prod';
const appIdMap: MapInterface = { const appIdMap: MapInterface = {
dev: 'wx3ea60e78ddfa277e', dev: 'wx3ea60e78ddfa277e',
dev1: 'wx3ea60e78ddfa277e', dev1: 'wx3ea60e78ddfa277e',
rc: 'wx5c5a1fb71ecab7bc', rc: 'wx5c5a1fb71ecab7bc',
gray: "wxdd6b458500d4c224", // 小麦校讯通 gray: "wx3dda02036493ada6", // 小麦校讯通
prod: 'wxdd6b458500d4c224' prod: 'wx3dda02036493ada6'
} }
const shareUrlMap: MapInterface = { const shareUrlMap: MapInterface = {
...@@ -25,14 +25,17 @@ const shareUrlMap: MapInterface = { ...@@ -25,14 +25,17 @@ const shareUrlMap: MapInterface = {
'gray': 'https://prod.xiaomai5.com/share/show?appid=' 'gray': 'https://prod.xiaomai5.com/share/show?appid='
} }
const LIVE_SHARE_MAP: MapInterface = { const LIVE_SHARE_MAP: MapInterface = {
dev: 'https://dev.xiaomai5.com/xiaomai-live-share/index.html#/', dev: 'https://dev.xiaomai5.com/store-live/index.html#/',
dev1: 'https://dev.xiaomai5.com/xiaomai-live-share/index.html#/', dev1: 'https://dev.xiaomai5.com/store-live/index.html#/',
rc: 'https://rc.xiaomai5.com/xiaomai-live-share/index.html#/', rc: 'https://rc.xiaomai5.com/store-live/index.html#/',
gray: 'https://res.xiaomai5.com/xiaomai-live-share/gray/index.html#/', gray: 'https://res.xiaomai0.com/store-live/gray/index.html#/',
prod: 'https://res.xiaomai5.com/xiaomai-live-share/index.html#/', prod: 'https://res.xiaomai0.com/store-live/index.html#/',
} }
export const appId: string = appIdMap[ENV]; export const appId: string = appIdMap[ENV];
export const shareUrl: string = shareUrlMap[ENV]; export const shareUrl: string = shareUrlMap[ENV];
export const LIVE_SHARE: string = LIVE_SHARE_MAP[ENV]; export const LIVE_SHARE: string = LIVE_SHARE_MAP[ENV];
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditTime: 2021-01-12 13:52:14
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="icon" href="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> -->
<link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/KGSYFEpcHT.png">
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_qb6r10go4s.css">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>小麦企培</title>
<script type="text/javascript" charset="utf-8" src="//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
import React, { useEffect, useState } from "react";
import ReactDOM from 'react-dom';
// import '@/core/function';
// import Service from "@/common/js/service";
// declare var getParameterByName: any;
function mount() {
ReactDOM.render(
<Main />,
document.getElementById('root'));
}
mount()
function Main() {
return <div>212121</div>
}
<!-- <!--
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-24 12:20:57 * @Date: 2020-08-24 12:20:57
* @LastEditors: zhangleyuan * @LastEditors: wufan
* @LastEditTime: 2020-12-30 13:58:49 * @LastEditTime: 2021-01-18 21:18:43
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
--> -->
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_w7su9rdwngo.css"> <link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_qb6r10go4s.css">
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>小麦云课堂</title> <title>小麦企培</title>
<script type="text/javascript" charset="utf-8" src="//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"></script> <script type="text/javascript" charset="utf-8" src="//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"></script>
</head> </head>
......
...@@ -18,6 +18,11 @@ import 'antd/dist/antd.less'; ...@@ -18,6 +18,11 @@ import 'antd/dist/antd.less';
import 'video-react/dist/video-react.css'; import 'video-react/dist/video-react.css';
import '@/common/less/index.less'; import '@/common/less/index.less';
import '@/core/function'; import '@/core/function';
import User from '@/common/js/user';
import Service from "@/common/js/service";
declare var getParameterByName: any;
const history = createHashHistory(); const history = createHashHistory();
...@@ -38,10 +43,29 @@ window.RCHistory = _.extend({}, history, { ...@@ -38,10 +43,29 @@ window.RCHistory = _.extend({}, history, {
} }
}); });
export async function mount() { function mount() {
ReactDOM.render( ReactDOM.render(
<RootRouter/>, <RootRouter />,
document.getElementById('root')); document.getElementById('root'));
} }
mount() function isWeiXin() {
\ No newline at end of file const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('micromessenger') > 0;
}
console.log(isWeiXin(), 'isWeiXin()')
if (getParameterByName('code') && isWeiXin()) {
Service.Hades('anon/hades/wXWorkUserLogin', {
appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN',
code: getParameterByName('code')
}).then((res) => {
User.setUserId(res.result.loginInfo.userId);
User.setToken(res.result.loginInfo.xmToken);
mount()
})
} else {
mount()
}
...@@ -106,9 +106,7 @@ class CourseSelect extends React.Component { ...@@ -106,9 +106,7 @@ class CourseSelect extends React.Component {
loading: false loading: false
}); });
}).finally((res) => { })
this.setState({ loading: false });
});
} }
......
...@@ -13,13 +13,12 @@ class DateRangePicker extends React.Component { ...@@ -13,13 +13,12 @@ class DateRangePicker extends React.Component {
} }
render() { render() {
const showTime = { showTime: true } const showTime = { showTime: false }
return ( return (
<RangePicker <RangePicker
{...this.props} {...this.props}
format={this.props.format || 'YYYY-MM-DD'} format={this.props.format || 'YYYY-MM-DD'}
allowClear={this.props.allowClear} allowClear={this.props.allowClear}
ranges={this.props.ranges || { '本月': [moment().startOf('month'), moment().endOf('month')], '本周': [moment().startOf('week'), moment().endOf('week')], '上月': [moment().subtract(1, 'M').startOf('month'), moment().subtract(1, 'M').endOf('month')], '上周': [moment().subtract(1, 'w').startOf('week'), moment().subtract(1, 'w').endOf('week')] }}
onChange={(date) => { onChange={(date) => {
if (!_.isEmpty(date)) { if (!_.isEmpty(date)) {
date[0] = date[0].startOf('day') date[0] = date[0].startOf('day')
......
...@@ -82,6 +82,8 @@ class AddLive extends React.Component { ...@@ -82,6 +82,8 @@ class AddLive extends React.Component {
teacherId: null, teacherId: null,
teacherName: null, teacherName: null,
assistant:[], assistant:[],
assistantStoreUserId:[],
assistantNames:[],
liveDate: null, liveDate: null,
timeHorizonStart: null, timeHorizonStart: null,
timeHorizonEnd: null, timeHorizonEnd: null,
...@@ -169,6 +171,8 @@ class AddLive extends React.Component { ...@@ -169,6 +171,8 @@ class AddLive extends React.Component {
const timeHorizonStart = startTime; const timeHorizonStart = startTime;
const timeHorizonEnd = endTime; const timeHorizonEnd = endTime;
const assistant = _.pluck(admins, "adminId"); const assistant = _.pluck(admins, "adminId");
const assistantStoreUserId = _.pluck(admins, "adminStoreUserId"); //编辑时的选中的助教的查询用storeUserId查询
const assistantNames = _.pluck(admins, "adminName");
const addLiveClassInfo = { const addLiveClassInfo = {
assistant, assistant,
liveDate, liveDate,
...@@ -179,6 +183,8 @@ class AddLive extends React.Component { ...@@ -179,6 +183,8 @@ class AddLive extends React.Component {
timeHorizonEnd, timeHorizonEnd,
startTime, startTime,
endTime, endTime,
assistantNames,
assistantStoreUserId
} }
// liveCourseMediaRequests = liveCourseMediaRequests.length // liveCourseMediaRequests = liveCourseMediaRequests.length
...@@ -220,16 +226,21 @@ handleChangeBasicInfo = (field, value) => { ...@@ -220,16 +226,21 @@ handleChangeBasicInfo = (field, value) => {
} }
// 修改上课信息 // 修改上课信息
handleChangeClassInfo = (field, value ,_teacherName) => { handleChangeClassInfo = (field, value ,type, optionValue) => {
const _value = value ? value.valueOf() : null; const _value = value ? value.valueOf() : null;
const { teacherName } = this.state.addLiveClassInfo; const { teacherName } = this.state.addLiveClassInfo;
const { assistantNames } = this.state.addLiveClassInfo;
const { assistantStoreUserId } = this.state.addLiveClassInfo
this.setState({ this.setState({
addLiveClassInfo: { addLiveClassInfo: {
...this.state.addLiveClassInfo, ...this.state.addLiveClassInfo,
[field]: _value, [field]: _value,
teacherName:_teacherName?_teacherName:teacherName teacherName:type==='teacherType'?optionValue:teacherName,
assistantNames:type==='assistantType'?_.pluck(optionValue, "children"):assistantNames,
assistantStoreUserId:type==='assistantType'?_.pluck(optionValue, "key"):assistantStoreUserId,
} }
}); });
// 批量开始时间改变,结束时间自动同步一致 // 批量开始时间改变,结束时间自动同步一致
if (field === 'startTime') { if (field === 'startTime') {
this.setState({ this.setState({
...@@ -388,7 +399,7 @@ handleChangeBasicInfo = (field, value) => { ...@@ -388,7 +399,7 @@ handleChangeBasicInfo = (field, value) => {
message.warning('请选择上课日期'); message.warning('请选择上课日期');
resolve(false); resolve(false);
return; return;
} else if(startTime === endTime) { } else if(startTime === endTime || startTime > endTime) {
message.warning('结束时间必须晚于开始时间'); message.warning('结束时间必须晚于开始时间');
resolve(false); resolve(false);
return; return;
...@@ -444,36 +455,11 @@ handleChangeBasicInfo = (field, value) => { ...@@ -444,36 +455,11 @@ handleChangeBasicInfo = (field, value) => {
} }
} }
if(!teacherId){ if(!teacherId){
message.warning('上课老师不能为空'); message.warning('请选择讲师');
resolve(false); resolve(false);
return; return;
} }
resolve(true) resolve(true)
// if(!teacherId) {
// message.warning('上课老师不能为空');
// resolve(false);
// return;
// } else if(!applyMode) {
// message.warning('请选择分享设置');
// resolve(false);
// return;
// } else {
// const textIntro = liveCourseMediaRequests.filter(item => { return item.mediaType === 'TEXT'; });
// for (let i = 0, len = textIntro.length; i < len; i++) {
// if (textIntro[i].mediaContent && textIntro[i].mediaContentLength.length > 1000) {
// message.warning(`第${i+1}个文字简介的字数超过了1000个字`);
// resolve(false);
// return;
// }
// }
// }
// if(window.NewVersion && type === 'add') {
// this.handleValidateLackConsumeModal(consumeHourNum, calendarTime, consumeStudentList).then(res => {
// resolve(res)
// })
// } else {
// resolve(true);
// }
}); });
} }
...@@ -537,7 +523,7 @@ handleChangeBasicInfo = (field, value) => { ...@@ -537,7 +523,7 @@ handleChangeBasicInfo = (field, value) => {
/> />
<div className="box"> <div className="box">
<div className="show-tips"> <div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦助教保有依据国家规定及平台规则进行处理的权利" /> <ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企培保有依据国家规定及平台规则进行处理的权利" />
</div> </div>
<div className="add-live-page__form"> <div className="add-live-page__form">
<div className="basic-info__wrap"> <div className="basic-info__wrap">
......
...@@ -151,8 +151,8 @@ class DataList extends React.Component { ...@@ -151,8 +151,8 @@ class DataList extends React.Component {
}, },
{ {
title: "累计在线时长", title: "累计在线时长",
dataIndex: "watchDuration", dataIndex: "totalDuration",
sorter: (a, b) => a.watchDuration - b.watchDuration, sorter: (a, b) => a.totalDuration - b.totalDuration,
sortDirections: ["descend", "ascend"], sortDirections: ["descend", "ascend"],
render: (text, record) => { render: (text, record) => {
//如无离开时间,就置空 //如无离开时间,就置空
......
...@@ -95,6 +95,9 @@ ...@@ -95,6 +95,9 @@
&.avatar-name-phone { &.avatar-name-phone {
justify-content: flex-start; justify-content: flex-start;
padding-left: 26px; padding-left: 26px;
.avatar{
border-radius:50%;
}
.name { .name {
height: 22px; height: 22px;
font-size: 16px; font-size: 16px;
......
...@@ -28,7 +28,7 @@ class LiveCoursePage extends React.Component { ...@@ -28,7 +28,7 @@ class LiveCoursePage extends React.Component {
const params = { const params = {
...query, ...query,
..._query, ..._query,
storeId:User.getStoreId() storeId: User.getStoreId()
}; };
this.setState({ query: params }); this.setState({ query: params });
CourseService.getLiveCloudCoursePage(params).then((res) => { CourseService.getLiveCloudCoursePage(params).then((res) => {
...@@ -37,9 +37,7 @@ class LiveCoursePage extends React.Component { ...@@ -37,9 +37,7 @@ class LiveCoursePage extends React.Component {
total, total,
courseList: records courseList: records
}); });
}) .finally(() => { })
this.setState({ loading: false });
});
} }
render() { render() {
const { query, total, courseList } = this.state; const { query, total, courseList } = this.state;
......
...@@ -30,10 +30,12 @@ class AddLiveBasic extends React.Component { ...@@ -30,10 +30,12 @@ class AddLiveBasic extends React.Component {
showCutModal: false, showCutModal: false,
courseCatalogList:[], courseCatalogList:[],
showSelectFileModal: false, showSelectFileModal: false,
cutImageBlob: null cutImageBlob: null,
hasImgReady: false // 图片是否上传成功
} }
} }
componentWillUnmount() { componentWillUnmount() {
} }
componentDidMount(){ componentDidMount(){
...@@ -71,7 +73,6 @@ class AddLiveBasic extends React.Component { ...@@ -71,7 +73,6 @@ class AddLiveBasic extends React.Component {
} }
catalogChange= (value) => { catalogChange= (value) => {
console.log('111');
const changeValueLength = value.length; const changeValueLength = value.length;
switch (changeValueLength){ switch (changeValueLength){
case 1: case 1:
...@@ -143,20 +144,22 @@ class AddLiveBasic extends React.Component { ...@@ -143,20 +144,22 @@ class AddLiveBasic extends React.Component {
const _dataUrl = this.clip() const _dataUrl = this.clip()
self.setState({ self.setState({
dataUrl: _dataUrl, dataUrl: _dataUrl,
hasImgReady: true
}) })
}, 100) }, 100)
}, },
}; };
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(imageFile.ossUrl); _photoclip.load(imgUrl);
this.setState({ this.setState({
photoclip: _photoclip, photoclip: _photoclip,
}); });
} else { } else {
this.state.photoclip.clear(); this.state.photoclip.clear();
this.state.photoclip.load(imageFile.ossUrl); this.state.photoclip.load(imgUrl);
} }
}, 200); }, 200);
...@@ -198,7 +201,8 @@ class AddLiveBasic extends React.Component { ...@@ -198,7 +201,8 @@ class AddLiveBasic extends React.Component {
} }
render() { render() {
const { showCutModal, imageFile,courseCatalogList,showSelectFileModal,visible,cutImageBlob} = this.state; const { showCutModal, imageFile,courseCatalogList,showSelectFileModal,visible,cutImageBlob,hasImgReady
} = this.state;
const { data,pageType,isEdit} = this.props; const { data,pageType,isEdit} = this.props;
const { courseName,categoryName,coverUrl} = data; const { courseName,categoryName,coverUrl} = data;
const fileName = ''; const fileName = '';
...@@ -255,7 +259,7 @@ class AddLiveBasic extends React.Component { ...@@ -255,7 +259,7 @@ class AddLiveBasic extends React.Component {
<div className="course-catalog"> <div className="course-catalog">
<span className="label"><span className="require">*</span>课程分类:</span> <span className="label"><span className="require">*</span>课程分类:</span>
{ pageType === 'add' && { pageType === 'add' &&
<Cascader defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" /> <Cascader options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" />
} }
{ (pageType === 'edit' && categoryName) && { (pageType === 'edit' && categoryName) &&
<Cascader disabled={!isEdit ? true: false} defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" /> <Cascader disabled={!isEdit ? true: false} defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" />
...@@ -279,8 +283,9 @@ class AddLiveBasic extends React.Component { ...@@ -279,8 +283,9 @@ class AddLiveBasic extends React.Component {
onClose={() => this.setState({ showCutModal: false })} onClose={() => this.setState({ showCutModal: false })}
reUpload={() => { this.state.currentInputFile.click() }} reUpload={() => { this.state.currentInputFile.click() }}
/> />
{showSelectFileModal &&
<SelectPrepareFileModal <SelectPrepareFileModal
key="basic"
operateType="select" operateType="select"
multiple={false} multiple={false}
accept="image/jpeg,image/png,image/jpg" accept="image/jpeg,image/png,image/jpg"
...@@ -292,6 +297,7 @@ class AddLiveBasic extends React.Component { ...@@ -292,6 +297,7 @@ class AddLiveBasic extends React.Component {
}} }}
onSelect={this.handleSelectCover} onSelect={this.handleSelectCover}
/> />
}
<Modal <Modal
title="设置图片" title="设置图片"
width={1080} width={1080}
...@@ -312,6 +318,7 @@ class AddLiveBasic extends React.Component { ...@@ -312,6 +318,7 @@ class AddLiveBasic extends React.Component {
<Button <Button
key="submit" key="submit"
type="primary" type="primary"
disabled={!hasImgReady}
onClick={() => { onClick={() => {
if (!cutFlag) { if (!cutFlag) {
cutFlag = true; cutFlag = true;
......
...@@ -48,12 +48,19 @@ class AddLiveClass extends React.Component { ...@@ -48,12 +48,19 @@ class AddLiveClass extends React.Component {
this.getTeacherList(); this.getTeacherList();
this.getAssistantList(); this.getAssistantList();
} }
componentWillReceiveProps(nextProps) {
if(nextProps.data.assistantStoreUserId.sort().toString() !== this.props.data.assistantStoreUserId.sort().toString()) {
console.log('我在改变')
// 获取助教老师列表
this.getAssistantList(1, nextProps.data.assistantStoreUserId);
}
}
getTeacherList(current = 1, selectList){ getTeacherList(current = 1, selectList){
const { teacherQuery,teacherList} = this.state; const { teacherQuery,teacherList} = this.state;
const _query = { const _query = {
...teacherQuery, ...teacherQuery,
current, current,
size:10 size:15
}; };
StoreService.getStoreUserBasicPage( _query).then((res) => { StoreService.getStoreUserBasicPage( _query).then((res) => {
const { result = {} } = res; const { result = {} } = res;
...@@ -67,17 +74,24 @@ class AddLiveClass extends React.Component { ...@@ -67,17 +74,24 @@ class AddLiveClass extends React.Component {
} }
// 获取助教老师列表 // 获取助教老师列表
getAssistantList = (current = 1, selectList) => { getAssistantList = (current = 1, selectList) => {
console.log('zhujiao',current);
const { assistantQuery,assistantList} = this.state; const { assistantQuery,assistantList} = this.state;
const { assistantStoreUserId } = this.props.data;
const idList = selectList ? selectList : assistantStoreUserId;
const _query = { const _query = {
...assistantQuery, ...assistantQuery,
current, current,
size:10 idList,
size: idList.length <= 10 ? 10 : idList.length + 10
}; };
StoreService.getStoreUserBasicPage( _query).then((res) => { StoreService.getStoreUserBasicPage( _query).then((res) => {
const { result = {} } = res; const { result = {} } = res;
const { records = [], total = 0, hasNext} = result; const { records = [], total = 0, hasNext} = result;
const { teacherId } = this.props.data const { teacherId } = this.props.data
let list = current > 1 ? assistantList.concat(records) : records; let list = current > 1 ? assistantList.concat(records) : records;
console.log("hasNext",typeof(hasNext),hasNext)
this.setState({ this.setState({
assistantHasNext:hasNext, assistantHasNext:hasNext,
assistantList: list, assistantList: list,
...@@ -92,7 +106,11 @@ class AddLiveClass extends React.Component { ...@@ -92,7 +106,11 @@ class AddLiveClass extends React.Component {
const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop; const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop;
if (scrollToBottom && hasNext) { if (scrollToBottom && hasNext) {
const { teacherQuery } = this.state; const { teacherQuery } = this.state;
this.getTeacherList(teacherQuery.current + 1); let _teacherQuery = teacherQuery;
_teacherQuery.current = _teacherQuery.current + 1
this.setState({
assistantQuery:{..._teacherQuery}
},()=>{this.getTeacherList(_teacherQuery.current)})
} }
} }
...@@ -103,7 +121,11 @@ class AddLiveClass extends React.Component { ...@@ -103,7 +121,11 @@ class AddLiveClass extends React.Component {
const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop; const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop;
if (scrollToBottom && assistantHasNext) { if (scrollToBottom && assistantHasNext) {
const { assistantQuery } = this.state; const { assistantQuery } = this.state;
this.getAssistantList(assistantQuery.current + 1); let _assistantQuery = assistantQuery;
_assistantQuery.current = _assistantQuery.current + 1
this.setState({
assistantQuery:{..._assistantQuery}
},()=>{this.getAssistantList(_assistantQuery.current)})
} }
} }
...@@ -134,7 +156,9 @@ class AddLiveClass extends React.Component { ...@@ -134,7 +156,9 @@ class AddLiveClass extends React.Component {
liveDate, liveDate,
timeHorizonStart, timeHorizonStart,
timeHorizonEnd, timeHorizonEnd,
assistant assistant,
assistantNames,
teacherName
} = data; } = data;
console.log("teacherId",teacherId); console.log("teacherId",teacherId);
return ( return (
...@@ -241,19 +265,23 @@ class AddLiveClass extends React.Component { ...@@ -241,19 +265,23 @@ class AddLiveClass extends React.Component {
</div> </div>
} }
<div className="teacher"> <div className="teacher" id="teacher">
<span className="label"><span className="require">* </span>讲师:</span> <span className="label"><span className="require">* </span>讲师:</span>
<Select <Select
placeholder="请选择讲师" placeholder="请选择讲师"
// key={teacherName}
// defaultValue={teacherName}
value={teacherName}
style={{ width: 240, marginTop: 6 }} style={{ width: 240, marginTop: 6 }}
disabled={!isEdit ? true: false} disabled={!isEdit ? true: false}
showSearch showSearch
value={teacherId}
filterOption={(input, option) => option} filterOption={(input, option) => option}
onPopupScroll={this.handleScrollTeacherList} onPopupScroll={this.handleScrollTeacherList}
onChange={(value,option) => { onChange={(value,option) => {
this.props.onChange('teacherId', value,option.children) console.log("value",value);
this.props.onChange('teacherId',value,'teacherType',option.children)
}} }}
onSearch={(value) => { onSearch={(value) => {
teacherQuery.nickName = value teacherQuery.nickName = value
this.setState({ this.setState({
...@@ -262,6 +290,9 @@ class AddLiveClass extends React.Component { ...@@ -262,6 +290,9 @@ class AddLiveClass extends React.Component {
this.getTeacherList() this.getTeacherList()
}) })
}} }}
getPopupContainer={() =>
document.getElementById("teacher")
}
> >
{_.map(teacherList, (item, index) => { {_.map(teacherList, (item, index) => {
if( !assistant.includes(item.userId) ){ if( !assistant.includes(item.userId) ){
...@@ -271,12 +302,15 @@ class AddLiveClass extends React.Component { ...@@ -271,12 +302,15 @@ class AddLiveClass extends React.Component {
} }
})} })}
</Select> </Select>
</div> </div>
<div className="assistant-teacher"> <div className="assistant-teacher" id="assistant-teacher">
<span className="label">助教:</span> <span className="label">助教:</span>
<Select <Select
id="assistant" id="assistant"
placeholder="请选择助教老师" placeholder="请选择助教老师"
// key={assistantNames}
// defaultValue={assistantNames}
value={assistant} value={assistant}
disabled={!isEdit ? true: false} disabled={!isEdit ? true: false}
mode={'multiple'} mode={'multiple'}
...@@ -285,8 +319,9 @@ class AddLiveClass extends React.Component { ...@@ -285,8 +319,9 @@ class AddLiveClass extends React.Component {
style={{ width: 240, marginTop: 6 }} style={{ width: 240, marginTop: 6 }}
filterOption={(input, option) => option} filterOption={(input, option) => option}
onPopupScroll={this.handleScrollAssistantList} onPopupScroll={this.handleScrollAssistantList}
onChange={(value) => { onChange={(value,option) => {
this.props.onChange('assistant', value) console.log('option',option);
this.props.onChange('assistant',value,'assistantType',option)
}} }}
onSearch={(value) => { onSearch={(value) => {
assistantQuery.nickName = value assistantQuery.nickName = value
...@@ -296,11 +331,14 @@ class AddLiveClass extends React.Component { ...@@ -296,11 +331,14 @@ class AddLiveClass extends React.Component {
this.getAssistantList() this.getAssistantList()
}) })
}} }}
getPopupContainer={() =>
document.getElementById("assistant-teacher")
}
> >
{_.map(assistantList, (item, index) => { {_.map(assistantList, (item, index) => {
if(item.userId !== teacherId){ if(item.userId !== teacherId){
return ( return (
<Select.Option value={item.userId} key={item.userId}>{item.nickName}</Select.Option> <Select.Option value={item.userId} key={item.id}>{item.nickName}</Select.Option>
); );
} }
......
...@@ -52,7 +52,7 @@ class AddLiveIntro extends React.Component { ...@@ -52,7 +52,7 @@ class AddLiveIntro extends React.Component {
if(selectType === 'WARMUP'){ if(selectType === 'WARMUP'){
const liveCourseWarmMedia = { const liveCourseWarmMedia = {
contentType: 'WARMUP', contentType: 'WARMUP',
mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE', mediaType: folderFormat === 'MP4' || folderFormat === 'video/mp4' ? 'VIDEO' : 'PICTURE',
mediaContent: resourceId, mediaContent: resourceId,
mediaUrl: ossUrl, mediaUrl: ossUrl,
mediaName: folderName, mediaName: folderName,
...@@ -271,15 +271,15 @@ class AddLiveIntro extends React.Component { ...@@ -271,15 +271,15 @@ class AddLiveIntro extends React.Component {
</div> </div>
</div> </div>
<div className="allow-tourist-join"> <div className="allow-tourist-join">
<span className="label">允许游客加入</span> <span className="label">观看设置</span>
<div className="content"> <div className="content">
<div> <div>
<Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/> <Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/>
</div> </div>
<div> <div>
<div class="instro-text"> <div class="instro-text">
<div>开启:用户可直接进入直播间观看直播</div> <div>开启:允许未绑定手机号的用户进入直播间观看直播</div>
<div>关闭:用户需先填写手机号并短信验证,通过后才可进入直播间观看直播</div> <div>关闭:仅限绑定了手机号的用户可以进入直播间观看直播</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -391,7 +391,9 @@ class AddLiveIntro extends React.Component { ...@@ -391,7 +391,9 @@ class AddLiveIntro extends React.Component {
</div> </div>
</div> </div>
{/* 选择暖场图文件弹窗 */} {/* 选择暖场图文件弹窗 */}
{ showSelectFileModal &&
<SelectPrepareFileModal <SelectPrepareFileModal
key="instro"
operateType="select" operateType="select"
accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"} accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"}
selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] } selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] }
...@@ -402,6 +404,8 @@ class AddLiveIntro extends React.Component { ...@@ -402,6 +404,8 @@ class AddLiveIntro extends React.Component {
}} }}
onSelect={this.handleSelectVideo} onSelect={this.handleSelectVideo}
/> />
}
</div> </div>
) )
......
...@@ -15,6 +15,7 @@ import TeacherSearchSelect from "@/modules/common/TeacherSearchSelect"; ...@@ -15,6 +15,7 @@ import TeacherSearchSelect from "@/modules/common/TeacherSearchSelect";
import RangePicker from "@/modules/common/DateRangePicker"; import RangePicker from "@/modules/common/DateRangePicker";
import moment from 'moment'; import moment from 'moment';
import StoreService from "@/domains/store-domain/storeService"; import StoreService from "@/domains/store-domain/storeService";
import User from '@/common/js/user';
import './LiveCourseFilter.less'; import './LiveCourseFilter.less';
const { Search } = Input; const { Search } = Input;
...@@ -98,8 +99,10 @@ class LiveCourseFilter extends React.Component { ...@@ -98,8 +99,10 @@ class LiveCourseFilter extends React.Component {
query.endTime = dates[1].valueOf(); query.endTime = dates[1].valueOf();
} }
this.setState({ this.setState({
query, query:{
...query,
current: 1, current: 1,
}
}, () => { }, () => {
this.props.onChange(this.state.query); this.props.onChange(this.state.query);
}) })
...@@ -124,7 +127,6 @@ class LiveCourseFilter extends React.Component { ...@@ -124,7 +127,6 @@ class LiveCourseFilter extends React.Component {
handleReset = () => { handleReset = () => {
this.setState({ this.setState({
query: { query: {
...this.state.query,
courseName: null, courseName: null,
startTime: null, startTime: null,
endTime: null, endTime: null,
...@@ -132,6 +134,7 @@ class LiveCourseFilter extends React.Component { ...@@ -132,6 +134,7 @@ class LiveCourseFilter extends React.Component {
teacherName: null, teacherName: null,
courseState: undefined, courseState: undefined,
current: 1, current: 1,
shelfState:null,
}, },
}, () => { }, () => {
this.props.onChange(this.state.query); this.props.onChange(this.state.query);
...@@ -172,8 +175,10 @@ class LiveCourseFilter extends React.Component { ...@@ -172,8 +175,10 @@ class LiveCourseFilter extends React.Component {
format={"YYYY-MM-DD"} format={"YYYY-MM-DD"}
onChange={(dates) => { this.handleChangeDates(dates) }} onChange={(dates) => { this.handleChangeDates(dates) }}
style={{ width: "calc(100% - 70px)" }} style={{ width: "calc(100% - 70px)" }}
/> />
</div> </div>
{ User.getUserRole()!=="CloudLecturer" &&
<div className="search-condition__item"> <div className="search-condition__item">
<span>讲师:</span> <span>讲师:</span>
<Select <Select
...@@ -185,7 +190,7 @@ class LiveCourseFilter extends React.Component { ...@@ -185,7 +190,7 @@ class LiveCourseFilter extends React.Component {
onPopupScroll={this.handleScrollTeacherList} onPopupScroll={this.handleScrollTeacherList}
value={teacherId} value={teacherId}
onChange={(value) => { onChange={(value) => {
this.handleChangeQuery('teacherId', value) this.handleChangeQuery('teacherId', value);
}} }}
onSearch={(value) => { onSearch={(value) => {
teacherQuery.nickName = value teacherQuery.nickName = value
...@@ -195,6 +200,18 @@ class LiveCourseFilter extends React.Component { ...@@ -195,6 +200,18 @@ class LiveCourseFilter extends React.Component {
this.getTeacherList() this.getTeacherList()
}) })
}} }}
onClear ={(value)=>{
this.setState({
teacherQuery:{
size: 10,
current: 1,
nickName:null
}
}, () => {
this.getTeacherList()
})
}
}
> >
{_.map(teacherList, (item, index) => { {_.map(teacherList, (item, index) => {
return ( return (
...@@ -203,8 +220,8 @@ class LiveCourseFilter extends React.Component { ...@@ -203,8 +220,8 @@ class LiveCourseFilter extends React.Component {
})} })}
</Select> </Select>
</div> </div>
}
{ expandFilter && { ((expandFilter && User.getUserRole()!=="CloudLecturer") || User.getUserRole()==="CloudLecturer") &&
<div className="search-condition__item"> <div className="search-condition__item">
<span className="select-status">上课状态:</span> <span className="select-status">上课状态:</span>
<Select <Select
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
color: #333333; color: #333333;
line-height: 20px; line-height: 20px;
font-weight: bold; font-weight: bold;
max-width:238px; max-width:244px;
overflow: hidden; overflow: hidden;
text-overflow:ellipsis; text-overflow:ellipsis;
white-space: nowrap; white-space: nowrap;
...@@ -77,9 +77,11 @@ ...@@ -77,9 +77,11 @@
color: #5289FA; color: #5289FA;
line-height: 20px; line-height: 20px;
text-align:right; text-align:right;
cursor:pointer;
} }
.quota-icon{ .quota-icon{
color:#5289FA; color:#5289FA;
cursor:pointer;
} }
.operate { .operate {
display: flex; display: flex;
...@@ -124,8 +126,14 @@ ...@@ -124,8 +126,14 @@
font-size: 12px; font-size: 12px;
} }
} }
}
}
.ant-tooltip{
max-width:700px !important;
}
.ant-tooltip-inner{
max-width:700px !important;
}
.live-course-more-menu { .live-course-more-menu {
background: white; background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
import React from 'react'; import React from 'react';
import { Button, Modal, message } from 'antd'; import { Button, Modal, message } from 'antd';
import Service from '@/common/js/service';
import './liveCourseOpt.less'; import './liveCourseOpt.less';
import BaseService from "@/domains/basic-domain/baseService";
import User from '@/common/js/user'
class LiveCourseOpt extends React.Component { class LiveCourseOpt extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
...@@ -22,30 +25,30 @@ class LiveCourseOpt extends React.Component { ...@@ -22,30 +25,30 @@ class LiveCourseOpt extends React.Component {
handleDownloadClient = () => { handleDownloadClient = () => {
const isMac = /macintosh|mac os x/i.test(navigator.userAgent); const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
// 判断用户系统 // 判断用户系统
if(!isMac) { let platform;
// axios if(!isMac){
// .Apollo("anon/version/getLastedVersion", { model: 1, platform: 1 }) platform = 1
// .then((res) => { }else{
// const a = document.createElement("a"); platform = 4
// document.body.appendChild(a);
// a.href = res.result.releaseUrl;
// a.click();
// document.body.removeChild(a);
// })
}else {
Modal.info({
title: "抱歉,暂不支持Mac版",
content: "Mac版正在开发中,敬请期待",
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
okText: '我知道了'
});
} }
BaseService
.getLastedVersion({ model: 5, platform})
.then((res) => {
const a = document.createElement("a");
document.body.appendChild(a);
a.href = res.result.releaseUrl;
a.click();
document.body.removeChild(a);
})
} }
render() { render() {
const userRole = User.getUserRole();
return ( return (
<div className="live-course-opt"> <div className="live-course-opt">
<div className="opt__left"> <div className="opt__left">
{ userRole !== "CloudLecturer" &&
<Button type="primary" onClick={this.handleCreateLiveCouese}>新建直播课</Button> <Button type="primary" onClick={this.handleCreateLiveCouese}>新建直播课</Button>
}
<Button onClick={this.handleDownloadClient}>下载直播客户端</Button> <Button onClick={this.handleDownloadClient}>下载直播客户端</Button>
</div> </div>
</div> </div>
......
...@@ -43,7 +43,7 @@ class AbnormalModal extends React.Component { ...@@ -43,7 +43,7 @@ class AbnormalModal extends React.Component {
</div> </div>
) : ( ) : (
<div <div
className="content"> 你的小麦云课堂余额不足(<span className="high-light">{balance.toFixed(2)}</span>元),为保障您直播间的正常使用,请您及时充值。余额耗尽后将无法进行直播,学员无法观看回放视频。 className="content"> 你的小麦云企培余额不足(<span className="high-light">{balance.toFixed(2)}</span>元),为保障您直播间的正常使用,请您及时充值。余额耗尽后将无法进行直播,学员无法观看回放视频。
</div> </div>
); );
......
...@@ -122,7 +122,7 @@ class ManageCoursewareModal extends React.Component { ...@@ -122,7 +122,7 @@ class ManageCoursewareModal extends React.Component {
// 上传文件 // 上传文件
addFile() { addFile() {
// 判断是否早于开课前45分钟 // 判断是否早于开课前30分钟
const { startTime } = this.props.data; const { startTime } = this.props.data;
const currentTime = new Date().getTime(); const currentTime = new Date().getTime();
if (currentTime >= startTime - 30 * 60 * 1000) { if (currentTime >= startTime - 30 * 60 * 1000) {
...@@ -313,7 +313,7 @@ class ManageCoursewareModal extends React.Component { ...@@ -313,7 +313,7 @@ class ManageCoursewareModal extends React.Component {
const uploadFail = failObject[item.id]; const uploadFail = failObject[item.id];
// 上课前45分钟/上课中/已结束的情况下都不可操作 // 上课前45分钟/上课中/已结束的情况下都不可操作
if (this.props.data.startTime < Date.now() + 2700000 || item.progress || uploadFail) { if (this.props.data.startTime < Date.now() + 1800000 || item.progress || uploadFail) {
return <span>-</span> return <span>-</span>
} }
return ( return (
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-07-23 14:54:16 * @Date: 2020-07-23 14:54:16
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-24 10:23:44 * @LastEditTime: 2021-01-09 16:26:03
* @Description: 大班直播课预览弹窗 * @Description: 大班直播课预览弹窗
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -36,7 +36,16 @@ class PreviewCourseModal extends React.Component { ...@@ -36,7 +36,16 @@ class PreviewCourseModal extends React.Component {
} }
} }
dealTimeDuration = (time) => {
const diff = Math.floor(time % 3600);
let hours = Math.floor(time / 3600);
let mins = Math.floor(diff / 60);
let seconds = Math.floor(time % 60);
hours = hours < 10 ? ("0" + hours) : hours;
mins = mins < 10 ? ("0" + mins) : mins;
seconds = seconds < 10 ? ("0" + seconds) : seconds;
return hours + ":" + mins + ":" + seconds;
}
dealWithTime = (startTime, endTime) => { dealWithTime = (startTime, endTime) => {
const startDate = new Date(Number(startTime)); const startDate = new Date(Number(startTime));
const endDate = new Date(Number(endTime)); const endDate = new Date(Number(endTime));
...@@ -64,8 +73,8 @@ class PreviewCourseModal extends React.Component { ...@@ -64,8 +73,8 @@ class PreviewCourseModal extends React.Component {
render() { render() {
const { courseBasicInfo, courseClassInfo = {}, courseIntroInfo, type,courseState} = this.props; const { courseBasicInfo, courseClassInfo = {}, courseIntroInfo, type,courseState,origin} = this.props;
const { coverUrl, courseName, scheduleVideoUrl } = courseBasicInfo; const { coverUrl, courseName, scheduleVideoUrl,videoDuration} = courseBasicInfo;
const { liveDate, calendarTime,startTime,endTime,timeHorizonStart, timeHorizonEnd, teacherName } = courseClassInfo; const { liveDate, calendarTime,startTime,endTime,timeHorizonStart, timeHorizonEnd, teacherName } = courseClassInfo;
const { liveCourseMediaRequests } = courseIntroInfo; const { liveCourseMediaRequests } = courseIntroInfo;
...@@ -128,13 +137,15 @@ class PreviewCourseModal extends React.Component { ...@@ -128,13 +137,15 @@ class PreviewCourseModal extends React.Component {
<img src={coverUrl} className="course-cover" /> <img src={coverUrl} className="course-cover" />
} }
</div> </div>
{ {
type === 'videoCourse' ? type === 'videoCourse' ?
<div className="container__body"> <div className="container__body">
<div className="title__name">{courseName}</div> <div className="title__name">{courseName}</div>
<div className="title__inst-name">{window.currentUserInstInfo.name}</div> {videoDuration &&
</div> : <div>视频时长:{this.dealTimeDuration(videoDuration)}</div>
}
</div>
:
<div className="container__body"> <div className="container__body">
<div className="container__body__title"> <div className="container__body__title">
<div className="title__name">{courseName}</div> <div className="title__name">{courseName}</div>
...@@ -144,13 +155,11 @@ class PreviewCourseModal extends React.Component { ...@@ -144,13 +155,11 @@ class PreviewCourseModal extends React.Component {
<span className="time__label">上课时间:</span> <span className="time__label">上课时间:</span>
<span className="time__value"> <span className="time__value">
{ {
[ [
<span>{liveDateStr}&nbsp;</span>, <span>{liveDateStr}&nbsp;</span>,
<span>{startTimeStr}~{endTimeStr }</span> <span>{startTimeStr}~{endTimeStr }</span>
] ]
} }
</span> </span>
</div> </div>
<div className="container__body__teacher"> <div className="container__body__teacher">
...@@ -161,7 +170,11 @@ class PreviewCourseModal extends React.Component { ...@@ -161,7 +170,11 @@ class PreviewCourseModal extends React.Component {
} }
<div className="container__introduction"> <div className="container__introduction">
{ type === 'videoCourse' ?
<div className="container__introduction__title">视频简介</div>
:
<div className="container__introduction__title">直播简介</div> <div className="container__introduction__title">直播简介</div>
}
<div className="container__introduction__list editor-box"> <div className="container__introduction__list editor-box">
{ {
liveCourseMediaRequests.map((item, index) => { liveCourseMediaRequests.map((item, index) => {
......
...@@ -13,6 +13,7 @@ import html2canvas from 'html2canvas'; ...@@ -13,6 +13,7 @@ import html2canvas from 'html2canvas';
import qrcode from "@/libs/qrcode/qrcode.js"; import qrcode from "@/libs/qrcode/qrcode.js";
import User from '@/common/js/user'; import User from '@/common/js/user';
import $ from 'jquery'; import $ from 'jquery';
import CourseService from "@/domains/course-domain/CourseService";
import './ShareLiveModal.less'; import './ShareLiveModal.less';
...@@ -36,22 +37,22 @@ class ShareLiveModal extends React.Component { ...@@ -36,22 +37,22 @@ class ShareLiveModal extends React.Component {
handleConvertShortUrl = () => { handleConvertShortUrl = () => {
const { longUrl } = this.props.data; const { longUrl } = this.props.data;
// // 发请求 // 发请求
// axios.Sales('public/businessShow/convertShortUrls', { CourseService.getQrcode({
// urls: [longUrl] urls: [longUrl]
// }).then((res) => { }).then((res) => {
// const { result = [] } = res; const { result = [] } = res;
// this.setState({ this.setState({
// shareUrl: result[0].shortUrl shareUrl: result[0].shortUrl
// }, () => { }, () => {
// const qrcodeWrapDom = document.querySelector('#qrcodeWrap'); const qrcodeWrapDom = document.querySelector('#qrcodeWrap');
// const qrcodeNode = new qrcode({ const qrcodeNode = new qrcode({
// text: this.state.shareUrl, text: this.state.shareUrl,
// size: 98, size: 98,
// }) })
// qrcodeWrapDom.appendChild(qrcodeNode); qrcodeWrapDom.appendChild(qrcodeNode);
// }); });
// }) })
} }
componentWillUnmount() { componentWillUnmount() {
...@@ -92,8 +93,8 @@ class ShareLiveModal extends React.Component { ...@@ -92,8 +93,8 @@ class ShareLiveModal extends React.Component {
// 如果是默认图, 显示视频的第一帧, 否则显示上传的视频封面 // 如果是默认图, 显示视频的第一帧, 否则显示上传的视频封面
? ((!coverUrl || isDefaultCover) ? ((!coverUrl || isDefaultCover)
? `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast&anystring=anystring` ? `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast&anystring=anystring`
: `${coverUrl}${!needStr ? '&anystring=anystring': ''}`) : `${coverUrl}`)
: `${coverUrl}${(!needStr && !isDefaultCover) ? '&anystring=anystring' : ''}` : `${coverUrl}`
return ( return (
...@@ -112,10 +113,14 @@ class ShareLiveModal extends React.Component { ...@@ -112,10 +113,14 @@ class ShareLiveModal extends React.Component {
</div> </div>
<div className="course-name-title">{type === 'videoClass' ? `${courseName}开课啦`: `邀请你观看直播:`}</div> <div className="course-name-title">{type === 'videoClass' ? `${courseName}开课啦`: `邀请你观看直播:`}</div>
<div className="course-name">{courseName}</div> {
type === "liveClass" &&
<div class="live-couse-name">{courseName}</div>
}
<img <img
src={coverImgSrc} src={coverImgSrc}
crossOrigin="*"
className="course-cover" className="course-cover"
/> />
...@@ -132,13 +137,26 @@ class ShareLiveModal extends React.Component { ...@@ -132,13 +137,26 @@ class ShareLiveModal extends React.Component {
<div className="right"> <div className="right">
<div className="share-poster right__item"> <div className="share-poster right__item">
<div className="title">① 海报分享</div> <div className="title">① 海报分享</div>
<div className="sub-title">学生可通过微信识别二维码,报名观看直播</div> { type === "liveClass" &&
<div className="sub-title">用户可通过微信扫描海报二维码,观看直播</div>
}
{ type === "videoClass" &&
<div className="sub-title">用户可通过微信识别二维码,报名观看视频</div>
}
<div className="content" onClick={this.handleDownloadPoster}>下载海报</div> <div className="content" onClick={this.handleDownloadPoster}>下载海报</div>
</div> </div>
<div className="share-url right__item"> <div className="share-url right__item">
<div className="title">② 链接分享</div> <div className="title">② 链接分享</div>
<div className="sub-title">学生可通过微信打开链接,报名观看直播</div> { type === "liveClass" &&
<div className="sub-title">用户可通过微信打开以下链接,观看直播</div>
}
{ type === "videoClass" &&
<div className="sub-title">用户可通过打开链接,报名观看视频</div>
}
<div className="content"> <div className="content">
<div className="share-url" id="shareUrl">{shareUrl}</div> <div className="share-url" id="shareUrl">{shareUrl}</div>
<Button type="primary" onClick={this.handleCopy}>复制</Button> <Button type="primary" onClick={this.handleCopy}>复制</Button>
......
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
line-height: 20px; line-height: 20px;
margin-bottom: 4px; margin-bottom: 4px;
} }
.live-couse-name{
font-size:16px;
color:#333333;
font-weight: 600;
}
.course-name { .course-name {
color: #333; color: #333;
font-size: 16px; font-size: 16px;
......
.add-video-course-page {
.ant-radio-group {
display: flex;
flex-direction: column;
.radio-item {
margin-bottom: 12px;
.text {
color: #333;
}
.sub-text {
color: #999;
}
}
.ant-radio {
vertical-align: top;
padding-top: 2px;
}
}
.form {
margin-top: 16px;
padding: 0 16px;
.required {
position: relative;
&::before {
position: absolute;
content: '*';
color: red;
left: -10px;
top: 6px;
}
&.label::before {
top: 0;
}
}
.course-catalog{
margin-bottom:16px;
margin-top:16px;
}
.course-ware {
display: flex;
align-items: center;
margin-bottom: 4px;
&__img {
width: 24px;
margin-right: 4px;
}
&__name {
color: #333;
}
}
.flex {
display: flex;
}
.cover-url__wrap {
.img-content {
width: 298px;
height: 172px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.empty-img {
width: 298px;
height: 172px;
border: 1px dashed #EBEBEB;
border-radius: 4px;
padding: 12px;
color: #999;
padding: 52px 24px;
text-align: center;
}
.opt-btns {
margin-top: 8px;
display: flex;
align-items: center;
.tips {
margin-left: 12px;
color: #999;
}
}
}
.select-student {
align-items: center;
margin-left: 24px;
margin-top: 8px;
.has-selected {
margin-left: 12px;
color: #333;
}
}
.sub-content {
margin-left: 70px;
margin-top: 4px;
.tips {
margin-left: 16px;
color: #999;
}
}
}
.footer {
position: fixed;
bottom: 0;
height: 58px;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 252px;
background: #fff;
border-top: 1px solid #E8E8E8;
z-index: 999;
.ant-btn {
margin-left: 10px;
}
}
}
\ No newline at end of file
/*
* @Author: 吴文洁
* @Date: 2020-07-16 11:05:17
* @Last Modified by: mikey.zhaopeng
* @Last Modified time: 2020-11-24 14:29:52
* @Description: 添加直播-简介
*/
import React from 'react';
import { Input, message, Upload, Radio, Row, Col, Button, Popover, Switch } from 'antd';
import Service from '@/common/js/service';
import EditorBox from '../../components/EditorBox';
import User from '@/common/js/user';
import UploadOss from '@/core/upload';
import './AddVideoIntro.less';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { DISK_MAP } from '@/common/constants/academic/lessonEnum';
import { ImgCutModalNew } from '@/components';
const { TextArea } = Input;
const defaultCover = 'https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1599635741526.png';
class AddVideoIntro extends React.Component {
constructor(props) {
super(props);
this.state = {
warmUrl: defaultCover,
showSelectFileModal: false,
diskList: [],
selectType:null
}
}
// 上传封面图
handleShowImgCutModal = (event) => {
const imageFile = event.target.files[0];
if (!imageFile) return;
this.setState({
imageFile,
showCutModal: true,
});
}
// 选择暖场资源
handleSelectVideo = (file) => {
const { selectType } = this.state;
this.setState({
showSelectFileModal: false
})
const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file;
if(selectType === 'WARMUP'){
const liveCourseWarmMedia = {
contentType: 'WARMUP',
mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE',
mediaContent: resourceId,
mediaUrl: ossUrl,
mediaName: folderName,
size: folderSize
}
this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia);
}else{
// 最多添加九图片
const { liveCourseMediaRequests } = this.props.data;
const list = _.filter(liveCourseMediaRequests, (item) => {
return item.mediaType == "PICTURE";
});
if (list.length > 8) {
message.warning("最多添加9张图片");
return;
}
liveCourseMediaRequests.push({
contentType: 'INTRO',
size: folderSize,
mediaName: folderName,
mediaContent: resourceId,
mediaType: 'PICTURE',
mediaUrl: ossUrl,
});
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
}
// 删除简介
handleDeleteIntro = (index) => {
const { liveCourseMediaRequests } = this.props.data;
liveCourseMediaRequests.splice(index, 1);
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
// 上移简介
handleMoveUpIntro = (index) => {
const { liveCourseMediaRequests } = this.props.data;
const prevItem = liveCourseMediaRequests[index];
const nextItem = liveCourseMediaRequests[index + 1];
liveCourseMediaRequests.splice(index, 2, nextItem, prevItem);
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
// 下移简介
handleMoveDownIntro = (index) => {
const { liveCourseMediaRequests } = this.props.data;
const prevItem = liveCourseMediaRequests[index - 1];
const nextItem = liveCourseMediaRequests[index];
liveCourseMediaRequests.splice(index - 1, 2, nextItem, prevItem);
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
renderLittleIcon = (index) => {
const { liveCourseMediaRequests } = this.props.data;
return (
<div className="little-icon">
<span
className="icon iconfont close"
onClick={() => { this.handleDeleteIntro(index); }}
></span>
{
index > 0 &&
<span
className="icon iconfont"
onClick={() => { this.handleMoveDownIntro(index); }}
>&#xe6d1;</span>
}
{
index !== liveCourseMediaRequests.length - 1 &&
<span
className="icon iconfont"
onClick={() => { this.handleMoveUpIntro(index); }}
>&#xe6cf;</span>
}
</div>
)
}
handleChangeIntro = (index, value, length) => {
const { liveCourseMediaRequests } = this.props.data;
liveCourseMediaRequests[index].mediaContent = value;
liveCourseMediaRequests[index].mediaContentLength = length
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
handleAddIntroText = () => {
const { liveCourseMediaRequests } = this.props.data;
liveCourseMediaRequests.push({
contentType:"INTRO",
mediaType: 'TEXT',
mediaContent: '',
key: Math.random()
});
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
handleUpload = (Blob) => {
this.setState({
showSelectFileModal: true,
selectType:'INTRO'
})
}
whetherVisitorsJoinChange = ()=>{
if(this.props.data.whetherVisitorsJoin==="NO"){
this.props.onChange('whetherVisitorsJoin','YES')
}else{
this.props.onChange('whetherVisitorsJoin','NO')
}
}
shelfStateChange = ()=>{
if(this.props.data.shelfState==="NO"){
this.props.onChange('shelfState','YES')
}else{
this.props.onChange('shelfState','NO')
}
}
componentWillMount() {
}
render() {
const {data: { whetherVisitorsJoin,liveCourseMediaRequests = [], shelfState} } = this.props;
const {showSelectFileModal,selectType} = this.state
return (
<div className="add-video__intro-info">
<div className="allow-tourist-join">
<span className="label">观看设置:</span>
<div className="content">
<Row>
<Col span={3}>
<Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/>
</Col>
<Col span={21}>
<div className="desc">
<div>开启:允许未绑定手机号的用户进入直播间观看直播</div>
<div>关闭:仅限绑定了手机号的用户可以进入直播间观看直播</div>
</div>
</Col>
</Row>
</div>
</div>
<div className="store-show">
<span className="label">店铺展示:</span>
<div className="content">
<Row>
<Col span={3}>
<Switch checked={shelfState==="YES"? true:false} onChange={this.shelfStateChange}/>
</Col>
<Col span={21}>
<div className="desc">
<div>开启:此视频将在用户店铺的视频列表中出现</div>
<div>关闭:此视频将在用户店铺的视频列表中隐藏</div>
</div>
</Col>
</Row>
</div>
</div>
<div className="introduce">
<span className="label">视频课简介:</span>
<div className="content">
<div className="intro-list">
{
liveCourseMediaRequests.map((item, index) => {
if (item.mediaType === 'TEXT') {
return (
<div className="intro-list__item" key={item.key}>
<EditorBox
detail={{
content: item.mediaContent
}}
onChange={(val, length) => { this.handleChangeIntro(index, val, length) }}
/>
{this.renderLittleIcon(index)}
</div>
)
}
if (item.mediaType === 'PICTURE') {
return (
<div className="intro-list__item picture" key={index}>
<div className="img__wrap">
<img src={item.mediaUrl} />
</div>
{this.renderLittleIcon(index)}
</div>
)
}
})
}
</div>
<div className="operate">
<div className="operate__item" onClick={this.handleAddIntroText}>
<span className="icon iconfont">&#xe639;</span>
<span className="text">文字</span>
</div>
<div className="operate__item" onClick={this.handleUpload}>
<span className="icon iconfont">&#xe63b;</span>
<span className="text">图片</span>
</div>
</div>
<div className="tips">
• 图片支持jpeg、jpg、png、gif格式
</div>
</div>
</div>
{/* 选择暖场图文件弹窗 */}
<SelectPrepareFileModal
operateType="select"
accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"}
selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] }
tooltip={ selectType==="INTRO"?'支持文件类型:jpg、jpeg、png':'支持文件类型:jpg、jpeg、png、mp4'}
isOpen={showSelectFileModal}
onClose={() => {
this.setState({ showSelectFileModal: false })
}}
onSelect={this.handleSelectVideo}
/>
</div>
)
}
}
export default AddVideoIntro;
.add-video__intro-info {
.playback {
margin-bottom: 10px;
.require {
color: #EC4B35;
}
&__text {
color: #999;
}
}
.playback,
.introduce {
display: flex;
flex-direction: row;
}
.allow-tourist-join{
display:flex;
.desc{
margin-left:16px;
font-size:14px;
color:#999;
}
}
.store-show{
display:flex;
margin-top:16px;
margin-bottom:16px;
.desc{
margin-left:16px;
font-size:14px;
color:#999;
}
}
.radio {
display: block;
height: 30px;
line-height: 30px;
}
.interactive-playback {
display: flex;
margin-bottom: 20px;
}
textarea.ant-input {
min-height: 80px;
}
.intro-list__item {
display: flex;
margin-bottom: 16px;
position: relative;
&.picture {
width: 550px;
padding: 16px;
border: 1px solid #EEE;
border-radius: 4px;
.img__wrap {
width: 299px;
height: 168px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
}
.little-icon {
display: flex;
flex-direction: column;
position: absolute;
top: 0;
right: -20px;
.iconfont {
width: 20px;
height: 20px;
line-height: 20px;
font-size: 20px;
color: #999;
margin-bottom: 4px;
cursor: pointer;
&.close {
margin-top: 8px;
background-image: url('https://image.xiaomaiketang.com/xm/eesMPhNP3e.png');
background-size: 100% 100%;
}
}
}
}
.operate {
display: flex;
align-items: center;
justify-content: center;
width: 550px;
height: 80px;
line-height: 80px;
padding: 16px;
margin-top: 16px;
border: 1px dashed #EBEBEB;
border-radius: 4px;
.ant-upload {
vertical-align: middle;
}
&__item {
display: flex;
flex-direction: column;
cursor: pointer;
&:not(:last-child) {
margin-right: 82px;
}
.iconfont {
font-size: 22px;
line-height: 22px;
color: #BFBFBF;
text-align: center;
}
.text {
color: #999;
line-height: 20px;
margin-top: 4px;
}
}
}
.tips {
color: #999;
margin-top: 16px;
margin-bottom: 8px;
}
.checkExample {
width: 60px;
color: #FF7519;
cursor: pointer;
}
.warmup {
margin-bottom: 17px;
display: flex;
}
.course-cover__wrap {
display: flex;
flex-direction: row;
}
.img-content {
position: relative;
margin-right: 20px;
width: 300px;
height: 170px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
.img-delete-wrap {
opacity: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
img {
position: absolute;
left: 50%;
top: 50%;
width: 40px;
height: 40px;
transform: translate(-50%, -50%);
}
&:hover {
opacity: 1;
cursor: pointer;
}
}
}
.opt-btns {
.default-btn {
margin-left: 16px;
color: #FF7519;
cursor: pointer;
&.disabled {
color: #CCC;
cursor: not-allowed;
}
}
}
}
.example-wrap {
font-family: PingFangSC-Regular, PingFang SC;
text-align: center;
.title {
margin-bottom: 6px;
font-size: 14px;
color: #333333;
}
.text {
margin-bottom: 16px;
font-size: 12px;
color: #999999;
}
img {
width: 180px;
}
}
.check-record-rule {
width: 120px;
color: #FF7519;
cursor: pointer;
z-index: 2;
}
.record-rule-wrap {
text-align: left;
ul {
margin-top: 10px;
padding-left: 34px;
list-style-type: disc;
li {
color: #999;
}
}
.text {
color: #999;
}
}
.auto-send-class-report {
.label {
width: 57px;
height: 12px;
font-size: 14px;
font-weight: 400;
color: #666666;
line-height: 12px;
}
.open-text, .close-text {
width: 572px;
font-size: 14px;
font-weight: 400;
color: #999999;
line-height: 20px;
margin-left: 100px;
margin-top: 5px;
}
.open-text {
margin-top: 8px;
}
.close-text {
margin-bottom: 16px;
}
}
\ No newline at end of file
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:11:57
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-01-15 13:52:10
* @Description: 视频课-搜索模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import React from 'react';
import { Row, Input, Select,Tooltip } from 'antd';
import RangePicker from "@/modules/common/DateRangePicker";
// import TeacherSelectV5 from '@/modules/classManage_V5/classDetail/TeacherSelectV5';
import './VideoCourseFilter.less';
import moment from 'moment';
import StoreService from "@/domains/store-domain/storeService";
const { Search } = Input;
const { Option } = Select;
const DEFAULT_QUERY = {
courseName: null, // 课程名称
operatorId: null, // 创建人
beginTime: null, // 开始日期
endTime: null, // 结束日期
shelfState:null,
}
const defaultTeacherQuery = {
size: 10,
current: 1,
nickName:null
}
class VideoCourseFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
query: { ...DEFAULT_QUERY }, // 使用扩展运算符,避免浅拷贝
teacherQuery: defaultTeacherQuery,
teacherList:[],
expandFilter:false
}
}
componentDidMount() {
this.getTeacherList();
}
getTeacherList(current = 1, selectList){
const { teacherQuery,teacherList} = this.state;
const _query = {
...teacherQuery,
current,
size:10
};
StoreService.getStoreUserBasicPage( _query).then((res) => {
const { result = {} } = res;
const { records = [], total = 0, hasNext } = result;
const list = current > 1 ? teacherList.concat(records) : records;
this.setState({
hasNext,
teacherList: list,
})
});
}
// 滑动加载更多讲师列表
handleScrollTeacherList = (e) => {
const { hasNext } = this.state;
const container = e.target;
const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop;
if (scrollToBottom && hasNext) {
const { teacherQuery } = this.state;
this.getTeacherList(teacherQuery.current + 1);
}
}
// 改变搜索条件
handleChangeQuery = (field, value) => {
this.setState({
query: {
...this.state.query,
[field]: value,
current: 1,
}
}, () => {
if (field === 'courseName') return;
this.props.onChange(this.state.query)
});
}
handleChangeDates = (dates) => {
const query = _.clone(this.state.query);
if (_.isEmpty(dates)) {
delete query.beginTime;
delete query.endTime;
} else {
query.beginTime = dates[0].valueOf();
query.endTime = dates[1].valueOf();
}
this.setState({
query:{
...query,
current: 1,
}
}, () => {
this.props.onChange(this.state.query);
})
}
// 重置搜索条件
handleReset = () => {
this.setState({
query: DEFAULT_QUERY,
}, () => {
this.props.onChange(this.state.query);
})
}
render() {
const {
query: {
courseName,
operator,
beginTime,
endTime,
operatorId,
shelfState
},
expandFilter,
teacherList,
teacherQuery
} = this.state;
return (
<div className="video-course-filter">
<Row type="flex" justify="space-between" align="top">
<div className="search-condition">
<div className="search-condition__item">
<span className="search-name">视频课名称:</span>
<Search
value={courseName}
placeholder="搜索视频课名称"
onChange={(e) => { this.handleChangeQuery('courseName', e.target.value)}}
onSearch={ () => { this.props.onChange(this.state.query) } }
style={{ width: "calc(100% - 84px)" }}
/>
</div>
<div className="search-condition__item">
<span>创建人:</span>
<Select
placeholder="请选择创建人"
style={{width:"calc(100% - 70px)"}}
showSearch
allowClear
filterOption={(input, option) => option}
onPopupScroll={this.handleScrollTeacherList}
value={operatorId}
onChange={(value) => {
this.handleChangeQuery('operatorId', value)
}}
onSearch={(value) => {
teacherQuery.nickName = value
this.setState({
teacherQuery
}, () => {
this.getTeacherList()
})
}}
onClear ={(value)=>{
this.setState({
teacherQuery:{
size: 10,
current: 1,
nickName:null
}
}, () => {
this.getTeacherList()
})
}
}
>
{_.map(teacherList, (item, index) => {
return (
<Select.Option value={item.id} key={item.id}>{item.nickName}</Select.Option>
);
})}
</Select>
{/* <TeacherSelectV5
ref="TeacherSelect"
showSearch={true}
allowClear={true}
style={{ width: "calc(100% - 70px)" }}
onSelect={(teacherId) => { this.handleChangeQuery('teacherId', teacherId)}}
placeholder='请选择创建人'
label='创建人'
defaultValue={teacherId}
/> */}
</div>
<div className="search-condition__item">
<span className="search-date">创建日期:</span>
<RangePicker
id="course_date_picker"
allowClear={false}
value={ beginTime ? [moment(beginTime), moment(endTime)] : null }
format={"YYYY-MM-DD"}
onChange={(dates) => { this.handleChangeDates(dates) }}
style={{ width: "calc(100% - 70px)" }}
/>
</div>
{ expandFilter &&
<div className="search-condition__item">
<span className="shelf-status">店铺展示:</span>
<Select
style={{ width: "calc(100% - 84px)" }}
placeholder="请选择"
allowClear={true}
value={shelfState}
onChange={(value) => { this.handleChangeQuery('shelfState', value) }}
>
<Option value="YES">开启</Option>
<Option value="NO">关闭</Option>
</Select>
</div>
}
</div>
<div className="reset-fold-area">
<Tooltip title="清空筛选"><span className="resetBtn iconfont icon" onClick={this.handleReset}>&#xe61b; </span></Tooltip>
<span style={{ cursor: 'pointer' }} className="fold-btn" onClick={() => {
this.setState({expandFilter:!expandFilter});
}}>{this.state.expandFilter ? <span><span>收起</span><span className="iconfont icon fold-icon" >&#xe82d; </span> </span> : <span>展开<span className="iconfont icon fold-icon" >&#xe835; </span></span>}</span>
</div>
</Row>
</div>
)
}
}
export default VideoCourseFilter;
.video-course-filter {
position: relative;
.search-condition {
width: calc(100% - 80px);
display: flex;
align-items: center;
flex-wrap: wrap;
&__item {
width: 30%;
margin-right: 3%;
margin-bottom: 12px;
.search-name{
vertical-align: middle;
}
.shelf-status{
width:84px;
display:inline-block;
text-align:right;
}
}
}
.reset-fold-area {
position: absolute;
right: 12px;
}
.resetBtn {
color: #999999;
font-size: 18px;
margin-right: 8px;
}
.fold-btn {
font-size: 14px;
color: #666666;
line-height: 20px;
.fold-icon {
font-size: 12px;
}
}
}
.data-icon {
cursor: pointer;
}
.video-course-list {
margin-top: 12px;
.operate-text {
color: #5289FA;
cursor: pointer;
}
.operate {
display: flex;
&__item {
color: #5289FA;
cursor: pointer;
&.split {
margin: 0 8px;
color: #BFBFBF;
}
}
}
.record__item {
display: flex;
.course-cover {
min-width: 97px;
max-width: 97px;
height: 50px;
border-radius: 2px;
margin-right: 8px;
background-color: #666;
}
.course-name {
color: #666;
width:188px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
height:48px;
}
}
}
.video-course-more-menu {
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
border-radius: 4px;
div {
line-height: 30px;
padding: 0 15px;
cursor: pointer;
&:hover {
background: #f3f6fa;
}
}
}
.ant-tooltip{
max-width:700px !important;
}
.ant-tooltip-inner{
max-width:700px !important;
}
\ No newline at end of file
.video-course-opt {
margin-top: 16px;
.link {
color: #FF8534;
}
}
\ No newline at end of file
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:15
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 16:07:27
* @Description: 视频课-操作模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import React from 'react';
import { Button } from 'antd';
import './VideoCourseOpt.less';
export default function VideoCourseOpt() {
return (
<div className="video-course-opt">
<Button
type="primary"
onClick={() => {
RCHistory.push('/create-video-course?type=add');
}}
className="mr12"
>新建视频课</Button>
</div>
);
}
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:08:06
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 15:56:49
* @Description: 云课堂-视频课入口页面
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import React from 'react';
import VideoCourseFilter from './components/VideoCourseFilter';
import VideoCourseOpt from './components/VieoCourseOpt';
import VideoCourseList from './components/VideoCourseList';
import CourseService from "@/domains/course-domain/CourseService";
import User from '@/common/js/user'
class VideoCourse extends React.Component {
constructor(props) {
super(props);
this.state = {
query: {
size: 10,
current: 1,
storeId:User.getStoreId()
},
dataSource: [], // 视频课列表
totalCount: 0, // 视频课数据总条数
}
}
componentWillMount() {
// 获取视频课列表
this.handleFetchScheduleList();
}
// 获取视频课列表
handleFetchScheduleList = (_query = {}) => {
const query = {
...this.state.query,
..._query
};
// 更新请求参数
this.setState({ query });
CourseService.videoSchedulePage(query).then((res) => {
const { result = {} } = res || {};
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total)
});
});
}
render() {
const { dataSource, totalCount, query } = this.state;
return (
<div className="page video-course-page">
<div className="content-header">视频课</div>
<div className="box">
{/* 搜索模块 */}
<VideoCourseFilter
onChange={this.handleFetchScheduleList}
/>
{/* 操作模块 */}
<VideoCourseOpt />
{/* 视频课列表模块 */}
<VideoCourseList
query={query}
dataSource={dataSource}
totalCount={totalCount}
onChange={this.handleFetchScheduleList}
/>
</div>
</div>
)
}
}
export default VideoCourse;
/*
* @Author: 吴文洁
* @Date: 2020-05-19 11:01:31
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-05-25 16:50:47
* @Description 余额异常弹窗
*/
import React from 'react';
import {Table, Modal,Input} from 'antd';
import { PageControl } from "@/components";
import CourseService from "@/domains/course-domain/CourseService";
import User from '@/common/js/user'
import './WatchDataModal.less';
import dealTimeDuration from "../../utils/dealTimeDuration";
const { Search } = Input;
class WatchDataModal extends React.Component {
constructor(props) {
super(props);
this.state = {
visible:true,
dataSource:[],
size:10,
query: {
current: 1,
},
totalCount:0
};
}
componentDidMount() {
this.handleFetchDataList();
}
onClose = () =>{
this.props.close();
}
// 获取观看视频数据列表
handleFetchDataList = () => {
const {query,size,totalCount} = this.state
const { id } = this.props.data;
const params ={
...query,
size,
courseId:id,
storeId:User.getStoreId()
}
CourseService.videoWatchInfo(params).then((res) => {
const { result = {} } = res ;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total)
});
});
}
handleChangNickname = (value)=>{
const isPhone = (value || '').match(/^\d+$/);
const { query } = this.state;
if(isPhone){
query.phone = value;
query.nickName = null;
}else{
query.nickName = value;
query.phone = null;
}
query.current = 1;
this.setState({
query
})
}
onShowSizeChange = (current, size) => {
if (current == size) {
return
}
this.setState({
size
},()=>{this.handleFetchDataList()})
}
// 请求表头
parseColumns = () => {
const columns = [
{
title: '观看用户',
key: 'name',
dataIndex: 'name'
},
{
title: '手机号',
key: 'phone',
dataIndex: 'phone'
},
{
title: '观看者类型',
key: 'userRole',
dataIndex: 'userRole'
},
{
title: '首次观看时间',
key: 'firstWatch',
dataIndex: 'firstWatch',
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val)
}
},
{
title: '观看时长',
key: 'watchDuration',
dataIndex: 'watchDuration',
render: (val) => {
return <span>{val ? dealTimeDuration(val) : "00:00:00" }</span>
}
}
];
return columns;
}
render() {
const { visible,size,dataSource,totalCount,query,current } = this.state;
return (
<Modal
title="视频课观看数据"
visible={visible}
footer={null}
onCancel={this.onClose}
maskClosable={false}
className="watch-data-modal"
closable={true}
width={720}
>
<div className="search-container">
<Search placeholder="搜索用户姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} />
</div>
<div>
<Table
rowKey={record => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
/>
{dataSource.length >0 &&
<div className="box-footer">
<PageControl
current={current - 1}
pageSize={size}
total={totalCount}
toPage={(page) => {
const _query = {...query, current: page + 1};
this.setState({
query:_query
},()=>{ this.handleFetchDataList()})
}}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
}
</div>
</Modal>
)
}
}
export default WatchDataModal;
\ No newline at end of file
.watch-data-modal{
.search-container{
text-align:right;
margin-bottom:17px;
}
}
\ No newline at end of file
.personal-info-page{ .personal-info-page{
.page-content{ .page-content{
.box{ .box{
padding:60px !important; padding: 60px 60px 60px 40px !important;
} }
.label{ .label{
width:56px; width:84px;
text-align:right; text-align:right;
font-size: 14px; font-size: 14px;
color: #666666; color: #666666;
...@@ -31,7 +30,7 @@ ...@@ -31,7 +30,7 @@
background: #000; background: #000;
opacity:0; opacity:0;
position: absolute; position: absolute;
left:63px; left:92px;
text-align:center; text-align:center;
line-height:60px; line-height:60px;
.pen{ .pen{
......
/* /*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2020-11-27 15:06:31 * @Date: 2020-11-27 15:06:31
* @LastEditors: zhangleyuan * @LastEditors: wufan
* @LastEditTime: 2020-12-28 14:27:02 * @LastEditTime: 2021-01-18 21:22:16
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React, { useEffect, useState, useContext } from "react";
import React, { useEffect, useState,useContext } from "react";
import { withRouter } from "react-router-dom"; import { withRouter } from "react-router-dom";
import {Form,Button,Input,message} from "antd"; import { Form, Button, Input, message } from "antd";
import _ from 'underscore'; import _ from "underscore";
import $ from 'jquery'; import $ from "jquery";
import {CropperModal} from '@/components/'; import { CropperModal } from "@/components/";
import IdentificationModal from './IdentificationModal'; import IdentificationModal from "./IdentificationModal";
import ChangePhoneModal from './ChangePhoneModal'; import ChangePhoneModal from "./ChangePhoneModal";
import BaseService from "@/domains/basic-domain/baseService"; import BaseService from "@/domains/basic-domain/baseService";
import StoreService from "@/domains/store-domain/storeService"; import StoreService from "@/domains/store-domain/storeService";
import User from '@/common/js/user'; import User from "@/common/js/user";
import './index.less'; import "./index.less";
import { XMContext } from '@/store/context'; import { XMContext } from "@/store/context";
import { setStoreList } from '@/store/actions/index'; import { setStoreList } from "@/store/actions/index";
function PersonalInfoPage() { function PersonalInfoPage() {
const [avatar,setAvatar] = useState('https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png'); const [avatar, setAvatar] = useState(
"https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png"
);
const [imgUrl, setImgUrl] = useState(avatar); const [imgUrl, setImgUrl] = useState(avatar);
const [nickName,setNickName] = useState(''); const [nickName, setNickName] = useState("");
const [cropperModalVisible, setCropperModalVisible] = useState(false); const [cropperModalVisible, setCropperModalVisible] = useState(false);
const [IdentificationModalVisible, setIdentificationModalVisible] = useState(false); const [IdentificationModalVisible, setIdentificationModalVisible] = useState(
false
);
const [changePhoneModalVisible, setChangePhoneModalVisible] = useState(false); const [changePhoneModalVisible, setChangePhoneModalVisible] = useState(false);
const [roleCodes,setRoleCodes] = useState([]) const [roleCodes, setRoleCodes] = useState([]);
const [phone,setPhone] = useState(""); const [phone, setPhone] = useState("");
const storeUserId = User.getStoreUserId() const [weChatAccount, setWeChatAccount] = useState("");
const storeUserId = User.getStoreUserId();
const ctx: any = useContext(XMContext); const ctx: any = useContext(XMContext);
const userId = User.getUserId(); const userId = User.getUserId();
const isWorkWechat = !!(User.getStoreType() === "WE_CHAT_STORE");
window.ctx = ctx; window.ctx = ctx;
useEffect(() => { useEffect(() => {
storeUserId && getUserInfo(); storeUserId && getUserInfo();
},[storeUserId]) }, [storeUserId]);
function getUserInfo(){
const param ={ function getUserInfo() {
storeUserId:User.getStoreUserId() const param = {
} storeUserId: User.getStoreUserId(),
};
BaseService.getStoreUser(param).then((res) => { BaseService.getStoreUser(param).then((res) => {
const {nickName,phone,roleCodes} = res.result; const { nickName, phone, roleCodes, weChatAccount } = res.result;
setNickName(nickName); setNickName(nickName);
setPhone(phone); setPhone(phone);
setRoleCodes(roleCodes) setRoleCodes(roleCodes);
if(res.result.avatar){ setWeChatAccount(weChatAccount);
setAvatar(res.result.avatar) if (res.result.avatar) {
setAvatar(res.result.avatar);
} }
}); });
} }
function _handleUpdateAvatar(e: any): any { function _handleUpdateAvatar(e: any): any {
console.log('update'); console.log("update");
const avatar = e.target.files[0]; const avatar = e.target.files[0];
const newUrl = URL.createObjectURL(avatar); const newUrl = URL.createObjectURL(avatar);
const $image = $('#image'); const $image = $("#image");
setImgUrl(newUrl); setImgUrl(newUrl);
setCropperModalVisible(true); setCropperModalVisible(true);
} }
function _onUpload(): any { function _onUpload(): any {
$('#CrpperAvatarPic').trigger('click'); $("#CrpperAvatarPic").trigger("click");
} }
function changeAvatar(img:string):any{ function changeAvatar(img: string): any {
setAvatar(img); setAvatar(img);
setImgUrl(img); setImgUrl(img);
} }
function closeCropperModal():any { function closeCropperModal(): any {
setCropperModalVisible(false); setCropperModalVisible(false);
} }
function identificationConfirm():any {
function identificationConfirm(): any {
setIdentificationModalVisible(false); setIdentificationModalVisible(false);
setChangePhoneModalVisible(true); setChangePhoneModalVisible(true);
} }
function saveUserInfo(){
const params = { function saveUserInfo() {
const params = isWorkWechat ? {
nickName, nickName,
phone: String(phone), phone: String(phone),
roleCodes:roleCodes, roleCodes: roleCodes,
avatar,
storeUserId: User.getStoreUserId()
} : {
nickName,
roleCodes: roleCodes,
avatar, avatar,
storeUserId:User.getStoreUserId() storeUserId: User.getStoreUserId()
}; };
StoreService.editEmployee(params).then((res) => { StoreService.editEmployee(params).then((res) => {
getStoreGroupAndStoreList(); getStoreGroupAndStoreList();
message.success("保存成功"); message.success("保存成功");
}); });
} }
function getStoreGroupAndStoreList() { function getStoreGroupAndStoreList() {
BaseService.getUserStore({ userId }).then((res) => { BaseService.getUserStore({ userId }).then((res) => {
const {storeVOS = [] } = res.result; const { storeVOS = [] } = res.result;
ctx.dispatch(setStoreList(storeVOS)); ctx.dispatch(setStoreList(storeVOS));
}); });
} }
function changePhoneConfirm(phone:any){
function changePhoneConfirm(phone: any) {
setPhone(phone); setPhone(phone);
} }
console.log('User.getStoreType()',User.getStoreType());
return ( return (
<div className="page personal-info-page"> <div className="page personal-info-page">
<div className="page-content"> <div className="page-content">
<div className="content-header"> <div className="content-header">个人设置</div>
个人设置
</div>
<div className="box"> <div className="box">
<Form> <Form>
<div className="avatat-item"> <div className="avatat-item">
...@@ -113,54 +132,87 @@ function PersonalInfoPage() { ...@@ -113,54 +132,87 @@ function PersonalInfoPage() {
<input <input
type="file" type="file"
accept="image/*" accept="image/*"
value={''} value={""}
id="CrpperAvatarPic" id="CrpperAvatarPic"
style={{ display: 'none' }} style={{ display: "none" }}
onChange={_handleUpdateAvatar} /> onChange={_handleUpdateAvatar}
/>
<img className="avatar" src={avatar}></img> <img className="avatar" src={avatar}></img>
<span className="avatar-cover" onClick={_onUpload}> <span className="avatar-cover" onClick={_onUpload}>
<span className="icon iconfont pen"> <span className="icon iconfont pen">&#xe82c;</span>
&#xe82c;
</span>
</span> </span>
{ cropperModalVisible && {cropperModalVisible && (
<CropperModal <CropperModal
imgUrl={imgUrl} imgUrl={imgUrl}
save={changeAvatar} save={changeAvatar}
close={closeCropperModal} close={closeCropperModal}
/> />
} )}
</div> </div>
<div className="name-item"> <div className="name-item">
<span className="label">昵称:</span> <span className="label">昵称:</span>
<Input <Input
placeholder="请输入姓名,最多15个字" placeholder="请输入姓名,最多15个字"
style={{ width:300,height:32}} value={nickName} style={{ width: 300, height: 32 }}
value={nickName}
maxLength={15} maxLength={15}
onChange={(e) => { onChange={(e) => {
setNickName(e.target.value); setNickName(e.target.value);
}} }}
/> />
</div> </div>
{isWorkWechat ? (
<div className="phone-item">
<span className="label">企业微信号:</span>
<span>{weChatAccount}</span>
</div>
) : (
<div className="phone-item"> <div className="phone-item">
<span className="label">手机号:</span> <span className="label">手机号:</span>
<span>{phone}</span> <span>{phone}</span>
<Button className="changePhoneBtn" onClick={()=>{setIdentificationModalVisible(true)}}>更换手机号</Button> <Button
className="changePhoneBtn"
onClick={() => {
setIdentificationModalVisible(true);
}}
>
更换手机号
</Button>
</div> </div>
)}
<div> <div>
<Button type="primary" onClick={()=>{saveUserInfo()}}>保存</Button> <Button
type="primary"
onClick={() => {
saveUserInfo();
}}
>
保存
</Button>
</div> </div>
</Form> </Form>
</div> </div>
{ {IdentificationModalVisible && (
IdentificationModalVisible && <IdentificationModal phone={phone} onClose={()=>{setIdentificationModalVisible(false)}} onConfirm={()=>{identificationConfirm()}}/> <IdentificationModal
} phone={phone}
onClose={() => {
setIdentificationModalVisible(false);
}}
onConfirm={() => {
identificationConfirm();
}}
/>
)}
{ {changePhoneModalVisible && (
changePhoneModalVisible && <ChangePhoneModal onClose={()=>{setChangePhoneModalVisible(false)}} onConfirm={changePhoneConfirm}/> <ChangePhoneModal
} onClose={() => {
setChangePhoneModalVisible(false);
}}
onConfirm={changePhoneConfirm}
/>
)}
</div> </div>
</div> </div>
); );
} }
......
...@@ -76,7 +76,17 @@ class SelectPrepareFileModal extends React.Component { ...@@ -76,7 +76,17 @@ class SelectPrepareFileModal extends React.Component {
showNonCompliantFileModal: false, showNonCompliantFileModal: false,
} }
} }
componentDidMount() {
const { diskList = [], currentRootDisk} = this.props;
const _currentRootDisk = diskList[0] || currentRootDisk || defaultRootDisk;
this.setState({
query: defaultQuery,
currentRootDisk: _currentRootDisk,
folderPathList: [_currentRootDisk],
}, () => {
this.handleFetchFolderList();
});
}
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { diskList = [], currentRootDisk} = nextProps; const { diskList = [], currentRootDisk} = nextProps;
if (nextProps.isOpen) { if (nextProps.isOpen) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2019-07-10 10:30:49 * @Date: 2019-07-10 10:30:49
* @LastEditors: wufan * @LastEditors: wufan
* @LastEditTime: 2020-12-26 14:47:37 * @LastEditTime: 2021-01-18 21:22:33
* @Description: * @Description:
*/ */
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
...@@ -28,6 +28,9 @@ const App: React.FC = (props: any) => { ...@@ -28,6 +28,9 @@ const App: React.FC = (props: any) => {
useEffect(() => { useEffect(() => {
getStoreAndUserInfo(); getStoreAndUserInfo();
window.RCHistory.push({
pathname: `/switch-route`,
})
}, []) }, [])
async function getStoreAndUserInfo() { async function getStoreAndUserInfo() {
...@@ -39,13 +42,14 @@ const App: React.FC = (props: any) => { ...@@ -39,13 +42,14 @@ const App: React.FC = (props: any) => {
BaseService.getUserStore({ userId }).then((res) => { BaseService.getUserStore({ userId }).then((res) => {
const { storeGroupVOS = [], storeVOS = [] } = res.result; const { storeGroupVOS = [], storeVOS = [] } = res.result;
const { id, storeUserId, storeName, userRole } = storeVOS[0]; const { id, storeUserId, storeName, userRole, storeType } = storeVOS[0];
console.log("userRole----app",userRole)
User.setStoreId(id); User.setStoreId(id);
User.setStoreUserId(storeUserId); User.setStoreUserId(storeUserId);
User.setStoreName(storeName); User.setStoreName(storeName);
User.setUserRole(userRole); User.setUserRole(userRole);
User.setStoreType(storeType);
ctx.dispatch(setStoreGroupList(storeGroupVOS)) ctx.dispatch(setStoreGroupList(storeGroupVOS))
ctx.dispatch(setStoreList(storeVOS)); ctx.dispatch(setStoreList(storeVOS));
serStoreUserId(storeUserId) serStoreUserId(storeUserId)
......
/*
* @Author: 吴文洁
* @Date: 2019-09-10 18:26:03
* @LastEditors: wufan
* @LastEditTime: 2021-01-12 17:25:20
* @Description:
*/
import React, { useContext, useEffect, useState } from "react";
import "./Header.less";
import { Menu, Dropdown, Modal, Tooltip, message } from "antd";
import { LIVE_SHARE } from "@/domains/course-domain/constants";
import User from "@/common/js/user";
import BaseService from "@/domains/basic-domain/baseService";
import { XMContext } from "@/store/context";
import logoImg from "@/common/images/logo.png";
import CourseService from "@/domains/course-domain/CourseService";
import qrcode from "@/libs/qrcode/qrcode.js";
const baseImg = "https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png";
const { confirm } = Modal;
function Header(props) {
const { menuType, handleMenuType } = props;
const ctx = useContext(XMContext);
const htmlUrl = `${LIVE_SHARE}store/index?id=${User.getStoreId()}&userId=${User.getUserId()}&from=work_weixin`;
useEffect(() => {
htmlUrl && handleConvertShortUrl();
}, []);
function userMenu() {
return (
<Menu
style={{
maxWidth: "250px",
marginTop: 5,
}}
>
<Menu.Item
style={{ whiteSpace: "normal", wordBreak: "break-all" }}
key="1"
onClick={() => toPersonalInfoPage()}
>
个人设置
</Menu.Item>
<Menu.Item
style={{ whiteSpace: "normal", wordBreak: "break-all" }}
key="2"
onClick={(e) => {
handleLogoutConfirm();
}}
>
退出登录
</Menu.Item>
</Menu>
);
}
function handleMenu() {
handleMenuType();
}
function toPersonalInfoPage() {
window.RCHistory.push({
pathname: `/personal-info`,
});
}
function handleLogoutConfirm() {
return confirm({
title: "你确定要退出登录吗?",
content: "退出后,需重新登录",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
okText: "退出登录",
cancelText: "点错了",
onOk: () => {
handleLogout();
},
});
}
function handleLogout() {
BaseService.logout({}).then((res) => {
User.removeUserId();
User.removeToken();
window.RCHistory.push({
pathname: `/login`,
});
});
}
function handleConvertShortUrl() {
CourseService.getQrcode({
urls: [htmlUrl],
}).then((res) => {
const { result = [] } = res;
const qrcodeWrapDom = document.querySelector("#h5-qrcode");
const qrcodeNode = new qrcode({
text: result[0].shortUrl,
size: 110,
});
qrcodeWrapDom && qrcodeWrapDom.appendChild(qrcodeNode);
});
}
// 复制分享链接
function handleCopy() {
window.copyText(htmlUrl);
message.success('已复制店铺地址,快去分享吧~');
}
return (
<div id="top-container" className="top-container">
<div className="top top-nav">
<div>
<img src={logoImg} className="logo" alt="" />
{menuType && <span className="logo-name">小麦企培</span>}
</div>
{menuType ? (
<span
className="icon iconfont cursor ml20 handLike"
onClick={handleMenu}
>
&#xe83d;
</span>
) : (
<span
className="icon iconfont cursor ml20 handLike"
onClick={handleMenu}
>
&#xe615;
</span>
)}
<div className="message-help">
<div className="store-related">
<div className="store-name">{User.getStoreName()}</div>
<div className="line"></div>
<div className="link-to-store">
<div className="link">
<span className="icon iconfont tool-tip-right">&#xe85d;</span>
<div className="text">前往店铺</div>
<div className="store-popover">
<div className="pc-url">
<div className="name">网页端店铺</div>
<div
className="url-link"
onClick={() => {
window.open(htmlUrl);
}}
>
{"立即前往 >"}
</div>
</div>
<div className="h5-url">
<div className="name">手机端店铺</div>
<div id="h5-qrcode"></div>
<div className="tip">微信扫码,打开店铺</div>
</div>
</div>
</div>
<div className="share" onClick={handleCopy}>
<Tooltip title="分享店铺" placement="bottom">
<span className="icon iconfont tool-tip-right">&#xe85e;</span>
</Tooltip>
<div className="text">分享店铺</div>
</div>
</div>
</div>
<Dropdown overlay={userMenu()}>
<div className="user">
<img
style={{
width: 32 + "px",
height: 32 + "px",
borderRadius: "50%",
overflow: "hidden",
flexShrink: 0,
}}
src={
ctx.xmState &&
ctx.xmState.storeList &&
ctx.xmState.storeList[0].avatar
? ctx.xmState.storeList[0].avatar
: baseImg
}
/>
{ctx.xmState && ctx.xmState.storeList && (
<span className="name">
{ctx.xmState.storeList[0].nickName}
</span>
)}
</div>
</Dropdown>
</div>
</div>
</div>
);
}
export default Header;
@import '../../core/variables.less'; @import "../../core/variables.less";
@top-height: 50px; @top-height: 50px;
@icon-color:#939393; @icon-color: #939393;
.top-container { .top-container {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
height: @top-height; height: @top-height;
background-color: #FFF; background-color: #fff;
z-index: 112; z-index: 112;
.logo{ .logo {
display: inline-block; display: inline-block;
height: 24px; height: 24px;
margin-left: 20px; margin-left: 20px;
} }
.logo-name{ .logo-name {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: #FFB714; color: #ffb714;
line-height: 20px; line-height: 20px;
vertical-align: middle; vertical-align: middle;
font-weight:bold; font-weight: bold;
margin-left:11px; margin-left: 11px;
} }
.top { .top {
display: flex; display: flex;
...@@ -34,9 +34,9 @@ ...@@ -34,9 +34,9 @@
height: 100%; height: 100%;
justify-content: space-between; justify-content: space-between;
-webkit-justify-content: space-between; -webkit-justify-content: space-between;
border-bottom:1px solid @xm-color-border; border-bottom: 1px solid @xm-color-border;
.backCenter{ .backCenter {
color:rgba(0,0,0,1); color: rgba(0, 0, 0, 1);
font-size: 16px; font-size: 16px;
} }
.top-left { .top-left {
...@@ -109,11 +109,11 @@ ...@@ -109,11 +109,11 @@
overflow-y: hidden; overflow-y: hidden;
border-radius: 4px; border-radius: 4px;
padding: 4px 0; padding: 4px 0;
-webkit-transition: all .3s; -webkit-transition: all 0.3s;
-moz-transition: all .3s; -moz-transition: all 0.3s;
-ms-transition: all .3s; -ms-transition: all 0.3s;
-o-transition: all .3s; -o-transition: all 0.3s;
transition: all .3s; transition: all 0.3s;
li { li {
margin: 2px 10px; margin: 2px 10px;
font-size: 12px; font-size: 12px;
...@@ -123,16 +123,16 @@ ...@@ -123,16 +123,16 @@
&:hover { &:hover {
.area-list { .area-list {
height: auto; height: auto;
background: rgba(0, 0, 0, .6); background: rgba(0, 0, 0, 0.6);
li { li {
-webkit-transition: all .3s; -webkit-transition: all 0.3s;
-moz-transition: all .3s; -moz-transition: all 0.3s;
-ms-transition: all .3s; -ms-transition: all 0.3s;
-o-transition: all .3s; -o-transition: all 0.3s;
transition: all .3s; transition: all 0.3s;
} }
li:hover { li:hover {
background-color: rgba(255, 255, 255, .2); background-color: rgba(255, 255, 255, 0.2);
} }
} }
} }
...@@ -177,16 +177,118 @@ ...@@ -177,16 +177,118 @@
flex: 1; flex: 1;
-webkit-flex: 1; -webkit-flex: 1;
justify-content: space-between; justify-content: space-between;
.store-related {
width: 500px;
height: 49px;
display: flex;
position: relative;
.store-name { .store-name {
width: 200px;
height: 20px;
font-size: 14px; font-size: 14px;
color: #666; color: #666;
line-height: 20px; line-height: 49px;
margin-left: 36px; margin-left: 36px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
max-width: 230px;
margin-right: 32px;
}
.line {
width: 1px;
height: 16px;
background-color: #f4f4f4;
position: absolute;
left: 122px;
top: 50%;
transform: translateY(-50%);
}
.link-to-store {
display: flex;
height: 49px;
line-height: 49px;
.text {
font-size: 14px;
color: #666;
line-height: 49px;
margin-left: 7px;
}
.iconfont {
color: #8c8e93;
&:hover {
color: #555;
}
}
.link {
display: flex;
cursor: pointer;
position: relative;
.store-popover {
display: none;
}
&:hover {
.store-popover {
position: absolute;
display: flex;
width: 216px;
height: 260px;
top: 49px;
left: 0;
background-color: #fff;
flex-wrap: wrap;
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
.pc-url {
display: flex;
justify-content: space-between;
width: 100%;
height: 56px;
padding: 16px;
border-bottom: 1px solid #e8e8e8;
.name {
width: 70px;
font-size: 14px;
color: #333333;
line-height: 20px;
}
.url-link {
color: #5289fa;
width: 70px;
font-size: 14px;
line-height: 20px;
}
}
.h5-url {
width: 100%;
.name,
.tip {
width: 70px;
font-size: 14px;
color: #333333;
line-height: 52px;
margin: 0 auto;
}
#h5-qrcode {
width: 110px;
height: 110px;
margin: 0 auto;
}
.tip {
line-height: 41px;
width: 130px;
}
}
}
}
}
.share {
cursor: pointer;
display: flex;
margin-left: 16px;
}
}
} }
.inst-container { .inst-container {
width: calc(~'100% - 420px'); width: calc(~"100% - 420px");
position: relative; position: relative;
.inst { .inst {
margin-right: 12px; margin-right: 12px;
...@@ -203,7 +305,7 @@ ...@@ -203,7 +305,7 @@
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
max-width:230px; max-width: 230px;
} }
.icon { .icon {
font-size: 16px; font-size: 16px;
...@@ -237,7 +339,7 @@ ...@@ -237,7 +339,7 @@
} }
.ant-radio-wrapper { .ant-radio-wrapper {
display: inline-block; display: inline-block;
width: calc(~'100% - 28px'); width: calc(~"100% - 28px");
margin: 8px 0; margin: 8px 0;
.ant-radio { .ant-radio {
float: left; float: left;
...@@ -274,8 +376,8 @@ ...@@ -274,8 +376,8 @@
padding: 0 12px; padding: 0 12px;
width: 106px; width: 106px;
.icon-text { .icon-text {
margin-left:4px; margin-left: 4px;
color:#333; color: #333;
} }
} }
.icon { .icon {
...@@ -300,7 +402,7 @@ ...@@ -300,7 +402,7 @@
} }
.help-menu { .help-menu {
.help-center { .help-center {
box-shadow: 0 2px 8px rgba(0,0,0,0.15); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
position: absolute; position: absolute;
overflow: hidden; overflow: hidden;
top: 50px; top: 50px;
...@@ -333,7 +435,7 @@ ...@@ -333,7 +435,7 @@
} }
.message-menu { .message-menu {
.message-center { .message-center {
box-shadow: 0 0 8px rgba(0,0,0,0.15); box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
position: absolute; position: absolute;
overflow: hidden; overflow: hidden;
top: 50px; top: 50px;
...@@ -352,9 +454,10 @@ ...@@ -352,9 +454,10 @@
overflow: auto; overflow: auto;
// max-height: 255px; // max-height: 255px;
.message-item:hover { .message-item:hover {
background: #F3F6FA; background: #f3f6fa;
} }
li,a { li,
a {
width: 100%; width: 100%;
display: block; display: block;
border-bottom: 1px solid @xm-color-border; border-bottom: 1px solid @xm-color-border;
......
/*
* @Author: 吴文洁
* @Date: 2019-09-10 18:26:03
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-22 15:39:35
* @Description:
*/
import React , { useContext, useState}from 'react';
import './Header.less';
import {
Menu,
Dropdown,
Modal
} from 'antd';
import { QuestionCircleOutlined } from "@ant-design/icons";
import { withRouter } from 'react-router-dom';
import User from '@/common/js/user';
import BaseService from "@/domains/basic-domain/baseService";
import { XMContext } from '@/store/context';
import logoImg from '@/common/images/logo.png';
const baseImg ='https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png'
const { confirm } = Modal;
interface headerProps {
menuType:boolean,
handleMenuType:() => void
}
function Header(props:headerProps){
const { menuType ,handleMenuType} = props;
const ctx: any = useContext(XMContext);
function userMenu() {
return (
<Menu
style={{
maxWidth: "250px",
marginTop: 5,
}}
>
<Menu.Item
style={{whiteSpace: "normal", wordBreak: "break-all"}}
key="1"
onClick={() => toPersonalInfoPage()}
>
个人设置
</Menu.Item>
<Menu.Item
style={{whiteSpace: "normal", wordBreak: "break-all"}}
key="2"
onClick={e => {
handleLogoutConfirm();
}}
>
退出登录
</Menu.Item>
</Menu>
);
}
function handleMenu(){
handleMenuType();
};
function toPersonalInfoPage(){
window.RCHistory.push({
pathname: `/personal-info`,
})
}
function handleLogoutConfirm(){
return confirm({
title: "你确定要退出登录吗?",
content: "退出后,需重新登录",
icon: <span className="icon iconfont default-confirm-icon">&#xe839; </span>,
okText: "退出登录",
cancelText: "点错了",
onOk: () => {
handleLogout();
},
});
}
function handleLogout(){
BaseService.logout({}).then((res) => {
User.removeUserId();
User.removeToken();
window.RCHistory.push({
pathname: `/login`,
})
});
}
return (
<div id="top-container" className="top-container">
<div className="top top-nav">
<div>
<img src={logoImg} className="logo" alt="" />
{menuType && (
<span className="logo-name">小麦云课堂</span>
)}
</div>
{menuType ? (
<span className="icon iconfont cursor ml20 handLike" onClick={handleMenu}>
&#xe83d;
</span>
) : (
<span className="icon iconfont cursor ml20 handLike" onClick={handleMenu}>
&#xe615;
</span>
)}
<div className="message-help">
<div className="store-name">{User.getStoreName()}</div>
<Dropdown overlay={userMenu()}>
<div className="user">
<img
style={{
width: 32 + "px",
height: 32 + "px",
borderRadius: "50%",
overflow: "hidden",
flexShrink: 0,
}}
src={(ctx.xmState && ctx.xmState.storeList &&ctx.xmState.storeList[0].avatar) ? ctx.xmState.storeList[0].avatar:baseImg}
/>
{ ctx.xmState && ctx.xmState.storeList && (
<span className="name">{ctx.xmState.storeList[0].nickName}</span>
)
}
</div>
</Dropdown>
</div>
</div>
</div>
);
}
export default Header;
import React, { useEffect, useState} from 'react'; import React, { useEffect, useState } from 'react';
import { import {
withRouter withRouter
} from 'react-router-dom'; } from 'react-router-dom';
import './Login.less'; import './Login.less';
import {Input,Popover,message} from 'antd'; import { Input, Popover, message, Tabs } from 'antd';
import CheckBeforeSendCode from '../../components/CheckBeforeSendCode'; import CheckBeforeSendCode from '../../components/CheckBeforeSendCode';
import User from '@/common/js/user'; import User from '@/common/js/user';
import WechatLogin from './WechatLogin'
import BaseService from "@/domains/basic-domain/baseService"; import BaseService from "@/domains/basic-domain/baseService";
import axios from 'axios'; import axios from 'axios';
import _ from 'underscore'; import _ from 'underscore';
const { TabPane } = Tabs;
function Login(props) { function Login(props) {
const [phone, setPhone] = useState(''); // 登录手机号 const [phone, setPhone] = useState(''); // 登录手机号
...@@ -17,8 +20,8 @@ function Login(props) { ...@@ -17,8 +20,8 @@ function Login(props) {
const [checking1, setChecking1] = useState(false); const [checking1, setChecking1] = useState(false);
const [codeText, setCodeText] = useState('获取验证码'); // 验证码提示语 const [codeText, setCodeText] = useState('获取验证码'); // 验证码提示语
const [waitStatus, setWaitStatus] = useState(false); // 验证码是否在倒计时 const [waitStatus, setWaitStatus] = useState(false); // 验证码是否在倒计时
const [errorMessage,setErrorMessage] = useState(''); const [errorMessage, setErrorMessage] = useState('');
const [phoneError,setPhoneError] = useState(false); const [phoneError, setPhoneError] = useState(false);
const [checkObject1, setCheckObject1] = useState({}); const [checkObject1, setCheckObject1] = useState({});
async function checkAccount(code, callback = () => { }) { async function checkAccount(code, callback = () => { }) {
...@@ -48,7 +51,7 @@ function Login(props) { ...@@ -48,7 +51,7 @@ function Login(props) {
token: checkData.token, token: checkData.token,
scene: 'nc_login', scene: 'nc_login',
serverType: "CLOUD_CLASS_LOGIN", serverType: "CLOUD_CLASS_LOGIN",
appTermEnum:'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN' appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN'
} }
BaseService.sendLoginAuthCode(params).then((res) => { BaseService.sendLoginAuthCode(params).then((res) => {
if (!res.success) { if (!res.success) {
...@@ -86,14 +89,14 @@ function Login(props) { ...@@ -86,14 +89,14 @@ function Login(props) {
setErrorMessage("请输入11位手机号") setErrorMessage("请输入11位手机号")
return; return;
} }
if(!phoneverify){ if (!phoneverify) {
setErrorMessage("请输入验证码"); setErrorMessage("请输入验证码");
return; return;
} }
const params = { const params = {
phone, phone,
authCode:phoneverify, authCode: phoneverify,
appTermEnum:"XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN" appTermEnum: "XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN"
} }
BaseService.login(params).then((res) => { BaseService.login(params).then((res) => {
if (!res.success) { if (!res.success) {
...@@ -113,15 +116,17 @@ function Login(props) { ...@@ -113,15 +116,17 @@ function Login(props) {
<div className="login-main"> <div className="login-main">
<div className="left-banner"> <div className="left-banner">
<div><img src={require("../../common/images/logo.png")} alt="" style={{ width: 60,height:61}} /></div> <div><img src={require("../../common/images/logo.png")} alt="" style={{ width: 60,height:61}} /></div>
<div className="name">小麦云课堂</div> <div className="name">小麦企培</div>
<div className="desc">一键开启直播授课 让知识更有价值</div> <div className="desc">一键开启直播授课 让知识更有价值</div>
</div> </div>
<div className="login-box"> <div className="login-box">
<div className="login"> <div className="login">
<div className="r"> <div className="r">
<div className="title"> <Tabs defaultActiveKey="1" >
手机号登录 <TabPane tab="企业微信登录" key="1">
</div> <WechatLogin></WechatLogin>
</TabPane>
<TabPane tab="手机号登录" key="2">
<div className="login-form"> <div className="login-form">
<div className="form"> <div className="form">
<div className="username" style={{ marginBottom: 16 }}> <div className="username" style={{ marginBottom: 16 }}>
...@@ -189,11 +194,15 @@ function Login(props) { ...@@ -189,11 +194,15 @@ function Login(props) {
</div> </div>
<div className="submit"> <div className="submit">
<div className="btn"> <div className="btn">
<button id='loginIn' onClick={ () => { handleSubmit() } } >登录</button> <button id='loginIn' onClick={() => { handleSubmit() }} >登录</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</TabPane>
</Tabs>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -78,6 +78,38 @@ ...@@ -78,6 +78,38 @@
overflow: hidden; overflow: hidden;
background-color: #ffffff; background-color: #ffffff;
border-radius: 4px; //box-shadow: 0 0 17px @sun; border-radius: 4px; //box-shadow: 0 0 17px @sun;
.ant-tabs-tab-btn{
color: #999999;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
line-height: 25px;
&.ant-tabs-tab-active{
color: #333333;
}
}
.ant-tabs-tab-active{
.ant-tabs-tab-btn{
color: #333333;
}
}
.ant-tabs-nav::before{
display: none;
}
.ant-tabs-tab{
width: 105px;
text-align: center;
}
.ant-tabs > .ant-tabs-nav .ant-tabs-nav-list{
margin: 0 auto;
}
.ant-tabs-top > .ant-tabs-nav .ant-tabs-ink-bar{
width: 24px !important;
height: 4px;
margin-left: 30px;
}
.l { .l {
width: 280px; width: 280px;
height: 100%; height: 100%;
...@@ -420,4 +452,5 @@ ...@@ -420,4 +452,5 @@
} }
} }
} }
} }
\ No newline at end of file
.wechatLoginBox{
height: 320px;
text-align: center;
.text{
margin-top: 12px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
}
.rwm{
position: relative;
width: 160px;
height: 160px;
text-align: center;
display: inline-block;
margin-top: 24px;
.error{
position: absolute;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.95);
display: flex;
align-items:center;
justify-content:center;
left:0px;
top: 0px;
div{
margin: 0 10px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
}
.ope{
cursor: pointer;
color:rgba(82, 137, 250, 1);
}
}
}
.ant-tabs-tab-active{
.ant-tabs-tab-btn{
color: #333333;
}
}
.ant-tabs-tab-btn{
color: #999999;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
line-height: 25px;
}
.ant-tabs-nav::before{
display: none;
}
.ant-tabs-tab{
width: 105px;
text-align: center;
}
.ant-tabs > .ant-tabs-nav .ant-tabs-nav-list{
margin: 0 auto;
}
.ant-tabs-top > .ant-tabs-nav .ant-tabs-ink-bar{
width: 24px !important;
height: 4px;
margin-left: 30px;
}
}
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