Commit e6b0a291 by zhangleyuan

Merge branch 'master' into feature/zhangleyuan/20210608/optimize

parents 4d6d1112 a1e475c8
......@@ -105,6 +105,10 @@
},
"scripts": {
"start": "node scripts/start.js",
"start:dev": "cross-env DEPLOY_ENV=dev node scripts/start.js",
"start:dev1": "cross-env DEPLOY_ENV=dev node scripts/start.js",
"start:rc": "cross-env DEPLOY_ENV=rc node scripts/start.js",
"start:gray": "cross-env DEPLOY_ENV=gray node scripts/start.js",
"build:dev": "cross-env DEPLOY_ENV=dev node scripts/build.js",
"build:dev1": "cross-env DEPLOY_ENV=dev node scripts/build.js",
"build:rc": "cross-env DEPLOY_ENV=rc node scripts/build.js",
......
......@@ -3,7 +3,7 @@
* @Date: 2020-08-31 09:34:25
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-05-12 17:27:08
* @Description:
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -11,32 +11,34 @@ import Storage from './storage';
import { PREFIX, USER_PREFIX } from '@/domains/basic-domain/constants';
class User {
getStoreId(){
return Storage.get(`${PREFIX}_storeId`)
getStoreId() {
return Storage.get(`${PREFIX}_storeId`);
}
getEnterpriseId() {
return Storage.get(`${PREFIX}_enterpriseId`)
return Storage.get(`${PREFIX}_enterpriseId`);
}
getStoreName(){
return Storage.get(`${PREFIX}_storeName`)
getStoreName() {
return Storage.get(`${PREFIX}_storeName`);
}
getStoreType(){
return Storage.get(`${PREFIX}_storeType`)
getStoreType() {
return Storage.get(`${PREFIX}_storeType`);
}
getStoreUserId(){
return Storage.get(`${PREFIX}_storeUserId`)
getStoreUserId() {
return Storage.get(`${PREFIX}_storeUserId`);
}
getUserId(){
return Storage.get(`${PREFIX}_userId`)
getCustomerId() {
return Storage.get(`${PREFIX}_customerId`);
}
getUserRole(){
return Storage.get(`${PREFIX}_userRole`)
getUserId() {
return Storage.get(`${PREFIX}_userId`);
}
getUserRole() {
return Storage.get(`${PREFIX}_userRole`);
}
getToken() {
......@@ -47,67 +49,71 @@ class User {
return Storage.get(`${PREFIX}_isAdmin`);
}
setStoreId(value:any){
return Storage.set(`${PREFIX}_storeId`,value)
setStoreId(value: any) {
return Storage.set(`${PREFIX}_storeId`, value);
}
setEnterpriseId(value: any) {
return Storage.set(`${PREFIX}_enterpriseId`,value)
return Storage.set(`${PREFIX}_enterpriseId`, value);
}
setStoreName(value: any) {
return Storage.set(`${PREFIX}_storeName`, value);
}
setStoreName(value:any){
return Storage.set(`${PREFIX}_storeName`,value)
setStoreType(value: any) {
return Storage.set(`${PREFIX}_storeType`, value);
}
setStoreType(value:any){
return Storage.set(`${PREFIX}_storeType`,value)
setStoreUserId(value: any) {
return Storage.set(`${PREFIX}_storeUserId`, value);
}
setStoreUserId(value:any){
return Storage.set(`${PREFIX}_storeUserId`,value)
setCustomerId(value: any) {
return Storage.set(`${PREFIX}_customerId`, value);
}
setUserId(value:any){
return Storage.set(`${PREFIX}_userId`,value)
setUserId(value: any) {
return Storage.set(`${PREFIX}_userId`, value);
}
setUserRole(value:any){
return Storage.set(`${PREFIX}_userRole`,value)
setUserRole(value: any) {
return Storage.set(`${PREFIX}_userRole`, value);
}
setToken(value:any) {
return Storage.set(`${PREFIX}_token`,value);
setToken(value: any) {
return Storage.set(`${PREFIX}_token`, value);
}
setIsAdmin(value: any) {
return Storage.set(`${PREFIX}_isAdmin`, value);
}
removeToken(){
removeToken() {
return Storage.remove(`${PREFIX}_token`);
}
removeUserId(){
removeUserId() {
return Storage.remove(`${PREFIX}_userId`);
}
removeEnterpriseId() {
return Storage.remove(`${PREFIX}_enterpriseId`)
return Storage.remove(`${PREFIX}_enterpriseId`);
}
getCustomerStoreId(){
getCustomerStoreId() {
return Storage.get(`${PREFIX}_customerStoreId`);
}
setCustomerStoreId(value:any) {
return Storage.set(`${PREFIX}_customerStoreId`,value);
setCustomerStoreId(value: any) {
return Storage.set(`${PREFIX}_customerStoreId`, value);
}
setIdentifier(value:any){
return Storage.set(`${PREFIX}_identifier`,value);
setIdentifier(value: any) {
return Storage.set(`${PREFIX}_identifier`, value);
}
getIdentifier(){
getIdentifier() {
return Storage.get(`${PREFIX}_identifier`);
}
clearUserInfo(){
clearUserInfo() {
Storage.remove(`${USER_PREFIX}_token`);
Storage.remove(`${USER_PREFIX}_userId`);
Storage.remove(`${USER_PREFIX}_userPhone`);
......@@ -119,4 +125,4 @@ class User {
}
}
export default new User();
\ No newline at end of file
export default new User();
import React, { useEffect, useState } from 'react';
import { Empty, ConfigProvider, Table } from 'antd';
import Lottie from 'react-lottie';
import * as nodata from '../modules/lottie/nodata/data.json';
function XMTable(props) {
const [empty, setEmpty] = useState(props.renderEmpty || {});
......@@ -12,9 +14,25 @@ function XMTable(props) {
// 自定义表格空状态
function customizeRenderEmpty() {
const defaultOptions = {
loop: true,
autoplay: true,
animationData: empty.image || nodata,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
}
}
return (
<Empty
image={empty.image || Empty.PRESENTED_IMAGE_SIMPLE}
image={<div style={{ marginTop: 24 }}>
<Lottie
options={defaultOptions}
height={150}
width={150}
isStopped={false}
isPaused={false}
/>
</div>}
imageStyle={{
height: 150,
}}
......
......@@ -7,7 +7,7 @@
left: 0px;
right: 0;
bottom: 0;
z-index:3;
z-index: 3;
background-color: #fff;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
......@@ -20,12 +20,12 @@
bottom: 0;
z-index: 102;
overflow: auto;
margin:0 16px;
.box{
&:first-child{
margin: 0 16px;
.box {
&:first-child {
margin-bottom: 8px;
}
&:last-child{
&:last-child {
margin-bottom: 16px;
}
}
......@@ -48,10 +48,10 @@
.content-header {
padding: 16px 16px 8px 16px;
line-height: 30px;
font-size:24px;
color:#333;
font-weight:bold;
background: #FFF;
font-size: 24px;
color: #333;
font-weight: bold;
background: #fff;
h1 {
font-weight: normal;
display: inline-block;
......
......@@ -6,9 +6,11 @@
import React from 'react';
import { Modal, Input, Table, message, Tooltip, Empty } from 'antd';
import { XMTable } from '@/components';
import Service from '@/common/js/service';
import User from '@/common/js/user'
import SetEmployeeModal from "./SetEmployeeModal";
import search from '../../lottie/search/data.json';
import './ChooseMembersModal.less';
import _ from 'underscore';
......@@ -311,19 +313,18 @@ class ChooseMembersModal extends React.Component {
enterButton={<span className="icon iconfont">&#xe832;</span>}
/>
<div className='container-left-body-table'>
<Table
<XMTable
rowKey={(record) => record.enterpriseVisibleUserId}
dataSource={allUserList}
columns={this.selectedColumnsLeft()}
pagination={false}
scroll={{ y: 290}}
// bordered={true}
locale={{
emptyText: <div>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={false} />
<div style={{ color: '#333', marginTop: -70 }}>暂无数据</div>
renderEmpty={{
image: searchKey ? search : '',
description: <div>
<div style={{ color: '#333' }}>暂无数据</div>
<div style={{ color: '#666', padding: '0 32px', fontSize: '12px' }}>需要先将员工添加到企微可见范围后,员工才会出现在这里</div>
</div>,
</div>
}}
size={'small'}
rowSelection={{
......
/*
* @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({
......
/*
* @Author: 吴文洁
* @Date: 2020-06-22 14:26:37
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-07-23 09:33:02
* @Last Modified by: chenshu
* @Last Modified time: 2021-06-08 18:18:46
*/
import React, { useEffect, useState } from 'react';
import { Modal, Button, Table, Progress, message, Tooltip, Spin, Popconfirm } from 'antd';
......@@ -40,7 +40,7 @@ class ManageCoursewareModal extends React.Component {
componentDidMount() {
this.getCoursewareList();
var animation = Lottie.loadAnimation({
path: "https://image.xiaomaiketang.com/xm/MQwp2aJaxf.json",
path: "https://image.xiaomaiketang.com/xm/SDBkP7mbJX.json",
name: "test",
renderer: "svg",
loop: true,
......
......@@ -8,8 +8,8 @@
.empty-image {
display: block;
margin: 24px auto 12px;
width:100px;
height:100px;
width:150px;
height:150px;
}
.empty-button {
display: block;
......
......@@ -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 {
......
import React from 'react'
import { Tabs } from 'antd'
import VideoCourseFilter from './components/VideoCourseFilter'
import VideoCourseOpt from './components/VieoCourseOpt'
import VideoCourseList from './components/VideoCourseList'
import CourseService from '@/domains/course-domain/CourseService'
import User from '@/common/js/user'
const { TabPane } = Tabs
import React from 'react';
import { Tabs } from 'antd';
import VideoCourseFilter from './components/VideoCourseFilter';
import VideoCourseOpt from './components/VieoCourseOpt';
import VideoCourseList from './components/VideoCourseList';
import CourseService from '@/domains/course-domain/CourseService';
import User from '@/common/js/user';
const { TabPane } = Tabs;
class VideoCourse extends React.Component {
constructor(props) {
super(props)
super(props);
this.state = {
query: {
size: 10,
......@@ -18,45 +18,43 @@ class VideoCourse extends React.Component {
dataSource: [], // 视频课列表
totalCount: 0, // 视频课数据总条数
currentTabKey: 'internal',
}
};
}
componentWillMount() {
// 获取视频课列表
this.handleFetchScheduleList()
this.handleFetchScheduleList();
}
// 获取视频课列表
handleFetchScheduleList = (_query = {}) => {
const { currentTabKey } = this.state
const { currentTabKey } = this.state;
const query = {
...this.state.query,
..._query,
courseDivision: currentTabKey === 'external' ? 1 : null,
}
// 更新请求参数
this.setState({ query })
};
CourseService.videoSchedulePage(query).then((res) => {
const { result = {} } = res || {}
const { records = [], total = 0 } = result
const { result = {} } = res || {};
const { records = [], total = 0 } = result;
if (Number(total) && query.size * (query.current - 1) >= Number(total)) {
this.handleFetchScheduleList({
...query,
current: 1,
})
return
});
return;
}
this.setState({
query,
dataSource: records,
totalCount: Number(total),
})
})
}
});
});
};
currenTabChange = (currentTabKey) => {
const { query } = this.state
const { query } = this.state;
this.setState(
{
currentTabKey,
......@@ -66,20 +64,21 @@ class VideoCourse extends React.Component {
},
},
() => {
this.handleFetchScheduleList()
console.log('this.state.query===>', this.state.query);
// this.handleFetchScheduleList()
}
)
}
);
};
changeShelfState = (index, shelfState) => {
const { dataSource } = this.state
dataSource[index].shelfState = shelfState
const { dataSource } = this.state;
dataSource[index].shelfState = shelfState;
this.setState({
dataSource,
})
}
});
};
render() {
const { dataSource, totalCount, query, currentTabKey } = this.state
const { dataSource, totalCount, query, currentTabKey } = this.state;
return (
<div className='page video-course-page'>
<div className='content-header'>视频课</div>
......@@ -107,8 +106,8 @@ class VideoCourse extends React.Component {
/>
</div>
</div>
)
);
}
}
export default VideoCourse
export default VideoCourse;
......@@ -10,7 +10,6 @@
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";
......@@ -18,7 +17,6 @@ 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
......@@ -494,14 +492,6 @@ 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">
<XMTable
......@@ -515,15 +505,6 @@ class KnowledgeBaseList extends React.Component {
bordered
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>
}}
/>
......
......@@ -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-10 19:55:24
* @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.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -10,7 +10,7 @@
import React, { useState } from 'react';
import { Table, Modal, message, Tooltip, Switch, Dropdown } from 'antd';
import { withRouter } from 'react-router-dom';
import { PageControl } from '@/components';
import { PageControl, XMTable } from "@/components";
import PlanService from '@/domains/plan-domain/planService';
import SharePlanModal from '../modal/SharePlanModal';
import { LIVE_SHARE } from '@/domains/course-domain/constants';
......@@ -305,7 +305,7 @@ function PlanList(props) {
}
return (
<div className='plan-list'>
<Table
<XMTable
rowKey={(record) => record.id}
showSorterTooltip={false}
dataSource={props.planListData}
......@@ -316,6 +316,9 @@ function PlanList(props) {
size='middle'
scroll={{ x: 1400 }}
className='plan-list-table'
renderEmpty={{
description: <span style={{ display: 'block', paddingBottom: 24 }}>暂无数据</span>
}}
/>
<div className='box-footer'>
<PageControl
......
......@@ -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>
)
......
/*
* @Author: 吴文洁
* @Date: 2020-06-09 10:47:51
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-07-23 09:33:09
* @Last Modified by: chenshu
* @Last Modified time: 2021-06-08 18:10:25
* @Description: 文件夹列表
*/
......@@ -11,12 +11,13 @@ import { Table, Menu, Dropdown, Modal, message,Tooltip } from 'antd';
import _ from 'underscore';
// import * as lodash from 'lodash';
import { PageControl, LottieIcon } from 'xiaomai-b-components';
import { XMTable } from '@/components';
import Service from '@/common/js/service';
import { formatDate } from '@/domains/basic-domain/utils';
import { FILE_TYPE_ICON_MAP, SUPPORT_FILE_TYPE_MAP, DEFAULT_SIZE_UNIT } from '@/domains/resource-disk/constants';
import { getFileTypeByName } from '@/domains/resource-disk/utils';
import addData from '../../lottie/addData/data.json';
import search from '../../lottie/search/data.json';
import UploadProgressModal from '@/bu-components/UploadProgressModal';
import SelectPrepareFileModal from '@/bu-components/SelectPrepareFileModal';
import CopyFileModal from '@/bu-components/CopyFileModal';
......@@ -693,9 +694,11 @@ class FolderList extends React.Component {
</When>
<Otherwise>
<LottieIcon
title={
<Choose>
<XMTable
className="add-empty"
renderEmpty={{
image: !showResultPage ? addData : search,
description: <Choose>
<When condition={!showResultPage}>
<input
multiple
......@@ -709,7 +712,7 @@ class FolderList extends React.Component {
{
<Choose>
<When condition={hasManagementAuthority}>
<div>你还没有上传文件,点击
<div className="lottie-icon-title">你还没有上传文件,点击
<Tooltip title="支持文件类型:ppt、word、excel、pdf、jpg、mp3、mp4">
<span
className="upload-btn"
......@@ -729,7 +732,7 @@ class FolderList extends React.Component {
<div className="desc">搜索无结果</div>
</Otherwise>
</Choose>
}
}}
/>
</Otherwise>
</Choose>
......
......@@ -215,14 +215,12 @@
cursor: pointer;
}
.lottie-icon {
&__title {
color: #999;
.upload-btn {
color: #5A8EFA;
margin: 0 4px;
cursor: pointer;
}
.lottie-icon-title {
color: #999;
.upload-btn {
color: #5A8EFA;
margin: 0 4px;
cursor: pointer;
}
}
// td.ant-table-column-sort{
......@@ -230,6 +228,11 @@
// }
}
}
.add-empty {
.ant-table-cell {
border: none;
}
}
}
......
import User from '@/common/js/user';
import React from 'react';
import Header from './Header'
import Lottie from "lottie-web";
import { Modal } from "antd";
import Service from "@/common/js/service";
import { LIVE_SHARE } from "@/domains/course-domain/constants";
import BaseService from "@/domains/basic-domain/baseService";
import './ErrorCollege.less';
export default class ErrorCollege extends React.Component {
constructor(props) {
super(props);
this.state = {
menuType: true,
nickName: '',
}
}
componentDidMount() {
this.getUserInfo();
this.getStorePermission();
var animation = Lottie.loadAnimation({
path: "https://image.xiaomaiketang.com/xm/AhcJZHdMZf.json",
name: "test",
renderer: "svg",
loop: true,
autoplay: true,
container: document.getElementById("lottie-box")
});
}
getStorePermission() {
......@@ -29,17 +41,62 @@ export default class ErrorCollege extends React.Component {
});
}
handleMenuType() {
this.setState({ menuType: !menuType });
getUserInfo() {
const param = {
storeUserId: User.getStoreUserId(),
};
BaseService.getStoreUser(param).then((res) => {
const { nickName } = res.result;
this.setState({ nickName });
});
}
handleLogoutConfirm() {
return Modal.confirm({
title: "你确定要退出登录吗?",
content: "退出后,需重新登录",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
okText: "退出登录",
cancelText: "点错了",
onOk: () => {
this.handleLogout();
},
});
}
handleLogout() {
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;
});
}
render() {
const { menuType } = this.state;
const { nickName } = this.state;
return (
<div className="error-college-page">
<Header id="error" handleMenuType={this.handleMenuType} menuType={menuType} />
<div className="header">
<img src='https://image.xiaomaiketang.com/xm/FEdG7BMwKr.png' className="logo" alt="" />
<div className="name-box">
<img src='https://image.xiaomaiketang.com/xm/hcp6zs5HTn.png' className="avatar" alt="" />
<span className="name">{nickName}</span>
<span
className="control"
onClick={() => {
this.handleLogoutConfirm();
}}
>退出登录</span>
</div>
</div>
<div className="error-college-box">
<img src="https://image.xiaomaiketang.com/xm/MQRaYkbr6J.png" className="error-college-image" />
<div id="lottie-box" className="error-college-image"></div>
<span className="error-college-tip">{User.getStoreName()}已停用</span>
</div>
</div>
......
......@@ -2,6 +2,36 @@
position: relative;
width: 100vw;
height: 100vh;
.header {
display: flex;
align-items: center;
height: 60px;
padding: 0 344px;
justify-content: space-between;
.logo {
width: 117px;
height: 30px;
}
.name-box {
display: flex;
align-items: center;
.avatar {
width: 24px;
height: 24px;
border-radius: 50%;
margin-right: 6px;
}
.name {
color: #666;
font-size: 16px;
margin-right: 8px;
}
.control {
color: #2966FF;
cursor: pointer;
}
}
}
.error-college-box {
position: absolute;
top: 50px;
......@@ -10,20 +40,20 @@
bottom: 0;
.error-college-image {
position: absolute;
top: 246px;
top: 266px;
left: 50%;
transform: translateX(-50%);
width: 246px;
height: 132px;
width: 200px;
height: 200px;
display: block;
}
.error-college-tip {
position: absolute;
top: 404px;
top: 482px;
left: 50%;
transform: translateX(-50%);
color: #8C8E93;
font-size: 13px;
color: #000;
font-size: 18px;
}
}
}
\ No newline at end of file
......@@ -5,15 +5,15 @@
* @Last Modified time: 2020-04-18 10:54:32
*/
import React, { useState, useEffect, useRef } from "react";
import "./XMAudio.less";
import VideoUpload from "@/core/upload";
import React, { useState, useEffect, useRef } from 'react';
import './XMAudio.less';
import VideoUpload from '@/core/upload';
let timerInterval;
const XMAudio = (props) => {
const ref = useRef();
const { style, size, getDuration } = props;
const { style, size, getDuration } = props;
const [url, setUrl] = useState(props.url);
const [playing, setPlaying] = useState(false);
const [timer, setTimer] = useState(null);
......@@ -22,7 +22,7 @@ const XMAudio = (props) => {
const [totalTime, setTotalTime] = useState(Math.round(Number(size)));
const prevTimeRef = useRef();
useEffect(() => {
if(!props.forbidParse){
if (!props.forbidParse) {
VideoUpload.getVideoParseRoute(props.url).then((newUrl) => {
setUrl(newUrl);
});
......@@ -30,7 +30,7 @@ const XMAudio = (props) => {
setLeftTime(Math.round(Number(size)));
setTotalTime(Math.round(Number(size)));
ref.current.addEventListener("pause", () => {
ref.current.addEventListener('pause', () => {
clearInterval(timer);
setPlaying(false);
setTimer(null);
......@@ -42,7 +42,6 @@ const XMAudio = (props) => {
}, [props.url]);
useEffect(() => {
if (playing) {
timerInterval = setInterval(() => {
setPlayedTime((preTime) => {
......@@ -53,18 +52,18 @@ const XMAudio = (props) => {
if ((prevTimeRef.current + 20) % 1000 === 0) {
setLeftTime(totalTime - (prevTimeRef.current + 20));
}
if ((prevTimeRef.current + 30) >= totalTime) {
if (prevTimeRef.current + 30 >= totalTime) {
clearInterval(timerInterval);
setPlayedTime(0);
setLeftTime(totalTime);
setPlaying(false);
}
}, 20);
const audioDomList = document.querySelectorAll("audio");
const audioDomList = document.querySelectorAll('audio');
for (let i = 0; i < Array.from(audioDomList).length; i++) {
if (audioDomList[i] === ref.current) {
ref.current.play();
setTimer(timerInterval)
setTimer(timerInterval);
} else {
audioDomList[i].pause();
}
......@@ -75,9 +74,7 @@ const XMAudio = (props) => {
}
}, [playing]);
const audioImg = `https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/${
playing ? 1584514990496 : 1584514999661
}.png`;
const audioImg = `https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/${playing ? 1584514990496 : 1584514999661}.png`;
function _togglePlay() {
playing ? pausePlay() : startPlay();
......@@ -112,78 +109,74 @@ const XMAudio = (props) => {
}
}
function _startTime() {
let time = Math.floor(playedTime / 1000);
let second = 0
let second = 0;
let minute = 0;
let result = 0
let result = 0;
if (time > 0) {
minute = Math.floor(time % 3600 / 60);
minute = Math.floor((time % 3600) / 60);
second = Math.floor((time - 60 * minute) % 60);
if (minute < 10) {
minute = "0" + minute;
minute = '0' + minute;
}
if (second < 10) {
second = "0" + second;
second = '0' + second;
}
result = minute + ':' + second
}else{
result = "00:00"
result = minute + ':' + second;
} else {
result = '00:00';
}
return result;
}
function _endTime() {
let time = Math.floor(totalTime / 1000);
let second = 0
let second = 0;
let minute = 0;
let result = 0
let result = 0;
if (time > 0) {
minute = Math.floor(time % 3600 / 60);
minute = Math.floor((time % 3600) / 60);
second = Math.floor((time - 60 * minute) % 60);
if (minute < 10) {
minute = "0" + minute;
minute = '0' + minute;
}
if (second < 10) {
second = "0" + second;
second = '0' + second;
}
result = minute + ':' + second
result = minute + ':' + second;
}
if(time === 0){
result = "00:00"
if (time === 0) {
result = '00:00';
}
return result;
}
function putDownFlag(event) {
let dragDiv = event.target;
dragDiv.style.cursor = "pointer";
dragDiv.style.cursor = 'pointer';
let offsetX = parseInt(dragDiv.style.left); // 获取当前的x轴距离
let innerX = event.clientX - offsetX; // 获取鼠标在方块内的x轴距
// 按住鼠标时为div修改样式
dragDiv.style.width = "16px";
dragDiv.style.height = "16px";
dragDiv.style.top = "-7px";
dragDiv.style.backGround = "linear-gradient(180deg, #FFB467 0%, #FF9143 100%)"
dragDiv.style.width = '16px';
dragDiv.style.height = '16px';
dragDiv.style.top = '-7px';
dragDiv.style.backGround = 'linear-gradient(180deg, #FFB467 0%, #FF9143 100%)';
// 鼠标移动的时候不停的修改div的left和top值
document.onmousemove = function (event) {
dragDiv.style.left = event.clientX - innerX + "px";
dragDiv.style.left = event.clientX - innerX + 'px';
// 边界判断
if (parseInt(dragDiv.style.left) <= 0) {
dragDiv.style.left = "0px";
dragDiv.style.left = '0px';
}
if (parseInt(dragDiv.style.left) >= 154) {
dragDiv.style.left = "149px";
dragDiv.style.left = '149px';
}
setPlayedTime(parseInt(dragDiv.style.left) / 150 * totalTime)
}
setPlayedTime((parseInt(dragDiv.style.left) / 150) * totalTime);
};
// 鼠标抬起时,清除绑定在文档上的mousemove和mouseup事件
// 否则鼠标抬起后还可以继续拖拽方块
document.onmouseup = function () {
......@@ -191,50 +184,43 @@ const XMAudio = (props) => {
document.onmouseup = null;
// 清除border
dragDiv.style.top = "-4px";
dragDiv.style.width = "10px";
dragDiv.style.height = "10px";
}
dragDiv.style.top = '-4px';
dragDiv.style.width = '10px';
dragDiv.style.height = '10px';
};
}
function mouseOver(event){
function mouseOver(event) {
let dragDiv = event.target;
dragDiv.style.cursor = "pointer";
dragDiv.style.width = "16px";
dragDiv.style.height = "16px";
dragDiv.style.top = "-7px";
dragDiv.style.backGround = "linear-gradient(180deg, #FFB467 0%, #FF9143 100%)"
dragDiv.style.cursor = 'pointer';
dragDiv.style.width = '16px';
dragDiv.style.height = '16px';
dragDiv.style.top = '-7px';
dragDiv.style.backGround = 'linear-gradient(180deg, #FFB467 0%, #FF9143 100%)';
}
function mouseLeave (event){
function mouseLeave(event) {
let dragDiv = event.target;
dragDiv.style.top = "-4px";
dragDiv.style.width = "10px";
dragDiv.style.height = "10px";
dragDiv.style.top = '-4px';
dragDiv.style.width = '10px';
dragDiv.style.height = '10px';
ref.current.currentTime = playedTime / 1000;
}
return (
<div className="xm-audio" style={style}>
<img src={audioImg} onClick={_togglePlay} className="audio-image" />
<div className="process-area">
<div
className="complete-area"
style={{ width: `${(playedTime / totalTime) * 150}px ` }}
/>
<div className='xm-audio' style={style}>
<img src={audioImg} onClick={_togglePlay} className='audio-image' />
<div className='process-area'>
<div className='complete-area' style={{ width: `${(playedTime / totalTime) * 150}px ` }} />
<div
className="flag"
className='flag'
style={{ left: `${(playedTime / totalTime) * 150}px ` }}
onMouseDown={(e) => putDownFlag(e)}
onMouseOver={(e)=> mouseOver(e)}
onMouseLeave={(e)=>mouseLeave(e)}
onMouseOver={(e) => mouseOver(e)}
onMouseLeave={(e) => mouseLeave(e)}
/>
</div>
<span className="sec-time">
{`${_startTime()}`}/{`${_endTime()}`}
</span>
<audio
src={url}
ref={ref}
autoPlay={false}
onCanPlayThrough={_getDuration}
/>
<span className='sec-time'>
{`${_startTime()}`}/{`${_endTime()}`}
</span>
<audio src={url} ref={ref} autoPlay={false} onCanPlayThrough={_getDuration} />
</div>
);
};
......
......@@ -5,10 +5,11 @@
* @Last Modified time: 2020-03-24 10:18:43
*/
.xm-audio {
.xm-audio {
display: flex;
align-items: center;
width: 280px;
padding: 10px 20px;
border-radius: 5px;
background-color: #ffffff;
.audio-image {
......@@ -24,11 +25,11 @@
cursor: pointer;
}
.play-icon {
color: #FC8540;
color: #fc8540;
}
.sec-time{
.sec-time {
white-space: nowrap;
color: #FF8534;
color: #ff8534;
margin-left: 12px;
font-size: 13px;
}
......@@ -38,11 +39,11 @@
border-radius: 3px;
margin-left: 12px;
position: relative;
background:rgba(255,133,52,0.2);
background: rgba(255, 133, 52, 0.2);
.complete-area {
height: 100%;
background-color: #FF8534;
background-color: #ff8534;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
......@@ -52,7 +53,7 @@
width: 10px;
height: 10px;
border-radius: 50%;
background:linear-gradient(180deg,rgba(255,180,103,1) 0%,rgba(255,145,67,1) 100%);
background: linear-gradient(180deg, rgba(255, 180, 103, 1) 0%, rgba(255, 145, 67, 1) 100%);
}
}
}
/*
* @Author: yuananting
* @Date: 2021-04-07 16:10:21
* @LastEditors: wufan
* @LastEditTime: 2021-04-26 10:21:19
* @Description: 助学工具-考试-考试结果
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { useState, useEffect } from 'react';
import { withRouter } from 'react-router-dom';
import User from '@/common/js/user';
import './TestDetailPage.less';
import Service from '@/common/js/service';
import { message } from 'antd';
import AnswerDescPage from '../components/AnswerDescPage';
import Breadcrumbs from '@/components/Breadcrumbs';
function TestDetailPage(props) {
const examId = props.match.params.testId.replace(/\?.+/, '');
const paperId = window.getParameterByName('paperId');
const userId = window.getParameterByName('userId');
const [examDetail, setExamDetail] = useState({
answerAnalysis: '',
resultShow: '',
examDesc: '',
examDuration: 0,
examEndTime: '',
examName: '',
examStartTime: '',
paperId: 0,
passRate: 0,
passScore: 0,
resultContent: '',
totalQuestionCount: 0,
totalScore: 0,
userCorrectQuestion: 0,
userExamDuration: 0,
userScore: 0,
}); // 考试详情
const [paperDetail, setPaperDetail] = useState({}); // 试卷详情
const [questionList, setQuestionList] = useState([]); // 试卷题目列表
const [userAnswerList, setUserAnswerList] = useState([]); // 用户答案列表
const [isScrollShow, setIsScrollShow] = useState(false); // 是否展示回到顶部按钮
const { answerAnalysis, resultContent, examName, totalScore, totalQuestionCount, passScore, examDuration, userExamDuration, userScore, userCorrectQuestion } =
examDetail;
useEffect(() => {
bindScroll();
getPaperDetail();
getExamDetail();
}, []);
function bindScroll() {
window.addEventListener('scroll', handleScroll, true);
}
function getExamDetail() {
const params = {
examId,
source: 0,
tenantId: User.getStoreId() || window.getParameterByName('id'),
userId,
};
Service.Hades('public/customerHades/queryUserExamResult', params, {
reject: true,
})
.then((res) => {
const data = { ...res.result };
setExamDetail(data);
})
.catch((res) => {
if (res.code === 'EXAM_IS_NOT_EXIST') {
handleChangeShowErrorPage();
} else {
message.error(res.message);
}
});
}
function getPaperDetail() {
Service.Hades('public/customerHades/queryUserExamAnswer', {
examId,
paperId,
source: 0,
readAnswer: true,
tenantId: User.getStoreId() || window.getParameterByName('id'),
userId,
}).then((res) => {
if (res.success) {
const { paperDetailVO, userExamAnswerVO } = res.result;
const userAnswerList = [...userExamAnswerVO];
const { questionList } = paperDetailVO;
setPaperDetail(paperDetail);
setUserAnswerList(userAnswerList);
setQuestionList(questionList || []);
}
});
}
function handleChangeShowErrorPage() {
setIsShowErrorPage(true);
}
// 用户时长转换
function formatTime(msTime) {
let time = msTime / 1000;
let hour = Math.floor(time / 60 / 60) % 24 > 9 ? Math.floor(time / 60 / 60) % 24 : '0' + (Math.floor(time / 60 / 60) % 24);
let minute = Math.floor(time / 60) % 60 > 9 ? Math.floor(time / 60) % 60 : '0' + (Math.floor(time / 60) % 60);
let second = time % 60 > 9 ? Math.round(time % 60) : '0' + Math.round(time % 60);
return `${hour}:${minute}:${second}`;
}
// 快速跳转题目
function handleQuickActiveQuestion(questionId) {
let selectDom = document.getElementById(`${questionId}`);
selectDom.scrollIntoView({
block: 'center',
});
}
// 回到顶部
function handleGoTop() {
window.scrollTo(0, 0);
}
// 监听滚动,200以后出现回到顶部按钮
function handleScroll() {
if (window.pageYOffset > 200) {
setIsScrollShow(true);
} else {
setIsScrollShow(false);
}
}
function renderResultInfo() {
return (
<div>
<div className='exam-info'>
<div className='info-score item'>
<div className='current-score'>
{userScore}
<img src='https://image.xiaomaiketang.com/xm/TsaApiPyxA.png' />
</div>
<div className='origin-data'>总分{totalScore}</div>
</div>
<div className='info-level item'>
<div className='current-level'>{userScore < passScore ? '不及格' : '及格'}</div>
<div className='origin-data'>及格分{passScore}</div>
</div>
<div className='info-correct item'>
<div className='current-correct'>
{userCorrectQuestion}
<div className='text'>答对题数</div>
</div>
<div className='origin-data'>{totalQuestionCount}</div>
</div>
<div className='info-time item'>
<div className='current-time'>
{formatTime(Number(userExamDuration > examDuration ? examDuration : userExamDuration || 0))}
<div className='text'>用时</div>
</div>
<div className='origin-data'>考试时长{(examDuration || 0) / 60 / 1000}分钟</div>
</div>
</div>
<div className='exam-result'>
<div className='result-title'>
<div className='left-title'>答题情况</div>
<div className='right-tip'>
<span className='correct-num'>{userCorrectQuestion}</span>
<span className='incorrect-num'>/{totalQuestionCount} </span>
道正确
</div>
</div>
<div className='result-content'>
{sortedAnswerList.map((item, index) => {
return (
<div
className='result-content__item'
onClick={() => {
console.log('item', item);
handleQuickActiveQuestion(item.questionId);
}}>
<img
className='icon'
src={item.isCorrect === 1 ? 'https://image.xiaomaiketang.com/xm/FwZa2Kaypc.png' : 'https://image.xiaomaiketang.com/xm/7tRHDf6ysA.png'}
/>
<div className='result-content-box'>{index + 1}</div>
</div>
);
})}
</div>
</div>
<AnswerDescPage userId={userId} />
</div>
);
}
let sortedAnswerList = [];
questionList.map((item) => {
userAnswerList &&
userAnswerList.map((answerItem) => {
if (item.questionId === answerItem.questionId) {
sortedAnswerList.push(answerItem);
}
});
});
return (
<div className='exam-result-page page'>
<Breadcrumbs navList={'答题详情'} goBack={props.history.goBack} />
<div className='center'>
<div className='box'>
<div className='box-content'>
<div
className='exam-head'
style={{
padding: examName.length > 20 ? '8px 0 14px' : '16px 0 29px',
}}>
<div className={`exam-name ${examName.length > 20 ? 'many' : 'few'}`}>{examName}</div>
</div>
{renderResultInfo()}
</div>
</div>
</div>
{isScrollShow && <div className='go-top' onClick={handleGoTop}></div>}
</div>
);
}
export default withRouter(TestDetailPage);
.exam-result-page {
margin: 0 auto;
.go-top {
cursor: pointer;
position: fixed;
width: 48px;
height: 48px;
background-image: url('https://image.xiaomaiketang.com/xm/jWix2xDm4t.png');
background-size: 100%;
box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.08);
border-radius: 4px;
bottom: 125px;
right: calc(~'(100vw - 1232px)/2');
display: flex;
justify-content: center;
align-items: center;
&:hover {
background-image: url('https://image.xiaomaiketang.com/xm/GHBBNDtTDd.png');
}
}
.box {
.box-content {
position: relative;
width: 840px;
margin: 0 auto;
.exam-head {
color: #333;
text-align: center;
.exam-name {
width: 600px;
font-weight: 500;
margin: 0 auto;
font-size: 24px;
line-height: 33px;
}
.many {
font-size: 21px;
line-height: 29px;
}
.few {
font-size: 25px;
line-height: 36px;
}
}
.empty-result {
box-sizing: border-box;
margin: 0 16px;
background: #ffffff;
box-shadow: 0 -15px 10px 0 rgba(0, 34, 121, 0.1);
border-radius: 4px 4px 0 0;
padding-top: 56px;
.lack-desc {
margin-top: 16px;
.title {
font-size: 17px;
font-weight: 500;
color: #333333;
line-height: 24px;
margin-bottom: 4px;
}
.content {
font-size: 15px;
color: #999999;
line-height: 21px;
}
}
.after-desc {
margin-top: 16px;
.title {
font-size: 17px;
font-weight: 500;
color: #333333;
line-height: 24px;
margin-bottom: 20px;
}
.after-show-box {
// margin: 0 37px;
padding: 11px 21px;
background: #f4f6fa;
border-radius: 4px;
font-size: 15px;
color: #999999;
line-height: 21px;
text-align: center;
}
}
}
.exam-info {
width: 840px;
box-sizing: border-box;
margin: 0 auto;
padding: 24px 0 12px;
height: 130px;
background: #ffffff;
box-shadow: 0px 5px 30px 0px rgba(12, 54, 158, 0.08);
border-radius: 4px;
display: flex;
justify-content: center;
.item {
flex: 1 25%;
display: flex;
flex-direction: column;
// height: 130px;
align-items: center;
justify-content: space-between;
position: relative;
.origin-data {
text-align: center;
font-size: 14px;
color: #999999;
line-height: 20px;
}
.line {
&::before {
width: 1px;
height: 40px;
content: '';
position: absolute;
right: 0;
top: 0;
background-color: rgba(232, 232, 232, 1);
}
}
&.info-score {
.current-score {
font-size: 40px;
font-weight: 500;
color: #ff4f4f;
text-align: center;
line-height: 42px;
img {
display: block;
margin: 0 auto;
width: 27px;
height: 12px;
padding-left: 4px;
}
}
}
&.info-level {
.current-level {
font-size: 24px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 33px;
text-align: center;
}
}
&.info-correct {
.current-correct {
display: flex;
flex-direction: column;
padding-bottom: 20px;
justify-content: space-between;
align-items: center;
font-size: 20px;
font-weight: 500;
color: #333333;
line-height: 28px;
.text {
margin-top: 4px;
width: 48px;
height: 17px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9b9b9b;
line-height: 17px;
text-align: center;
}
}
}
&.info-time {
.current-time {
display: flex;
flex-direction: column;
padding-bottom: 20px;
justify-content: space-between;
align-items: center;
font-size: 20px;
font-weight: 500;
color: #333333;
line-height: 28px;
}
.text {
margin-top: 4px;
width: 48px;
height: 17px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9b9b9b;
line-height: 17px;
text-align: center;
}
}
}
}
.left-title {
font-size: 20px;
font-weight: 500;
color: #333333;
position: relative;
margin-left: 8px;
line-height: 28px;
&::before {
position: absolute;
content: '';
left: -8px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
background-image: linear-gradient(#2966ff 83.5%, #0acca4 16.5%);
}
}
.exam-result {
padding: 44px 0 24px 0;
vertical-align: middle;
.result-title {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
line-height: 24px;
.right-tip {
font-size: 15px;
font-weight: 500;
color: #999999;
.correct-num {
color: #16e0b7;
}
.incorrect-num {
font-size: 11px;
}
}
}
.result-content {
display: flex;
flex-wrap: wrap;
&__item {
position: relative;
margin: 0 16px 16px 0;
width: 36px;
height: 36px;
background: #f4f6fa;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&:nth-child(5n) {
margin-right: 50px;
}
&:nth-child(15n) {
margin-right: 0px;
}
.icon {
width: 16px;
height: 16px;
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%, -50%);
}
.result-content-box {
width: 36px;
height: 36px;
font-size: 15px;
line-height: 36px;
background: #f4f6fa;
border-radius: 4px;
text-align: center;
}
}
}
}
}
}
.footer-btn {
width: 100%;
position: fixed;
bottom: 0;
left: 0;
height: 64px;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
border-top: 1px solid rgba(238, 238, 238, 1);
box-sizing: border-box;
.text {
cursor: pointer;
background: #ffb714;
border-radius: 5px;
width: 342px;
font-size: 15px;
color: #ffffff;
line-height: 44px;
text-align: center;
&.disabled {
background-color: #ccc;
}
}
}
}
.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;
&::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;
}
.dataAnalysic {
.titleBox {
position: relative;
font-size: 19px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 26px;
background: #ffffff;
&::before {
width: 4px;
height: 12px;
content: '';
background-image: linear-gradient(#2966ff 83.5%, #0acca4 16.5%);
display: inline-block;
margin-right: 8px;
}
.ant-tabs-content-holder {
margin-top: 8px;
}
}
\ No newline at end of file
}
.ant-tabs-content-holder {
margin-top: 8px;
}
}
.examination-manager{
.status{
display: inline-block;
margin-left: 4px;
border: 1px solid #999;
padding: 2px 4px;
line-height: 16px;
}
.ant-table-column-sorters {
justify-content: flex-end;
}
.examination-manager {
.status {
display: inline-block;
margin-left: 4px;
border: 1px solid #999;
padding: 2px 4px;
line-height: 16px;
}
.ant-table-column-sorter {
margin-top: 0px !important;
.ant-table-column-sorter {
margin-top: 0px !important;
}
.ant-table tbody tr {
&:nth-child(even) {
background: #fff;
}
.ant-table tbody tr {
&:nth-child(even) {
background: #fff;
}
&:nth-child(odd) {
background: #fafafa;
}
&:nth-child(odd) {
background: #fafafa;
}
}
\ No newline at end of file
}
}
.dataPanal{
border-radius: 4px;
border: 1px solid #E8E8E8;
display: flex;
.item{
text-align: center;
// width: 29.9%;
.dataPanal {
border-radius: 4px;
border: 1px solid #e8e8e8;
display: flex;
.item {
text-align: center;
// width: 29.9%;
position: relative;
flex: 1;
.num {
font-size: 26px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 26px;
margin-top: 12px;
}
.percent {
margin-top: 6px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 17px;
height: 20px;
margin-bottom: 18px;
}
.subTitle {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
margin-bottom: 12px;
}
.type {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
span {
color: rgba(153, 153, 153, 1);
}
.icon {
color: rgba(204, 204, 204, 1);
font-size: 16px;
margin-right: 4px;
position: relative;
flex: 1;
.num{
font-size: 26px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 26px;
margin-top: 12px;
}
.percent{
margin-top: 6px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 17px;
height: 20px;
margin-bottom: 18px;
}
.subTitle{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
margin-bottom: 12px;
}
.type{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
span{
color: rgba(153, 153, 153, 1);
}
.icon{
color: rgba(204, 204, 204, 1);
font-size: 16px;
margin-right: 4px;
position: relative;
top: 1px;
}
}
&:after{
content: '';
width: 0px;
height: 40px;
position: absolute;
width: 1px;
background-color: rgba(232, 232, 232, 1);
top: 40px;
right: 0px;
}
top: 1px;
}
}
&:last-child{
&:after{
display: none;
}
}
&:after {
content: '';
width: 0px;
height: 40px;
position: absolute;
width: 1px;
background-color: rgba(232, 232, 232, 1);
top: 40px;
right: 0px;
}
&:last-child {
&:after {
display: none;
}
}
.exstatus{
width: 4px;
height: 4px;
background: rgb(35, 143, 255);
display: inline-block;
border-radius: 50%;
position: relative;
top: -4px;
}
.exstatus {
width: 4px;
height: 4px;
background: rgb(35, 143, 255);
display: inline-block;
border-radius: 50%;
position: relative;
top: -4px;
}
}
.answer-detail {
color: rgb(35, 143, 255);
}
.analysic-content {
.ant-table-bordered .ant-table-tbody tr {
&.analysic-content-row {
height: 50px;
}
}
\ No newline at end of file
}
}
......@@ -88,4 +88,23 @@
.ant-dropdown-menu-item-selected > span {
color: #333333;
}
\ No newline at end of file
}
.type-order-modal {
.type-order-table {
tr {
background: #F7F8F9 !important;
display: flex;
margin-bottom: 8px;
width: 521px;
justify-content: space-between;
td {
border: none !important;
}
}
.ant-table-tbody > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td {
background: #F7F8F9 !important;
}
}
}
......@@ -19,7 +19,6 @@ import {
ConfigProvider,
Empty,
} from "antd";
import Lottie from 'react-lottie';
import { PageControl, XMTable } from "@/components";
import "./PaperList.less";
import { Route, withRouter } from "react-router-dom";
......@@ -31,7 +30,6 @@ 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;
......@@ -547,14 +545,6 @@ 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">
......@@ -635,15 +625,6 @@ class PaperList extends Component {
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>
}}
/>
......@@ -660,16 +641,7 @@ class PaperList extends Component {
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>
description: <span style={{ display: 'block', paddingBottom: 24 }}>还没有试卷</span>
}}
/>
)}
......
......@@ -8,6 +8,7 @@
*/
import React, { Component } from "react";
import { Modal, ConfigProvider, Empty } from "antd";
import Lottie from 'react-lottie';
import User from "@/common/js/user";
import AidToolService from "@/domains/aid-tool-domain/AidToolService";
import "./PreviewPaperModal.less";
......@@ -15,6 +16,7 @@ import ScanFileModal from "@/modules/resource-disk/modal/ScanFileModal";
import _ from "underscore";
import XMAudio from "../../components/XMAudio";
import { NUM_TO_WORD_MAP } from "@/common/constants/punchClock/punchClock";
import previewEmpty from '../../../lottie/previewEmpty/data.json';
const questionTypeList = {
SINGLE_CHOICE: "单选题",
MULTI_CHOICE: "多选题",
......@@ -254,13 +256,28 @@ class PreviewPaperModal extends Component {
// 自定义空状态
customizeRenderEmpty = () => {
const defaultOptions = {
loop: true,
autoplay: true,
animationData: previewEmpty,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
}
}
return (
<Empty
image="https://image.xiaomaiketang.com/xm/emptyTable.png"
imageStyle={{
height: 100,
}}
description={"暂无内容"}
image={
<div style={{ marginTop: 24 }}>
<Lottie
options={defaultOptions}
height={150}
width={150}
isStopped={false}
isPaused={false}
/>
</div>
}
description={<span style={{ display: 'block', paddingBottom: 24, marginTop: 50 }}>暂无内容</span>}
></Empty>
);
};
......
......@@ -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-09 12:00:12
* @Description: 助学工具-题库-操作题目Tab
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -66,23 +66,25 @@ class OperateQuestionTab extends Component {
}
componentDidMount() {
const { chooseOptions } = this.state;
const { questionTypeKey } = this.props;
const isEditCurrent =
getParameterByName("id") &&
getParameterByName("type") === questionTypeKey;
const optionSize = isEditCurrent ? 20 : 4;
if (
["INDEFINITE_CHOICE", "MULTI_CHOICE", "SINGLE_CHOICE"].includes(
this.props.questionTypeKey
questionTypeKey
)
) {
if (chooseOptions.length === 0) {
// 选择题(单选 多选 不定项)-插入4条默认选项
for (var i = 0; i < 4; i++) {
this.handleAddOption();
this.setState({
[`optionsValidate_${i}`]: "success",
[`optionsText_${i}`]: "",
});
}
// 选择题(单选 多选 不定项)-插入4条默认选项
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("错误");
}
......@@ -634,9 +636,9 @@ class OperateQuestionTab extends Component {
this.state.stemContent,
(contentItem) => contentItem.type === "RICH_TEXT"
);
if(stemContent.textLength > 1000) {
if (stemContent.textLength > 1000) {
validateError++;
}
}
let stem = stemContent.content.replace(/<[^>]+>/g, "");
stem = stem.replace(/\&nbsp\;/gi, "");
stem = stem.replace(/\s+/g, "");
......@@ -694,7 +696,7 @@ class OperateQuestionTab extends Component {
optionUnChecked = item.isCorrectAnswer
? optionUnChecked
: optionUnChecked + 1;
if(optionContent[0].textLength > 1000) {
if (optionContent[0].textLength > 1000) {
validateError++;
}
let optionInput = optionContent[0].content.replace(/<[^>]+>/g, "");
......@@ -1040,11 +1042,11 @@ class OperateQuestionTab extends Component {
return dom ? (
<div
className="question-item_question-content"
style={{
display: ["PICTURE", "VIDEO"].includes(type)
? "inline-grid"
: "flex",
}}
style={
!["PICTURE", "VIDEO"].includes(type)
? { display: "flex" }
: { float: "left" }
}
key={index}
>
{dom}
......@@ -1194,10 +1196,8 @@ class OperateQuestionTab extends Component {
data-label="正确答案"
>
{_.map(chooseOptions, (optionItem, optionIndex) => {
const {
questionOptionContentList,
isCorrectAnswer,
} = optionItem;
const { questionOptionContentList, isCorrectAnswer } =
optionItem;
optionItem.optionSort = optionIndex;
const mediaBtn = ["VOICE", "AUDIO", "PICTURE"];
const placeHold =
......
......@@ -2,7 +2,7 @@
border-radius: 2px;
padding: 16px;
position: relative;
margin-bottom: 35px;
margin-bottom: 70px;
.editor-fill-box_single {
border-radius: 4px;
......@@ -24,7 +24,7 @@
color: #999999;
margin-top: 8px;
.fill-info_icon {
color: #2966FF;
color: #2966ff;
font-size: 14px;
padding-left: 9px;
cursor: pointer;
......@@ -72,7 +72,6 @@
}
.audio-box {
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
}
.img-box {
max-width: 88px;
......@@ -229,7 +228,7 @@
line-height: 33px;
align-self: stretch;
.option-operate_item__icon:hover {
color: #2966FF;
color: #2966ff;
}
.icon {
color: #bfbfbf;
......@@ -252,7 +251,7 @@
border-radius: 4px;
border: 1px dashed #e8e8e8;
font-size: 14px;
color: #2966FF;
color: #2966ff;
line-height: 44px;
text-align: center;
cursor: pointer;
......
......@@ -32,7 +32,7 @@
color: #666666;
.input-box {
margin-bottom: 8px;
display: inline-block;
// display: inline-block;
*:not(p) {
font-weight: normal !important;
font-size: 14px !important;
......
......@@ -14,13 +14,13 @@ import UserManage from '@/modules/college-manage/UserManagePage';
import StoreDecorationPage from '@/modules/store-manage/StoreDecorationPage';
import CourseCatalogPage from '@/modules/store-manage/CourseCatalogPage';
import LiveCoursePage from '@/modules/course-manage/LiveCoursePage';
import AddLivePage from '@/modules/course-manage/AddLive'
import VideoCoursePage from '@/modules/course-manage/video-course'
import GraphicsCoursePage from '@/modules/course-manage/graphics-course'
import OfflineCoursePage from '@/modules/course-manage/offline-course'
import AddVideoCoursePage from '@/modules/course-manage/video-course/AddVideoCourse'
import AddGraphicsCoursePage from '@/modules/course-manage/graphics-course/AddGraphicsCourse'
import AddOfflineCoursePage from '@/modules/course-manage/offline-course/AddOfflineCourse'
import AddLivePage from '@/modules/course-manage/AddLive';
import VideoCoursePage from '@/modules/course-manage/video-course';
import GraphicsCoursePage from '@/modules/course-manage/graphics-course';
import OfflineCoursePage from '@/modules/course-manage/offline-course';
import AddVideoCoursePage from '@/modules/course-manage/video-course/AddVideoCourse';
import AddGraphicsCoursePage from '@/modules/course-manage/graphics-course/AddGraphicsCourse';
import AddOfflineCoursePage from '@/modules/course-manage/offline-course/AddOfflineCourse';
// import DataList from '@/modules/course-manage/DataList/DataList';
// import ClassBook from '@/modules/resource-disk';
import ResourceDisk from '@/modules/resource-disk';
......@@ -33,145 +33,152 @@ import CourseCategoryManage from '@/modules/teach-tool/components/CourseCategory
import QuestionManageIndex from '@/modules/teach-tool/question-manage/Index';
import PaperManageIndex from '@/modules/teach-tool/paper-manage/Index';
import ExaminationManagerIndex from '@/modules/teach-tool/examination-manager/Index';
import KnowledgeBase from "@/modules/knowledge-base/index";
import ExaminationManagerTestDetail from '@/modules/teach-tool/examination-manager/TestDetailPage';
import KnowledgeBase from '@/modules/knowledge-base/index';
import CollegeInfoPage from '@/modules/college-manage/CollegeInfoPage';
const mainRoutes = [
{
path: "/home",
path: '/home',
component: Home,
name: "中心首页",
name: '中心首页',
},
{
path: "/employees-manage",
path: '/employees-manage',
component: EmployeesManagePage,
name: "员工管理",
name: '员工管理',
},
{
path: '/college-employee',
component: EmployeeManage,
name: '员工管理'
component: EmployeeManage,
name: '员工管理',
},
{
path: '/personal-info',
component: personalInfoPage,
name: '个人信息'
component: personalInfoPage,
name: '个人信息',
},
{
path: "/user-manage",
path: '/user-manage',
component: UserManagePage,
name: "学员管理",
name: '学员管理',
},
{
path: '/college-user',
component: UserManage,
name: '学员管理'
component: UserManage,
name: '学员管理',
},
{
path: '/store-decoration',
component: StoreDecorationPage,
name: '学院装修'
component: StoreDecorationPage,
name: '学院装修',
},
{
path: "/live-course",
path: '/live-course',
component: LiveCoursePage,
name: "直播课",
name: '直播课',
},
{
path: "/video-course",
path: '/video-course',
component: VideoCoursePage,
name: "视频课",
name: '视频课',
},
{
path: "/graphics-course",
path: '/graphics-course',
component: GraphicsCoursePage,
name: "图文课",
name: '图文课',
},
{
path: "/offline-course",
path: '/offline-course',
component: OfflineCoursePage,
name: "线下课",
name: '线下课',
},
{
path: "/create-live-course",
path: '/create-live-course',
component: AddLivePage,
name: "创建直播课",
name: '创建直播课',
},
{
path: "/create-video-course",
path: '/create-video-course',
component: AddVideoCoursePage,
name: "创建视频课",
name: '创建视频课',
},
{
path: "/knowledge-base",
path: '/knowledge-base',
// component:ResourceDisk,
component: KnowledgeBase,
name: "知识库",
name: '知识库',
},
{
path: "/create-graphics-course",
path: '/create-graphics-course',
component: AddGraphicsCoursePage,
name: "创建图文课",
name: '创建图文课',
},
{
path: "/create-offline-course",
path: '/create-offline-course',
component: AddOfflineCoursePage,
name: "创建线下课",
name: '创建线下课',
},
{
path: "/resource-disk",
path: '/resource-disk',
component: ResourceDisk,
name: "资料云盘",
name: '资料云盘',
},
{
path: '/question-manage-index',
component:QuestionManageIndex,
name: '题库'
component: QuestionManageIndex,
name: '题库',
},
{
path: '/paper-manage-index',
component:PaperManageIndex,
name: '试卷'
component: PaperManageIndex,
name: '试卷',
},
{
path: '/examination-manage-index',
component:ExaminationManagerIndex,
name: '考试'
component: ExaminationManagerIndex,
name: '考试',
},
{
path: '/test-detail/:testId',
component: ExaminationManagerTestDetail,
// () => import('@/modules/teach-tool/examination-manager/TestDetailPage'),
name: '答题详情',
},
{
path: '/course-category-manage',
component:CourseCategoryManage,
name: '分类管理'
component: CourseCategoryManage,
name: '分类管理',
},
{
path: "/switch-route",
path: '/switch-route',
component: SwitchRoute,
name: "登录后跳转承载页",
name: '登录后跳转承载页',
},
{
path: "/plan",
path: '/plan',
component: PlanPage,
name: "培训计划",
name: '培训计划',
},
{
path: "/create-plan",
path: '/create-plan',
component: AddPlanPage,
name: "创建视频课",
name: '创建视频课',
},
{
path: '/store-info',
component:StoreInfoPage,
name: '学院信息'
component: StoreInfoPage,
name: '学院信息',
},
{
path: '/college-info',
component: CollegeInfoPage,
name: '学院信息'
component: CollegeInfoPage,
name: '学院信息',
},
{
path: "/learning-data",
path: '/learning-data',
component: LearningDataPage,
name: "学习数据",
name: '学习数据',
},
];
......
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