Commit 98a0b83a by chenshu

fix:merge

parents 1eeefb2b ae9dbed4
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
# 小麦企学院B端
## Available Scripts
小麦企学院是一个全场景企业培训数字化平台。提供了多场景解决方案,同时满足对客对内培训需求;提供了完善的服务保障体系,助力各行业持续经营进阶以及客户成功。
In the project directory, you can run:
## 目录
### `yarn start`
- [安装](#安装)
- [用法](#用法)
- [开发](#开发)
- [发布地址](#发布地址)
- [关联项目](#关联项目)
- [项目网址](#项目网址)
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
## 安装
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
```bash
git clone ssh://git@xmgit.ixm5.cn:10022/xiaomai-cloud-class/xiaomai-cloud-class-web.git
cd xiaomai-cloud-class-web
cnpm install
```
### `yarn test`
## 用法
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
```bash
npm start
```
### `yarn build`
## 开发
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
```bash
git add .
git commit -m 'commit comments'
git pull
git push
```
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
## 发布地址
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
开发环境发布地址: [http://jenkins-web.ixm5.cn/view/%E5%89%8D%E7%AB%AF/job/web-dev-%E5%B0%8F%E9%BA%A6%E4%BC%81%E5%9F%B9-cloud-class-web/](http://jenkins-web.ixm5.cn/view/%E5%89%8D%E7%AB%AF/job/web-dev-%E5%B0%8F%E9%BA%A6%E4%BC%81%E5%9F%B9-cloud-class-web/)
### `yarn eject`
正式环境发布地址:[http://jenkins-web.ixm5.cn/view/%E5%89%8D%E7%AB%AF-%E7%BA%BF%E4%B8%8A/job/web-prod-cloud-class/](http://jenkins-web.ixm5.cn/view/%E5%89%8D%E7%AB%AF-%E7%BA%BF%E4%B8%8A/job/web-prod-cloud-class/)
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
## 关联项目
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
小麦企学院c端: [https://xmgit.ixm5.cn/xiaomai-cloud-class/xiaomai-live-room](https://xmgit.ixm5.cn/xiaomai-cloud-class/xiaomai-live-room)
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
## 项目网址
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
dev环境: [https://dev.xiaomai5.com/xiaomai-cloud-class-web/index.html#/login](https://dev.xiaomai5.com/xiaomai-cloud-class-web/index.html#/login)
## Learn More
rc环境: [https://rc.xiaomai5.com/xiaomai-cloud-class-web/index.html#/login](https://rc.xiaomai5.com/xiaomai-cloud-class-web/index.html#/login)
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
灰度环境: [https://res.xiaomai5.com/xiaomai-cloud-class-web/gray/index.html#/login](https://res.xiaomai5.com/xiaomai-cloud-class-web/gray/index.html#/login)
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `yarn build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
线上环境: [https://res.xiaomai5.com/xiaomai-cloud-class-web/index.html#/login](https://res.xiaomai5.com/xiaomai-cloud-class-web/index.html#/login)
\ No newline at end of file
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditTime: 2021-01-09 11:18:27
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-05-10 10:14:39
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
......@@ -17,7 +17,7 @@
<!-- <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>
<title>小麦企学院</title>
<script type="text/javascript" charset="utf-8" src="./jquery.min.js"></script>
<style type="text/css">
......
......@@ -19,7 +19,7 @@ class ChooseMembersModal extends React.Component {
this.state = {
allUserList : [], // 所有成员列表
selectUserList: [], // 已选则成员
temporaryList: [], // 临时用户成员列表(搜索时使用)
temporaryList: [], // 临时学员成员列表(搜索时使用)
instId : window.currentUserInstInfo.instId, // 机构Id
searchKey : null, // 搜索内容
selectedRowKeys : [], // 勾选的成员
......@@ -229,7 +229,7 @@ class ChooseMembersModal extends React.Component {
selectedColumnsRight = () => {
const selectColumns = [
{
title: '用户名',
title: '学员名',
key: 'adminNameRight',
dataIndex: 'adminName',
width: '70%',
......
/*
* @Author: 吴文洁
* @Date: 2020-08-31 09:34:25
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-04-13 17:56:34
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-05-12 17:27:08
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -101,7 +101,12 @@ class User {
setCustomerStoreId(value:any) {
return Storage.set(`${PREFIX}_customerStoreId`,value);
}
setIdentifier(value:any){
return Storage.set(`${PREFIX}_identifier`,value);
}
getIdentifier(){
return Storage.get(`${PREFIX}_identifier`);
}
clearUserInfo(){
Storage.remove(`${USER_PREFIX}_token`);
Storage.remove(`${USER_PREFIX}_userId`);
......
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class ClickOutside extends Component {
static propTypes = {
onClickOutside: PropTypes.func.isRequired
}
constructor(props) {
super(props)
this.getContainer = this.getContainer.bind(this)
this.isTouch = false
}
getContainer(ref) {
this.container = ref
}
render() {
const { children, onClickOutside, ...props } = this.props
return <div {...props} ref={this.getContainer}>{children}</div>
}
componentDidMount() {
document.addEventListener('touchend', this.handle, true)
document.addEventListener('click', this.handle, true)
}
componentWillUnmount() {
document.removeEventListener('touchend', this.handle, true)
document.removeEventListener('click', this.handle, true)
}
handle = e => {
if (e.type === 'touchend') this.isTouch = true
if (e.type === 'click' && this.isTouch) return
const { onClickOutside } = this.props
const el = this.container
if (el && !el.contains(e.target)) onClickOutside(e)
}
}
\ No newline at end of file
/*
* @Author: wufan
* @Date: 2020-11-25 18:25:02
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-22 13:58:04
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:25:01
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -23,7 +23,7 @@ export default class courseService {
return getQrcode(params);
}
// 获取用户上课数据
// 获取学员上课数据
static fetchUserData(params: any) {
return fetchUserData(params);
}
......
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-02 14:58:57
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-05-10 13:41:44
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
......@@ -18,7 +18,7 @@
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">
<link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/c4KiP2epBP.png">
<!--
manifest.json provides metadata used when your web app is installed on a
......@@ -36,7 +36,7 @@
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>
<title>小麦企学院</title>
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/iscroll-zoom-min.js"></script>
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/hammer.min.js"></script>
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/lrz.all.bundle.js"></script>
......
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-02 14:59:11
* @LastEditors: wufan
* @LastEditTime: 2021-05-17 19:53:24
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
......@@ -13,12 +13,10 @@
<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"
/>
<meta name="description" content="小麦企学院,一站式企业培训数字化服务商,通过“工具+内容”,帮助企业快速从0到1搭建数字化培训体系,并让整个培训过程可视化,降低培训成本,提升培训效率。">
<meta name="keywords" content="小麦企学院,企业培训,员工培训,企业大学,企业内训,企业外训,培训计划,培训素材,企培,企训,资料云盘,培训课程,培训任务,直播课,视频课,图文课,线下课,知识库,作业,考试,排行榜,培训类别管理,定制培训计划,管理数据,学习数据,企学院,资料共享,培训数字化,数字化培训,培训工具,在线培训,线上培训,培训saas,培训管理,企业微信培训,对客培训,客户培训,直播培训,互联网培训,新员工培训,管理培训,管理者培训,工人培训,制造业培训,餐饮培训,服务业培训,零售培训,门店培训,工厂培训,车间培训,培训补贴,人事培训,财务培训,职场培训,企业学院平台,教育企业学院,教育企业平台,教育平台学院,企业学习,酷学院,小鹅通,企业学院,云学堂,时代光华,云课堂,魔学院,云大学,米知云,授课学堂">
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> -->
<link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/KGSYFEpcHT.png">
<link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/c4KiP2epBP.png">
<!--
manifest.json provides metadata used when your web app is installed on a
......@@ -36,7 +34,7 @@
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>
<title>小麦企学院</title>
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/iscroll-zoom-min.js"></script>
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/hammer.min.js"></script>
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/lrz.all.bundle.js"></script>
......
/*
* @Author: wufan
* @Date: 2020-11-30 10:47:38
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-02-02 10:22:34
* @Description: 用户管理页面
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 17:45:53
* @Description: 学员管理页面
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -60,7 +60,7 @@ function UserManagePage() {
function parseColumn() {
const list = [
{
title: "用户姓名",
title: "学员姓名",
dataIndex: "nickName",
render: (val: string, item: any) => {
return (
......@@ -117,16 +117,16 @@ function UserManagePage() {
return (
<div className=" page user-manage-page">
<div className="content-header">用户管理</div>
<div className="content-header">学员管理</div>
<div className="box">
<div className="box-header">
<div className="header-item">
<span className="item-name">搜索用户</span>
<span className="item-name">搜索学员</span>
<Search
style={{
width: 300,
}}
placeholder="搜索用户姓名/手机号"
placeholder="搜索学员姓名/手机号"
onSearch={(value) => {
const _query = { ...query };
if (value) {
......@@ -149,7 +149,7 @@ function UserManagePage() {
</div>
<div className="header-item">
<span className="item-name">用户来源:</span>
<span className="item-name">学员来源:</span>
<Select
style={{ width: '100%' }}
placeholder="请选择"
......@@ -195,7 +195,7 @@ function UserManagePage() {
onClick={() => {
handleToAddEmployee();
}}
>添加用户</Button>
>添加学员</Button>
}
<div className="box-body">
<Table
......
......@@ -21,7 +21,7 @@ class ChooseMembersModal extends React.Component {
isOpen: props.isOpen,
allUserList : [], // 所有成员列表
selectUserList: [], // 已选则成员
temporaryList: [], // 临时用户成员列表(搜索时使用)
temporaryList: [], // 临时学员成员列表(搜索时使用)
instId : window.currentUserInstInfo.instId, // 机构Id
searchKey : null, // 搜索内容
selectedRowKeys : [], // 勾选的成员
......@@ -230,7 +230,7 @@ class ChooseMembersModal extends React.Component {
selectedColumnsRight = () => {
const selectColumns = [
{
title: '用户名',
title: '学员名',
key: 'nameRight',
dataIndex: 'name',
width: '70%',
......@@ -274,7 +274,7 @@ class ChooseMembersModal extends React.Component {
isOpen,
selectObject,
} = this.state;
const title = type === 'USER' ? '添加员工' : '添加用户';
const title = type === 'USER' ? '添加员工' : '添加学员';
return (
<div>
{/* 添加学员页面 */}
......@@ -284,7 +284,7 @@ class ChooseMembersModal extends React.Component {
onCancel={() => this.handleClose()}
onOk={() => {
if (_.isEmpty(selectUserList)) {
message.warning(type === 'USER' ? '请选择员工' : '请选择用户')
message.warning(type === 'USER' ? '请选择员工' : '请选择学员')
return null;
}
type === 'USER' ? this.setState({ openSetModal: true, isOpen: false }) : this.addCustomer();
......@@ -341,7 +341,7 @@ class ChooseMembersModal extends React.Component {
</div>
{/* 已选择的成员列表 */}
<div className='container-right'>
<span className='span-left'>已选择{type === 'USER' ? '员工' : '用户'}</span>
<span className='span-left'>已选择{type === 'USER' ? '员工' : '学员'}</span>
<div className='span-right' onClick={() => this.clearAllUser()}>
<span className={ (selectUserList.length > 0) ? 'span-right-l' : null }>清空</span>
</div>
......
......@@ -88,7 +88,7 @@ export default class SetEmployeeModal extends React.Component {
<Radio value={"Cloud_Operator"} className="mt-4">
<span style={{ color: "#333" }}>运营师</span>
<p className="radio-tip">
仅可查看/转发培训计划内容,并查看负责的用户学习进度
仅可查看/转发培训计划内容,并查看负责的学员学习进度
</p>
</Radio>
<Radio value={"Cloud_Lecturer"} className="mt-4">
......
......@@ -544,7 +544,7 @@ handleChangeBasicInfo = (field, value) => {
/>
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企保有依据国家规定及平台规则进行处理的权利" />
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div>
<div className="add-live-page__form">
<div className="basic-info__wrap">
......
......@@ -106,7 +106,7 @@ class DataList extends React.Component {
getStudentColumns() {
const columns = [
{
title: "用户姓名",
title: "学员姓名",
dataIndex: "userName",
},
{
......@@ -304,9 +304,9 @@ class DataList extends React.Component {
</div>
</div>
{/* 用户上课数据 */}
{/* 学员上课数据 */}
<div className="courseData-student">
<p className="title">用户上课数据</p>
<p className="title">学员上课数据</p>
<div className="filter-wrap">
<div className="filter">
<Button
......
......@@ -56,7 +56,7 @@ class PlaybackData extends React.Component {
getPlaybackColumns() {
const columns = [
{
title: "观看用户",
title: "观看学员",
dataIndex: "userName",
},
{
......
......@@ -132,8 +132,8 @@ class AddLiveIntro extends React.Component {
</div>
<div>
<div class="instro-text">
<div>开启:允许未绑定手机号的用户进入直播间观看直播</div>
<div>关闭:仅限绑定了手机号的用户可以进入直播间观看直播</div>
<div>开启:允许未绑定手机号的学员进入直播间观看直播</div>
<div>关闭:仅限绑定了手机号的学员可以进入直播间观看直播</div>
</div>
</div>
</div>
......
......@@ -15,16 +15,15 @@ class GraphicsEditor extends React.Component {
textLength: 0,
showSelectImageModal: false,
showSelectVideoModal: false,
diskList: [],
}
this.editorInt = null;
this.isContent = true;
}
componentDidMount() {
this.renderEditor()
this.resetIndex(true);
this.initBus();
this.bindClick();
}
......@@ -32,23 +31,6 @@ class GraphicsEditor extends React.Component {
componentWillUnmount() {
this.resetIndex();
this.removeBus();
this.removeClick();
}
bindClick = () => {
window.addEventListener('click', this.clickEditor)
}
removeClick = () => {
window.removeEventListener('click', this.clickEditor)
}
clickEditor = (e) => {
if (e && e.target.closest('.content-editor')) {
this.isContent = true
} else if (e && e.target.closest('.introduce-editor')) {
this.isContent = false
}
}
resetIndex = (bool) => {
......@@ -102,9 +84,10 @@ class GraphicsEditor extends React.Component {
}
this.editorInt = new E(`#editor${editorId}`);
this.editorInt.config.focus = false;
this.editorInt.config.showFullScreen = !isIntro
this.editorInt.menus.extend('xmimage', ImageMenu);
this.editorInt.menus.extend('xmvideo', VideoMenu);
!isIntro && this.editorInt.menus.extend('xmvideo', VideoMenu);
this.editorInt.config.menus = isIntro ?
[
'head',
......@@ -184,19 +167,21 @@ class GraphicsEditor extends React.Component {
// 选择图文
handleSelectVideo = (file) => {
const { ossUrl } = file || {};
if (!ossUrl) return null;
this.setState({
showSelectVideoModal: false
})
const { ossUrl } = file;
const { detail } = this.props;
this.editorInt && this.editorInt.txt.html(`${detail.content}<p style="width: 100%;padding-top: 56.25%;position: relative;"><iframe style="position: absolute;width: 100%;height: 100%;top: 0;left: 0;" src="${ossUrl}"></iframe><br/></p><p><br/></p>`)
}
handleSelectImage = (file) => {
const { ossUrl } = file || {};
if (!ossUrl) return null;
this.setState({
showSelectImageModal: false
})
const { ossUrl } = file;
const { detail } = this.props;
this.editorInt && this.editorInt.txt.html(`${detail.content}<p><img style="max-width: 100%;" src="${ossUrl}" /><br/><p>`)
}
......@@ -204,13 +189,13 @@ class GraphicsEditor extends React.Component {
initBus = () => {
const { isIntro } = this.props;
Bus.bind(`graphicsEditorImage${isIntro ? '' : 'Content'}`, this.uploadImage)
Bus.bind('graphicsEditorVideo', this.uploadVideo)
!isIntro && Bus.bind('graphicsEditorVideo', this.uploadVideo)
}
removeBus = () => {
const { isIntro } = this.props;
Bus.unbind(`graphicsEditorImage${isIntro ? '' : 'Content'}`, this.uploadImage)
Bus.unbind('graphicsEditorVideo', this.uploadVideo)
!isIntro && Bus.unbind('graphicsEditorVideo', this.uploadVideo)
}
uploadImage = () => {
......@@ -222,7 +207,13 @@ class GraphicsEditor extends React.Component {
}
render() {
const { editorId, textLength, showSelectImageModal, showSelectVideoModal } = this.state;
const {
editorId,
textLength,
showSelectImageModal,
showSelectVideoModal,
diskList,
} = this.state;
const { limitLength = 1000, isIntro, maxLimit } = this.props;
return <div className={`graphics-editor-container${isIntro ? ' introduce' : ''} ${(textLength > maxLimit)&& 'warning'}`}>
<div className="editor-box" id={`editor${editorId}`} ></div>
......
......@@ -262,7 +262,7 @@ class LiveCourseList extends React.Component {
{
title: <span>
<span>学院展示</span>
<Tooltip title={<div>开启后,用户可在学院内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”学院展示。<br/>关闭后,学院内不再展示此课程,但用户仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
<Tooltip title={<div>开启后,学员可在学院内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”学院展示。<br/>关闭后,学院内不再展示此课程,但学员仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
</span>,
width: "9%",
key: "shelfState",
......@@ -580,7 +580,7 @@ class LiveCourseList extends React.Component {
handleDelete = (record)=>{
return confirm({
title: '你确定要删除直播课?',
content: '删除后,用户将不能观看直播课/回放',
content: '删除后,学员将不能观看直播课/回放',
icon: <span className="icon iconfont default-confirm-icon">&#xe839; </span>,
okText: '删除',
okType: 'danger',
......@@ -658,7 +658,7 @@ class LiveCourseList extends React.Component {
}
getDownloadVersion() {
const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
// 判断用户系统
// 判断学员系统
let platform;
if(!isMac){
platform = 1
......
......@@ -28,7 +28,7 @@ class LiveCourseOpt extends React.Component {
// 下载直播客户端
handleDownloadClient = () => {
const { isMac } = this.state;
// 判断用户系统
// 判断学员系统
let platform;
if(!isMac){
platform = 1
......
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-05 10:07:47
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-29 14:08:47
* @LastEditTime: 2021-05-10 10:15:31
* @Description: 图文课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -56,7 +56,6 @@ class AddGraphicsCourse extends React.Component {
coverUrl: defaultCoverUrl, // 图文课封面
studentList: [], // 上课学员列表
shelfState:'YES', //是否开启学院展示
diskList: [], // 机构可见磁盘目录
selectedFileList: [], // 已经从资料云盘中勾选的文件
showCutModal: false, // 是否显示截图弹窗
showSelectVideoModal: false,
......@@ -65,7 +64,6 @@ class AddGraphicsCourse extends React.Component {
courseCatalogList:[], //分类列表
categoryId:null, //分类的Id值
whetherVisitorsJoin: 'NO', // 是否允许游客加入
isContent: true,
}
}
......@@ -513,7 +511,6 @@ class AddGraphicsCourse extends React.Component {
courseMedia,
introduce,
showCutModal,
diskList,
imageFile,
videoType,
shelfState,
......@@ -541,7 +538,7 @@ class AddGraphicsCourse extends React.Component {
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企保有依据国家规定及平台规则进行处理的权利" />
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div>
<div className="form">
......
......@@ -118,8 +118,8 @@ class AddGraphicsIntro extends React.Component {
</div>
<div>
<div className="desc">
<div>开启:允许未绑定手机号的用户观看</div>
<div>关闭:仅限绑定了手机号的用户可以进入观看图文课</div>
<div>开启:允许未绑定手机号的学员观看</div>
<div>关闭:仅限绑定了手机号的学员可以进入观看图文课</div>
</div>
</div>
</div>
......@@ -133,8 +133,8 @@ class AddGraphicsIntro extends React.Component {
</Col>
<Col span={21}>
<div className="desc">
<div>开启:图文课将在用户学院图文课列表中展示</div>
<div>关闭:图文课将在用户学院图文课列表中隐藏</div>
<div>开启:图文课将在学员学院图文课列表中展示</div>
<div>关闭:图文课将在学员学院图文课列表中隐藏</div>
</div>
</Col>
</Row>
......
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-27 16:24:47
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:32:38
* @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -137,7 +137,7 @@ class GraphicsCourseList extends React.Component {
{
title: <span>
<span>学院展示</span>
<Tooltip title={<div>开启后,用户可在学院内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”学院展示。<br/>关闭后,学院内不再展示此课程,但用户仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
<Tooltip title={<div>开启后,学员可在学院内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”学院展示。<br/>关闭后,学院内不再展示此课程,但学员仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
</span>,
width: 120,
dataIndex: "courseware",
......@@ -148,7 +148,7 @@ class GraphicsCourseList extends React.Component {
},
},
{
title: "观看用户数",
title: "观看学员数",
width: 110,
key: "watchUserCount",
dataIndex: "watchUserCount",
......
......@@ -84,7 +84,7 @@ class WatchDataModal extends React.Component {
parseColumns = () => {
const columns = [
{
title: '观看用户',
title: '观看学员',
key: 'name',
dataIndex: 'name'
},
......@@ -141,7 +141,7 @@ class WatchDataModal extends React.Component {
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
>
<div className="search-container">
<Search placeholder="搜索用户姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
<Search placeholder="搜索学员姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
</div>
<div>
<Table
......
......@@ -197,10 +197,10 @@ class ShareLiveModal extends React.Component {
<div className="share-poster right__item">
<div className="title">① 海报分享</div>
{ type === "liveClass" &&
<div className="sub-title">用户可通过微信扫描海报二维码,观看{title}</div>
<div className="sub-title">学员可通过微信扫描海报二维码,观看{title}</div>
}
{ type === "videoClass" &&
<div className="sub-title">用户可通过微信识别二维码,报名观看{title}</div>
<div className="sub-title">学员可通过微信识别二维码,报名观看{title}</div>
}
<div className="content" onClick={this.handleDownloadPoster}>下载海报</div>
......@@ -209,10 +209,10 @@ class ShareLiveModal extends React.Component {
<div className="share-url right__item">
<div className="title">② 链接分享</div>
{ type === "liveClass" &&
<div className="sub-title">用户可通过微信打开以下链接,观看{title}</div>
<div className="sub-title">学员可通过微信打开以下链接,观看{title}</div>
}
{ type === "videoClass" &&
<div className="sub-title">用户可通过打开链接,报名观看{title}</div>
<div className="sub-title">学员可通过打开链接,报名观看{title}</div>
}
<div className="content url-content">
<div className="share-url" id="shareUrl">{shareUrl}</div>
......
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:07:47
* @LastEditors: yuananting
* @LastEditTime: 2021-03-24 19:34:37
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-05-10 10:15:46
* @Description: 视频课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -565,7 +565,7 @@ class AddVideoCourse extends React.Component {
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企保有依据国家规定及平台规则进行处理的权利" />
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div>
<div className="form">
......
......@@ -121,8 +121,8 @@ class AddVideoIntro extends React.Component {
</div>
<div>
<div className="desc">
<div>开启:允许未绑定手机号的用户观看</div>
<div>关闭:仅限绑定了手机号的用户可以进入观看视频</div>
<div>开启:允许未绑定手机号的学员观看</div>
<div>关闭:仅限绑定了手机号的学员可以进入观看视频</div>
</div>
</div>
</div>
......@@ -136,8 +136,8 @@ class AddVideoIntro extends React.Component {
</Col>
<Col span={21}>
<div className="desc">
<div>开启:此视频将在用户学院的视频列表中出现</div>
<div>关闭:此视频将在用户学院的视频列表中隐藏</div>
<div>开启:此视频将在学员学院的视频列表中出现</div>
<div>关闭:此视频将在学员学院的视频列表中隐藏</div>
</div>
</Col>
</Row>
......
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors: yuananting
* @LastEditTime: 2021-03-24 19:34:48
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:34:11
* @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -126,7 +126,7 @@ class VideoCourseList extends React.Component {
{
title: <span>
<span>学院展示</span>
<Tooltip title={<div>开启后,用户可在学院内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”学院展示。<br/>关闭后,学院内不再展示此课程,但用户仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
<Tooltip title={<div>开启后,学员可在学院内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”学院展示。<br/>关闭后,学院内不再展示此课程,但学员仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
</span>,
width: 120,
dataIndex: "courseware",
......@@ -137,7 +137,7 @@ class VideoCourseList extends React.Component {
},
},
{
title: "观看用户数",
title: "观看学员数",
width: 110,
key: "watchUserCount",
dataIndex: "watchUserCount",
......
......@@ -84,7 +84,7 @@ class WatchDataModal extends React.Component {
parseColumns = () => {
const columns = [
{
title: '观看用户',
title: '观看学员',
key: 'name',
dataIndex: 'name'
},
......@@ -133,7 +133,7 @@ class WatchDataModal extends React.Component {
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
>
<div className="search-container">
<Search placeholder="搜索用户姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
<Search placeholder="搜索学员姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
</div>
<div>
<Table
......
......@@ -270,7 +270,7 @@ class Home extends React.Component {
<div className="data-item">
<div className="header">
<img className="header-icon" src="https://image.xiaomaiketang.com/xm/wAaFtjeRsM.png" />
<span className="header-word">用户总数 (人)</span>
<span className="header-word">学员总数 (人)</span>
</div>
<div className="data-number">{totalCustomerNum}</div>
<div className="data-footer">
......
......@@ -2,8 +2,8 @@
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-15 16:51:40
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-10 16:13:07
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:34:39
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -116,7 +116,7 @@ class CourseData extends React.Component {
getStudentColumns() {
const columns = [
{
title: "用户姓名",
title: "学员姓名",
dataIndex: "userName",
},
{
......@@ -314,9 +314,9 @@ class CourseData extends React.Component {
</div>
</div>
{/* 用户上课数据 */}
{/* 学员上课数据 */}
<div className="courseData-student">
<p className="title">用户上课数据</p>
<p className="title">学员上课数据</p>
<div className="filter-wrap">
<div className="filter">
<Button
......
......@@ -2,8 +2,8 @@
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-12 14:49:40
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-12 10:31:53
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:35:41
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -251,7 +251,7 @@ class KnowledgeBaseList extends React.Component {
{record.hideToUser && (
<Tooltip
title={
<div>课程未成功开课,已在用户知识列表中隐藏</div>
<div>课程未成功开课,已在学员知识列表中隐藏</div>
}
>
<i
......@@ -423,7 +423,7 @@ class KnowledgeBaseList extends React.Component {
},
},
{
title: "观看用户数",
title: "观看学员数",
key: "watchUserCount",
dataIndex: "watchUserCount",
align:'right',
......
......@@ -56,7 +56,7 @@ class PlaybackData extends React.Component {
getPlaybackColumns() {
const columns = [
{
title: "观看用户",
title: "观看学员",
dataIndex: "userName",
},
{
......
......@@ -2,8 +2,8 @@
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-16 10:18:31
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-30 10:17:59
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:36:00
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -101,7 +101,7 @@ class WatchDataModal extends React.Component {
const { type } = this.props;
const columns = [
{
title: "观看用户",
title: "观看学员",
key: "name",
dataIndex: "name",
},
......@@ -195,7 +195,7 @@ class WatchDataModal extends React.Component {
<div className="watch-data">
<div className="search-container">
<Search
placeholder="搜索用户姓名/手机号"
placeholder="搜索学员姓名/手机号"
style={{ width: 200 }}
onChange={(e) => {
this.handleChangNickname(e.target.value);
......
......@@ -2,7 +2,7 @@
* @Author: zhangleyuan
* @Date: 2021-02-20 16:13:39
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-30 18:07:11
* @LastEditTime: 2021-05-10 10:15:58
* @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -260,7 +260,7 @@ function AddPlan() {
/>
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企保有依据国家规定及平台规则进行处理的权利" />
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div>
<div className="add-plan-page__form">
<div className="basic-info__wrap">
......
......@@ -102,7 +102,7 @@ class LearningData extends React.Component {
<Tabs.TabPane tab="员工分享数据" key="employeeShareData" forceRender="true">
<EmployeeShareData/>
</Tabs.TabPane>
<Tabs.TabPane tab="用户学习数据" key="userLearningData" forceRender="true">
<Tabs.TabPane tab="学员学习数据" key="userLearningData" forceRender="true">
<UserLearningData/>
</Tabs.TabPane>
</Tabs>)
......
/*
* @Author: zhangleyuan
* @Date: 2021-02-20 16:45:51
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-27 11:20:27
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:36:26
* @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -267,8 +267,8 @@ class BasicInfo extends React.Component{
</div>
<div>
<div className="instro-text">
<div>开启:此培训计划可以分享给用户进行学习</div>
<div>关闭:此培训计划暂不可分享给用户进行学习,后续可开启</div>
<div>开启:此培训计划可以分享给学员进行学习</div>
<div>关闭:此培训计划暂不可分享给学员进行学习,后续可开启</div>
</div>
</div>
</div>
......@@ -313,7 +313,7 @@ class BasicInfo extends React.Component{
<div>
<div className="live-standard-info">
<span className="icon iconfont">&#xe865;</span>
<span className="instro">直播课单个课程,用户学习进度达到
<span className="instro">直播课单个课程,学员学习进度达到
<Input
width="40"
value={percentCompleteLive}
......@@ -326,7 +326,7 @@ class BasicInfo extends React.Component{
</div>
<div className="live-standard-info">
<span className="icon iconfont">&#xe864;</span>
<span className="instro">视频课单个课程,用户学习进度达到
<span className="instro">视频课单个课程,学员学习进度达到
<Input
width="40"
value={percentCompleteVideo}
......@@ -339,7 +339,7 @@ class BasicInfo extends React.Component{
</div>
<div className="live-standard-info">
<span className="icon iconfont">&#xe601;</span>
<span className="instro">图文课单个课程,用户学习进度达到
<span className="instro">图文课单个课程,学员学习进度达到
<Input
width="40"
value={percentCompletePicture}
......@@ -350,19 +350,6 @@ class BasicInfo extends React.Component{
%,即视为"已完成"学习
</span>
</div>
{/* <div className="video-standard-info">
<span className="icon iconfont">&#xe864;</span>
<span>图文课单个课程,用户学习进度达到
<Input
width="40"
value={percentCompleteVideo}
onChange={(e) => { this.props.onChange('percentCompleteVideo', e.target.value.replace(/\D/g,'')) }}
onBlur={(e) => this.percentCompleteBlur(e, 'percentCompleteVideo')}
className="input-box"
/>
%,即视为“已完成”学习
</span>
</div> */}
</div>
</div>
{ operatorModalVisible &&
......
/*
* @Author: zhangleyuan
* @Date: 2021-02-20 16:46:46
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-16 15:53:59
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:36:43
* @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -242,7 +242,7 @@ function PlanList(props) {
function handleDelete(record){
return confirm({
title: '你确定要删除吗?',
content: '删除后,此培训计划的用户将无法继续学习,所有学习数据将同步删除不可恢复',
content: '删除后,此培训计划的学员将无法继续学习,所有学习数据将同步删除不可恢复',
icon: <span className="icon iconfont default-confirm-icon">&#xe839; </span>,
okText: '删除',
okType: 'danger',
......
......@@ -110,8 +110,8 @@ class UserLearningData extends React.Component {
UnbundEmployee = (record)=>{
if(User.getUserRole()==='CloudOperator'){
return confirm({
title: "你确定要解绑与用户的关系吗?",
content: "解绑后,用户该培训计划的学习数据将同步移出",
title: "你确定要解绑与学员的关系吗?",
content: "解绑后,学员该培训计划的学习数据将同步移出",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
......@@ -156,7 +156,7 @@ class UserLearningData extends React.Component {
if(User.getUserRole() === "CloudManager" || User.getUserRole() === "StoreManager"){
columns = [
{
title: '用户',
title: '学员',
key: 'storeCustomerName',
dataIndex: 'storeCustomerName',
render: (val, record) => {
......@@ -225,7 +225,7 @@ class UserLearningData extends React.Component {
{
title: <span>
<span>学习进度</span>
<Tooltip title="用户培训计划中达到“已完成”状态的课程数/总课程数"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
<Tooltip title="学员培训计划中达到“已完成”状态的课程数/总课程数"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
</span>,
key: 'learnNum',
dataIndex: 'learnNum',
......@@ -259,7 +259,7 @@ class UserLearningData extends React.Component {
}else{
columns = [
{
title: '用户',
title: '学员',
key: 'storeCustomerName',
dataIndex: 'storeCustomerName',
render: (val, record) => {
......@@ -311,7 +311,7 @@ class UserLearningData extends React.Component {
{
title: <span>
<span>学习进度</span>
<Tooltip title="用户培训计划中达到“已完成”状态的课程数/总课程数"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
<Tooltip title="学员培训计划中达到“已完成”状态的课程数/总课程数"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
</span>,
key: 'learnNum',
dataIndex: 'learnNum',
......
......@@ -126,10 +126,10 @@ function UserLearningDataFilter(props) {
<Row>
<div className="search-condition">
<div className="search-condition__item">
<span className="label customer-label">用户</span>
<span className="label customer-label">学员</span>
<Search
value={query.customerName}
placeholder="搜索用户名称"
placeholder="搜索学员名称"
onChange={(e) => { handleChangeQuery('customerName', e.target.value)}}
onSearch={ () => { props.onChange(query) } }
style={{ width: "calc(100% - 70px)" }}
......
......@@ -136,13 +136,13 @@ class ShareLiveModal extends React.Component {
<div className="right">
<div className="share-poster right__item">
<div className="title">① 海报分享</div>
<div className="sub-title">用户可通过微信扫描海报二维码,查看培训计划</div>
<div className="sub-title">学员可通过微信扫描海报二维码,查看培训计划</div>
<div className="content" onClick={this.handleDownloadPoster}>下载海报</div>
</div>
<div className="share-url right__item">
<div className="title">② 链接分享</div>
<div className="sub-title">用户可通过微信或浏览器打开以下链接,查看培训计划</div>
<div className="sub-title">学员可通过微信或浏览器打开以下链接,查看培训计划</div>
<div className="content url-content">
<div className="share-url" id="shareUrl">{shareUrl}</div>
<Button type="primary" onClick={this.handleCopy}>复制</Button>
......
......@@ -163,7 +163,7 @@ class UserLearnDetailModal extends React.Component {
const { visible } = this.props;
return (
<Modal
title="用户学习详情"
title="学员学习详情"
onCancel={this.props.onClose}
onOk={this.props.onClose}
maskClosable={false}
......@@ -175,7 +175,7 @@ class UserLearnDetailModal extends React.Component {
>
<div className="customer-info">
<span className="customer-name">
<span>用户</span>
<span>学员</span>
<span>{storeCustomerName}</span>
</span>
<span className="customer-phone">
......
......@@ -288,7 +288,8 @@ class SelectPrepareFileModal extends React.Component {
const hasMore = folderList.length < totalCount;
const { fileListRef } = this.refs;
const hasReachBottom = fileListRef.scrollTop + fileListRef.clientHeight === fileListRef.scrollHeight;
// const hasReachBottom = fileListRef.scrollTop + fileListRef.clientHeight === fileListRef.scrollHeight;
const hasReachBottom = fileListRef.scrollTop + fileListRef.clientHeight > fileListRef.scrollHeight - 1;
if (!hasReachBottom || !hasMore) return;
const currentFolder = folderPathList[folderPathList.length - 1];
......
......@@ -40,6 +40,23 @@ const App: React.FC = (props: any) => {
}
}, [])
useEffect(() => {
getStorePermission();
}, [window.location.hash])
function getStorePermission() {
const params = {
storeId: User.getStoreId(),
};
Service.Hades('public/customerHades/whetherStopStore', params).then((res) => {
if (res.result) {
window.RCHistory.replace({
pathname: '/error-college',
})
}
});
}
async function getStoreAndUserInfo() {
await (enterpriseId ? getStoreInfo() : getStoreGroupAndStoreList());
}
......@@ -106,7 +123,7 @@ const App: React.FC = (props: any) => {
return (
<div id="home">
<Header handleMenuType={handleMenuType} menuType={menuType} />
<Header id="app" handleMenuType={handleMenuType} menuType={menuType} />
<ConfigProvider locale={zhCN} autoInsertSpaceInButton={false}>
<Main menuType={menuType} />
</ConfigProvider>
......
......@@ -23,6 +23,8 @@ export default class CollegeManagePage extends React.Component {
list: [],
enterpriseId: User.getEnterpriseId(),
isAdmin: false,
createStoreList:[],
joinStoreList:[]
};
}
......@@ -45,6 +47,7 @@ export default class CollegeManagePage extends React.Component {
getStoreList() {
const { enterpriseId } = this.state;
if (!enterpriseId) return null;
const params = {
enterpriseId,
userId: User.getUserId(),
......@@ -52,13 +55,46 @@ export default class CollegeManagePage extends React.Component {
Service.Hades('public/customerHades/getStoreListUser', params).then((res) => {
const list = res.result;
if (!User.getStoreId()) {
const mainStore = _.find(list, item => item.mainStore) || {};
const mainStore = _.find(list, item => item.mainStore) || list[0] || {};
User.setStoreId(mainStore.id);
User.setStoreUserId(mainStore.storeUserId);
}
this.setState({ list })
const createStoreList = list.filter((item)=>{
return item.userRole === 'StoreManager'
})
const joinStoreList = list.filter((item)=>{
return item.userRole !== 'StoreManager'
})
this.setState({createStoreList:createStoreList,joinStoreList:joinStoreList})
});
}
checkCollege(item, bool) {
const data = {
storeId: item.id,
}
Service.Hades('public/hades/whetherStartLiveCourse', data).then((res) => {
if (res.result) {
Modal.warning({
title: '停用失败',
content: '当前学院有正在上课的直播课,请课程结束后再进行操作。',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
okText: '我知道了',
})
} else {
Modal.confirm({
title: '确定停用吗?',
content: '停用学院,所有学院相关信息不可使用,学员无法继续学习,请谨慎操作!',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
onOk: () => {
this.changeCollege(item, bool);
},
okText: '停用',
cancelText: '取消',
})
}
})
}
changeCollege(item, bool) {
const data = {
......@@ -75,7 +111,7 @@ export default class CollegeManagePage extends React.Component {
}
handleLogout() {
BaseService.logout({}).then((res) => {
BaseService.logout({identifier:User.getIdentifier()}).then((res) => {
User.removeUserId();
User.removeToken();
User.removeEnterpriseId();
......@@ -91,12 +127,14 @@ export default class CollegeManagePage extends React.Component {
avatar,
list,
isAdmin,
createStoreList,
joinStoreList
} = this.state;
return (
<div className="college-manage-page">
<div className="college-header">
<div className="box">
<img className="box-image" src="https://image.xiaomaiketang.com/xm/JDjBDAPDwD.png" />
<img className="box-image" src="https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png" />
<div className="user">
<img className="image" src={avatar} />
<span className="name">{name}</span>
......@@ -125,12 +163,13 @@ export default class CollegeManagePage extends React.Component {
<img className="image" src={avatar} />
<span className="name">{name}</span>
</div>
<div>
<div className="title-box">
<span className="title">企学院 ({list.length})</span>
{isAdmin && <span className="text">最多可创建10个企学院,您还能创建{10 - list.length}</span>}
<span className="title">我创建的({createStoreList.length})</span>
{isAdmin && <span className="text">最多可创建10个企学院,您还能创建{10 - createStoreList.length}</span>}
</div>
<div className="college-list">
{list.map((item) => (
{createStoreList.map((item) => (
<div
key={item.id}
className={`college-item${item.state === 'VALID' ? '' : ' disabled'}${item.userRole === 'StoreManager' ? ' enabled' : ''}`}
......@@ -144,13 +183,13 @@ export default class CollegeManagePage extends React.Component {
}}
>
<div className="header">
<img className="image" src={item.logo || "https://image.xiaomaiketang.com/xm/JDjBDAPDwD.png"} />
<img className="image" src={item.logo || "https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png"} />
<span className="tag">{roleMap[item.userRole]}</span>
</div>
<div className="title">{item.storeName}</div>
<div className="time">{moment(item.createTime).format('YYYY-MM-DD HH:mm')}</div>
<div className="control-box">
{item.userRole === 'StoreManager' && item.state === 'VALID' && !item.mainStore &&
{item.userRole === 'StoreManager' && item.state === 'VALID' &&
<span
className="control-button"
onClick={(e) => {
......@@ -168,16 +207,7 @@ export default class CollegeManagePage extends React.Component {
if (item.state !== 'VALID') return null;
e.preventDefault();
e.stopPropagation();
Modal.confirm({
title: '确定停用吗?',
content: '禁用学院,所有学院相关信息不可使用,用户无法继续学习,请谨慎操作!',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
onOk: () => {
this.changeCollege(item, false);
},
okText: '停用',
cancelText: '取消',
})
this.checkCollege(item, false);
}}
>{item.state === 'VALID' ? '停用' : '已停用'}</span>
}
......@@ -192,7 +222,7 @@ export default class CollegeManagePage extends React.Component {
</div>
</div>
))}
{list.length < 10 && isAdmin &&
{createStoreList.length < 10 && isAdmin &&
<div
className="college-create"
onClick={() => {
......@@ -204,6 +234,70 @@ export default class CollegeManagePage extends React.Component {
}
</div>
</div>
{ joinStoreList.length > 0 &&
<div className="join-container">
<div className="title-box">
<span className="title">我加入的({joinStoreList.length})</span>
</div>
<div className="college-list">
{joinStoreList.map((item) => (
<div
key={item.id}
className={`college-item${item.state === 'VALID' ? '' : ' disabled'}${item.userRole === 'StoreManager' ? ' enabled' : ''}`}
onClick={() => {
if (item.state !== 'VALID') {
message.warning('学院已停用,请启用后使用或联系学院管理员');
return null;
};
User.setStoreId(item.id);
window.RCHistory.push('/home')
}}
>
<div className="header">
<img className="image" src={item.logo || "https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png"} />
<span className="tag">{roleMap[item.userRole]}</span>
</div>
<div className="title">{item.storeName}</div>
<div className="time">{moment(item.createTime).format('YYYY-MM-DD HH:mm')}</div>
<div className="control-box">
{item.userRole === 'StoreManager' && item.state === 'VALID' && !item.mainStore &&
<span
className="control-button"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
User.setStoreId(item.id);
window.RCHistory.push('/college-info')
}}
>编辑</span>
}
{((item.userRole === 'StoreManager' && !item.mainStore) || item.state !== 'VALID') &&
<span
className="control-button"
onClick={(e) => {
if (item.state !== 'VALID') return null;
e.preventDefault();
e.stopPropagation();
this.checkCollege(item, false);
}}
>{item.state === 'VALID' ? '停用' : '已停用'}</span>
}
<span
className="control-button disable-button"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
this.changeCollege(item, true);
}}
>启用</span>
</div>
</div>
))}
</div>
</div>
}
</div>
</div>
)
}
......
......@@ -20,8 +20,7 @@
align-items: center;
justify-content: space-between;
.box-image {
width: 91px;
height: 25px;
height: 30px;
margin-left: 27px;
}
.user {
......@@ -49,6 +48,9 @@
width: 1280px;
margin: 0 auto;
padding: 60px 0 30px 60px;
.join-container{
margin-top:48px;
}
.user {
margin-bottom: 85px;
.image {
......
......@@ -14,7 +14,7 @@ export default class CreateCollege extends React.Component {
super(props);
this.state = {
avatar: 'https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png',
logo: 'https://image.xiaomaiketang.com/xm/JDjBDAPDwD.png',
logo: 'https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png',
name: '',
enterpriseId: User.getEnterpriseId(),
};
......@@ -187,7 +187,7 @@ export default class CreateCollege extends React.Component {
<div className="college-manage-page">
<div className="college-header">
<div className="box">
<img className="box-image" src="https://image.xiaomaiketang.com/xm/JDjBDAPDwD.png" />
<img className="box-image" src="https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png" />
</div>
</div>
<Breadcrumbs
......@@ -198,7 +198,7 @@ export default class CreateCollege extends React.Component {
/>
<div className="create-box">
<div className="image-box">
<img className="image" src={logo} />
<img className="image" src="https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png"/>
<div className="image-mask">
<span
className="icon iconfont"
......@@ -208,7 +208,7 @@ export default class CreateCollege extends React.Component {
className="icon iconfont"
onClick={() => {
this.setState({
logo: 'https://image.xiaomaiketang.com/xm/JDjBDAPDwD.png',
logo: 'https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png',
visible: false,
})
}}
......
import User from '@/common/js/user';
import React from 'react';
import Header from './Header'
import Service from "@/common/js/service";
import './ErrorCollege.less';
export default class ErrorCollege extends React.Component {
constructor(props) {
super(props);
this.state = {
menuType: true,
}
}
componentDidMount() {
this.getStorePermission();
}
getStorePermission() {
const params = {
storeId: User.getStoreId(),
};
Service.Hades('public/customerHades/whetherStopStore', params).then((res) => {
if (!res.result) {
window.RCHistory.replace({
pathname: '/home',
})
}
});
}
handleMenuType() {
this.setState({ menuType: !menuType });
}
render() {
const { menuType } = this.state;
return (
<div className="error-college-page">
<Header id="error" handleMenuType={this.handleMenuType} menuType={menuType} />
<div className="error-college-box">
<img src="https://image.xiaomaiketang.com/xm/MQRaYkbr6J.png" className="error-college-image" />
<span className="error-college-tip">{User.getStoreName()}已停用</span>
</div>
</div>
)
}
}
\ No newline at end of file
.error-college-page {
position: relative;
width: 100vw;
height: 100vh;
.error-college-box {
position: absolute;
top: 50px;
left: 0;
right: 0;
bottom: 0;
.error-college-image {
position: absolute;
top: 246px;
left: 50%;
transform: translateX(-50%);
width: 246px;
height: 132px;
display: block;
}
.error-college-tip {
position: absolute;
top: 404px;
left: 50%;
transform: translateX(-50%);
color: #8C8E93;
font-size: 13px;
}
}
}
\ No newline at end of file
/*
* @Author: 吴文洁
* @Date: 2019-09-10 18:26:03
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-04-14 19:29:09
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-05-12 17:30:25
* @Description:
*/
import React, { useContext, useEffect, useState } from "react";
import React, { useRef, useContext, useEffect, useState } from "react";
import "./Header.less";
import { Menu, Dropdown, Modal, Tooltip, message } from "antd";
import { Radio, Button, Dropdown, Modal, Tooltip, message } from "antd";
import { LIVE_SHARE } from "@/domains/course-domain/constants";
import User from "@/common/js/user";
import Service from "@/common/js/service";
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";
import Bus from '@/core/tbus';
import ClickOutside from '../../components/ClickOutside';
const baseImg = "https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png";
const { confirm } = Modal;
const RadioGroup = Radio.Group;
function Header(props) {
const { menuType, handleMenuType } = props;
const [storeId, setStoreId] = useState(User.getStoreId());
const [storeName, setStoreName] = useState(User.getStoreName())
const [avatar, setAvatar] = useState('');
const [nickName, setNickName] = useState('');
const [phone, setPhone] = useState('');
const [list, setList] = useState([]);
const [openDropdown, setOpenDropdown] = useState(false);
const [instScroll, setInstScroll] = useState(false);
const ctx = useContext(XMContext);
const htmlUrl = `${LIVE_SHARE}store/index?id=${User.getStoreId()}&userId=${User.getUserId()}&from=work_weixin`;
const storeUserId = User.getStoreUserId();
const enterpriseId = User.getEnterpriseId();
const domRef = useRef(null);
const listRef = useRef(list);
useEffect(() => {
htmlUrl && handleConvertShortUrl();
Bus.bind('storeNameChange', (value) => {
setStoreName(value);
});
getStoreList();
}, []);
useEffect(() => {
......@@ -66,6 +77,40 @@ function Header(props) {
});
}
function getStoreList() {
if (!enterpriseId) return null;
const params = {
enterpriseId,
userId: User.getUserId(),
};
Service.Hades('public/customerHades/getStoreListUser', params).then((res) => {
const newList = _.filter(res.result, item => item.state === 'VALID');
setList(newList);
listRef.current = newList;
});
}
// 动态改变校区选择的阴影
function addShadow() {
domRef.current = document.querySelector('#college-radio-group');
if (listRef.current.length > 4) {
setInstScroll(true);
} else {
setInstScroll(false);
}
// 滚动到底部阴影就消失
domRef.current.addEventListener('scroll', scrollEventListener);
}
function scrollEventListener() {
if (domRef.current.scrollHeight === 190 + domRef.current.scrollTop) {
setInstScroll(false);
} else {
setInstScroll(true);
}
};
function userMenu() {
return (
<div className="user-center-dropdown">
......@@ -138,13 +183,14 @@ function Header(props) {
}
function handleLogout() {
BaseService.logout({}).then((res) => {
BaseService.logout({identifier:User.getIdentifier()}).then((res) => {
User.removeUserId();
User.removeToken();
User.removeEnterpriseId();
User.clearUserInfo();
const url = `${LIVE_SHARE}store/index?id=${User.getCustomerStoreId()||User.getStoreId()}&userId=${User.getUserId()}&from=work_weixin`;
window.location.href = url;
});
}
......@@ -173,7 +219,7 @@ function Header(props) {
<div id="top-container" className="top-container">
<div className="top top-nav">
<div>
{menuType ? <img src='https://image.xiaomaiketang.com/xm/4swGidkYR6.png' className="logo" alt="" />:<img src={logoImg} className="logo" alt="" />}
{menuType ? <img src='https://image.xiaomaiketang.com/xm/fe4NCjr7XF.png' className="logo" alt="" />:<img src="https://image.xiaomaiketang.com/xm/c4KiP2epBP.png" className="logo" alt="" />}
</div>
{menuType ? (
<span
......@@ -191,14 +237,86 @@ function Header(props) {
</span>
)}
<div className="message-help">
{list.length ? (
<ClickOutside
onClickOutside={() => {
if (openDropdown) {
setOpenDropdown(false);
}
}}
className="college-container"
>
<div>
<div className="college" onClick={() => setOpenDropdown(false)}>
<span
className="college-name"
onClick={(e) => {
e.stopPropagation();
setOpenDropdown(!openDropdown);
addShadow();
}}
>{storeName}</span>
{list.length > 1 && <span
className={`icon iconfont ${list.length > 1 ? 'select' : ''}`}
onClick={(e) => {
e.stopPropagation();
setOpenDropdown(!openDropdown);
addShadow();
}}
>&#xe651;</span>}
</div>
<div className={`select-college ${openDropdown ? 'active' : ''}`}>
<h2>切换学院</h2>
<RadioGroup
onChange={(e) => {
setStoreId(e.target.value)
User.setStoreId(e.target.value);
window.RCHistory.push('/home');
window.location.reload();
}}
value={storeId}
id="college-radio-group"
>
{_.map(list, (item) => (
<Radio value={item.id} key={item.id}>
<span className="name">{item.storeName}</span>
</Radio>
))}
</RadioGroup>
{instScroll && <div className="scroll-shadow"></div>}
{/* <div className="control">
<Button
size="small"
onClick={() => {
setOpenDropdown(false);
}}
>
取消
</Button>
<Button
size="small"
type="primary"
onClick={() => {
User.setStoreId(storeId);
window.location.reload();
}}
>
确定
</Button>
</div> */}
</div>
</div>
</ClickOutside>
) : (
<div className="store-related">
<div className="store-name">{storeName}</div>
<div className="line"></div>
</div>
)}
<div className="right-box">
<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>
......@@ -222,8 +340,6 @@ function Header(props) {
<span className="icon iconfont tool-tip-right">&#xe85e;</span>
<div className="text">分享学院</div>
</div>
</div>
</div>
<Dropdown overlay={userMenu()} arrow>
<div className="user">
......@@ -245,6 +361,7 @@ function Header(props) {
</div>
</div>
</div>
</div>
);
}
export default Header;
......@@ -11,7 +11,7 @@
z-index: 112;
.logo {
display: inline-block;
height: 24px;
height: 30px;
margin-left: 20px;
}
.logo-name {
......@@ -177,8 +177,95 @@
flex: 1;
-webkit-flex: 1;
justify-content: space-between;
margin-left: 54px;
.college-container {
position: relative;
width: 360px;
height: 50px;
display: flex;
align-items: center;
.college {
display: flex;
align-items: center;
margin-right: 16px;
cursor: pointer;
.select {
cursor: pointer;
}
.college-name {
color: #666;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
max-width: 280px;
}
.icon {
font-size: 14px;
margin-left: 8px;
color: #8c8e93;
&:hover {
color: #555;
}
}
}
.select-college {
position: absolute;
top: 50px;
left: 0;
background: #fff;
width: 282px;
padding: 14px;
box-shadow: 0 2px 7px 0 rgba(0, 0, 0, 0.06);
max-height: 240px;
border-radius: 2px;
display: none;
padding-right: 0;
z-index: 10;
&.active {
display: block;
}
h2 {
margin-bottom: 10px;
font-size: 16px;
font-weight: 500;
}
.ant-radio-group {
overflow-y: auto;
width: 100%;
max-height: 190px;
}
.ant-radio-wrapper {
display: flex;
width: calc(~'100% - 8px');
margin: 8px 0;
.ant-radio {
float: left;
margin: 3px 0;
}
.name {
color: #666;
white-space: pre-wrap;
}
}
.control {
display: flex;
justify-content: flex-end;
button {
margin-left: 8px;
}
}
.scroll-shadow {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 40px;
background: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
}
}
}
.store-related {
width: 500px;
width: 360px;
height: 49px;
display: flex;
position: relative;
......@@ -200,6 +287,11 @@
background-color: #f4f4f4;
margin-right:16px;
}
}
.right-box {
display: flex;
align-items: center;
}
.link-to-store {
display: flex;
height: 49px;
......@@ -284,79 +376,6 @@
margin-left: 16px;
}
}
}
.inst-container {
width: calc(~"100% - 420px");
position: relative;
.inst {
margin-right: 12px;
display: flex;
align-items: center;
border-right: 1px solid #e8e8e8;
padding-right: 24px;
justify-content: flex-end;
.select {
cursor: pointer;
}
.name {
color: #333;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
max-width: 230px;
}
.icon {
font-size: 16px;
margin-left: 8px;
color: #8c8e93;
&:hover {
color: #555;
}
}
}
.select-inst {
position: absolute;
top: 37px;
right: 11px;
background: #fff;
width: 285px;
padding: 14px;
box-shadow: 0 2px 7px 0 rgba(0, 0, 0, 0.06);
max-height: 321px;
border-radius: 2px;
display: none;
&.active {
display: block;
}
h2 {
margin-bottom: 10px;
}
.ant-radio-group {
overflow-y: auto;
max-height: 200px;
}
.ant-radio-wrapper {
display: inline-block;
width: calc(~"100% - 28px");
margin: 8px 0;
.ant-radio {
float: left;
margin: 3px 0;
}
.name {
color: #666;
white-space: pre-wrap;
}
}
.control {
display: flex;
justify-content: flex-end;
button {
margin-left: 8px;
}
}
}
}
.drop-menu {
height: 100%;
display: flex;
......
......@@ -153,8 +153,8 @@ function Login(props) {
<div className="login-page" >
<div className="login-main">
<div className="left-banner">
<div><img src={require("../../common/images/logo.png")} alt="" style={{ width: 60, height: 61 }} /></div>
<div className="name">小麦企</div>
<div><img src="https://image.xiaomaiketang.com/xm/Newk4NrxKC.png" alt="" style={{ width: 60, height: 61 }} /></div>
<div className="name">小麦企学院</div>
<div className="desc">一键开启直播授课 让知识更有价值</div>
</div>
<div className="login-box">
......
......@@ -19,14 +19,14 @@
margin-top: 24px;
.error{
position: absolute;
width: 100%;
height: 100%;
width: 170px;
height: 170px;
background: rgba(255, 255, 255, 0.95);
display: flex;
align-items:center;
justify-content:center;
left:0px;
top: 0px;
left:-5px;
top:-5px;
div{
margin: 0 10px;
font-size: 14px;
......
......@@ -37,7 +37,7 @@ export default function WechatLogin(props: any) {
text: redirect,
correctLevel: 2,
size: 160,
image: Logo,
image: 'https://image.xiaomaiketang.com/xm/Newk4NrxKC.png',
imageSize: 50
});
qrcodeWrapDom.innerHTML = '';
......@@ -77,6 +77,7 @@ export default function WechatLogin(props: any) {
User.setUserId(_res.result.loginInfo.userId);
User.setToken(_res.result.loginInfo.xmToken);
User.setEnterpriseId(_res.result.enterpriseId);
User.setIdentifier(_res.result.identifier)
window.RCHistory.push({
pathname: `/switch-route`,
})
......
......@@ -12,11 +12,12 @@
margin-top: 5px !important;
}
.radio-tip {
padding-left: 24px;
font-size: 14px;
font-weight: 400;
color: #999;
line-height: 20px;
white-space: nowrap;
margin: 6px 0 16px;
}
.avatar-box {
text-align: center;
......
......@@ -83,8 +83,8 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
}, [props.choosedItem.nickName]);
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 12 },
labelCol: { span: 6 },
wrapperCol: { span: 18 },
};
function handleChangeRole(value: string) {
......@@ -210,8 +210,8 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
>
<Row>
<Col span={16}>
<Row style={{ height: 271 }}>
<Col span={18}>
<Form
{...layout}
form={form}
......@@ -223,9 +223,8 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
name="nickName"
rules={[{ required: true }]}
validateStatus={nameStatus}
help={nameErrorMsg}
style={{marginBottom:'-2px !important'}}
className="mt-4"
help={nameErrorMsg || undefined}
style={{ marginBottom: 0 }}
>
<Input
style={{ width: 200 }}
......@@ -239,8 +238,6 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
<Form.Item
label="企业微信账号"
name="weChatAccount"
style={{marginBottom:'-2px !important'}}
className="mt-10"
>
<Tooltip title={props.choosedItem.weChatAccount}>
<div style={{
......@@ -257,8 +254,6 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
rules={[{ required: true }]}
validateStatus={phoneStatus}
help={phoneErrorMessage}
style={{marginBottom:'-2px !important'}}
className="mt-10"
>
<Input
style={{ width: 200 }}
......@@ -290,12 +285,6 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
}}
className="mt5"
>
<Radio value={"CloudOperator"} className="mt-4">
<span style={{ color: "#333" }}>运营师</span>
<p className="radio-tip">
仅可查看/转发培训计划内容,并查看其负责的用户学习进度
</p>
</Radio>
<Radio value={"CloudLecturer"} className="mt-4">
<span style={{ color: "#333" }}>普通讲师</span>
<p className="radio-tip">
......@@ -306,12 +295,18 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
<span style={{ color: "#333" }}>管理员</span>
<p className="radio-tip">可执行学院中所有的操作</p>
</Radio>
<Radio value={"CloudOperator"} className="mt-4">
<span style={{ color: "#333" }}>运营师</span>
<p className="radio-tip">
仅可查看/转发培训计划内容,并查看其负责的学员学习进度
</p>
</Radio>
</RadioGroup>
</Form.Item>
</Form>
</Col>
<Col span={8}>
<Col span={6}>
<div className="avatar-box">
<div className="avatar-text">头像</div>
<div className="avatart-img">
......@@ -319,7 +314,7 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
</div>
<div className="upload-avatar">
<Button id="click_upload_btn" onClick={_onUpload}>
点击上传
上传头像
</Button>
<input
type="file"
......
......@@ -251,7 +251,7 @@ function EmployeesManagePage() {
function handleDeleteWorkWechatEmployeeConfirm(record: RecordTypes) {
return confirm({
title: "你确定要删除此员工吗?",
content: "管理员需在企业微信后台的“小麦企培”应用管理中移除此员工,此员工才无法继续登陆小麦企培",
content: "管理员需在企业微信后台的“小麦企学院”应用管理中移除此员工,此员工才无法继续登陆小麦企学院",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
......
/*
* @Author: wufan
* @Date: 2020-11-30 10:47:38
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-02-02 10:22:34
* @Description: 用户管理页面
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:38:40
* @Description: 学员管理页面
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -49,7 +49,7 @@ function UserManagePage() {
function parseColumn() {
return [
{
title: "用户姓名",
title: "学员姓名",
dataIndex: "nickName",
render: (val: string) => {
return (
......@@ -81,7 +81,7 @@ function UserManagePage() {
return (
<div className=" page user-manage-page">
<div className="content-header">用户管理</div>
<div className="content-header">学员管理</div>
<div className="box">
<div className="box-header">
<div
......@@ -93,13 +93,13 @@ function UserManagePage() {
}}
>
<div>
搜索用户
搜索学员
<Search
style={{
width: 300,
marginRight: 40,
}}
placeholder="搜索用户姓名/手机号"
placeholder="搜索学员姓名/手机号"
onSearch={(value) => {
const _query = { ...query };
if (value) {
......
......@@ -54,7 +54,7 @@ function AddExam(props: any) {
}, [paperInfo.paperId])
useEffect(() => {
setPassScore(parseInt((paperInfo.totalScore || 0) * (passRate || 0) as any / 100 + ''))
setPassScore(Math.round((paperInfo.totalScore || 0) * (passRate || 0) as any / 100))
setExamTotal(paperInfo.singleChoiceCnt + paperInfo.multiChoiceCnt + paperInfo.judgeCnt + paperInfo.gapFillingCnt + paperInfo.indefiniteChoiceCnt || 0)
}, [paperInfo.paperId, passRate])
......@@ -230,7 +230,7 @@ function AddExam(props: any) {
<Breadcrumbs navList={props.type === 'edit' ? "编辑考试" : "新建考试"} goBack={handleGoBack} />
<div className="box">
<Alert message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企保有依据国家规定及平台规则进行处理的权利" type="info" showIcon />
<Alert message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" type="info" showIcon />
<div className="form">
<div className="title">基本信息</div>
<Form
......@@ -243,7 +243,7 @@ function AddExam(props: any) {
help={check && !examName && '请选择课程'}
required>
<Input placeholder='请输入试卷名称(40字以内)' maxLength={40} value={examName} onChange={(e) => {
<Input placeholder='请输入考试名称(40字以内)' maxLength={40} value={examName} onChange={(e) => {
setExamName(e.target.value)
}} style={{ width: 320 }} />
</Form.Item>
......@@ -365,7 +365,7 @@ function AddExam(props: any) {
checked={needPhone == 'NEED_PHONE_VERIFY'}
onChange={(val) => { setNeedPhone(val ? 'NEED_PHONE_VERIFY' : 'DO_NOT_NEED_PHONE_VERIFY') }}
></Switch>
<div style={{ position: 'relative', top: 3, left: 8, color: "#999" }}><p>开启:需要绑定手机号的用户才能参加考试</p>
<div style={{ position: 'relative', top: 3, left: 8, color: "#999" }}><p>开启:需要绑定手机号的学员才能参加考试</p>
<p>关闭:微信/企业微信登陆直接参加考试</p></div>
</div>
......
......@@ -122,25 +122,11 @@ class ExamShareModal extends React.Component {
</div>
<div className="right">
<div className="share-poster right__item">
<div className="title">① 海报分享</div>
<div className="sub-title">用户可通过微信扫描海报二维码,查看考试</div>
<div className="sub-title">学员可通过微信扫描海报二维码,查看考试</div>
<div className="content" onClick={this.handleDownloadPoster}>下载海报</div>
</div>
{/* <div className="share-url right__item" style={{ marginTop: 40 }}>
<div className="title">② 链接分享</div>
<div className="sub-title">用户可通过微信或浏览器打开以下链接,查看考试(建议使用谷歌浏览器)</div>
<div className="content">
<div className="share-url" id="shareUrl">{shareUrl}</div>
<Button
type="primary"
onClick={this.handleCopy}
>复制</Button>
</div>
</div> */}
</div>
</Modal>
)
......
......@@ -16,6 +16,7 @@ function SelectPaperModal(props: any) {
}, [item])
return <Modal
maskClosable={false}
width={900}
title="选择试卷"
visible={true}
......
......@@ -115,7 +115,7 @@ function DataAnalysic(props: any) {
const columns = [
{
title: "用户",
title: "学员",
dataIndex: "userName",
render: (text: any, record: any) => <span>{text}<span style={{ color: record.userSource === 'WORK_WE_CHAT' ? 'rgba(255, 157, 20, 1)' : 'rgba(29, 204, 101, 1)' }} >@{(userTypeEnum as any)[record.userSource]}</span></span>,
},
......@@ -221,11 +221,11 @@ function DataAnalysic(props: any) {
<div style={{ display: 'flex' }}>
<div className="search-condition">
<div className="search-condition__item">
<span className="search-name">用户:</span>
<span className="search-name">学员:</span>
<Search
value={query.examName}
className='search-input'
placeholder="搜索用户名或手机号"
placeholder="搜索学员名或手机号"
onChange={(e) => {
const _query = { ...query }
_query.searchKey = e.target.value
......@@ -237,8 +237,8 @@ function DataAnalysic(props: any) {
</div>
<div className="search-condition__item">
<span className="search-name">用户类型:</span>
<Select value={query.userSource} placeholder="请选择用户类型" onChange={(val) => {
<span className="search-name">学员类型:</span>
<Select value={query.userSource} placeholder="请选择学员类型" onChange={(val) => {
const _query = { ...query }
_query.userSource = val
setQuery(_query);
......
/*
* @Author: yuananting
* @Date: 2021-03-27 16:15:13
* @LastEditors: yuananting
* @LastEditTime: 2021-04-15 14:50:02
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-05-10 10:16:31
* @Description: 助学工具-新建/复制/编辑试卷
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -705,7 +705,7 @@ class OperatePaper extends Component {
<Spin spinning={loading}>
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企保有依据国家规定及平台规则进行处理的权利" />
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div>
<Form ref={this.formRef} style={{ marginTop: 24 }}>
<Form.Item
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-04-15 11:04:03
* @LastEditTime: 2021-05-20 11:37:40
* @Description: 助学工具-题库-试卷列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -441,7 +441,6 @@ class PaperList extends Component {
pagination={false}
bordered
loading={loading}
onChange={this.handleChangeTable}
/>
) : (
<Table
......@@ -455,7 +454,6 @@ class PaperList extends Component {
columns={this.parseColumns()}
pagination={false}
bordered
onChange={this.handleChangeTable}
/>
)}
</ConfigProvider>
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-04-13 13:56:05
* @LastEditTime: 2021-05-20 11:43:21
* @Description: 助学工具-新建试卷-选择题目列表
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -108,15 +108,14 @@ class SelectQuestionList extends Component {
handleChangeTable = (pagination, filters, sorter) => {
const { columnKey, order } = sorter;
let sort = "UPDATED_DESC";
if (order === "ascend") {
if (columnKey === "accuracy" && order === "ascend") {
sort = "ACCURACY_ASC";
}
if (order === "descend") {
if (columnKey === "accuracy" && order === "descend") {
sort = "ACCURACY_DESC";
}
const _query = this.state.query;
_query.order = sort;
_query.current = 1;
this.setState({ query: _query }, () => this.queryQuestionPageListWithContent());
};
......
......@@ -53,8 +53,14 @@
}
.input-box {
line-height: 20px;
* {
display: inline;
display: inline-block;
vertical-align: top;
*:not(p) {
font-weight: normal !important;
font-size: 14px !important;
font-style: normal !important;
text-decoration: none !important;
margin: 0 !important;
}
.add-fill-line {
padding: 0 10px;
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-03-29 10:52:26
* @LastEditors: yuananting
* @LastEditTime: 2021-04-07 15:23:06
* @LastEditTime: 2021-05-08 16:11:27
* @Description: 助学工具-试卷-新建选择题目弹窗
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -35,6 +35,7 @@ class SelectQuestionModal extends Component {
return (
<Modal
className="select-question-modal"
maskClosable={false}
destroyOnClose={true}
title="选择题目"
visible={true}
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-25 13:46:35
* @LastEditors: yuananting
* @LastEditTime: 2021-04-07 09:48:34
* @LastEditTime: 2021-05-10 20:33:16
* @Description: 助学工具-题库-新建/编辑题目
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -164,6 +164,8 @@ class OperateQuestion extends Component {
window.RCHistory.push({
pathname: `/question-manage-index?categoryId=${getParameterByName("categoryId")}`,
});
Bus.trigger("queryCategoryTree", "remain");
Bus.trigger("queryQuestionPageList", getParameterByName("categoryId"));
},
});
};
......@@ -307,7 +309,7 @@ class OperateQuestion extends Component {
/>
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企保有依据国家规定及平台规则进行处理的权利" />
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div>
<Tabs
style={{ marginTop: 32 }}
......@@ -334,7 +336,7 @@ class OperateQuestion extends Component {
key="SINGLE_CHOICE"
>
<OperateQuestionTab
questionTypeKey={activeKey}
questionTypeKey={"SINGLE_CHOICE"}
onRef={(ref) => {
this.singleChoiceRef = ref;
}}
......@@ -363,7 +365,7 @@ class OperateQuestion extends Component {
key="MULTI_CHOICE"
>
<OperateQuestionTab
questionTypeKey={activeKey}
questionTypeKey={"MULTI_CHOICE"}
onRef={(ref) => {
this.multiChoiceRef = ref;
}}
......@@ -391,7 +393,7 @@ class OperateQuestion extends Component {
key="JUDGE"
>
<OperateQuestionTab
questionTypeKey={activeKey}
questionTypeKey={"JUDGE"}
onRef={(ref) => {
this.judgeRef = ref;
}}
......@@ -419,7 +421,7 @@ class OperateQuestion extends Component {
key="GAP_FILLING"
>
<OperateQuestionTab
questionTypeKey={activeKey}
questionTypeKey={"GAP_FILLING"}
onRef={(ref) => {
this.gapRef = ref;
}}
......@@ -457,7 +459,7 @@ class OperateQuestion extends Component {
key="INDEFINITE_CHOICE"
>
<OperateQuestionTab
questionTypeKey={activeKey}
questionTypeKey={"INDEFINITE_CHOICE"}
onRef={(ref) => {
this.indefiniteRef = ref;
}}
......
......@@ -634,6 +634,9 @@ class OperateQuestionTab extends Component {
this.state.stemContent,
(contentItem) => contentItem.type === "RICH_TEXT"
);
if(stemContent.textLength > 1000) {
validateError++;
}
let stem = stemContent.content.replace(/<[^>]+>/g, "");
stem = stem.replace(/\&nbsp\;/gi, "");
stem = stem.replace(/\s+/g, "");
......@@ -691,7 +694,9 @@ class OperateQuestionTab extends Component {
optionUnChecked = item.isCorrectAnswer
? optionUnChecked
: optionUnChecked + 1;
if(optionContent[0].textLength > 1000) {
validateError++;
}
let optionInput = optionContent[0].content.replace(/<[^>]+>/g, "");
optionInput = optionInput.replace(/\&nbsp\;/gi, "");
optionInput = optionInput.replace(/\s+/g, "");
......
......@@ -120,24 +120,31 @@ class QuestionEditor extends Component {
};
editorRoot.config.zIndex = 999;
editorRoot.config.placeholder = "";
editorRoot.config.pasteFilterStyle = false;
editorRoot.config.pasteFilterStyle = true;
editorRoot.config.pasteIgnoreImg = true;
editorRoot.config.focus = false;
// 自定义处理粘贴的文本内容
editorRoot.config.pasteTextHandle = function (content) {
if (content == "" && !content) return "";
var str = content;
str = str.replace(/<xml>[\s\S]*?<\/xml>/gi, "");
str = str.replace(/<style>[\s\S]*?<\/style>/gi, "");
str = str.replace(/<\/?[^>]*>/g, "");
str = str.replace(/[ | ]*\n/g, "\n");
str = str.replace(/\&nbsp\;/gi, " ");
str = str.replace(/[\r\n]/g, "");
if (str.length > 1000) {
str = str.substring(0, 1000);
var str1 = content; // 所有特殊字符
str1 = str1.replace(/<xml>[\s\S]*?<\/xml>/gi, "");
str1 = str1.replace(/<style>[\s\S]*?<\/style>/gi, "");
str1 = str1.replace(/<\/?[^>]*>/g, "");
str1 = str1.replace(/[ | ]*\n/g, "\n");
str1 = str1.replace(/\&nbsp\;/gi, " ");
str1 = str1.replace(/[\r\n]/g, "");
str1 = str1.replace(/<\/?a.*?>/g, "");
var str2 = content; // 保留空格和换行的其他字符
str2 = str2.replace(/<xml>[\s\S]*?<\/xml>/gi, "");
str2 = str2.replace(/<style>[\s\S]*?<\/style>/gi, "");
str2 = str2.replace(/<\/?a.*?>/g, "");
if (editorRoot.txt.text().length + str1.length > 1000) {
content = str2.substring(0, 1000);
message.error("内容过长,不能超过1000字");
} else {
content = str2;
}
return str;
return content;
};
let prevList = [];
......
......@@ -38,10 +38,18 @@
border: 1px solid #e8e8e8;
display: flex;
justify-content: space-between;
font-size: 14px !important;
.editor-box_content {
width: calc(100% - 80px);
p {
display: inline-block;
font-size: 14px !important;
}
*:not(p){
font-weight: normal !important;
font-size: 14px !important;
font-style: normal !important;
text-decoration: none !important;
margin: 0 !important;
}
}
.editor-limit {
......@@ -56,13 +64,21 @@
border-radius: 4px;
padding: 4px 0;
border: 1px solid #e8e8e8;
font-size: 14px !important;
.editor-box_content {
max-height: 110px;
overflow: auto;
p {
display: inline-block;
font-size: 14px !important;
overflow-y: scroll;
}
*:not(p) {
font-weight: normal !important;
font-size: 14px !important;
font-style: normal !important;
text-decoration: none !important;
margin: 0 !important;
}
}
.editor-limit {
text-align: right;
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-04-12 14:14:19
* @LastEditTime: 2021-05-20 11:35:07
* @Description: 助学工具-题库-题目列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -161,7 +161,7 @@ class QuestionList extends Component {
height: 100,
}}
description={
<div>
<span>
<span>还没有题目</span>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
categoryId && (
......@@ -178,7 +178,7 @@ class QuestionList extends Component {
吧!
</span>
)}
</div>
</span>
}
></Empty>
);
......@@ -202,7 +202,6 @@ class QuestionList extends Component {
}
const _query = this.state.query;
_query.order = sort || "UPDATED_DESC";
_query.current = 1;
this.setState({ query: _query }, () => this.queryQuestionPageList());
};
......@@ -225,16 +224,27 @@ class QuestionList extends Component {
handleVal = handleVal.replace(/<(?!img|input).*?>/g, "");
handleVal = handleVal.replace(/<\s?input[^>]*>/gi, "_、");
handleVal = handleVal.replace(/\&nbsp\;/gi, " ");
handleVal = handleVal.replace(/style\s*?=\s*?([‘"])[\s\S]*?\1/gi, "");
return (
<Tooltip
overlayClassName="aid-tool-list"
title={
<div style={{ maxWidth: 700, width: "auto" }}>{handleVal}</div>
<div
style={{ maxWidth: 700, width: "auto" }}
dangerouslySetInnerHTML={{
__html: handleVal,
}}
/>
}
placement="topLeft"
overlayStyle={{ maxWidth: 700 }}
>
{handleVal}
<div
className="one-line-text"
dangerouslySetInnerHTML={{
__html: handleVal,
}}
/>
</Tooltip>
);
},
......
......@@ -32,8 +32,13 @@
color: #666666;
.input-box {
margin-bottom: 8px;
* {
display: inline-block;
*:not(p) {
font-weight: normal !important;
font-size: 14px !important;
font-style: normal !important;
text-decoration: none !important;
margin: 0 !important;
}
}
.picture-box {
......@@ -102,6 +107,13 @@
display: inline-block;
max-width: calc(100% - 20px);
vertical-align: top;
*:not(p) {
font-weight: normal !important;
font-size: 14px !important;
font-style: normal !important;
text-decoration: none !important;
margin: 0 !important;
}
}
}
......@@ -197,8 +209,13 @@
color: #666666;
.desc-input-box {
margin-bottom: 8px;
* {
display: inline-block;
*:not(p) {
font-weight: normal !important;
font-size: 14px !important;
font-style: normal !important;
text-decoration: none !important;
margin: 0 !important;
}
}
.desc-picture-box {
......
/*
* @Author: 吴文洁
* @Date: 2020-04-29 10:26:32
* @LastEditors: yuananting
* @LastEditTime: 2021-04-15 21:45:42
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:39:51
* @Description: 内容线路由配置
*/
import Home from '@/modules/home/Home';
......@@ -60,23 +60,18 @@ const mainRoutes = [
{
path: "/user-manage",
component: UserManagePage,
name: "用户管理",
name: "学员管理",
},
{
path: '/college-user',
component: UserManage,
name: '用户管理'
name: '学员管理'
},
{
path: '/store-decoration',
component: StoreDecorationPage,
name: '学院装修'
},
// {
// path: "/course-catalog",
// component: CourseCatalogPage,
// name: "课程分类",
// },
{
path: "/live-course",
component: LiveCoursePage,
......
/*
* @Author: yuananting
* @Date: 2021-02-21 15:53:31
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 15:20:42
* @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:40:11
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -102,7 +102,7 @@ export const menuList: any = [
link: '/college-employee'
},
{
groupName: "用户管理",
groupName: "学员管理",
groupCode: "ShopUser",
link: '/college-user'
},
......
......@@ -18,6 +18,7 @@ import CreateCollege from '../modules/root/CreateCollege';
import _ from 'underscore';
import { asyncComponent } from 'react-async-component'
import SwitchRoute from '@/modules/root/SwitchRoute';
import ErrorCollege from '@/modules/root/ErrorCollege';
const history = createHashHistory();
window.RCHistory = _.extend({}, history, {
push: (obj: any) => {
......@@ -55,10 +56,11 @@ export const RootRouter = () => {
<Router {...history}>
<Switch>
<Route key="1" exact path="/login" render={() => <Login />} />
<Route key="1" exact path="/switch-route" render={() => <SwitchRoute />} />
<Route key="1" exact path="/college-manage" render={() => <CollegeManagePage />} />
<Route key="1" exact path="/college-manage/create" render={() => <CreateCollege />} />
<Route key="2" path="/" render={() => <AppContext />} />
<Route key="2" exact path="/switch-route" render={() => <SwitchRoute />} />
<Route key="3" exact path="/college-manage" render={() => <CollegeManagePage />} />
<Route key="4" exact path="/college-manage/create" render={() => <CreateCollege />} />
<Route key="6" exact path="/error-college" render={() => <ErrorCollege />} />
<Route key="5" path="/" render={() => <AppContext />} />
</Switch>
</Router>
)
......
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