Commit a9f21050 by guomingpang

Merge branch 'dev' of…

Merge branch 'dev' of ssh://xmgit.ixm5.cn:10022/xiaomai-cloud-class/xiaomai-cloud-class-web into dev
parents 2d3de4a2 ac1cc224
......@@ -4,7 +4,7 @@
* @Author: 吴文洁
* @Date: 2020-06-05 14:59:14
* @LastEditors: 吴文洁
* @LastEditTime: 2020-08-04 19:28:08
* @LastEditTime: 2020-10-09 15:30:45
* @Description:
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
......@@ -2,11 +2,11 @@
/*
* @Author: 吴文洁
* @Date: 2020-06-05 09:38:03
* @LastEditors: 吴文洁
* @LastEditTime: 2020-09-02 15:45:50
* @Description:
* @LastEditors: louzhedong
* @LastEditTime: 2020-12-26 16:08:19
* @Description:
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
*/
const execSync = require('child_process').execSync;
......@@ -14,7 +14,7 @@ const execSync = require('child_process').execSync;
const branchName = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
// 校验分支名是否合法
const firstPattern = new RegExp('dev|rc|gray|master');
const secondPattern = new RegExp('(feature|hotfix)/[a-z]{4,}/[0-9]{8,}/[a-zA-Z-]{4,}');
const secondPattern = new RegExp('(feature|hotfix)/[a-z]{4,}/[0-9]{8,}/[0-9a-zA-Z-]{3,}');
const firstMatch = firstPattern.test(branchName);
const secondMatch = secondPattern.test(branchName);
......@@ -27,10 +27,11 @@ if (!firstMatch && !secondMatch) {
// 获取缓存区内容
// 通过diff指令获得所有改动过(不包括删除)的js文件路径
const fileNameStr = execSync('git diff --diff-filter=AM --cached HEAD --name-only').toString();
const fileNameList = fileNameStr.split('\n').filter(item => !!item);
// 过滤掉空格
const fileNameList = fileNameStr.split('\n').filter((item) => !!item);
// 获取需要检测的文件
const detectedFileList = fileNameList.filter(file => {
const detectedFileList = fileNameList.filter((file) => {
// 过滤掉空的和hooks文件夹下所有的文件
return file && file.indexOf('hooks') < 0;
});
......@@ -39,7 +40,7 @@ const detectedFileList = fileNameList.filter(file => {
let errorFileList = [];
detectedFileList.forEach((file) => {
const results = execSync(`git diff --cached ${file}`);
const pattern = /^http:\/\/{1,}/;
const pattern = /^http\:\/\/.{1,}/;
if (pattern.test(results.toString())) {
errorFileList.push(file);
}
......@@ -60,7 +61,7 @@ fileNameList.forEach((file) => {
if (conflictPattern.test(results)) {
conflictFileList.push(file);
}
})
});
if (conflictFileList.length > 0) {
const conflictFileStr = JSON.stringify(conflictFileList);
// eslint-disable-next-line no-console
......@@ -68,4 +69,4 @@ if (conflictFileList.length > 0) {
process.exit(1);
}
process.exit(0);
\ No newline at end of file
process.exit(0);
......@@ -55,7 +55,7 @@
"fs-extra": "^8.1.0",
"html-webpack-plugin": "4.0.0-beta.11",
"html2canvas": "^1.0.0-rc.7",
"husky": "^4.2.5",
"husky": "^4.3.0",
"identity-obj-proxy": "3.0.0",
"jest": "24.9.0",
"jest-environment-jsdom-fourteen": "1.0.1",
......@@ -140,5 +140,12 @@
"ali-oss": "^6.12.0",
"react-sortable-hoc": "^1.11.0",
"vconsole-webpack-plugin": "^1.5.2"
},
"husky": {
"hooks": {
"pre-commit": "node hooks/pre-commit.js",
"commit-msg": "node hooks/commit-msg.js",
"pre-push": "node hooks/pre-commit.js"
}
}
}
......@@ -9,8 +9,7 @@ import { Modal, Input, Table } from 'antd';
import Service from '@/common/js/service';
// import _ from 'underscore';
import './ChooseMembersModal.less';
import User from '@/common/js/user'
import User from '@/common/js/user';
const { Search } = Input;
class ChooseMembersModal extends React.Component {
......
/*
* @Author: wufan
* @Date: 2021-05-11 10:21:37
* @LastEditors: wufan
* @LastEditTime: 2021-06-02 16:51:26
* @Description: 企业微信api
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import User from "@/common/js/user";
import Service from "@/common/js/service";
export default class WechatApi {
static async initConfig(params = { isAgentConfig: false, url: "" }) {
return Service.Hades("anon/hades/getWxCorpJSAPISignature", {
storeId: User.getStoreId(),
url: params.url,
}).then((result) => {
const res = result.result;
this.config({
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: res.appId, // 必填,企业微信的corpID
timestamp: res.timestamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr, // 必填,生成签名的随机串
signature: res.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: [
"chooseImage",
"shareToExternalContact",
"selectExternalContact",
"selectEnterpriseContact",
],
});
if (params.isAgentConfig) {
return new Promise(async (resolve, reject) => {
Service.Hades("anon/hades/getWxWorkJSAPISignature", {
storeId: User.getStoreId(),
url: params.url,
}).then((result2) => {
const res2 = result2.result;
this.agentConfig({
corpid: res2.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: res2.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: res2.timestamp, // 必填,生成签名的时间戳
nonceStr: res2.nonceStr, // 必填,生成签名的随机串
signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: [
"selectExternalContact",
"getCurExternalContact",
"getContext",
"shareToExternalContact",
"sendChatMessage",
"shareToExternalChat",
],
success: (res) => {
console.log(res, "res-agentconfig");
console.info("window.WWOpenData", window.WWOpenData);
resolve(res);
},
fail: (err) => {
console.log(err, "err-agentconfig");
reject(err);
},
});
});
});
}
});
}
static async config(config) {
return new Promise((resolve, reject) => {
console.info("wx.config", config);
wx.config(config);
wx.ready(resolve);
wx.error(reject);
}).then(
() => {
console.info("wx.ready");
},
(error) => {
console.error("wx.error", error);
throw error;
}
);
}
static async agentConfig(config) {
return new Promise((success, fail) => {
console.info("wx.agentConfig", config);
wx.agentConfig({ ...config, success, fail });
}).then(
(res) => {
console.info("wx.agentConfig success", res);
return res;
},
(error) => {
console.error("wx.agentConfig fail", error);
throw error;
}
);
}
static getCurExternalContact() {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.invoke("getCurExternalContact", {}, function (res) {
if (res.err_msg == "getCurExternalContact:ok") {
resolve(res.userId); //返回当前外部联系人userId
} else {
reject(res.err_msg); //错误处理
}
});
});
});
}
static getContext() {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.invoke("getContext", {}, function (res) {
if (res.err_msg == "getContext:ok") {
resolve(res.entry); //返回进入H5页面的入口类型,目前有normal、contact_profile、single_chat_tools、group_chat_tools、chat_attachment
} else {
reject(res.err_msg); //错误处理
}
});
});
});
}
}
import React, { useRef, useLayoutEffect } from 'react'
export default function WWOpenDataCom({ type, openid }) {
const ref = useRef(null)
useLayoutEffect(() => {
WWOpenData.bind(ref.current)
})
return <ww-open-data ref={ref} type={type} openid={openid} />
}
\ No newline at end of file
import React, { useEffect, useState } from 'react';
import { Empty, ConfigProvider, Table } from 'antd';
function XMTable(props) {
const [empty, setEmpty] = useState(props.renderEmpty || {});
const [data, setData] = useState({});
useEffect(() => {
setEmpty(props.renderEmpty || {})
setData(props);
}, [props]);
// 自定义表格空状态
function customizeRenderEmpty() {
return (
<Empty
image={empty.image || Empty.PRESENTED_IMAGE_SIMPLE}
imageStyle={{
height: 150,
}}
description={empty.description}
></Empty>
);
};
return (
<ConfigProvider className="xm-table-component" renderEmpty={customizeRenderEmpty}>
<Table
{...data}
/>
</ConfigProvider>
)
}
export default XMTable;
\ No newline at end of file
.xm-table-component {
}
\ No newline at end of file
/*
* @Author: wufan
* @Date: 2020-11-26 14:48:57
* @Last Modified by: mikey.zhaopeng
* @Last Modified time: 2020-11-26 14:52:02
* @Last Modified by: chenshu
* @Last Modified time: 2021-06-03 15:21:09
*/
import SearchBar from './SearchBar.tsx';
......@@ -10,6 +10,7 @@ import PageControl from './PageControl.tsx';
import CheckBox from './CheckBox.tsx';
import CropperModal from './CropperModal.tsx';
import ImgCutModalNew from './ImgCutModalNew';
import XMTable from './XMTable';
export {
......@@ -17,5 +18,6 @@ export {
PageControl,
CheckBox,
CropperModal,
ImgCutModalNew
ImgCutModalNew,
XMTable,
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
* @Author: Michael
* @Date: 2017-09-08 17:38:18
* @Last Modified by: chenshu
* @Last Modified time: 2020-08-31 14:55:30
* @Last Modified time: 2021-06-04 18:19:23
*/
@import './variables.less';
......@@ -602,7 +602,7 @@ td.ant-table-column-sort {
background: none;
}
.ant-modal-content .ant-table-thead > tr > th {
padding: 9px 24px;
padding: 9px 24px !important;
}
.ant-modal-content tr > td {
......@@ -766,11 +766,12 @@ td.ant-table-column-sort {
}
}
.ant-table-column-title {
flex: initial !important;
}
// 排序小三角
.ant-table-column-sorter {
margin-left: 2px !important;
}
.ant-table-column-sorter-full {
margin-top: -0.32rem !important;
margin-left: 8px !important;
}
......@@ -1698,4 +1698,24 @@ input:focus {
.ant-tag-blue{
background: transparent !important;
}
.createQWCourse{
.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
module.exports = {
isWeiXin() {
const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('micromessenger') > 0;
},
isWorkWx (){
return /wxwork/i.test(navigator.userAgent)
},
isAlipay() {
const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('aliapp') > 0 || ua.indexOf('alipay') > 0;
},
isXiaoMaiApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_ios/i) === 'xiaomai_ios' || ua.match(/xiaomai_android/i) === 'xiaomai_android';
},
isXiaoMaiIOSApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_ios/i) === 'xiaomai_ios';
},
isXiaoMaiAndroidApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_android/i) === 'xiaomai_android';
},
isAndroid() {
const ua = navigator.userAgent.toLowerCase();
return /android/i.test(ua);
},
isIOS() {
const ua = navigator.userAgent.toLowerCase();
return /iphone|ipad|ipod/i.test(ua);
},
isMeiKe() {
const ua = navigator.userAgent.toLowerCase();
return /xmappc/i.test(ua);
},
};
\ No newline at end of file
import Platform from './platform';
import Service from "@/common/js/service";
import User from '@/common/js/user';
export default class WechatApi {
static initShareConfig() {
// if (Platform.isWeiXin()) {
const data = { url: window.location.href.split('#')[0], storeId: User.getStoreId(), }
Service.Hades('anon/hades/getWxWorkJSAPISignature', data).then((result) => {
const res = result.result;
const conf ={
corpid: res.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: res.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: res.timestamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr,// 必填,生成签名的随机串
signature: res.signature,
jsApiList: ['startLiving'],
success: function(res) {
console.log(res,'agentConfig')
},
fail: function(res) {
console.log(res,' agentConfig 错误')
if(res.errMsg.indexOf('function not exist') > -1){
alert('版本过低请升级')
}
},
complete:(res)=>{
console.log(res,' agentConfig 错误')
}
}
console.log(conf)
wx.agentConfig(conf);
});
// }
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditTime: 2021-05-27 10:24:06
* @LastEditTime: 2021-06-02 10:20:59
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
......@@ -41,6 +41,8 @@
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/PhotoClip.js"></script>
<script type="text/javascript" charset="utf-8" src="//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"></script>
<script type="text/javascript" src="https://xiaomai-js.oss-cn-hangzhou.aliyuncs.com/loghub-xm-0.0.1-beta.js"></script>
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script type="text/javascript" src="//open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
......
......@@ -15,7 +15,8 @@ import Service from '@/common/js/service';
import StoreService from "@/domains/store-domain/storeService";
import EmployeeAddOrEditModal from "../store-manage/EmployeeAddOrEditModal";
import User from "@/common/js/user";
import WechatApi from '@/common/js/wechatApi';
import WWOpenDataCom from '@/components/WWOpenDataCom';
import "./EmployeeManage.less";
import ChooseMembersModal from "./modal/ChooseMembersModal";
import SetEmployeeModal from "./modal/SetEmployeeModal";
......@@ -94,8 +95,13 @@ function EmployeeManage() {
useEffect(() => {
getListInfo();
initWechatConfig();
}, [storeId]);
async function initWechatConfig() {
WechatApi.initConfig({ isAgentConfig: true, url: window.location.href.split('#')[0] })
}
async function getListInfo() {
await getStoreRole();
}
......@@ -140,7 +146,10 @@ function EmployeeManage() {
/>
)}
<span className="title">{val}</span>
{/* <span className="title">{val}</span> */}
<span className="title">
<WWOpenDataCom type="userName" openid={val}/>
</span>
</div>
);
},
......
......@@ -11,6 +11,8 @@ import User from '@/common/js/user'
import SetEmployeeModal from "./SetEmployeeModal";
import './ChooseMembersModal.less';
import _ from 'underscore';
import WechatApi from '@/common/js/wechatApi';
import WWOpenDataCom from '@/components/WWOpenDataCom';
const { Search } = Input;
......@@ -39,8 +41,48 @@ class ChooseMembersModal extends React.Component {
componentDidMount() {
this.getUserAuthority();
this.initWechatConfig();
}
initWechatConfig = async () => {
WechatApi.initConfig({ isAgentConfig: true, url: window.location.href.split('#')[0] }).then(()=>{
console.info('window.WWOpenData', window.WWOpenData);
// if (WWOpenData.checkSession) {
// WWOpenData.checkSession({
// success() {
// console.info('open-data 登录态校验成功')
// },
// fail() {
// console.error('open-data 登录态过期')
// },
// })
// }
// if (WWOpenData.on) {
// /**
// * ww-open-data 元素数据发生变更时触发
// */
// WWOpenData.on('update', event => {
// const openid = event.detail.element.getAttribute('openid')
// console.info('渲染数据发生变更', openid, event.detail.hasData)
// })
// /**
// * ww-open-data 获取数据失败时触发
// */
// WWOpenData.on('error', () => {
// console.error('获取数据失败')
// })
// }
// WWOpenData.bindAll(document.querySelectorAll('ww-open-data'))
})
.catch(error=>{
console.log("error-----",error);
})
}
// 获取对应文件相关成员
getUserAuthority = (searchKey='') => {
const { query } = this.state;
......@@ -216,7 +258,8 @@ class ChooseMembersModal extends React.Component {
<div className='avatar'>
<span className="icon iconfont avatar-icon">&#xe84a;</span>
<Tooltip title={name}>
<span className='userImg'>{name}</span>
{/* <span className='userImg'>{name}</span> */}
<WWOpenDataCom type="userName" openid={name}/>
</Tooltip>
</div>
)
......
/*
* @Author: zhujian
* @Date: 2018-10-10 20:49:11
* @Last Modified by: zhujiapeng
* @Last Modified time: 2020-11-16 17:02:11
* @Last Modified by: chenshu
* @Last Modified time: 2021-06-03 16:42:22
*/
// import './s.less'
......@@ -42,6 +42,7 @@ class DefaultIcon extends React.Component {
preserveAspectRatio: 'xMidYMid slice'
}
}
console.log(defaultOptions, this.props, 777777)
return (
<div style={this.props.style} className="DefaultIcon" key="icon">
<Lottie
......
import React, { useState, useRef, useEffect, useContext } from 'react'
import { Route, withRouter } from 'react-router-dom';
import Breadcrumbs from "@/components/Breadcrumbs";
import moment from 'moment'
import { LIVE_SHARE } from "@/domains/course-domain/constants";
import { Form, Alert, Input, Button, InputNumber, DatePicker, Select, Radio, message, Modal } from 'antd';
import Service from "@/common/js/service";
import User from "@/common/js/user";
import qrcode from "@/libs/qrcode/qrcode.js";
declare var wx: any;
const { Option } = Select;
const courseType = {
0: '通用直播',
1: '小班课',
2: '大班课',
3: '企业培训',
4: '活动直播'
}
function CerateQWCourse(props: any) {
const [courseName, setCourseName] = useState('');
const [liveDuration, setLiveDuration] = useState(60);
const [liveStart, setLiveStart] = useState(0);
const [type, setType] = useState('0');
function handleSave() {
const param = {
courseName,
description: '直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节',
liveDuration: liveDuration * 60 * 100,
liveStart,
remindTime: 1000 * 60 * 10,
storeId: User.getStoreId(),
storeUserId: User.getStoreUserId(),
type: parseInt(type)
}
Service.Hades('anon/hades/wxWorkCreateLiveDemo', param).then((res) => {
console.log(22)
handleConvertShortUrl(res.result)
wx.invoke('startLiving', {
"livingId": res.result,
}, function (res: any) {
console.log(122, res)
if (res.err_msg == "startLiving:ok") {
// livingId = res.livingId;
}
});
})
}
function handleConvertShortUrl(id: any) {
const longUrl = `${LIVE_SHARE}qw/live/${id}?id=${User.getStoreId()}`
console.log(longUrl)
// 发请求
Service.Sales('public/businessShow/convertShortUrls', {
urls: [longUrl]
}).then((res) => {
const { result = [] } = res;
const qrcodeWrapDom: any = document.querySelector('.qrcode');
qrcodeWrapDom.innerHTML = ''
const qrcodeNode = new qrcode({
text: result[0].shortUrl,
size: 100,
});
(qrcodeWrapDom as any).appendChild(qrcodeNode);
})
}
return <div className="page createQWCourse ">
<Breadcrumbs navList={props.type === 'edit' ? "编辑考试" : "新建直播课"} goBack={props.history.goBack} />
<div className="box">
<div className="form">
<div className="title">直播信息</div>
<Form
labelCol={{ span: 3 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
>
<Form.Item label="课程名称"
required>
<Input value={courseName} onChange={(e) => { setCourseName(e.target.value) }} style={{ width: 200 }} ></Input>
</Form.Item>
<Form.Item label="持续时长"
required>
<InputNumber value={liveDuration} max={1440} min={1} onChange={(value: any) => { setLiveDuration(parseInt(value) as any) }} style={{ width: 100 }} />
</Form.Item>
<Form.Item label="开始时间"
required>
<DatePicker
format="YYYY/MM/DD HH:mm"
value={liveStart ? moment(Number(liveStart)) : null}
style={{ width: 200 }}
placeholder="开始时间"
showTime
onChange={(date: any) => { setLiveStart(date ? date.valueOf() : 0) }}
/>
</Form.Item>
<Form.Item label="直播的类型"
required>
<Select value={type} placeholder="请选直播的类型" style={{ width: 200 }} onChange={(val) => {
setType(val)
}} >
{
Object.keys(courseType).map((key: any) => {
return <Option value={key}>{(courseType as any)[key]}</Option>
})
}
</Select>
</Form.Item>
</Form>
</div>
</div>
<div style={{marginTop:100}} className="qrBox">
<div style={{width:100,margin:'0 auto'}} className="qrcode"></div>
</div>
<div className="footer">
<Button onClick={props.history.goBack}>取消</Button>
<Button type="primary" onClick={handleSave}>保存</Button>
</div>
</div>
}
export default withRouter(CerateQWCourse);
\ No newline at end of file
......@@ -9,8 +9,10 @@
import React from 'react';
import { Button, Modal, message } from 'antd';
import Service from '@/common/js/service';
import { withRouter ,Route} from "react-router-dom";
import './liveCourseOpt.less';
import BaseService from "@/domains/basic-domain/baseService";
import CerateQWCourse from './CerateQWCourse'
import User from '@/common/js/user'
class LiveCourseOpt extends React.Component {
constructor(props) {
......@@ -25,6 +27,13 @@ class LiveCourseOpt extends React.Component {
pathname: '/create-live-course?type=add',
})
}
handleCreateQWCouese=()=>{
const { match } = this.props;
this.props.history.push(`${match.url}/createqwcourse`)
}
// 下载直播客户端
handleDownloadClient = () => {
const { isMac } = this.state;
......@@ -47,17 +56,20 @@ class LiveCourseOpt extends React.Component {
}
render() {
const userRole = User.getUserRole();
const { match } = this.props;
return (
<div className="live-course-opt">
<div className="opt__left">
{ userRole !== "CloudLecturer" &&
<Button type="primary" onClick={this.handleCreateLiveCouese}>新建直播课</Button>
}
<Button type="primary" onClick={this.handleCreateQWCouese}>新建企微直播课</Button>
{!this.state.isMac && <Button onClick={this.handleDownloadClient}>下载直播客户端</Button>}
</div>
<Route path={`${match.url}/createqwcourse`} component={CerateQWCourse} />
</div>
)
}
}
export default LiveCourseOpt;
\ No newline at end of file
export default withRouter(LiveCourseOpt);
\ No newline at end of file
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-05-27 20:13:53
* @LastEditors: yuananting
* @LastEditTime: 2021-06-02 15:05:54
* @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -364,7 +364,7 @@ class GraphicsCourseList extends React.Component {
<ShareLiveModal
needStr={needStr}
data={shareData}
type="videoClass"
type="graphicsClass"
title="图文课"
close={() => {
this.setState({
......
......@@ -18,8 +18,6 @@ import CourseService from '@/domains/course-domain/CourseService'
import './ShareLiveModal.less'
const DEFAULT_COVER = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'
class ShareLiveModal extends React.Component {
constructor(props) {
super(props)
......@@ -98,27 +96,31 @@ class ShareLiveModal extends React.Component {
render() {
const { courseDivision, data, type, title } = this.props
const { courseName, coverUrl = DEFAULT_COVER, scheduleVideoUrl } = data
const { courseName, scheduleVideoUrl, courseMediaVOS, coverUrl } = data
const { shareUrl, showImg, time } = this.state
// 判断是否是默认图, 默认图不需要在URL后面增加字符串
const isDefaultCover = coverUrl === DEFAULT_COVER
let coverImgSrc = coverUrl
if (type === 'videoClass') {
if ((!coverUrl || isDefaultCover) && title !== '图文课' && title !== '线下课') {
if (courseDivision === 'external') {
coverImgSrc = 'https://image.xiaomaiketang.com/xm/mt3ZQRxGKB.png'
let coverImgSrc = '';
switch (type) {
case 'liveClass': // 直播课
if (courseMediaVOS && courseMediaVOS.length > 0) {
data.courseMediaVOS.map((item, index) => {
if (item.contentType === 'COVER') {
coverImgSrc = item.mediaUrl
}
})
} else {
coverImgSrc = `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast&anystring=anystring`
}
}
} else {
data.courseMediaVOS.map((item, index) => {
if (item.contentType === 'COVER') {
coverImgSrc = item.mediaUrl
coverImgSrc = 'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png';
}
})
break;
case 'videoClass': // 视频课
coverImgSrc = coverUrl || (courseDivision === 'internal' ? `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast&anystring=anystring` : 'https://image.xiaomaiketang.com/xm/mt3ZQRxGKB.png')
break;
case 'graphicsClass': // 图文课
coverImgSrc = coverUrl || 'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png';
break;
case 'offlineClass': // 线下课
coverImgSrc = coverUrl || 'https://image.xiaomaiketang.com/xm/pxbWKsYA87.png';
break;
}
return (
......@@ -137,7 +139,7 @@ class ShareLiveModal extends React.Component {
<span className='text'>{User.getStoreName()}</span>
</div>
<div className='course-name-title'>{type === 'videoClass' ? `${courseName}开课啦` : `邀请你观看直播:`}</div>
<div className='course-name-title'>{type === 'liveClass' ? `邀请你观看直播:` : `${courseName}开课啦`}</div>
{type === 'liveClass' && <div class='live-couse-name'>{courseName}</div>}
<Choose>
<When condition={showImg}>
......
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:07:47
* @LastEditors: wufan
* @LastEditTime: 2021-05-27 19:25:48
* @LastEditors: yuananting
* @LastEditTime: 2021-06-07 15:06:26
* @Description: 线下课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -518,6 +518,11 @@ class AddOfflineCourse extends React.Component {
if(coverId){
scheduleMediaRequests = [coverObj]
}
// 编辑且使用默认图时不传
if (pageType === 'edit' && coverUrl === defaultCoverUrl) {
scheduleMediaRequests = []
}
const commonParams = {
categoryId,
courseName,
......
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-05-27 20:14:01
* @LastEditors: yuananting
* @LastEditTime: 2021-06-02 16:15:55
* @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -25,7 +25,7 @@ import QRCodeModal from '../modal/QRCodeModal';
import './OfflineCourseList.less';
const ENV = process.env.DEPLOY_ENV || 'dev';
const defaultCoverUrl = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png';
const defaultCoverUrl = 'https://image.xiaomaiketang.com/xm/pxbWKsYA87.png';
class OfflineCourseList extends React.Component {
......@@ -358,7 +358,7 @@ class OfflineCourseList extends React.Component {
<ShareLiveModal
needStr={needStr}
data={shareData}
type="videoClass"
type="offlineClass"
title="线下课"
close={() => {
this.setState({
......
......@@ -6,7 +6,7 @@ import Service from "@/common/js/service";
import './PreviewOfflineModal.less';
import ENUM from '@/modules/knowledge-base/ENUM';
const defaultCoverUrl = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png';
const defaultCoverUrl = 'https://image.xiaomaiketang.com/xm/pxbWKsYA87.png';
class PreviewOfflineModal extends React.Component {
......
......@@ -23,7 +23,6 @@ import User from '@/common/js/user';
import './Home.less';
const Option = Select.Option;
class Home extends React.Component {
constructor(props) {
super(props);
......
......@@ -7,17 +7,19 @@
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from "react"
import { Table, Modal, message, Tooltip, Switch, Dropdown, Button } from "antd"
import { Route, withRouter } from "react-router-dom"
import { PageControl } from "@/components"
import { LIVE_SHARE_MAP } from "@/common/constants/academic/cloudClass"
import { appId, shareUrl, LIVE_SHARE } from "@/domains/course-domain/constants"
import ScanFileModal from "../../resource-disk/modal/ScanFileModal"
import WatchData from "./WatchData"
import KnowledgeAPI from "@/data-source/knowledge/request-api"
import ENUM from "../ENUM.js"
import "./KnowledgeBaseList.less"
import React from "react";
import { Modal, message, Tooltip, Switch, Dropdown, Button } from "antd";
import { Route, withRouter } from "react-router-dom";
import Lottie from 'react-lottie';
import { PageControl, XMTable } from "@/components";
import { LIVE_SHARE_MAP } from "@/common/constants/academic/cloudClass";
import { appId, shareUrl, LIVE_SHARE } from "@/domains/course-domain/constants";
import ScanFileModal from "../../resource-disk/modal/ScanFileModal";
import WatchData from "./WatchData";
import KnowledgeAPI from "@/data-source/knowledge/request-api";
import ENUM from "../ENUM.js";
import * as nodata from '../../lottie/nodata/data.json';
import "./KnowledgeBaseList.less";
const DEFAULT_SIZE_UNIT = 1000 * 1000 // 将B转换成M
const { confirm } = Modal
......@@ -492,9 +494,17 @@ class KnowledgeBaseList extends React.Component {
preserveSelectedRowKeys: true,
onChange: onSelectChange,
}
const defaultOptions = {
loop: true,
autoplay: true,
animationData: nodata,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
}
}
return (
<div className='knowledge-base-list'>
<Table
<div className="knowledge-base-list">
<XMTable
rowKey={(record) => record.id}
rowSelection={rowSelection}
size="middle"
......@@ -503,7 +513,19 @@ class KnowledgeBaseList extends React.Component {
pagination={false}
scroll={{ x: 900 }}
bordered
className='knowledge-list-table'
className="knowledge-list-table"
renderEmpty={{
image: <div style={{ marginTop: 24 }}>
<Lottie
options={defaultOptions}
height={150}
width={150}
isStopped={false}
isPaused={false}
/>
</div>,
description: <span style={{ display: 'block', paddingBottom: 24 }}>暂无数据</span>
}}
/>
<div className='box-footer'>
......
......@@ -3,7 +3,7 @@
.select-container{
margin-right: 24px;
.con{
background: #FFF4DD;
background: #E9EFFF;
border-radius: 4px;
padding: 3px 16px;
display: inline-flex;
......@@ -11,7 +11,7 @@
justify-content: space-between;
.tip{
font-size:14px;
color:#FF9D14;
color:#2966FF;
margin-right:8px;
}
.text{
......
......@@ -77,9 +77,9 @@ export default class KnowledgeBase extends React.Component {
onSelectChange = (selectedRowKeys) => {
if (selectedRowKeys.length > 50) {
message.warning('最多只能选择50个题目');
return null;
}
this.setState({ selectedRowKeys });
const list = _.filter(selectedRowKeys, (item, index) => index < 50);
this.setState({ selectedRowKeys: list });
};
render() {
......
......@@ -2,8 +2,8 @@
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-13 09:54:26
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-06-01 10:26:46
* @LastEditors: yuananting
* @LastEditTime: 2021-06-04 10:46:59
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -324,7 +324,7 @@ class AddCourse extends React.Component {
return <img className='course-cover' src={item.mediaUrl} alt='' />;
}
})}
{!hasCover && <img className='course-cover' src={'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'} alt='' />}
{!hasCover && <img className='course-cover' src={'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png'} alt='' />}
<div>
<Choose>
<When condition={record.courseName.length > 17}>
......@@ -501,8 +501,7 @@ class AddCourse extends React.Component {
const { coverUrl } = record;
return (
<div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className='course-cover' src={coverUrl || 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'} alt='' />
<img className='course-cover' src={coverUrl || 'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png'} alt='' />
<Choose>
<When condition={record.courseName.length > 25}>
<Tooltip title={record.courseName}>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -16,7 +16,7 @@ import CourseService from '@/domains/course-domain/CourseService'
import './SharePlanModal.less'
const DEFAULT_COVER = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'
const DEFAULT_COVER = 'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
class ShareLiveModal extends React.Component {
constructor(props) {
......
......@@ -304,7 +304,7 @@ class SelectOperatorModal extends React.Component {
return null
})}
<If condition={!hasCover}>
<img className='course-cover' src={"https://image.xiaomaiketang.com/xm/YNfi45JwFA.png"} alt='' />
<img className='course-cover' src={"https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png"} alt='' />
</If>
<div>
......@@ -432,8 +432,7 @@ class SelectOperatorModal extends React.Component {
const { coverUrl } = record
return (
<div className='course-info'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className='course-cover' src={coverUrl || "https://image.xiaomaiketang.com/xm/YNfi45JwFA.png"} alt='' />
<img className='course-cover' src={coverUrl || "https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png"} alt='' />
<div className='course-name'>{record.courseName}</div>
</div>
)
......
......@@ -15,6 +15,7 @@ import zhCN from 'antd/es/locale/zh_CN'
import User from '@/common/js/user';
import BaseService from "@/domains/basic-domain/baseService";
import { XMContext } from '@/store/context';
import WechatApi from '../../core/wechatApi';
import { setStoreGroupPermission, setStorePermission, setStoreGroupList, setStoreList } from '@/store/actions/index';
import Service from "@/common/js/service";
import Bus from '@/core/tbus';
......@@ -32,6 +33,7 @@ const App: React.FC = (props: any) => {
useEffect(() => {
WechatApi.initShareConfig();
getStoreAndUserInfo();
if (window.location.hash === "#/") {
window.RCHistory.replace({
......
......@@ -54,6 +54,7 @@ function Login(props) {
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`
})
......
......@@ -4,8 +4,7 @@
@import '../../core/global.less';
@import '../../core/filter.less';
@top-height: 60px;
@top-height: 60px;
.right-container {
position: absolute;
left: @xm-left-width;
......
......@@ -48,8 +48,8 @@
margin-right: 20px
}
.icon-img{
width:16px;
height:16px;
width:18px;
height:18px;
margin-right:16px;
}
.listType {
......
......@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from 'react';
import qrcode from "@/libs/qrcode/qrcode.js";
import Service from "@/common/js/service";
import User from '@/common/js/user';
import qrcode from "@/libs/qrcode/qrcode.js";
import { PATH } from '@/domains/basic-domain/constants';
import './WechatLogin.less'
const Logo = require("@/common/images/logo.png")
......
/*
* @Author: wufan
* @Date: 2020-11-27 16:21:49
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-09 14:21:35
* @LastEditors: wufan
* @LastEditTime: 2021-05-11 10:58:58
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
......@@ -15,6 +15,8 @@ import { QuestionCircleOutlined } from "@ant-design/icons";
import StoreService from "@/domains/store-domain/storeService";
import EmployeeAddOrEditModal from "./EmployeeAddOrEditModal";
import User from "@/common/js/user";
import WechatApi from '@/common/js/wechatApi';
import WWOpenDataCom from '@/components/WWOpenDataCom';
import "./EmployeesManagePage.less";
import Item from "antd/lib/list/Item";
......@@ -86,12 +88,22 @@ function EmployeesManagePage() {
useEffect(() => {
getEmployeeList();
initWechatConfig();
}, [query]);
useEffect(() => {
getListInfo();
}, [storeId]);
async function initWechatConfig() {
WechatApi.initConfig({ isAgentConfig: true, url: window.location.href.split('#')[0] }).then(()=>{
console.info('window.WWOpenData', window.WWOpenData);
})
.catch(error=>{
console.log("error-----",error);
})
}
async function getListInfo() {
await getStoreRole();
}
......@@ -136,7 +148,10 @@ function EmployeesManagePage() {
/>
)}
<span className="title">{val}</span>
{/* <span className="title">{val}</span> */}
<span className="title">
<WWOpenDataCom type="userName" openid={val}/>
</span>
</div>
);
},
......
/*
* @Author: yuananting
* @Date: 2021-02-23 18:28:50
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-05-21 17:57:59
* @LastEditors: yuananting
* @LastEditTime: 2021-06-02 14:25:06
* @Description: 助学工具-课程分类
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -153,9 +153,7 @@ class CourseCategoryManage extends Component {
<Space className='title-opts' size={16}>
<span
onClick={() => {
let nodesCount = 0
const { originTreeData } = this.state
console.log('orororo', originTreeData)
const { originTreeData } = this.state;
if (
(item.categoryLevel === 0 && originTreeData.length >= 29) ||
(item.categoryLevel > 0 && this.getRelatedNodes(item.parentId).length >= 30)
......@@ -343,8 +341,10 @@ class CourseCategoryManage extends Component {
let dragNodes = []
dragNodes.push(dragNode.id)
if (dragNode.parentId != 0) {
dragNodes = dragNodes.concat(this.getParentDragNodesLevel(this.state.treeMap[dragNode.parentId]))
if (dragNode.parentId !== "0") {
dragNodes = dragNodes.concat(
this.getParentDragNodesLevel(this.state.treeMap[dragNode.parentId])
);
}
return dragNodes
}
......@@ -365,14 +365,24 @@ class CourseCategoryManage extends Component {
// 拖拽
onDrop = (info) => {
if (this.state.categoryName) {
return
// 带搜索时的分类树不允许拖拽
// 不允许其他节点拖拽到未分类中
// 不允许其他节点拖拽到未分类之前
if (
this.state.categoryName ||
(info.node.categoryName === "未分类" && info.dropPosition === 0) ||
(info.node.categoryName === "未分类" &&
info.dropToGap &&
info.dropPosition === -1)
) {
return;
}
// 未分类不可以拖拽
if (info.dragNode.categoryName === '未分类' && info.dragNode.categoryLevel === 0) return message.info('未分类”为默认分类暂不支持移动')
// 不允许其他节点拖拽到未分类之前
if (info.node.categoryName === '未分类' && info.dropToGap && info.dropPosition === -1) return
if (
info.dragNode.categoryName === "未分类" &&
info.dragNode.categoryLevel === 0
)
return message.info("“未分类”为默认分类暂不支持移动");
let targetParentId = info.dropToGap ? info.node.parentId : info.node.id
let relatedNodes = this.getRelatedNodes(targetParentId)
......@@ -383,8 +393,7 @@ class CourseCategoryManage extends Component {
let nodesArr = this.getDragNodesLevel(this.state.treeMap[info.dragNode.id])
let parentArr = this.getParentDragNodesLevel(this.state.treeMap[targetParentId])
if (nodesArr.length + parentArr.length > 4) {
console.log(nodesArr.length, parentArr.length)
return message.info('最多支持5级分类')
return message.info("最多支持5级分类");
}
}
if (relatedNodes && relatedNodes.length >= 30) {
......
......@@ -44,7 +44,7 @@
white-space: nowrap;
}
.ant-tree-node-content-wrapper.ant-tree-node-selected {
color: #666666;
color: #2966FF;
}
}
.ant-tree-treenode-selected:hover::before,
......
.examPage{
padding-bottom: 50px;
.box {
padding-bottom: 40px!important;
padding-bottom: 66px!important;
}
.ant-form-item{
margin-bottom: 24px !important;
&:last-child{
margin-bottom: 0px !important;
}
}
.form{
margin-top: 12px;
margin-top: 24px;
margin-bottom: 32px;
width: 1000px;
.title{
position: relative;
padding-left: 28px;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: bold;
color: #333333;
line-height: 22px;
margin-bottom: 8px;
margin-bottom: 24px;
&.first {
&::before{
width:4px;
height:12px;
content:'';
background-image: linear-gradient(#2966FF 83.5%, #0ACCA4 16.5%);
display:inline-block;
position: absolute;
left:16px;
top:6px;
}
}
}
}
......
......@@ -132,6 +132,11 @@ function AddExam(props: any) {
return
}
if (param.examName && param.examName.length > 40) {
message.warning('考试名称最多40字');
return
}
if (!paperId) {
message.warning('请选择试卷');
return
......@@ -266,18 +271,17 @@ function AddExam(props: any) {
<Breadcrumbs navList={title} goBack={handleGoBack} />
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div> <div className="form">
<div className="title">基本信息</div>
<div className="form">
<div className="title first">基本信息</div>
<Form
labelCol={{ span: 3 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
>
<Form.Item label="考试名称"
validateStatus={(check && !examName) ? 'error' : ''}
help={check && !examName && '请选择课程'}
validateStatus={(check && (!examName ? '请输入考试名称' : (examName.length > 40) && '考试名称最多40字')) ? 'error' : ''}
help={check && (!examName ? '请输入考试名称' : (examName.length > 40) && '考试名称最多40字')}
required>
<Input placeholder='请输入考试名称(40字以内)' maxLength={40} value={examName} onChange={(e) => {
......@@ -357,9 +361,9 @@ function AddExam(props: any) {
style={{ width: 320 }}
showTime={{ defaultValue: [moment().add(5, 'minutes'), moment().add(5, 'minutes')] }}
ranges={{
'近七天': [moment(), moment().add(6, 'day').endOf('day')],
'近1个月': [moment(), moment().add(1, 'month').endOf('day')],
'近3个月': [moment(), moment().add(3, 'month').endOf('day')],
'近七天': [moment().add(5, 'minute'), moment().add(6, 'day').endOf('day')],
'近1个月': [moment().add(5, 'minute'), moment().add(1, 'month').endOf('day')],
'近3个月': [moment().add(5, 'minute'), moment().add(3, 'month').endOf('day')],
}}
disabledDate={disabledDate}
value={[
......
......@@ -39,11 +39,10 @@ function DataAnalysic(props: any) {
<Breadcrumbs navList={"考试数据"} goBack={props.history.goBack} />
<div className="box">
<div className="titleBox ">
<span className='tips'></span>
考试名称:{examDetail.examName}
</div>
</div>
<div className="box">
<div className="box" style={{ paddingTop: 0 }}>
<Tabs activeKey={selectKey} onChange={(key: any) => {
setSelectKey(key)
}}>
......
......@@ -127,6 +127,18 @@ class ExamShareModal extends React.Component {
<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>
)
......
import React, { useState, useRef, useEffect, useContext } from 'react'
import { Input, Select, DatePicker, Tooltip, Button, Table, Dropdown, Menu, Modal } from 'antd';
import Lottie from 'react-lottie';
import TeacherSelect from '@/modules/common/TeacherSelect';
import { Route, withRouter } from 'react-router-dom';
import Service from "@/common/js/service";
import moment from 'moment';
import { PageControl } from "@/components";
import { PageControl, XMTable } from "@/components";
import AddExam from './AddExam';
import User from "@/common/js/user";
import { XMContext } from "@/store/context";
import ExamShareModal from './ExamShareModal'
import DataAnalysic from './DataAnalysic'
import PreviewModal from './PreviewModal'
import * as nodata from '../../lottie/nodata/data.json';
import './index.less'
const { RangePicker } = DatePicker;
const { Search } = Input;
......@@ -68,8 +70,8 @@ function ExaminationManager(props: any) {
descend: 'PASS_CNT_DESC'
},
examCreateTime: {
ascend: 'EXAM_START_TIME_ASC',
descend: 'EXAM_START_TIME_DESC'
ascend: 'CREATED_ASC',
descend: 'CREATED_DESC'
}
}
......@@ -142,6 +144,7 @@ function ExaminationManager(props: any) {
title: "操作",
fixed:fixStr.right,
dataIndex: "operate",
width: 150,
render: (text: any, record: any) => <div className="table_operate">
{
ctx.xmState?.userPermission?.SeeExamData() && [<div
......@@ -308,6 +311,14 @@ function ExaminationManager(props: any) {
setQuery(_query)
}
const defaultOptions = {
loop: true,
autoplay: true,
animationData: nodata,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
}
}
return <div className="page examination-manager">
<div className="content-header">考试</div>
<div className="box content-body">
......@@ -402,7 +413,7 @@ function ExaminationManager(props: any) {
<div className="content">
<Table
<XMTable
bordered
size="small"
columns={columns}
......@@ -411,8 +422,20 @@ function ExaminationManager(props: any) {
onChange={onChange}
pagination={false}
style={{ margin: '0px 0 16px' }}
renderEmpty={{
image: <div style={{ marginTop: 24 }}>
<Lottie
options={defaultOptions}
height={150}
width={150}
isStopped={false}
isPaused={false}
/>
</div>,
description: <span style={{ display: 'block', paddingBottom: 24 }}>暂无数据</span>
}}
>
</Table>
</XMTable>
{total > 0 &&
<PageControl
size="small"
......
......@@ -123,6 +123,7 @@
border-radius: 4px;
padding: 14px;
padding-bottom: 8px;
padding-right: 0;
.item{
margin-bottom: 8px;
.name{
......
......@@ -33,18 +33,18 @@ function PreviewModal(props: any) {
<div className="phone">
<div className="content">
<div className="topContent">
<div className="title" style={{ fontSize: props.info.examName.length > 24 ? 13 : 22 ,marginTop: 20}}>{props.info.examName || ' '}</div>
<div className="title" style={{ fontSize: props.info.examName.length > 24 ? 13 : 22 ,marginTop: 20 }}>{(props.info.examName.length > 40 ? props.info.examName.substring(0, 40) : props.info.examName) || ' '}</div>
{
props.info.examStartTime && <div className="time">{moment(props.info.examStartTime).format("YYYY-MM-DD HH:mm")}~{moment(props.info.examEndTime).format("YYYY-MM-DD HH:mm")}</div>
}
<div className="rule">
<div className="item">
<div className="num">{props.info.totalScore || props.info.examPaper.totalScore || 0}</div>
<div className="num">{props.info.totalScore || (props.info.examPaper || {}).totalScore || 0}</div>
<div className="text">总分 <span className="dw" style={{color:'#999'}}>(分)</span></div>
</div>
<div className="item">
<div className="num">{props.info.examTotal || props.info.examPaper.questionCnt || 0}</div>
<div className="num">{props.info.examTotal || (props.info.examPaper || {}).questionCnt || 0}</div>
<div className="text">总题数<span className="dw" style={{color:'#999'}} >(道)</span></div>
</div>
<div className="item">
......
......@@ -216,7 +216,7 @@ function DataAnalysic(props: any) {
</div>
</div>
<div className="xm-search-filter" style={{ marginTop: 12 }}>
<div className="xm-search-filter" style={{ marginTop: 16 }}>
<div style={{ display: 'flex' }}>
<div className="search-condition">
<div className="search-condition__item">
......
.dataAnalysic{
.titleBox{
position: relative;
padding-left: 28px;
font-size: 19px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 26px;
background: #FFFFFF;
// padding: 20px 24px;
// margin-bottom: 8px;
.tips{
width: 4px;
height: 16px;
background: #336DFF;
display: inline-block;
margin-right: 4px;
&::before{
width:4px;
height:12px;
content:'';
background-image: linear-gradient(#2966FF 83.5%, #0ACCA4 16.5%);
display:inline-block;
position: absolute;
left:16px;
top:7px;
}
}
.ant-tabs-content-holder {
margin-top: 8px;
}
}
\ No newline at end of file
......@@ -13,4 +13,12 @@
.ant-table-column-sorter {
margin-top: 0px !important;
}
.ant-table tbody tr {
&:nth-child(even) {
background: #fff;
}
&:nth-child(odd) {
background: #fafafa;
}
}
}
\ No newline at end of file
......@@ -42,11 +42,12 @@ class MoveModal extends React.Component {
<span className="icon iconfont">&#xe6f2;</span>
<span className="text">已选择<span style={{ color: '#2966FF' }}>{length}</span>{title},移动后,原有分类将移除此{title}</span>
</div>
<div className="move-item">
<div className="move-item" id="move-item">
<span className="label">选择分类:</span>
<TreeSelect
showSearch
treeNodeFilterProp="title"
getPopupContainer={() => document.querySelector('#move-item')}
style={{ width: 240 }}
treeData={moveData}
placeholder="请选择分类"
......
......@@ -18,4 +18,7 @@
color: #333;
}
}
.ant-select-tree .ant-select-tree-node-content-wrapper.ant-select-tree-node-selected {
background: rgba(41, 102, 255, 0.06);
}
}
\ No newline at end of file
.operate-paper-page {
.box {
margin-bottom: 52px !important;
.ant-form-item {
margin-bottom: 24px !important;
}
.table-style {
border: 1px solid #f0f0f0 !important;
}
......@@ -12,7 +15,6 @@
margin-left: 12px;
}
.choose-btn {
margin-top: 8px;
margin-bottom: 12px;
}
.paper-info-tip {
......@@ -60,10 +62,14 @@
}
}
.ant-table tbody tr {
&:last-child {
td {
border-bottom: none!important;
}
&:nth-child(even) {
background: #fff;
}
&:nth-child(odd) {
background: #fafafa;
}
td {
border-bottom: none!important;
}
}
......
......@@ -2,13 +2,12 @@
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-05-31 13:42:54
* @LastEditTime: 2021-06-03 17:13:30
* @Description: 助学工具-题库-试卷列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import {
Table,
Dropdown,
Row,
Input,
......@@ -20,7 +19,8 @@ import {
ConfigProvider,
Empty,
} from "antd";
import { PageControl } from "@/components";
import Lottie from 'react-lottie';
import { PageControl, XMTable } from "@/components";
import "./PaperList.less";
import { Route, withRouter } from "react-router-dom";
import OperatePaper from "@/modules/teach-tool/paper-manage/OperatePaper";
......@@ -31,6 +31,7 @@ import Service from "@/common/js/service";
import _ from "underscore";
import PaperPreviewModal from "../modal/PreviewPaperModal";
import MoveModal from '../../modal/MoveModal';
import * as nodata from '../../../lottie/nodata/data.json';
import Bus from "@/core/bus";
const { Search } = Input;
......@@ -249,19 +250,6 @@ class PaperList extends Component {
}
};
// 自定义表格空状态
customizeRenderEmpty = () => {
return (
<Empty
image="https://image.xiaomaiketang.com/xm/emptyTable.png"
imageStyle={{
height: 100,
}}
description={"还没有试卷"}
></Empty>
);
};
// 表头设置
parseColumns = () => {
const columns = [
......@@ -305,7 +293,7 @@ class PaperList extends Component {
},
},
{
title: "试卷数量",
title: "题目数量",
key: "questionCnt",
dataIndex: "questionCnt",
width: this.props.type !== "modal-select" ? "12%" : "20%",
......@@ -439,7 +427,7 @@ class PaperList extends Component {
}
batchMoveRemote = (categoryId) => {
const { selectedPaperKeys } = this.state;
const { selectedPaperKeys, query } = this.state;
const data = {
categoryId,
paperId: selectedPaperKeys,
......@@ -450,7 +438,17 @@ class PaperList extends Component {
Service.Hades('public/hades/batchMovePaperCategory', data, { reject: true }).then((res) => {
if (res.success) {
message.success('移动成功');
this.queryPaperPageList();
this.setState(
{
query: {
...query,
current: 1,
},
},
() => {
this.queryPaperPageList();
}
);
Bus.trigger("queryCategoryTree", "remain");
this.clearSelect();
} else {
......@@ -462,7 +460,7 @@ class PaperList extends Component {
}
batchDelete = () => {
const { selectedPaperKeys } = this.state;
const { selectedPaperKeys, query } = this.state;
if (_.isEmpty(selectedPaperKeys)) {
message.warning('请先选择要删除的试卷');
return null;
......@@ -485,7 +483,17 @@ class PaperList extends Component {
Service.Hades('public/hades/batchDeletePaper', data, { reject: true }).then((res) => {
if (res.success) {
message.success('删除成功');
this.queryPaperPageList();
this.setState(
{
query: {
...query,
current: 1,
},
},
() => {
this.queryPaperPageList();
}
);
Bus.trigger("queryCategoryTree", "remain");
this.clearSelect();
} else {
......@@ -500,8 +508,9 @@ class PaperList extends Component {
onSelectPaper = (selectedPaperKeys) => {
if (selectedPaperKeys.length > 50) {
const extraLength = selectedPaperKeys.length - 50;
selectedPaperKeys.splice(selectedPaperKeys.length - extraLength, extraLength);
message.warning('最多只能选择50个试卷');
return null;
}
this.setState({ selectedPaperKeys });
};
......@@ -538,6 +547,14 @@ class PaperList extends Component {
User.getUserRole()
);
const { match } = this.props;
const defaultOptions = {
loop: true,
autoplay: true,
animationData: nodata,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
}
}
return (
<div className={"paper-list " + this.props.type}>
<div className="paper-list-filter">
......@@ -608,32 +625,54 @@ class PaperList extends Component {
)}
<div className="paper-list-content">
<ConfigProvider renderEmpty={this.customizeRenderEmpty}>
{this.props.type !== "modal-select" ? (
<Table
rowKey={(record) => record.paperId}
rowSelection={paperRowSelection}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
loading={loading}
/>
) : (
<Table
rowKey={(record) => record.paperId}
dataSource={dataSource}
size={this.props.type == "modal-select" ? "small" : "middle"}
rowKey={(item) => {
return item.paperId;
}}
rowSelection={rowSelection}
columns={this.parseColumns()}
pagination={false}
bordered
/>
)}
</ConfigProvider>
{this.props.type !== "modal-select" ? (
<XMTable
rowKey={(record) => record.paperId}
rowSelection={paperRowSelection}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
loading={loading}
renderEmpty={{
image: <div style={{ marginTop: 24 }}>
<Lottie
options={defaultOptions}
height={150}
width={150}
isStopped={false}
isPaused={false}
/>
</div>,
description: <span style={{ display: 'block', paddingBottom: 24 }}>还没有试卷</span>
}}
/>
) : (
<XMTable
rowKey={(record) => record.paperId}
dataSource={dataSource}
size={this.props.type == "modal-select" ? "small" : "middle"}
rowKey={(item) => {
return item.paperId;
}}
rowSelection={rowSelection}
columns={this.parseColumns()}
pagination={false}
bordered
renderEmpty={{
image: <div style={{ marginTop: 24 }}>
<Lottie
options={defaultOptions}
height={150}
width={150}
isStopped={false}
isPaused={false}
/>
</div>,
description: <span style={{ display: 'block', paddingBottom: 24 }}>暂无数据</span>
}}
/>
)}
{total > 0 && (
<div className="box-footer">
......
......@@ -5,7 +5,7 @@
.select-container{
margin-right: 24px;
.con{
background: #FFF4DD;
background: #E9EFFF;
border-radius: 4px;
padding: 3px 16px;
display: inline-flex;
......@@ -13,7 +13,7 @@
justify-content: space-between;
.tip{
font-size:14px;
color:#FF9D14;
color:#2966FF;
margin-right:8px;
}
.text{
......@@ -74,7 +74,7 @@
}
.paper-list-content {
position: relative;
margin-top: 16px;
margin-top: 12px;
.empty-list-tip {
color: #2966FF;
cursor: pointer;
......
......@@ -154,6 +154,14 @@ class SelectQuestionList extends Component {
parseColumns = () => {
const columns = [
{
title: "题型",
key: "questionTypeEnum",
dataIndex: "questionTypeEnum",
render: (val) => {
return questionTypeEnum[val];
},
},
{
title: "题目",
key: "questionStem",
dataIndex: "questionStem",
......@@ -180,14 +188,6 @@ class SelectQuestionList extends Component {
},
},
{
title: "题型",
key: "questionTypeEnum",
dataIndex: "questionTypeEnum",
render: (val) => {
return questionTypeEnum[val];
},
},
{
title: "正确率",
key: "accuracy",
dataIndex: "accuracy",
......@@ -387,6 +387,17 @@ class SelectQuestionList extends Component {
})}
</Select>
</div>
<div className="search-condition__item">
<span className="search-label">更新时间:</span>
<RangePicker
value={[
query.updateDateStart ? moment(Number(query.updateDateStart)) : null,
query.updateDateEnd ? moment(Number(query.updateDateEnd)) : null
]}
onChange={(value) => {
this.handleChangeQuery("updatedTime", value)
}} />
</div>
</div>
<div className="reset-fold-area">
......@@ -398,24 +409,8 @@ class SelectQuestionList extends Component {
&#xe61b;{" "}
</span>
</Tooltip>
<span style={{ cursor: 'pointer' }} className="fold-btn" onClick={() => {
this.setState({expandFilter:!expandFilter})
}}>{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>
{expandFilter && <Row>
<div className="search-condition__item">
<span className="search-label">更新时间:</span>
<RangePicker
value={[
query.updateDateStart ? moment(Number(query.updateDateStart)) : null,
query.updateDateEnd ? moment(Number(query.updateDateEnd)) : null
]}
onChange={(value) => {
this.handleChangeQuery("updatedTime", value)
}} />
</div>
</Row>}
</div>
<div className="select-tip-box">
<div>
......
......@@ -2,19 +2,22 @@
.select-question-filter {
position: relative;
.search-condition {
width: calc(100% - 80px);
width: calc(100% - 20px);
display: flex;
align-items: center;
flex-wrap: wrap;
&__item {
margin-right: 3%;
width: 30%;
margin-bottom: 16px;
display: flex;
.search-label {
vertical-align: middle;
display: inline-block;
height: 32px;
line-height: 32px;
flex-shrink: 0;
}
}
}
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-03-27 11:15:03
* @LastEditors: yuananting
* @LastEditTime: 2021-04-15 13:22:10
* @LastEditTime: 2021-06-01 17:28:21
* @Description: 助学工具-试卷-预览试卷
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -284,7 +284,7 @@ class PreviewPaperModal extends Component {
footer={null}
onCancel={this.props.close}
>
{paperName && <div className="paper-title">{paperName}</div>}
{paperName && <div className="paper-title">{paperName.length > 40 ? paperName.substring(0, 40) : paperName}</div>}
{questionList && questionList.length > 0 ? (
<div className="question-list-box">
{_.map(questionList, (questionItem, questionIndex) => {
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-03-29 10:52:26
* @LastEditors: yuananting
* @LastEditTime: 2021-05-08 16:11:27
* @LastEditTime: 2021-06-07 14:45:02
* @Description: 助学工具-试卷-新建选择题目弹窗
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -42,7 +42,8 @@ class SelectQuestionModal extends Component {
width={1080}
onOk={() => {
this.props.setSelectedQuestion(
this.listRef.current.state.selectQuestionKeys.map((item) => {
this.listRef.current.state.selectQuestionKeys.map((item, index) => {
item.sorterIndex = index;
item.questionId = item.id || item.questionId;
item.questionType = item.questionTypeEnum || item.questionType;
item.score = item.score || 2;
......
/*
* @Author: yuananting
* @Date: 2021-02-25 14:34:29
* @LastEditors: wufan
* @LastEditTime: 2021-05-14 18:17:08
* @LastEditors: yuananting
* @LastEditTime: 2021-06-04 17:09:25
* @Description: 助学工具-题库-操作题目Tab
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -66,23 +66,19 @@ class OperateQuestionTab extends Component {
}
componentDidMount() {
const { chooseOptions } = this.state;
if (
["INDEFINITE_CHOICE", "MULTI_CHOICE", "SINGLE_CHOICE"].includes(
this.props.questionTypeKey
)
) {
if (chooseOptions.length === 0) {
const { questionTypeKey } = this.props;
const isEditCurrent = getParameterByName("id") && getParameterByName("type") === questionTypeKey;
const optionSize = isEditCurrent ? 20 : 4;
if (["INDEFINITE_CHOICE", "MULTI_CHOICE", "SINGLE_CHOICE"].includes(questionTypeKey)) {
// 选择题(单选 多选 不定项)-插入4条默认选项
for (var i = 0; i < 4; i++) {
this.handleAddOption();
this.setState({
[`optionsValidate_${i}`]: "success",
[`optionsText_${i}`]: "",
});
}
for (var i = 0; i < optionSize; i++) {
this.handleAddOption();
this.setState({
[`optionsValidate_${i}`]: "success",
[`optionsText_${i}`]: "",
});
}
} else if (this.props.questionTypeKey === "JUDGE") {
} else if (questionTypeKey === "JUDGE") {
this.initJudgeOption("正确");
this.initJudgeOption("错误");
}
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-06-01 11:31:17
* @LastEditTime: 2021-06-03 17:12:01
* @Description: 助学工具-题库-题目列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -23,10 +23,11 @@ import {
Dropdown,
DatePicker,
} from "antd";
import Lottie from 'react-lottie';
import _ from "underscore";
import { Route, withRouter } from "react-router-dom";
import { DownOutlined } from '@ant-design/icons';
import { PageControl } from "@/components";
import { PageControl, XMTable } from "@/components";
import User from "@/common/js/user";
import AidToolService from "@/domains/aid-tool-domain/AidToolService";
import PreviewQuestionModal from "../modal/PreviewQuestionModal";
......@@ -36,6 +37,7 @@ import Bus from "@/core/bus";
import moment from 'moment';
import Service from "@/common/js/service";
import MoveModal from '../../modal/MoveModal';
import * as nodata from '../../../lottie/nodata/data.json';
import "./QuestionList.less";
const { RangePicker } = DatePicker;
......@@ -193,39 +195,6 @@ class QuestionList extends Component {
});
};
// 自定义表格空状态
customizeRenderEmpty = () => {
const { categoryId } = this.state.query;
return (
<Empty
image="https://image.xiaomaiketang.com/xm/emptyTable.png"
imageStyle={{
height: 100,
}}
description={
<span>
<span>还没有题目</span>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
categoryId && (
<span>
,快去
<span
className="empty-list-tip"
onClick={() => {
this.handleCreateQuestion();
}}
>
新建一个
</span>
吧!
</span>
)}
</span>
}
></Empty>
);
};
// 排序
handleChangeTable = (pagination, filters, sorter) => {
const { columnKey, order } = sorter;
......@@ -477,8 +446,9 @@ class QuestionList extends Component {
onSelectChange = (selectedRowKeys) => {
if (selectedRowKeys.length > 50) {
const extraLength = selectedRowKeys.length - 50;
selectedRowKeys.splice(selectedRowKeys.length - extraLength, extraLength);
message.warning('最多只能选择50个题目');
return null;
}
this.setState({ selectedRowKeys });
};
......@@ -523,7 +493,7 @@ class QuestionList extends Component {
}
batchMoveRemote = (categoryId) => {
const { selectedRowKeys } = this.state;
const { selectedRowKeys, query } = this.state;
const data = {
categoryId,
id: selectedRowKeys,
......@@ -535,8 +505,18 @@ class QuestionList extends Component {
if (res.success) {
message.success('移动成功');
Bus.trigger('queryCategoryTree', 'remain');
this.queryQuestionPageList();
this.clearSelect();
this.setState(
{
query: {
...query,
current: 1,
},
},
() => {
this.queryQuestionPageList();
}
);
} else {
message.error('移动失败');
}
......@@ -546,7 +526,7 @@ class QuestionList extends Component {
}
batchDelete = () => {
const { selectedRowKeys } = this.state;
const { selectedRowKeys, query } = this.state;
if (_.isEmpty(selectedRowKeys)) {
message.warning('请先选择要删除的题目');
return null;
......@@ -570,8 +550,18 @@ class QuestionList extends Component {
if (res.success) {
message.success('删除成功');
Bus.trigger('queryCategoryTree', 'remain');
this.queryQuestionPageList();
this.clearSelect();
this.setState(
{
query: {
...query,
current: 1,
},
},
() => {
this.queryQuestionPageList();
}
);
} else {
message.error('删除失败');
}
......@@ -604,6 +594,14 @@ class QuestionList extends Component {
preserveSelectedRowKeys: true,
onChange: this.onSelectChange,
};
const defaultOptions = {
loop: true,
autoplay: true,
animationData: nodata,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
}
}
return (
<div className="question-list">
<div className="question-list-filter">
......@@ -690,7 +688,7 @@ class QuestionList extends Component {
</div>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
(
<Space size={16}>
<Space size={8}>
{_.isEmpty(selectedRowKeys) ?
(!!categoryId && [
<Button key="1" type="primary" onClick={this.handleCreateQuestion}>
......@@ -710,26 +708,59 @@ class QuestionList extends Component {
</span>
</div>
}
<Dropdown className="ml8" overlay={this.setMoreOperationOption()}>
<Button id="more_operate">
更多操作
<DownOutlined />
</Button>
</Dropdown>
{!!categoryId ? (
<Dropdown overlay={this.setMoreOperationOption()}>
<Button id="more_operate">
更多操作
<DownOutlined />
</Button>
</Dropdown>
) : (
<Space size={8}>
<Button onClick={() => this.batchMove()}>批量移动</Button>
<Button onClick={() => this.batchDelete()}>批量删除</Button>
</Space>
)}
</Space>
)}
<div className="question-list-content">
<ConfigProvider renderEmpty={this.customizeRenderEmpty}>
<Table
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
onChange={this.handleChangeTable}
rowSelection={rowSelection}
/>
</ConfigProvider>
<XMTable
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
onChange={this.handleChangeTable}
rowSelection={rowSelection}
renderEmpty={{
image: <div style={{ marginTop: 24 }}>
<Lottie
options={defaultOptions}
height={150}
width={150}
isStopped={false}
isPaused={false}
/>
</div>,
description: <span style={{ display: 'block', paddingBottom: 24 }}><span>还没有题目</span>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
categoryId && (
<span>
,快去
<span
className="empty-list-tip"
onClick={() => {
this.handleCreateQuestion();
}}
>
新建一个
</span>
吧!
</span>
)}
</span>
}}
/>
{total > 0 && (
<div className="box-footer">
<PageControl
......
......@@ -43,7 +43,7 @@
.select-container{
.con {
background: #FFF4DD;
background: #E9EFFF;
border-radius: 4px;
padding: 3px 16px;
display: inline-flex;
......@@ -51,7 +51,7 @@
justify-content: space-between;
.tip {
font-size: 14px;
color: #FF9D14;
color: #2966FF;
margin-right: 8px;
}
.text {
......@@ -70,7 +70,7 @@
}
.question-list-content {
position: relative;
margin-top: 16px;
margin-top: 12px;
.empty-list-tip {
color: #2966FF;
cursor: pointer;
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-21 15:53:31
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-05-30 11:00:09
* @LastEditTime: 2021-06-08 10:01:13
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -44,22 +44,6 @@ export const menuList: any = [
]
},
{
groupName: "知识库",
groupCode: "CloudKnowledge",
icon: '&#xe8a8;',
link: '/knowledge-base',
img:'https://image.xiaomaiketang.com/xm/8sbP5rGQWh.png',
selectImg:'https://image.xiaomaiketang.com/xm/hJKCfibC22.png'
},
{
groupName: "资料云盘",
groupCode: "CloudDisk",
icon: '&#xe8aa;',
link: '/resource-disk',
img:'https://image.xiaomaiketang.com/xm/zGKbXJPzXx.png',
selectImg:'https://image.xiaomaiketang.com/xm/5sN4MzjxYc.png',
},
{
groupName: "培训管理",
groupCode: "TrainManage",
icon: '&#xe8a6;',
......@@ -138,5 +122,20 @@ export const menuList: any = [
}
]
},
{
groupName: "知识库",
groupCode: "CloudKnowledge",
icon: '&#xe8a8;',
link: '/knowledge-base',
img:'https://image.xiaomaiketang.com/xm/8sbP5rGQWh.png',
selectImg:'https://image.xiaomaiketang.com/xm/hJKCfibC22.png'
},
{
groupName: "资料云盘",
groupCode: "CloudDisk",
icon: '&#xe8aa;',
link: '/resource-disk',
img:'https://image.xiaomaiketang.com/xm/zGKbXJPzXx.png',
selectImg:'https://image.xiaomaiketang.com/xm/5sN4MzjxYc.png',
},
]
\ No newline at end of file
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