Commit 9f343476 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 04a98954 3f74ea5d
@font-face {
font-family: 'iconfont'; /* Project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_2digpsfgq8l.woff2?t=1628853864698') format('woff2'),
url('//at.alicdn.com/t/font_2223403_2digpsfgq8l.woff?t=1628853864698') format('woff'),
url('//at.alicdn.com/t/font_2223403_2digpsfgq8l.ttf?t=1628853864698') format('truetype');
font-family: 'iconfont'; /* Project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_0b87tvtysw45.woff2?t=1629025918841') format('woff2'),
url('//at.alicdn.com/t/font_2223403_0b87tvtysw45.woff?t=1629025918841') format('woff'),
url('//at.alicdn.com/t/font_2223403_0b87tvtysw45.ttf?t=1629025918841') format('truetype');
}
.iconfont {
font-family: 'iconfont' !important;
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-08-06 17:35:35
* @LastEditors: yuananting
* @LastEditTime: 2021-08-14 09:51:12
* @LastEditTime: 2021-08-16 20:52:16
* @Description: 任务中心接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -52,3 +52,15 @@ export function updateTrainingTaskAssign(params: object) {
export function getTrainingCourseAutoCancel(params: object) {
return Service.Hades('public/hades/getTrainingCourseAutoCancel', params);
}
export function delTaskCancelContent(params: object) {
return Service.Hades('public/hades/delTaskCancelContent', params);
}
export function getStoreTaskAll(params: object) {
return Service.Hades('public/hades/getStoreTaskAll', params);
}
export function relatedCourseToTask(params: object) {
return Service.Hades('public/hades/relatedCourseToTask', params);
}
/*
* @Author: 陈剑宇
* @Date: 2020-05-07 14:43:01
* @LastEditTime: 2021-08-09 15:52:49
* @LastEditors: wufan
* @LastEditTime: 2021-08-16 16:39:13
* @LastEditors: yuananting
* @Description:
* @FilePath: /wheat-web-demo/src/domains/basic-domain/constants.ts
*/
import { MapInterface } from '@/domains/basic-domain/interface'
import { path, live } from '@/domains/brand/constants'
import { MapInterface } from '@/domains/basic-domain/interface';
import { path, live } from '@/domains/brand/constants';
// 默认是 dev 环境
const ENV: string = process.env.DEPLOY_ENV || 'dev'
console.log('process.env.DEPLOY_ENV', process.env, ENV, 'hjkkkk')
const ENV: string = process.env.DEPLOY_ENV || 'dev';
console.log('process.env.DEPLOY_ENV', process.env, ENV, 'hjkkkk');
console.log('process.env.DEPLOY_ENV', process);
const BASIC_HOST_MAP: MapInterface = {
dev: 'https://dev-heimdall.xiaomai5.com/',
dev1: 'https://dev-heimdall.xiaomai5.com/',
rc: 'https://rc-heimdall.xiaomai5.com/',
gray: 'https://gray-heimdall.xiaomai5.com/',
prod: 'https://gateway.xiaomai5.com/',
}
};
const PATH_MAP: MapInterface = {
dev: 'https://dev.xiaomai5.com/xiaomai-cloud-class-web/h5.html',
dev1: 'https://dev.xiaomai5.com/dev1/xiaomai-cloud-class-web/h5.html',
rc: 'https://rc.xiaomai5.com/xiaomai-cloud-class-web/h5.html',
gray: path + '/gray/h5.html',
prod: path + '/h5.html',
}
};
export const YZ_APPId = "yozoqvpO2Hvz8346";
export const YZ_PREVIEW_URL: string = 'http://eic.yozocloud.cn/api/view/file'
export const OFFICE_PREVIEW_URL: string = 'https://view.officeapps.live.com/op/view.aspx'
export const YZ_APPId = 'yozoqvpO2Hvz8346';
export const YZ_PREVIEW_URL: string = 'http://eic.yozocloud.cn/api/view/file';
export const OFFICE_PREVIEW_URL: string = 'https://view.officeapps.live.com/op/view.aspx';
// axios headers config
export const TIME_OUT: number = 20000
export const USER_TYPE: string = 'B'
export const PROJECT = 'xmzj-web-b'
export const VERSION = '5.4.8'
export const PREFIX = 'cloud-class'
export const USER_PREFIX = 'store-live'
export const TIME_OUT: number = 20000;
export const USER_TYPE: string = 'B';
export const PROJECT = 'xmzj-web-b';
export const VERSION = '5.4.8';
export const PREFIX = 'cloud-class';
export const USER_PREFIX = 'store-live';
// host
export const BASIC_HOST: string = BASIC_HOST_MAP[ENV]
export const PATH: string = PATH_MAP[ENV]
export const BASIC_HOST: string = BASIC_HOST_MAP[ENV];
export const PATH: string = PATH_MAP[ENV];
/*
* @Author: 吴文洁
* @Date: 2020-08-20 09:21:40
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-08-11 22:50:48
* @Description:
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 16:38:55
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import { MapInterface } from '@/domains/basic-domain/interface'
import { path, live } from '@/domains/brand/constants'
import { MapInterface } from '@/domains/basic-domain/interface';
import { path, live } from '@/domains/brand/constants';
const ENV: string = process.env.DEPLOY_ENV || 'dev';
const appIdMap: MapInterface = {
dev: 'wx3ea60e78ddfa277e',
dev1: 'wx3ea60e78ddfa277e',
rc: 'wx5c5a1fb71ecab7bc',
gray: "wx3dda02036493ada6", // 小麦校讯通
gray: 'wx3dda02036493ada6', // 小麦校讯通
prod: 'wx3dda02036493ada6',
}
};
const shareUrlMap: MapInterface = {
'dev': 'https://dev.xiaomai5.com/share/show?appid=',
'dev1': 'https://dev.xiaomai5.com/share/show?appid=',
'rc': 'https://rc.xiaomai5.com/share/show?appid=',
'prod': 'https://prod.xiaomai5.com/share/show?appid=',
'gray': 'https://prod.xiaomai5.com/share/show?appid=',
}
dev: 'https://dev.xiaomai5.com/share/show?appid=',
dev1: 'https://dev.xiaomai5.com/share/show?appid=',
rc: 'https://rc.xiaomai5.com/share/show?appid=',
prod: 'https://prod.xiaomai5.com/share/show?appid=',
gray: 'https://prod.xiaomai5.com/share/show?appid=',
};
const LIVE_SHARE_MAP: MapInterface = {
dev: 'https://dev.xiaomai5.com/store-live/index.html#/',
dev1: 'https://dev.xiaomai5.com/dev1/store-live/index.html#/',
rc: 'https://rc.xiaomai5.com/store-live/index.html#/',
gray: live+'/gray/index.html#/',
prod: live+'/index.html#/',
}
gray: live + '/gray/index.html#/',
prod: live + '/index.html#/',
};
export const appId: string = appIdMap[ENV];
export const shareUrl: string = shareUrlMap[ENV];
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-08-06 17:32:41
* @LastEditors: yuananting
* @LastEditTime: 2021-08-14 09:52:00
* @LastEditTime: 2021-08-16 20:56:36
* @Description: 任务中心-培训任务接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -19,6 +19,9 @@ import {
getTaskCustomerDetail,
updateTrainingTaskAssign,
getTrainingCourseAutoCancel,
delTaskCancelContent,
getStoreTaskAll,
relatedCourseToTask,
} from '@/data-source/taskCenter/request-apis';
export default class TaskCenterService {
......@@ -76,4 +79,19 @@ export default class TaskCenterService {
static getTrainingCourseAutoCancel(params: any) {
return getTrainingCourseAutoCancel(params);
}
// 删除失效课程
static delTaskCancelContent(params: any) {
return delTaskCancelContent(params);
}
// 获取培训任务学习基本信息
static getStoreTaskAll(params: any) {
return getStoreTaskAll(params);
}
// 课程关联培训任务
static relatedCourseToTask(params: any) {
return relatedCourseToTask(params);
}
}
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditTime: 2021-08-13 19:25:12
* @LastEditTime: 2021-08-15 19:12:48
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
......@@ -25,7 +25,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_2digpsfgq8l.css">
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_0b87tvtysw45.css">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
......
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditTime: 2021-08-13 19:25:18
* @LastEditTime: 2021-08-15 19:12:55
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
......@@ -30,7 +30,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_2digpsfgq8l.css" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_0b87tvtysw45.css" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
......
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors: wufan
* @LastEditTime: 2021-08-06 17:42:37
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 23:34:03
* @Description: 线上课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -194,7 +194,7 @@ class GraphicsCourseList extends React.Component {
<Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter>
{record.relatedPlanList.map((item, index) => {
return (
<span key={item.planId}>
<span key={item.taskId}>
{item.planName} {index < record.relatedPlanList.length - 1 && <span></span>}{' '}
</span>
);
......@@ -245,10 +245,10 @@ class GraphicsCourseList extends React.Component {
handleRelatedModalShow = (item) => {
const selectPlanList = {};
if (item.relatedPlanList) {
item.relatedPlanList.map((item, index) => {
selectPlanList[item.planId] = {};
selectPlanList[item.planId].planId = item.planId;
selectPlanList[item.planId].taskBaseVOList = [{ taskId: item.taskId }];
item.relatedPlanList.map((childItem, index) => {
selectPlanList[childItem.taskId] = {};
selectPlanList[childItem.taskId].taskId = childItem.taskId;
selectPlanList[childItem.taskId].taskBaseVOList = [{ stageId: childItem.stageId }];
return item;
});
}
......@@ -408,22 +408,7 @@ class GraphicsCourseList extends React.Component {
};
this.props.onChange(_query);
};
handleRelatedModalShow = (item) => {
const selectPlanList = {};
if (item.relatedPlanList) {
item.relatedPlanList.map((item, index) => {
selectPlanList[item.planId] = {};
selectPlanList[item.planId].planId = item.planId;
selectPlanList[item.planId].taskBaseVOList = [{ taskId: item.taskId }];
return item;
});
}
this.setState({
RelatedPlanModalVisible: true,
selectCourseId: item.id,
selectPlanList: selectPlanList,
});
};
closeRelatedPlanModalVisible = () => {
this.setState({
RelatedPlanModalVisible: false,
......@@ -487,16 +472,6 @@ class GraphicsCourseList extends React.Component {
onConfirm={this.onConfirmSelectPlanList}
/>
)}
{RelatedPlanModalVisible && (
<RelatedPlanModal
onClose={this.closeRelatedPlanModalVisible}
visible={RelatedPlanModalVisible}
selectCourseId={selectCourseId}
selectPlanList={selectPlanList}
onChange={this.onChangeSelectPlanList}
onConfirm={this.onConfirmSelectPlanList}
/>
)}
{this.state.shareLiveModal}
{this.state.watchDataModal}
</div>
......
......@@ -2,7 +2,7 @@ import User from '@/common/js/user';
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import CourseService from '@/domains/course-domain/CourseService';
import PlanService from '@/domains/plan-domain/planService';
import TaskCenterService from '@/domains/task-center-domain/TaskCenterService';
import { Input, Modal, Tooltip } from 'antd';
import React from 'react';
import _ from 'underscore';
......@@ -33,7 +33,7 @@ class RelatedPlanModal extends React.Component {
size,
storeId: User.getStoreId(),
};
PlanService.getStorePlanAll(params).then((res) => {
TaskCenterService.getStoreTaskAll(params).then((res) => {
const { result = {} } = res;
const { records = [], total = 0 } = result;
this.setState({
......@@ -66,20 +66,24 @@ class RelatedPlanModal extends React.Component {
};
renderTitle = () => {
return <div className="tip-title">
<p>为了不影响学员学习,系统已对数据进行筛选</p>
<p>1、课程不能直接关联「已发布」的培训任务筛选;</p>
<p>2、一个课程不能重复出现在同一培训任务中</p>
</div>
}
return (
<div className='tip-title'>
<p>为了不影响学员学习,系统已对数据进行筛选</p>
<p>1、课程不能直接关联「已发布」的培训任务筛选;</p>
<p>2、一个课程不能重复出现在同一培训任务中</p>
</div>
);
};
renderTableTitle = ()=> {
return <div>
<Tooltip title={this.renderTitle()} overlayClassName="table-title-tooltip">
培训任务<span className='icon iconfont table-title'>&#xe6f2;</span>
</Tooltip>
</div>
}
renderTableTitle = () => {
return (
<div>
<Tooltip title={this.renderTitle()} overlayClassName='table-title-tooltip'>
培训任务<span className='icon iconfont table-title'>&#xe6f2;</span>
</Tooltip>
</div>
);
};
// 请求表头
parsePlanColumns = () => {
......@@ -89,9 +93,7 @@ class RelatedPlanModal extends React.Component {
key: 'planName',
dataIndex: 'planName',
render: (val, record) => {
return <span>{val}
</span>;
return <span>{val}</span>;
},
},
];
......@@ -111,38 +113,37 @@ class RelatedPlanModal extends React.Component {
];
return columns;
};
selectPlanList = (record, selected, planId) => {
selectPlanList = (record, selected, taskId) => {
const { selectPlanList } = this.props;
let _selectPlanList = { ...selectPlanList };
if (selected) {
if (!_selectPlanList[planId]) {
_selectPlanList[planId] = {};
if (!_selectPlanList[taskId]) {
_selectPlanList[taskId] = {};
}
_selectPlanList[planId].taskBaseVOList = [];
_selectPlanList[planId].planId = planId;
_selectPlanList[planId].taskBaseVOList.push(record);
_selectPlanList[taskId].taskBaseVOList = [];
_selectPlanList[taskId].taskId = taskId;
_selectPlanList[taskId].taskBaseVOList.push({ ...record, stageId: record.taskId });
} else {
if (!_selectPlanList[planId]) {
_selectPlanList[planId] = {};
if (!_selectPlanList[taskId]) {
_selectPlanList[taskId] = {};
}
_selectPlanList[planId].taskBaseVOList = [];
_selectPlanList[planId].planId = planId;
_selectPlanList[taskId].taskBaseVOList = [];
_selectPlanList[taskId].taskId = taskId;
}
this.props.onChange(_selectPlanList);
// this.setState({selectPlanList:_selectPlanList});
};
handleSelectPlanListData(selectPlanList) {
let _selectPlanList = [];
for (let key in selectPlanList) {
let item = {};
if (selectPlanList[key].taskBaseVOList) {
item.planId = selectPlanList[key].planId;
item.taskId = selectPlanList[key].taskId;
if (selectPlanList[key].taskBaseVOList[0]) {
item.taskId = selectPlanList[key].taskBaseVOList[0].taskId;
item.stageId = selectPlanList[key].taskBaseVOList[0].stageId;
}
}
if (item.taskId) {
if (item.stageId) {
_selectPlanList.push(item);
}
}
......@@ -152,10 +153,10 @@ class RelatedPlanModal extends React.Component {
const { selectPlanList } = this.props;
const params = {
courseId: this.props.selectCourseId,
relatedPlanList: this.handleSelectPlanListData(selectPlanList),
relatedTaskList: this.handleSelectPlanListData(selectPlanList),
storeId: User.getStoreId(),
};
CourseService.relatedCourseToPlan(params).then((res) => {
TaskCenterService.relatedCourseToTask(params).then((res) => {
this.props.onConfirm();
});
};
......@@ -218,7 +219,7 @@ class RelatedPlanModal extends React.Component {
image: college,
description: '暂无数据',
}}
rowKey={(record) => record.planId}
rowKey={(record) => record.taskId}
className='plan-table'
dataSource={dataSource}
columns={this.parsePlanColumns()}
......@@ -228,7 +229,7 @@ class RelatedPlanModal extends React.Component {
return;
}
if (_record.taskBaseVOList.length !== 0) {
const selectPlan = selectPlanList[_record.planId];
const selectPlan = selectPlanList[_record.taskId];
let taskBaseVOList = [];
if (selectPlan) {
taskBaseVOList = selectPlan.taskBaseVOList;
......@@ -248,9 +249,9 @@ class RelatedPlanModal extends React.Component {
className='child-table'
rowSelection={{
type: 'checkbox',
selectedRowKeys: _.pluck(taskBaseVOList, 'taskId'),
selectedRowKeys: _.pluck(taskBaseVOList, 'stageId'),
onSelect: (record, selected) => {
this.selectPlanList(record, selected, _record.planId);
this.selectPlanList(record, selected, _record.taskId);
},
onSelectAll: (selected, _selectedRows, changeRows) => {},
}}
......
......@@ -2,29 +2,30 @@
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-13 11:48:24
* @LastEditors: wufan
* @LastEditTime: 2021-08-09 15:53:08
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 16:38:20
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from "react";
import { Table, Modal, message, Tooltip, Switch, Dropdown } from "antd";
import React from 'react';
import { Table, Modal, message, Tooltip, Switch, Dropdown } from 'antd';
import { PageControl } from "@/components";
import _ from "underscore";
import { LIVE_SHARE_MAP } from "@/common/constants/academic/cloudClass";
import { appId, shareUrl, LIVE_SHARE } from "@/domains/course-domain/constants";
import TableSelectedData from "@/components/TableSelectedData";
import "./LiveList.less";
import CourseService from "@/domains/course-domain/CourseService";
import User from "@/common/js/user";
import { PageControl } from '@/components';
import _ from 'underscore';
import { LIVE_SHARE_MAP } from '@/common/constants/academic/cloudClass';
import { appId, shareUrl, LIVE_SHARE } from '@/domains/course-domain/constants';
import TableSelectedData from '@/components/TableSelectedData';
import './LiveList.less';
import CourseService from '@/domains/course-domain/CourseService';
import User from '@/common/js/user';
const ENV = process.env.DEPLOY_ENV || 'dev';
class VideoList extends React.Component {
constructor(props) {
super(props);
this.state = {
id: "", // 线上课ID
id: '', // 线上课ID
studentIds: [],
selectedRowKeys: [],
query: {
......@@ -40,8 +41,7 @@ class VideoList extends React.Component {
componentDidUpdate(prevProps, prevState) {
//必须写在if里面并且重新进行一次this.props !== prevProps的判断
if (
((this.props.courseName || this.props.courseType) &&
this.props.courseName !== prevProps.courseName) ||
((this.props.courseName || this.props.courseType) && this.props.courseName !== prevProps.courseName) ||
this.props.courseType !== prevProps.courseType
) {
this.handleFetchScheduleList(this.props);
......@@ -78,10 +78,10 @@ class VideoList extends React.Component {
let hours = Math.floor(time / 3600);
let mins = Math.floor(diff / 60);
let seconds = Math.floor(time % 60);
hours = hours < 10 ? "0" + hours : hours;
mins = mins < 10 ? "0" + mins : mins;
seconds = seconds < 10 ? "0" + seconds : seconds;
return hours + ":" + mins + ":" + seconds;
hours = hours < 10 ? '0' + hours : hours;
mins = mins < 10 ? '0' + mins : mins;
seconds = seconds < 10 ? '0' + seconds : seconds;
return hours + ':' + mins + ':' + seconds;
};
// 请求表头
parseColumns = () => {
......@@ -90,71 +90,58 @@ class VideoList extends React.Component {
title: (
<span>
<span>课程信息</span>
<Tooltip
title={
<div>
已加入该分类的课程不支持重复选择,因此不显示。
</div>
}
>
<Tooltip title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}>
<i
className="icon iconfont"
className='icon iconfont'
style={{
marginLeft: "5px",
cursor: "pointer",
color: "#bfbfbf",
fontSize: "14px",
fontWeight:"400"
}}
>
marginLeft: '5px',
cursor: 'pointer',
color: '#bfbfbf',
fontSize: '14px',
fontWeight: '400',
}}>
&#xe61d;
</i>
</Tooltip>
</span>
),
key: "scheduleName",
dataIndex: "scheduleName",
key: 'scheduleName',
dataIndex: 'scheduleName',
width: 371,
render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record;
return (
<div className="record__item">
<div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img
className="course-cover"
src={
coverUrl ||
`${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`
}
/>
<img className='course-cover' src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} />
{record.courseName.length > 25 ? (
<Tooltip title={record.courseName}>
<div className="course-name">{record.courseName}</div>
<div className='course-name'>{record.courseName}</div>
</Tooltip>
) : (
<div className="course-name">{record.courseName}</div>
<div className='course-name'>{record.courseName}</div>
)}
</div>
);
},
},
{
title: "课程时长",
key: "videoDuration",
dataIndex: "videoDuration",
title: '课程时长',
key: 'videoDuration',
dataIndex: 'videoDuration',
render: (text, item) => {
return <span>{text ? this.dealTimeDuration(text) : "-"}</span>;
return <span>{text ? this.dealTimeDuration(text) : '-'}</span>;
},
},
{
title: "课程分类",
key: "categoryName",
dataIndex: "categoryName",
title: '课程分类',
key: 'categoryName',
dataIndex: 'categoryName',
render: (val, record) => {
return (
<div className="record__item">
<div className='record__item'>
{record.categoryOneName}
{record.categoryTwoName ? `-${record.categoryTwoName}` : ""}
{record.categoryTwoName ? `-${record.categoryTwoName}` : ''}
</div>
);
},
......@@ -167,11 +154,7 @@ class VideoList extends React.Component {
let { selectedRowKeys } = this.state;
let _list = [];
if (selected || !_.find(selectedRowKeys, (item) => item.id == record.id)) {
_list = _.uniq(
selectedRowKeys.concat([record]),
false,
(item) => item.id
);
_list = _.uniq(selectedRowKeys.concat([record]), false, (item) => item.id);
} else {
_list = _.reject(selectedRowKeys, (item) => item.id === record.id);
}
......@@ -182,27 +165,21 @@ class VideoList extends React.Component {
const { dataSource = [], totalCount, query, selectedRowKeys } = this.state;
const { current, size } = query;
const rowSelection = {
selectedRowKeys: _.pluck(selectedRowKeys, "id"),
selectedRowKeys: _.pluck(selectedRowKeys, 'id'),
onSelect: this.selectLiveList,
onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = [];
if (selected) {
_list = _.uniq(
selectedRowKeys.concat(changeRows),
false,
(item) => item.id
);
_list = _.uniq(selectedRowKeys.concat(changeRows), false, (item) => item.id);
} else {
_list = _.reject(selectedRowKeys, (item) =>
_.find(changeRows, (data) => data.id === item.id)
);
_list = _.reject(selectedRowKeys, (item) => _.find(changeRows, (data) => data.id === item.id));
}
this.setState({ selectedRowKeys: _list });
},
};
return (
<div className="live-list">
<div className='live-list'>
<TableSelectedData
selectedNum={selectedRowKeys.length}
clearSelectedData={() => {
......@@ -215,14 +192,14 @@ class VideoList extends React.Component {
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
size="middle"
size='middle'
rowSelection={rowSelection}
pagination={false}
bordered
className="video-list-table"
className='video-list-table'
/>
<div className="box-footer">
<div className='box-footer'>
{totalCount > 0 && (
<PageControl
current={current - 1}
......
import React, { useEffect, useState } from 'react';
import { withRouter } from "react-router-dom";
import { Tabs } from 'antd';
import { Route, withRouter } from 'react-router-dom';
import Service from '@/common/js/service';
import Breadcrumbs from "@/components/Breadcrumbs";
import UserLearningData from './UserLearningData';
import DataInfo from './components/DataInfo'
import CourseTable from './components/CourseTable';
import DataAnalysic from './components/DataAnalysic';
import ExamTable from './components/ExamTable';
import StudyTable from './components/StudyTable';
import './index.less'
const { TabPane } = Tabs;
function DataCenter(props: any) {
const { match: { params: { taskId } } } = props;
const { match } = props;
const { params: { taskId } } = match;
const [info, setInfo] = useState<any>({})
const [tabKey, setTabKey] = useState<any>('')
......@@ -21,16 +24,25 @@ function DataCenter(props: any) {
name: '课程目录',
key: 'course',
compoment: CourseTable,
show:()=>{
return true
}
},
{
name: '学习详情',
key: 'study',
compoment: StudyTable,
show:()=>{
return info.courseNum
}
},
{
name: '考试详情',
key: 'exam',
compoment: ExamTable,
show:()=>{
return info.examNum
}
},
]
......@@ -44,8 +56,8 @@ function DataCenter(props: any) {
res.result.trainingStageList.map((item: any) => {
item.open = true
})
res.result.cover =res.result.courseMediaVOS.filter((item:any) => item.contentType === 'COVER')[0] || {};
res.result.intro =res.result.courseMediaVOS.filter((item:any) => item.contentType === 'INTRO')[0] || {};
res.result.cover = res.result.courseMediaVOS.filter((item: any) => item.contentType === 'COVER')[0] || {};
res.result.intro = res.result.courseMediaVOS.filter((item: any) => item.contentType === 'INTRO')[0] || {};
setInfo(res.result)
})
}
......@@ -62,7 +74,7 @@ function DataCenter(props: any) {
<Tabs defaultActiveKey={'course'} onChange={() => { }}>
{
tabList.map((item: any) => {
return <TabPane tab={item.name} key={item.key}>
return item.show() && <TabPane tab={item.name} key={item.key}>
{
<item.compoment info={info} taskId={taskId} />
}
......@@ -72,7 +84,13 @@ function DataCenter(props: any) {
</Tabs>
</div>
<Route
path={`${match.url}/analysic/:id`}
render={() => {
return <DataAnalysic />;
}}
/>
<Route path={`${props.match.url}/user-learning-data/:storeCustomerId`} render={() => <UserLearningData taskId={taskId} />} />
</div>
}
......
/*
* @Author: yuananting
* @Date: 2021-08-16 17:35:15
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 22:06:40
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { useEffect, useState } from 'react';
import { withRouter } from "react-router-dom";
import RichText from '@/components/RichText'
import { withRouter } from 'react-router-dom';
import RichText from '@/components/RichText';
import ExpiredCourseList from '../../train-task/components/ExpiredCourseList';
import ENUM from '../../enum';
import './course.less'
import './course.less';
function CourseTable(props: any) {
const IndexText = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
const [list, setList] = useState<any[]>([]);
useEffect(() => {
console.log(props.info, 'rtyuio')
setList(props.info.trainingStageList || [])
}, [props.info.trainingStageList])
const taskId = props.match.params.taskId.replace(/\?.+/, '');
const IndexText = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
const [list, setList] = useState<any[]>([]);
useEffect(() => {
setList(props.info.trainingStageList || []);
}, [props.info.trainingStageList]);
return (
<div className='courseTabContent'>
<div className='tips'>
{`培训目的:`}
<RichText url={props.info?.intro?.mediaUrl} />
</div>
return <div className="courseTabContent">
<div className="tips">
{`培训目的:`}
<RichText url={props.info?.intro?.mediaUrl} />
<div className='coursecontent'>
{list?.map((item: any, index: number) => {
return (
<div className='task'>
<div
className='title'
onClick={() => {
const _list = [...list];
_list[index].open = !_list[index].open;
setList(_list);
}}>
{item.open ? <span className='icon iconfont open'>&#xe614;</span> : <span className='icon iconfont'>&#xe614;</span>}
{`${IndexText[index]}、 `}
{item.stageName}
</div>
{item.open && (
<div className='taskItemList'>
{item.contentVOList.map((_item: any, _index: number) => {
return (
<div className={_index == item.contentVOList.length - 1 ? 'item noBorder' : 'item'}>
<div className='name'>
<img className='type-option-icon' src={ENUM.LearningContentIcon[_item.courseType || _item.contentType]} />
<span style={{ marginRight: 4 }}> {`${index + 1}.${_index + 1}`}</span>
</div>
<div className="coursecontent">
{
list?.map((item: any, index: number) => {
return <div className="task">
<div className="title" onClick={() => {
const _list = [...list];
_list[index].open = !_list[index].open;
setList(_list)
}}>
{
item.open ? <span className="icon iconfont open">&#xe614;</span> : <span className="icon iconfont">&#xe614;</span>
}
{
`${IndexText[index]}、 `
}
{item.stageName}
{_item.contentName}
{_item.courseType == 'LIVE' && <span className='desc'>{ENUM.courseStateShow[_item.courseState].title}</span>}
{_item.courseType == 'VOICE' && <span className='desc'>{`(共${_item.courseChapterNum}节)`}</span>}
</div>
{
item.open && <div className="taskItemList">
{
item.contentVOList.map((_item: any, _index: number) => {
return <div className={_index == item.contentVOList.length - 1 ? "item noBorder" : "item"}>
<div className="name">
<img className='type-option-icon' src={ENUM.LearningContentIcon[_item.courseType || _item.contentType]} />
<span style={{ marginRight: 4 }}> {`${index + 1}.${_index + 1}`}</span>
{
_item.contentName
}
{
(_item.courseType == 'LIVE') && <span className='desc'>{ENUM.courseStateShow[_item.courseState].title}</span>
}
{
_item.courseType == 'VOICE' && <span className='desc'>{`(共${_item.courseChapterNum}节)`}</span>
}
</div>
</div>
})
}
</div>
}
</div>
})
}
</div>
<div className="expired">
<div className="title">失效课程</div>
<div className="list">
<ExpiredCourseList expiredCourseList={list} />
</div>
);
})}
</div>
)}
</div>
</div>
);
})}
</div>
<div className='expired'>
<ExpiredCourseList taskId={taskId} />
</div>
</div>
);
}
export default withRouter(CourseTable)
\ No newline at end of file
export default withRouter(CourseTable);
import React, { useState, useRef, useEffect, useContext } from 'react'
import { Route, withRouter } from 'react-router-dom';
import Breadcrumbs from "@/components/Breadcrumbs";
import UserData from './UserData';
import ExamData from './ExamData'
import Service from "@/common/js/service";
import { Tabs } from 'antd';
import User from "@/common/js/user";
import './dataAnalysic.less'
const { TabPane } = Tabs;
function DataAnalysic(props: any) {
const examDetailInit: any = {};
const [selectKey, setSelectKey] = useState('user')
const [examDetail, setExamDetail] = useState(examDetailInit);
const { match } = props;
const examId =match.params.id;
useEffect(() => {
queryExamDetail();
}, [])
function queryExamDetail() {
Service.Hades("public/hades/queryExamDetail", {
examId:examId,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
source: 0
}).then((res) => {
const { result } = res
setExamDetail(result)
})
}
return <div className="page dataAnalysic">
<Breadcrumbs navList={"考试数据"} goBack={props.history.goBack} />
<div className="box">
<div className="titleBox ">
考试名称:{examDetail.examName}
</div>
</div>
<div className="box" style={{ paddingTop: 0 }}>
<Tabs activeKey={selectKey} onChange={(key: any) => {
setSelectKey(key)
}}>
<TabPane tab="考试人员数据" key="user">
<UserData examDetail ={examDetail } examId={examId} />
</TabPane>
<TabPane tab="题目数据" key="exam">
<ExamData examDetail ={examDetail } examId={examId}></ExamData>
</TabPane>
</Tabs>
</div>
</div>
}
export default withRouter(DataAnalysic);
\ No newline at end of file
......@@ -22,7 +22,7 @@ function DataInfo(props: any) {
<span style={{ marginLeft: 24 }}> {`培训时间:${moment(props.info.startTime).format('YYYY-MM-DD HH:mm')} 至 ${moment(props.info.endTime).format('YYYY-MM-DD HH:mm')}`}</span>
</div>
<div className="info">
<div className="item">{`任务数:${props.info.contentNum}`}</div>
<div className="item">{`任务数: ${props.info.contentNum}`}</div>
{
!!props.info.courseNum && <div className="item"><span className="icon"><img src="https://image.xiaomaiketang.com/xm/6C2GjSpnDp.png" alt="" /></span>{`课程:${props.info.courseNum}`}</div>
}
......@@ -39,7 +39,18 @@ function DataInfo(props: any) {
</div>
<div className="right">
<div className="prog">
<Progress type="circle" width={85} percent={parseInt(props.info.finishCustomerNum /(props.info.cultureCustomerNum)*100 as any)} strokeWidth={10} format={percent => <div className='wcl'>{`${(parseInt(props.info.finishCustomerNum /(props.info.cultureCustomerNum)*100 as any))}% `} <div>完成率</div></div>} />
<Progress type="circle" width={85} percent={parseInt(props.info.finishCustomerNum /(props.info.cultureCustomerNum)*100 as any)} strokeWidth={10}
format={percent => <div className='wcl'>
{`${(parseInt(props.info.finishCustomerNum /(props.info.cultureCustomerNum)*100 as any))}% `}
<div>完成率</div>
</div>} />
{/* <div className='wcl'> */}
{/* {`${(parseInt(props.info.finishCustomerNum /(props.info.cultureCustomerNum)*100 as any))}% `} */}
{/* <div>完成率</div> */}
{/* </div> */}
</div>
<div className="num">
<div className="item"> {`指派人数:${props.info.cultureCustomerNum}`}</div>
......
import React, { useState, useRef, useEffect } from "react";
import Service from "@/common/js/service";
import { PageControl } from "@/components";
import { Input, Select, Tooltip, Button } from "antd";
import User from "@/common/js/user";
import { XMTable } from "@/components";
import college from "@/common/lottie/college.json";
import "./userData.less";
interface sortType {
type: "ascend" | "descend" | null | undefined;
}
function ExamData(props: any) {
const sortStatus: sortType = {
type: undefined,
};
const examDataInit: any = {};
const queryInit: any = { current: 1, size: 10, order: "SORT_ASC" };
const [examData, setUserData] = useState(examDataInit);
const [list, setList] = useState([]);
const [query, setQuery] = useState(queryInit);
const [total, setTotal] = useState(0);
const [field, setfield] = useState("");
const [allData, setAllData] = useState(0);
const [order, setOrder] = useState(sortStatus.type);
const questionTypeList = {
SINGLE_CHOICE: "单选题",
MULTI_CHOICE: "多选题",
JUDGE: "判断题",
GAP_FILLING: "填空题",
INDEFINITE_CHOICE: "不定项选择题",
};
const userTypeEnum = {
WORK_WE_CHAT: "企业微信",
WE_CHAT: "微信",
};
const userExamStateEnum = {
EXAM: "进行中",
LACK_EXAM: "缺考",
FINISH_EXAM: "已考试",
};
const orderEnum = {
currentAccuracy: {
ascend: "ACCURACY_ASC",
descend: "ACCURACY_DESC",
},
};
const queryRef = useRef({});
useEffect(() => {
queryExamUserData();
}, []);
useEffect(() => {
queryRef.current = query;
queryExamUserDataList();
}, [query]);
function queryExamUserData() {
Service.Hades("public/hades/queryExamQuestionData", {
examId: props.examId,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
source: 0,
}).then((res) => {
setUserData(res.result);
});
}
function queryExamUserDataList() {
Service.Hades("public/hades/queryExamQuestionDataList", {
...query,
examId: props.examId,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
source: 0,
}).then((res) => {
setList(res.result.records);
setTotal(parseInt(res.result.total));
if (!allData) {
setAllData(parseInt(res.result.total));
}
});
}
const columns = [
{
title: "序号",
dataIndex: "sort",
width: 60,
render: (text: any, record: any, index: any) => <span>{index + 1}</span>,
},
{
title: "题目",
dataIndex: "questionStem",
ellipsis: true,
width: 350,
render: (val: any) => {
var handleVal = val;
handleVal = handleVal.replace(/<(?!img|input).*?>/g, "");
handleVal = handleVal.replace(/<\s?input[^>]*>/gi, "_、");
handleVal = handleVal.replace(/\&nbsp\;/gi, " ");
return (
<Tooltip
overlayClassName="aid-tool-list"
title={
<div style={{ maxWidth: 700, width: "auto" }}>{handleVal}</div>
}
placement="topLeft"
overlayStyle={{ maxWidth: 700 }}
>
{handleVal}
</Tooltip>
);
},
},
{
title: "题型",
dataIndex: "questionType",
render: (text: any) => <span>{(questionTypeList as any)[text]}</span>,
filters: Object.keys(questionTypeList).map((key) => {
return {
text: (questionTypeList as any)[key],
value: key,
};
}),
},
{
title: "本次正确率",
dataIndex: "currentAccuracy",
sorter: true,
sortOrder: field === "currentAccuracy" ? order : sortStatus.type,
render: (text: any) => <span>{parseInt((text * 100) as any)}%</span>,
},
{
title: (
<div>
历史正确率{" "}
<Tooltip
overlayClassName="tool-list"
title="包含本次考试正确率"
placement="top"
overlayStyle={{ maxWidth: 700 }}
>
{" "}
<span
style={{ color: "rgba(191, 191, 191, 1)",fontWeight: 400 }}
className="icon iconfont"
>
&#xe61d;
</span>
</Tooltip>
</div>
),
dataIndex: "totalAccuracy",
render: (text: any) => <span>{parseInt((text * 100) as any)}%</span>,
},
];
function onChange(pagination: any, filters: any, sorter: any, extra: any) {
console.log(filters, sorter);
setfield(sorter.field);
setOrder(sorter.order);
console.log(sorter.field, sorter.order, (orderEnum as any)[sorter.field]);
let _query: any = { ...queryRef.current };
console.log(filters.questionType);
if (filters.questionType) {
console.log(233232);
_query.questionType = filters.questionType;
_query.current = 1;
} else {
delete _query.questionType;
}
_query.order = (orderEnum as any)[sorter.field][sorter.order];
setQuery(_query);
}
function download() {
Service.Hades("public/hades/exportExamData", {
// ...query,
examId: props.examId,
exportDataType: "EXAM_QUESTION_DATA",
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
source: 0,
}).then((res) => {
const dom = (document as any).getElementById("load-play-back-excel");
dom.setAttribute("href", res.result);
dom.click();
});
}
return (
<div className="rr">
<a
download
id="load-play-back-excel"
style={{ position: "absolute", left: "-10000px" }}
></a>
<div className="dataPanal">
{!!examData.singleChoiceCnt && (
<div className="item">
<div className="num">
{Math.round((examData.singleChoiceAccuracy || 0) * 100)}%
</div>
<div className="percent">正确率</div>
<div className="subTitle">
<div className="type">
<span className="icon iconfont">&#xe7fa;</span>单选题{" "}
<span>(共{examData.singleChoiceCnt}题)</span>
</div>
</div>
</div>
)}
{!!examData.multiChoiceCnt && (
<div className="item">
<div className="num">
{Math.round((examData.multiChoiceAccuracy || 0) * 100)}%
</div>
<div className="percent">正确率</div>
<div className="subTitle">
<div className="type">
<span className="icon iconfont">&#xe7fb;</span>多选题
<span>(共{examData.multiChoiceCnt}题)</span>
</div>
</div>
</div>
)}
{!!examData.judgeCnt && (
<div className="item">
<div className="num">
{Math.round((examData.judgeAccuracy || 0) * 100)}%
</div>
<div className="percent">正确率</div>
<div className="subTitle">
<div className="type">
<span className="icon iconfont">&#xe7fc;</span>判断题
<span>(共{examData.judgeCnt}题)</span>
</div>
</div>
</div>
)}
{!!examData.gapFillingCnt && (
<div className="item">
<div className="num">
{Math.round((examData.gapFillingAccuracy || 0) * 100)}%
</div>
<div className="percent">正确率</div>
<div className="subTitle">
<div className="type">
<span className="icon iconfont">&#xe7fd;</span>填空题
<span>(共{examData.gapFillingCnt}题)</span>
</div>
</div>
</div>
)}
{!!examData.indefiniteChoiceCnt && (
<div className="item">
<div className="num">
{Math.round((examData.indefiniteChoiceAccuracy || 0) * 100)}%
</div>
<div className="percent">正确率</div>
<div className="subTitle">
<div className="type">
<span className="icon iconfont">&#xe7fe;</span>不定项选择题{" "}
<span>(共{examData.indefiniteChoiceCnt}题)</span>
</div>
</div>
</div>
)}
</div>
{!!allData && (
<Button style={{ marginBottom: 12, marginTop: 12 }} onClick={download}>
导出
</Button>
)}
<div className="content">
<XMTable
renderEmpty={{
image: college,
description: '暂无数据'
}}
bordered
size="small"
columns={columns}
dataSource={list}
onChange={onChange}
pagination={false}
></XMTable>
{total > 0 && (
<PageControl
size="small"
current={query.current - 1}
pageSize={query.size}
total={total}
toPage={(page: any) => {
console.log(page);
let _query: any = { ...queryRef.current };
_query.current = page + 1;
setQuery(_query);
}}
/>
)}
</div>
</div>
);
}
export default ExamData;
import React, { useEffect, useState } from 'react';
import { withRouter } from "react-router-dom";
import { Route, withRouter } from 'react-router-dom';
import { PageControl, XMTable } from '@/components';
import Service from '@/common/js/service';
import User from '@/common/js/user';
function ExamTable(props: any) {
const { match } = props;
console.log(match)
const [query, setQuery] = useState<any>({
current: 1, size: 10,
taskId: props.taskId,
......@@ -22,8 +25,8 @@ function ExamTable(props: any) {
function getList() {
Service.Hades('public/hades/queryTrainingExamUserData', query).then((res: any) => {
setList(res.result.records)
setTotal(res.result.tatal)
setList(res.result.records);
setTotal(res.result.total);
})
}
......@@ -79,7 +82,11 @@ function ExamTable(props: any) {
render: (val: any, record: any) => {
return (
<div className='operate-area'>
<span className='operate-item' onClick={() => { }}>
<span className='operate-item' style={{ color: 'rgba(41, 102, 255, 1)', cursor: 'pointer' }} onClick={() => {
props.history.push({
pathname: `${match.url}/analysic/${record.examId}`,
});
}}>
查看数据
</span>
......@@ -90,6 +97,7 @@ function ExamTable(props: any) {
];
return <div className="study_Table">
<div style={{ marginTop: 12 }}>
......@@ -121,7 +129,7 @@ function ExamTable(props: any) {
</div>
)}
</div>
</div>
}
......
......@@ -31,12 +31,12 @@ function LeftStageList(props) {
>
<div className="icon">
{item.isShowMoreCourse ? (
<span className="icon iconfont edit-icon">&#xe6b2;</span>
<span className="icon iconfont edit-icon">&#xe677;</span>
) : (
<span className="icon iconfont edit-icon">&#xe600;</span>
)}
</div>
<div className="stage-name">
<div className="stage-name oneLineText">
{ENUM.IndexToSort[index + 1]}{item.stageName}
</div>
</div>
......
......@@ -8,8 +8,7 @@ import Service from '@/common/js/service';
import ENUM from '../../enum';
import User from '@/common/js/user';
import moment from 'moment';
import UserLearningData from '../UserLearningData';
import { timers } from 'jquery';
const { Search } = Input;
const { Option } = Select;
declare var formatDate: any;
......@@ -27,34 +26,46 @@ function StudyTable(props: any) {
const [list, setList] = useState<any[]>([]);
const [total, setTotal] = useState<any>(0);
const [name, setName] = useState<any>('');
const timer = useRef<any>(null)
const [orderFiled, setOrderFiled] = useState<any>(null);
const [sort, setSort] = useState<any>(null);
const timer = useRef<any>(null);
const sortNameMap: any = {
learnPercentage: 'LEARN_NUM',
latelyLearnTime: 'LATE_LEARN_TIME',
startLearnTime: 'START_LEARN_TIME',
}
useEffect(() => {
getList()
}, [query])
}, [query, orderFiled, sort])
function getList() {
Service.Hades('public/hades/getTaskCustomerRecordPage', query).then((res: any) => {
const _query = { ...query };
delete _query.sortMap;
if (sort) {
_query.sortMap = {
[sortNameMap[orderFiled]]: sort === "ascend" ? 'SORT_ASC' : 'SORT_DESC'
}
}
Service.Hades('public/hades/getTaskCustomerRecordPage', _query).then((res: any) => {
res.result.records.map((item: any) => {
item.department =item.departmentNameList.map((_item:any)=>{
item.department = item.departmentNameList.map((_item: any) => {
if (_item == '1000') {
return '微信'
} else {
return <WWOpenDataCom type="departmentName" openid={_item} />
}
})
})
setList(res.result.records)
setTotal(res.result.total)
})
}
const columns = [
{
title: '学员',
......@@ -74,13 +85,13 @@ function StudyTable(props: any) {
key: 'departmentNameList',
dataIndex: 'departmentNameList',
render: (val: any, record: any) => {
return <div>
return <div>
{
record.department.map((item:any,index:number)=>{
if((index+1) ==record.department.length){
record.department.map((item: any, index: number) => {
if ((index + 1) == record.department.length) {
return item
}else{
return [item,';']
} else {
return [item, ';']
}
})
......@@ -104,9 +115,17 @@ function StudyTable(props: any) {
},
},
{
title: '学习进度',
title: <div>学习进度 <Tooltip
title={'已完成任务数/任务总数'}>
<span
style={{ color: "rgba(191, 191, 191, 1)", fontWeight: 400 }}
className="iconfont"
>&#xe61d;</span>
</Tooltip></div>,
key: 'learnPercentage',
sorter: true,
dataIndex: 'learnPercentage',
sortOrder: (orderFiled == 'learnPercentage') ? sort : null,
render: (val: any, record: any) => {
return `${val}%`;
},
......@@ -118,8 +137,8 @@ function StudyTable(props: any) {
dataIndex: 'latelyLearnTime',
sorter: true,
width: 240,
sortOrder: (orderFiled == 'latelyLearnTime') ? sort : null,
render: (val: any, record: any) => {
return `${formatDate('YYYY-MM-DD H:i', parseInt(record.latelyLearnTime))}`;
},
},
......@@ -129,6 +148,8 @@ function StudyTable(props: any) {
dataIndex: 'startLearnTime',
width: 240,
sorter: true,
field: 'yuiooo',
sortOrder: (orderFiled == 'startLearnTime') ? sort : null,
render: (val: any, record: any) => {
return <div>{formatDate('YYYY-MM-DD H:i', val)}</div>;
},
......@@ -155,6 +176,13 @@ function StudyTable(props: any) {
},
];
function onChange(pagination: any, filters: any, sorter: any, extra: any) {
console.log(sorter)
setOrderFiled(sorter.field || null)
setSort(sorter.order)
}
return <div className="study_Table">
<div className="filter">
......@@ -257,6 +285,7 @@ function StudyTable(props: any) {
storeUserId: User.getStoreUserId(),
userId: User.getStoreUserId(),
})
setSort('')
}}>
&#xe61b;{' '}
</span>
......@@ -276,7 +305,7 @@ function StudyTable(props: any) {
columns={columns}
pagination={false}
className='user-learning-table'
onChange={() => { }}
onChange={onChange}
showSorterTooltip={false}
bordered
/>
......@@ -294,7 +323,7 @@ function StudyTable(props: any) {
</div>
)}
</div>
<Route path={`${props.match.url}/user-learning-data/:storeCustomerId`} render={() => <UserLearningData taskId={props.taskId} />} />
</div>
}
......
......@@ -38,13 +38,20 @@
.taskItemList{
margin-left: 64px;
.item{
padding: 16px 0px 16px 32px;
padding: 16px 0px 16px 16px;
border-bottom: 1px dashed #E8E8E8;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
.name{
img{
width: 20px;
position: relative;
top: -2px;
}
}
&.noBorder{
border:none;
}
......
.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;
}
}
.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;
top: 1px;
}
}
&: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;
}
}
.answer-detail {
color: rgb(35, 143, 255);
}
.analysic-content {
.ant-table-bordered .ant-table-tbody tr {
&.analysic-content-row {
height: 50px;
}
}
}
......@@ -33,8 +33,7 @@
line-height: 25px;
}
.status{
width: 42px;
height: 20px;
padding: 0px 8px;
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
......@@ -42,7 +41,9 @@
line-height: 20px;
text-align: center;
margin-left: 24px;
position: relative;
top: 2px;
height: 20px;
}
}
.info{
......@@ -79,14 +80,28 @@
width: 85px;
margin-top: 27px;
margin-right: 24px;
position: relative;
.wcl{
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #666666;
line-height: 22px;
text-align: center;
// left: 0px;
// top: 20px;
// width: 100%;
// height: 100%;
// display: none;
// position: absolute;
// z-index: 1;
}
// &:hover{
// .wcl{
// display: block;
// }
// }
}
.num{
margin-top: 27px;
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-28 11:25:58
* @LastEditors: yuananting
* @LastEditTime: 2021-08-10 15:10:44
* @LastEditTime: 2021-08-14 17:18:39
* @Description: 任务中心-培训任务
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -23,7 +23,7 @@ function TrainTaskPage(props) {
issueState: 'ALL', // 发布状态
myAssist: false, // 是否由我协同
size: 10,
sortMap: {}, // 排序
sortMap: { UPDATED: 'SORT_DESC' }, // 排序(默认更新时间倒序)
startTime: null,
storeId: User.getStoreId(),
storeUserId: User.getStoreUserId(),
......@@ -48,7 +48,9 @@ function TrainTaskPage(props) {
useEffect(() => {}, []);
const initPageData = () => {
Bus.bind('getTrainingTaskPage', getTrainingTaskPage);
Bus.bind('getTrainingTaskPage', (filterData) => {
getTrainingTaskPage(filterData);
});
Bus.bind('getStoreTaskNum', getStoreTaskNum);
};
......@@ -58,8 +60,8 @@ function TrainTaskPage(props) {
};
// 获取计划列表
function getTrainingTaskPage() {
let _query = _.clone(query);
function getTrainingTaskPage(filterData) {
const _query = { ...query, ...filterData };
if (_query.issueState === 'ALL') {
delete _query.issueState;
}
......
......@@ -2,41 +2,88 @@
* @Author: yuananting
* @Date: 2021-08-03 10:47:59
* @LastEditors: yuananting
* @LastEditTime: 2021-08-03 18:31:56
* @LastEditTime: 2021-08-16 22:04:31
* @Description: 编辑培训任务-失效课程
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from 'react';
import { List } from 'antd';
import React, { useState, useEffect } from 'react';
import { List, message, Modal } from 'antd';
import './ExpiredCourseList.less';
import ENUM from '../../enum';
import moment from 'moment';
import TaskCenterService from '@/domains/task-center-domain/TaskCenterService';
function ExpiredCourseList(props) {
const expiredCourseList = [1, 2, 3, 4];
const [expiredCourseList, setExpiredCourseList] = useState([]); // 失效课程
useEffect(() => {
getTrainingCourseAutoCancel();
}, []);
// 获取培训任务失效的课程
function getTrainingCourseAutoCancel() {
TaskCenterService.getTrainingCourseAutoCancel({ taskId: props.taskId }).then((res) => {
setExpiredCourseList(res.result);
});
}
// 移除未成功开课课程
function deLExpiredCourse(contentId) {
Modal.confirm({
content: '你确定要删除该数据内容吗?',
okText: '确定',
cancelText: '取消',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => {
const params = {
taskId,
contentIdList: [contentId],
};
TaskCenterService.delTaskCancelContent(params).then((res) => {
message.success('删除成功');
getTrainingCourseAutoCancel();
});
},
});
}
return (
<div className='expired-list-page'>
<div className='tip'>为了不影响学员学习,「未成功开课」的课程已从任务中移出,具体课程如下所示:</div>
<List
dataSource={expiredCourseList}
renderItem={(item) => (
<List.Item>
<div className='item-detail'>
<span className='icon iconfont'>&#xe80b;</span>
<span className='content-status'>未成功开课</span>
<span className='stage-name'>阶段一、</span>
<span className='content-name'>
<img src={ENUM.LearningContentIcon['LIVE']} />
<span>2.1 入门培训任务</span>
</span>
<span className='teacher-name'>张老师</span>
<span className='split'>|</span>
<span className='course-time'>2020-12-12 09:00~10:00</span>
<span className='del-btn'>删除记录</span>
</div>
</List.Item>
)}
/>
<div>
{expiredCourseList.length > 0 && (
<div className='expired-list-page'>
<div className='tip'>为了不影响学员学习,「未成功开课」的课程已从任务中移出,具体课程如下所示:</div>
<List
dataSource={expiredCourseList}
renderItem={(item) => (
<List.Item>
<div className='item-detail'>
<span className='icon iconfont'>&#xe80b;</span>
<span className='content-status'>未成功开课</span>
<span className='stage-name'>{item.stageName}</span>
<span className='content-name'>
<img src={ENUM.LearningContentIcon[item.courseType]} />
<span>{item.courseName}</span>
</span>
<span className='teacher-name'>{item.teacherName}</span>
<span className='split'>|</span>
<span className='course-time'>
{moment(item.startTime).format('YYYY-MM-DD HH:mm')}~{moment(item.endTime).format('HH:mm')}
</span>
<span
className='del-btn'
onClick={() => {
deLExpiredCourse(item.courseId);
}}>
删除记录
</span>
</div>
</List.Item>
)}
/>
</div>
)}
</div>
);
}
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-08-01 17:28:30
* @LastEditors: yuananting
* @LastEditTime: 2021-08-11 11:27:09
* @LastEditTime: 2021-08-16 19:53:06
* @Description: 新建培训任务-关联课程抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -10,14 +10,12 @@
import React, { Component } from 'react';
import _ from 'underscore';
import { Radio, Tabs, Drawer, Input, message, Button, Tooltip } from 'antd';
import { PageControl, XMTable } from '@/components';
import college from '@/common/lottie/college';
import CourseService from '@/domains/course-domain/CourseService';
import User from '@/common/js/user';
import Service from '@/common/js/service';
import ENUM from '../../enum';
import './RelatedCourseDrawer.less';
const { Search } = Input;
......@@ -97,7 +95,6 @@ class RelatedCourseDrawer extends Component {
handleFetchLiveDataList = () => {
const { liveQuery, liveSize } = this.state;
const _data = [...this.props.data];
console.log('data=========>', _data);
let currentLiveCourseListData = [];
_data.map((item) => {
item.contentList.map((childItem, childIndex) => {
......@@ -129,11 +126,13 @@ class RelatedCourseDrawer extends Component {
handleFetchVideoDataList = () => {
const { videoQuery, videoSize, videoDataSource, videoTotalCount, videoCourseDivision } = this.state;
const _data = [...this.props.data];
console.log('_data', _data);
let currentVideoCourseListData = [];
_data.map((item, index) => {
item.contentList.map((childItem, childIndex) => {
console.log('childItem', childItem);
if (childItem.courseType === 'VOICE') {
currentVideoCourseListData.push(childItem.courseId);
currentVideoCourseListData.push(childItem.contentId);
}
return childItem;
});
......@@ -171,7 +170,7 @@ class RelatedCourseDrawer extends Component {
_data.map((item, index) => {
item.contentList.map((childItem, childIndex) => {
if (childItem.courseType === 'PICTURE') {
currentPictureCourseListData.push(childItem.courseId);
currentPictureCourseListData.push(childItem.contentId);
}
return childItem;
});
......@@ -286,7 +285,7 @@ class RelatedCourseDrawer extends Component {
),
key: 'course',
dataIndex: 'course',
width: '40%',
width: '30%',
render: (val, record) => {
if (type === 'live') {
let hasCover = false;
......@@ -303,14 +302,7 @@ class RelatedCourseDrawer extends Component {
<img className='course-cover' src={'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png'} alt='' />
</If>
<div>
<div className='course-name'>{record.courseName}</div>
{/* <span
className='course-status'
style={{ color: courseStateShow[record.courseState].color, border: `1px solid ${courseStateShow[record.courseState].color}` }}>
{courseStateShow[record.courseState].title}
</span> */}
</div>
<div className='course-name'>{record.courseName}</div>
</div>
);
} else {
......@@ -332,10 +324,26 @@ class RelatedCourseDrawer extends Component {
},
type === 'live'
? {
title: '课程状态',
key: 'courseState',
dataIndex: 'courseState',
width: '25%',
render: (val, record) => {
return (
<div className='course-state'>
<span className='status-point' style={{ backgroundColor: ENUM.trainStatus[val || 'UN_START'].color }}></span>
<span>{ENUM.trainStatus[val || 'UN_START'].text}</span>
</div>
);
},
}
: {},
type === 'live'
? {
title: '上课时间',
key: 'courseTime',
dataIndex: 'courseTime',
width: '40%',
width: '25%',
render: (val, record) => {
return (
<div>
......
......@@ -70,19 +70,19 @@
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
width: 180px;
width: 140px;
}
.course-state {
* {
vertical-align: middle;
display: inline-block;
}
.status-point {
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 4px;
}
}
.course-state {
* {
vertical-align: middle;
display: inline-block;
}
.status-point {
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 4px;
}
}
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-08-03 17:05:32
* @LastEditors: yuananting
* @LastEditTime: 2021-08-11 11:49:11
* @LastEditTime: 2021-08-16 16:36:59
* @Description: 新建培训任务-关联考试抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -65,7 +65,7 @@ function RelatedExamDrawer(props) {
paperId,
examName,
passRate,
examDuration,
examDuration: (examDuration || 0) * 60 * 1000,
examDesc,
needOptionDisorder,
resultShow,
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-30 16:33:58
* @LastEditors: yuananting
* @LastEditTime: 2021-08-14 10:10:44
* @LastEditTime: 2021-08-16 22:10:08
* @Description: 任务中心-培训任务-新建-培训内容
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -46,25 +46,24 @@ const courseStateShow = {
const SortConvert = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
// const id = window.getParameterByName('id');
// const type = window.getParameterByName('type');
class TrainContent extends Component {
constructor(props) {
super(props);
this.state = {
basicInfo: props.basicInfo,
stageList: props.stageList,
finishStandard: props.finishStandard,
percentCompleteLive: props.percentCompleteLive,
percentCompleteVideo: props.percentCompleteVideo,
percentCompletePicture: props.percentCompletePicture,
showCourseDrawer: false,
showExamDrawer: false,
selectedStageIndex: 0,
expiredCourseList: props.expiredCourseList, // 失效课程
type: window.getParameterByName('type'),
showStandardDetail: false, // 是否展开高级设置
};
}
componentDidMount() {}
componentDidMount() { }
setTrianTypeOption = (index) => {
return (
......@@ -426,7 +425,6 @@ class TrainContent extends Component {
};
changePercentComplete = (e, field) => {
const { finishStandard } = this.state;
let _percentComplete = 0;
const value = e.target.value.replace(/\D/g, '');
if (value > 100) {
......@@ -440,24 +438,31 @@ class TrainContent extends Component {
}
this.setState(
{
finishStandard: {
...finishStandard,
[field]: _percentComplete,
},
[field]: _percentComplete,
},
() => {
this.props.onChange('finishStandard', this.state.finishStandard);
this.props.onChange(field, _percentComplete);
}
);
};
render() {
const { stageList, showCourseDrawer, showExamDrawer, expiredCourseList, showStandardDetail, finishStandard, basicInfo, selectedStageIndex } = this.state;
console.log('finishStandard==================>', finishStandard);
const { percentCompleteLive, percentCompleteVideo, percentCompletePicture } = finishStandard;
const {
stageList,
showCourseDrawer,
showExamDrawer,
showStandardDetail,
basicInfo,
selectedStageIndex,
percentCompleteLive,
percentCompleteVideo,
percentCompletePicture,
} = this.state;
const { startCheck } = this.props;
const taskId = window.getParameterByName('taskId');
return (
<div className='train-content-page'>
<div className='train-content__warp'>
......@@ -481,12 +486,12 @@ class TrainContent extends Component {
)}
{showExamDrawer && <RelatedExamDrawer basicInfo={basicInfo} stageList={stageList} onClose={this.onCloseExamDrawer} onSave={this.confirmCreateExam} />}
</div>
{window.getParameterByName('type') === 'edit' && expiredCourseList.length > 0 && (
<div className='expired-info__wrap'>
<div className='module-title'>失效课程</div>
<ExpiredCourseList expiredCourseList={expiredCourseList} />
</div>
)}
{
this.state.type === 'edit' && <ExpiredCourseList taskId={taskId} />
}
<div className='finish-standard__warp'>
<div
className='module-title'
......
......@@ -23,6 +23,7 @@
}
.finish-standard__warp {
margin-top: 24px;
margin-bottom: 60px;
.module-title {
height: 22px;
......
......@@ -2,12 +2,12 @@
* @Author: yuananting
* @Date: 2021-07-28 14:56:52
* @LastEditors: yuananting
* @LastEditTime: 2021-08-14 10:48:01
* @LastEditTime: 2021-08-16 22:08:57
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { useState } from 'react';
import { Route, withRouter } from 'react-router-dom';
import { withRouter } from 'react-router-dom';
import { Tooltip, Checkbox, Dropdown, Radio, Button, Space, Modal, message } from 'antd';
import './TrainList.less';
import { XMTable, PageControl } from '@/components';
......@@ -30,23 +30,21 @@ function TrainList(props) {
const [chooseAssignorModal, setChooseAssignorModal] = useState(null);
// 发布或取消发布培训任务
function updateIssueStateTrain(taskId, issueState) {
function updateIssueStateTrain(taskId, state) {
Modal.confirm({
title: '提示',
content:
issueState === 'YES'
? '发布后,被指派学员将任务列表中看到该任务,确定要发布?'
: '取消发布后,任务对学员暂不可见,可能会影响正在学习学员,确定要取消?',
state === 'YES' ? '发布后,被指派学员将任务列表中看到该任务,确定要发布?' : '取消发布后,任务对学员暂不可见,可能会影响正在学习学员,确定要取消?',
okText: '确定',
cancelText: '取消',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => {
TaskCenterService.updateIssueStateTraining({
taskId,
issueState,
issueState: state,
}).then((res) => {
message.success(issueState === 'YES' ? '发布成功' : '取消发布成功');
Bus.trigger('getTrainingTaskPage');
message.success(state === 'YES' ? '发布成功' : '取消发布成功');
Bus.trigger('getTrainingTaskPage', { issueState, myAssist });
Bus.trigger('getStoreTaskNum');
});
},
......@@ -66,7 +64,7 @@ function TrainList(props) {
taskId,
}).then((res) => {
message.success('删除成功');
Bus.trigger('getTrainingTaskPage');
Bus.trigger('getTrainingTaskPage', { issueState, myAssist });
Bus.trigger('getStoreTaskNum');
});
},
......@@ -140,7 +138,7 @@ function TrainList(props) {
}
TaskCenterService.updateTrainingTaskAssign(params).then((res) => {
message.success('指派成功');
Bus.trigger('getTrainingTaskPage');
Bus.trigger('getTrainingTaskPage', { issueState, myAssist });
setChooseAssignorModal(null);
});
}
......@@ -234,10 +232,9 @@ function TrainList(props) {
},
{
title: '学习人数',
width: '10%',
width: '12%',
key: 'cultureCustomerNum',
dataIndex: 'cultureCustomerNum',
sorter: true,
render: (val, record) => {
return (
<Tooltip
......@@ -248,7 +245,13 @@ function TrainList(props) {
<div>已逾期:{record.overdueCustomerNum}</div>
</div>
}>
<span style={{ color: '#2966FF' }}>{val}</span>
<span
style={{ color: '#2966FF', cursor: 'pointer' }}
onClick={() => {
props.history.push(`${match.path}/data/${record.taskId}`);
}}>
{val}
</span>
</Tooltip>
);
},
......@@ -272,17 +275,16 @@ function TrainList(props) {
</Tooltip>
</span>
),
width: '10%',
width: '11.5%',
key: 'finishPercent',
dataIndex: 'finishPercent',
sorter: true,
render: (val) => {
return <span>{val}%</span>;
},
},
{
title: '培训时间',
width: '12.5%',
width: '17%',
key: 'trainTime',
dataIndex: 'trainTime',
render: (val, record) => {
......@@ -291,7 +293,7 @@ function TrainList(props) {
}
return (
<span>
{window.formatDate('YYYY-MM-DD H:i', record.startTime)}~{window.formatDate('YYYY-MM-DD H:i', record.endTime)}
{window.formatDate('YYYY-MM-DD H:i', record.startTime)} ~ {window.formatDate('YYYY-MM-DD H:i', record.endTime)}
</span>
);
},
......@@ -307,7 +309,7 @@ function TrainList(props) {
},
{
title: '创建时间',
width: '12%',
width: '14%',
key: 'created',
dataIndex: 'created',
sorter: true,
......@@ -317,7 +319,7 @@ function TrainList(props) {
},
{
title: '更新时间',
width: '12%',
width: '14%',
key: 'updated',
dataIndex: 'updated',
sorter: true,
......@@ -331,7 +333,7 @@ function TrainList(props) {
key: 'operate',
dataIndex: 'operate',
fixed: 'right',
width: '16%',
width: '18%',
render: (val, record) => {
return (
<div className='operate'>
......@@ -383,28 +385,6 @@ function TrainList(props) {
let _columnKey;
let _order;
if (columnKey == 'cultureCustomerNum' && order === 'ascend') {
// 按学习人数升序排序
_columnKey = 'CUSTOMER_NUM';
_order = 'SORT_ASC';
}
if (columnKey == 'cultureCustomerNum' && order === 'descend') {
// 按学习人数降序排序
_columnKey = 'CUSTOMER_NUM';
_order = 'SORT_DESC';
}
if (columnKey == 'finishPercent' && order === 'ascend') {
// 按完成率升序排序
_columnKey = 'FINISH_PERCENT';
_order = 'SORT_ASC';
}
if (columnKey == 'finishPercent' && order === 'descend') {
// 按完成率降序排序
_columnKey = 'FINISH_PERCENT';
_order = 'SORT_DESC';
}
if (columnKey === 'created' && order === 'ascend') {
// 按创建时间升序排序
_columnKey = 'CREATED';
......@@ -429,13 +409,15 @@ function TrainList(props) {
const _query = {
...query,
sortMap: {},
sortMap: {
UPDATED: 'SORT_DESC',
},
};
_query.sortMap[_columnKey] = _order;
props.onChange(_query);
}
function handleCreatePlan() {
function handleCreateTask() {
window.RCHistory.push({
pathname: '/create-train-task?type=add',
});
......@@ -445,7 +427,7 @@ function TrainList(props) {
<div className='train-list-page'>
<div className='header-line'>
{(User.getUserRole() === 'CloudManager' || User.getUserRole() === 'StoreManager') && (
<Button type='primary' className='mr12' onClick={handleCreatePlan}>
<Button type='primary' className='mr12' onClick={handleCreateTask}>
新建培训任务
</Button>
)}
......@@ -475,7 +457,7 @@ function TrainList(props) {
onChange={handleChangeTable}
bordered
size='middle'
scroll={{ x: 1600 }}
scroll={{ x: 1400 }}
className='train-list-table'
renderEmpty={{
description: <span style={{ display: 'block', paddingBottom: 24 }}>暂无数据</span>,
......
......@@ -23,6 +23,7 @@
.train-task-name {
display: flex;
align-items: center;
cursor: pointer;
.train-cover {
width: 106px;
height: 60px;
......@@ -62,9 +63,12 @@
margin: 0 8px;
color: #bfbfbf;
}
.more-text {
color: #2966ff;
.more-operate {
cursor: pointer;
.more-text {
color: #2966ff;
cursor: pointer;
}
}
}
......
......@@ -3,10 +3,73 @@
display: flex;
height: 417px;
.left-list {
position: relative;
width: 50%;
margin-right: 24px;
padding: 0 0 12px 16px;
padding: 12px 0 12px 16px;
border: 1px solid #e8e8e8;
.ant-select-auto-complete .ant-select-clear {
font-size: 14px;
right: 15px;
}
.left-search-dropdown {
position: absolute;
padding: 16px;
background: #fff;
box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.08);
z-index: 999;
border-radius: 2px;
width: 274px;
max-height: 280px;
overflow-y: scroll;
.catalog-title {
font-size: 14px;
color: #666;
margin-bottom: 14px;
}
.search-result-item {
padding: 14px 0;
color: #333;
width: 220px;
display: flex;
justify-content: space-between;
.title-icon {
color: #999;
margin-right: 3px;
}
.search-result-item__left {
font-size: 14px;
}
.search-result-item__right {
font-size: 14px;
width: 84px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #999;
text-align: right;
}
}
.ant-select-dropdown-menu-item-group-title {
color: #666;
font-weight: bold;
}
.ant-select-item-option-grouped {
padding-left: 12px;
}
.empty-con {
text-align: center;
.empty-img {
width: 150px;
height: 150px;
}
.empty-text {
color: #666;
}
}
}
.data-body {
.ant-tabs-nav {
margin: 0 !important;
......@@ -18,7 +81,7 @@
.tree-con {
overflow-y: scroll;
overflow-x: hidden;
max-height: 367px;
max-height: 323px;
padding-right: 16px;
.ant-tree .ant-tree-treenode {
padding: 12px 0 !important;
......
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