Commit cff4cd0f by chenshu

feat:初始化

parent 553cbc40
......@@ -27,7 +27,7 @@ import ShowTips from "@/components/ShowTips";
import Breadcrumbs from "@/components/Breadcrumbs";
import SelectStudent from '../modal/select-student';
import SelectPrepareFileModal from '../../prepare-lesson/modal/SelectPrepareFileModal';
import PreviewGraphicsModal from '../modal/PreviewGraphicsModal';
import PreviewOfflineModal from './modal/PreviewOfflineModal';
import StoreService from "@/domains/store-domain/storeService";
import Service from '@/common/js/service';
import { randomString } from '@/domains/basic-domain/utils';
......@@ -304,24 +304,25 @@ class AddOfflineCourse extends React.Component {
const {
coverUrl,
courseName,
courseMedia,
startTime,
endTime,
introduce,
categoryName,
offlinePlace,
} = this.state;
const courseBasinInfo = {
const data = {
coverUrl,
courseName,
categoryName
}
const courseIntroInfo = {
courseMedia,
startTime,
endTime,
categoryName,
introduce,
offlinePlace,
}
const previewGraphicsModal = (
<PreviewGraphicsModal
courseBasicInfo={courseBasinInfo}
courseIntroInfo={courseIntroInfo}
<PreviewOfflineModal
data={data}
close={() => {
this.setState({
previewGraphicsModal: null
......@@ -749,10 +750,29 @@ class AddOfflineCourse extends React.Component {
<div className="course-catalog">
<span className="label"><span className="require">*</span>课程分类:</span>
{ (pageType === 'add') &&
<Cascader defaultValue={categoryName ? [categoryName] : undefined} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" suffixIcon={<span className="icon iconfont" style={{fontSize:'12px',color:'#BFBFBF'}}>&#xe835;</span>}/>
<Cascader
showSearch
defaultValue={categoryName ? [categoryName] : undefined}
options={courseCatalogList}
displayRender={ label => label.join('-')}
fieldNames={fieldNames}
onChange={this.catalogChange}
style={{ width: 240 }}
placeholder="请选择课程分类" suffixIcon={<span className="icon iconfont" style={{ fontSize: '12px', color: '#BFBFBF' }}>&#xe835;</span>}
/>
}
{ (pageType === 'edit' && categoryName ) &&
<Cascader defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" suffixIcon={<span className="icon iconfont" style={{fontSize:'12px',color:'#BFBFBF'}}>&#xe835;</span>}/>
<Cascader
showSearch
defaultValue={[categoryName]}
options={courseCatalogList}
displayRender={ label => label.join('-')}
fieldNames={fieldNames}
onChange={this.catalogChange}
style={{ width: 240 }}
placeholder="请选择课程分类"
suffixIcon={<span className="icon iconfont" style={{ fontSize: '12px', color: '#BFBFBF' }}>&#xe835;</span>}
/>
}
</div>
<div className="course-catalog">
......
import React from 'react';
import { Tooltip, Input, Radio, Table } from 'antd';
import moment from 'moment';
import _ from 'underscore';
import Breadcrumbs from "@/components/Breadcrumbs";
import PageControl from '@/components/PageControl';
import Service from "@/common/js/service";
import User from '@/common/js/user';
import './OfflineCourseData.less';
const { Search } = Input;
......@@ -11,19 +13,29 @@ const { Search } = Input;
export default class OfflineCourseData extends React.Component {
constructor(props) {
super(props);
const courseId = window.getParameterByName('id');
this.state = {
courseId: window.getParameterByName('id'),
courseId,
query: {
size: 10,
current: 1,
courseId,
storeId: User.getStoreId(),
joinInState: 'YES',
joinOutState: 'YES',
},
loading: false,
data: [],
total: 0,
courseName: '',
calendarTime: [],
currentIndex: 0,
fullJoin: 0,
totalJoin: 0,
fullJoinNum: 0,
joinInNum: 0,
joinNum: 0,
joinOutNum: 0,
}
}
......@@ -39,25 +51,52 @@ export default class OfflineCourseData extends React.Component {
const { result } = res;
this.setState({
courseName: result.courseName,
fullJoin: result.fullJoin,
totalJoin: result.totalJoin,
fullJoin: result.fullJoin || 0,
totalJoin: result.totalJoin || 0,
});
}
})
}
getOfflineCalendar = () => {
const { courseId } = this.state;
const { courseId, currentIndex } = this.state;
Service.Hades('public/customerHades/offlineDateList', { courseId }).then((res) => {
if (res.success) {
console.log(result.calendarTime, _.groupBy(result.calendarTime, item => moment(item).format('YYYY-MM')), 1111111)
const timeList = _.sortBy(_.pluck(res.result, 'date'));
const group = _.groupBy(timeList, item => moment(item).format('YYYY年M月'));
const calendarTime = _.map(group, (value, key) => ({ key, value }));
const currentDate = calendarTime[currentIndex].value[0];
this.setState({
calendarTime: _.pluck(res.result, 'date'),
})
calendarTime,
currentDate,
}, () => this.getDateDetail())
}
});
}
getDateDetail = (current = 1) => {
const { query, currentDate, courseId } = this.state;
if (currentDate !== query.date) {
Service.Hades('public/hades/getOfflineDateJoinStatistics', { courseId, date: currentDate }).then((res) => {
if (res.success) {
this.setState({
fullJoinNum: res.result.fullJoinNum || 0,
joinInNum: res.result.joinInNum || 0,
joinNum: res.result.joinNum || 0,
joinOutNum: res.result.joinOutNum || 0,
})
}
})
}
query.current = current;
query.date = currentDate;
Service.Hades('public/hades/getOfflineDateJoinPage', query).then((res) => {
if (res.success) {
this.setState({ data: res.result.records, total: res.result.total });
}
})
}
getColumns = () => {
const columns = [
{
......@@ -72,26 +111,26 @@ export default class OfflineCourseData extends React.Component {
},
{
title: "手机号",
key: "teacher",
dataIndex: "teacher",
key: "phone",
dataIndex: "phone",
render: (val, item) => {
return (
<div>{item.teacherName}</div>
<div>{item.phone}</div>
)
},
},
{
title: '报名时间',
key: 'updated',
dataIndex: 'updated',
key: 'joinTime',
dataIndex: 'joinTime',
render: (val, item) => {
return item.startTimeApply ? `${formatDate('MM-DD H:i', item.startTimeApply)} ~ ${formatDate('MM-DD H:i', item.endTimeApply)}` : '-'
return <div>{formatDate('YYYY-MM-DD H:i', item.joinTime)}</div>
}
},
{
title: '签到时间',
key: 'signIn',
dataIndex: 'signIn',
key: 'joinInTime',
dataIndex: 'joinInTime',
sorter: true,
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val)
......@@ -99,8 +138,8 @@ export default class OfflineCourseData extends React.Component {
},
{
title: '签退时间',
key: 'signOut',
dataIndex: 'signOut',
key: 'joinOutTime',
dataIndex: 'joinOutTime',
sorter: true,
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val)
......@@ -123,7 +162,16 @@ export default class OfflineCourseData extends React.Component {
courseName,
fullJoin,
totalJoin,
calendarTime,
currentIndex,
currentDate,
fullJoinNum,
joinInNum,
joinNum,
joinOutNum,
} = this.state;
const calendarLength = calendarTime.length;
const dateList = (calendarTime[currentIndex] || {}).value || [];
return (
<div className="page offline-course-data">
<Breadcrumbs
......@@ -143,29 +191,59 @@ export default class OfflineCourseData extends React.Component {
<div className="left-box">
<div className="left-title">上课日期</div>
<div className="left-calendar">
<div className="icon-box">
<div
className="icon-box"
onClick={() => {
const index = currentIndex - 1;
if (index >= 0 && index < calendarLength) {
this.setState({ currentIndex: index, currentDate: calendarTime[index][0] }, () => {
this.getDateDetail();
});
}
}}
>
<span className="icon iconfont">&#xe79c;</span>
</div>
<div className="calendar-text">2021年5月</div>
<div className="icon-box">
<div className="calendar-text">{(calendarTime[currentIndex] || {}).key}</div>
<div
className="icon-box"
onClick={() => {
const index = currentIndex + 1;
if (index >= 0 && index < calendarLength) {
this.setState({ currentIndex: index, currentDate: calendarTime[index][0] }, () => {
this.getDateDetail();
});
}
}}
>
<span className="icon iconfont">&#xe79b;</span>
</div>
</div>
<div className="date-list">
<div className="date-item">5月1日(周五)</div>
{dateList.map(item => (
<div
className={`date-item${item === currentDate ? ' selected' : ''}`}
key={item}
onClick={() => {
this.setState({ currentDate: item }, () => {
this.getDateDetail();
})
}}
>{window.formatDate('MM月DD日(WW)', item)}</div>
))}
</div>
</div>
<div className="right-box">
<div className="selected-date">5月1日</div>
<div className="detail-data">
<span className="icon iconfont">&#xe89f;</span>
<span className="data-text">报名人数:100</span>
<span className="data-text">报名人数:{joinNum}</span>
<span className="icon iconfont">&#xe89e;</span>
<span className="data-text">完成考勤数<Tooltip title="当日在规定时间内完成签到和签退的用户数"><span className="icon iconfont">&#xe7c4;</span></Tooltip>99</span>
<span className="data-text">完成考勤数<Tooltip title="当日在规定时间内完成签到和签退的用户数"><span className="icon iconfont">&#xe7c4;</span></Tooltip>{fullJoinNum}</span>
<span className="icon iconfont">&#xe8a0;</span>
<span className="data-text">签到人数:99</span>
<span className="data-text">签到人数:{joinInNum}</span>
<span className="icon iconfont">&#xe89d;</span>
<span className="data-text">签退人数:99</span>
<span className="data-text">签退人数:{joinOutNum}</span>
</div>
<div className="detail-filter">
<Search
......@@ -173,11 +251,28 @@ export default class OfflineCourseData extends React.Component {
placeholder="搜索用户姓名/手机号"
style={{ width: 200, marginRight: 24 }}
enterButton={<span className="icon iconfont">&#xe832;</span>}
onSearch={(value) => {
const _query = { ...query };
if (value) {
const isPhone = (value || "").match(/^\d+$/);
const name = isPhone ? "storeCustomerPhone" : "storeCustomerName";
_query.storeCustomerName = "";
_query.storeCustomerPhone = "";
_query[name] = value;
} else {
_query.storeCustomerName = "";
_query.storeCustomerPhone = "";
}
this.setState({ query: _query }, () => this.getDateDetail());
}}
/>
<div className="filter-box">
<span className="label">签到情况:</span>
<Radio.Group
defaultValue="YES"
value={query.joinInState}
onChange={(e) => {
this.setState({ query: { ...query, joinInState: e.target.value } }, () => this.getDateDetail());
}}
>
<Radio value="YES">已签到</Radio>
<Radio value="NO">未签到</Radio>
......@@ -186,7 +281,10 @@ export default class OfflineCourseData extends React.Component {
<div className="filter-box">
<span className="label">签退情况:</span>
<Radio.Group
defaultValue="YES"
value={query.joinOutState}
onChange={(e) => {
this.setState({ query: { ...query, joinOutState: e.target.value } }, () => this.getDateDetail());
}}
>
<Radio value="YES">已签退</Radio>
<Radio value="NO">未签退</Radio>
......@@ -208,9 +306,7 @@ export default class OfflineCourseData extends React.Component {
pageSize={query.size}
total={total}
toPage={(page) => {
const queryStates = _.clone(query);
queryStates.current = page;
this.setState({ query: queryStates });
this.getDateDetail(page);
}}
/>
</div>
......
......@@ -84,6 +84,9 @@
background: #F3F6FA;
cursor: pointer;
}
&.selected {
background: rgba(255, 183, 20, 0.06);
}
}
}
}
......
import React from 'react';
import { Button, Modal, Select } from 'antd';
import './PreviewModal.less';
const { Option } = Select;
export default class PreviewModal extends React.Component {
constructor(props) {
super(props);
}
render() {
const { visible, onCancel } = this.props;
return (
<Modal
title="预览"
width={680}
visible={visible}
footer={null}
onCancel={() => onCancel()}
className="offline-preview-modal"
>
<div className="image-box">
<img src="https://image.xiaomaiketang.com/xm/xYSpX2y6ri.png" className="image" />
</div>
</Modal>
)
}
}
\ No newline at end of file
.offline-preview-modal {
}
\ No newline at end of file
import React from 'react';
import { Modal } from 'antd';
import './PreviewOfflineModal.less';
const defaultCoverUrl = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png';
class PreviewOfflineModal extends React.Component {
constructor(props) {
super(props);
}
render() {
const { data } = this.props;
const { coverUrl, courseName, categoryName, introduce } = data;
return (
<Modal
title="预览"
visible={true}
width={680}
onCancel={this.props.close}
footer={null}
maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
className="preview-live-graphics-modal"
>
<div className="container__wrap">
<div className="container">
<div className="container__header">
<img src={coverUrl || defaultCoverUrl} className="course-cover" />
</div>
<div className="container__body">
<div className="title__name">{courseName}</div>
<div className="title__categery">课程分类:{categoryName}</div>
<div className="title__categery">上课时间:{categoryName}</div>
<div className="title__categery">上课地点{categoryName}</div>
</div>
<div className="container__introduction">
<div className="title">线下课简介</div>
<div className="container__introduction__list editor-box">
<div
className="intro-item text"
dangerouslySetInnerHTML={{
__html: introduce
}}
/>
</div>
</div>
</div>
</div>
</Modal>
)
}
}
export default PreviewOfflineModal;
.preview-live-graphics-modal {
.ant-modal-body {
background-image: url('https://image.xiaomaiketang.com/xm/xZWdziTCAf.png');
background-size: 100% 100%;
}
.container__wrap {
width: 340px;
height: 618px;
padding: 67px 46px 48px 47px;
margin: auto;
background-image: url('https://image.xiaomaiketang.com/xm/DHMzHiGc2E.png');
background-size: 100% 100%;
}
.container {
overflow: scroll;
height: 100%;;
.course-cover, .course-url {
width: 100%;
height: 141px;
background: #000;
}
&__body {
background-color: #FFF;
padding: 7px 0 11px 0;;
.title__name {
color: #333333;
font-weight: 500;
}
.title__categery {
font-size: 12px;
color: #999999;
}
}
&__introduction {
margin-top: 10px;
padding: 12px 0;
position: relative;
&::after {
content: '';
position: absolute;
width: 241px;
top: -10px;
height: 10px;
background: #F4F6FA;
}
.title {
height: 24px;
display: flex;
align-items: center;
font-size: 12px;
color: #333333;
padding: 0 10px;
border-bottom: 1px solid #E8E8E8;
.title-word {
position: relative;
margin-right: 15px;
cursor: pointer;
}
.selected {
color: #FFB714;
&::after {
content: '';
position: absolute;
bottom: -4px;
width: 20px;
height: 1px;
background: #FFB714;
left: 50%;
transform: translateX(-50%);
}
}
}
&__list {
margin-top: 12px;
.intro-item:not(:first-child) {
margin-top: 13px;
}
color: #666;
p {
font-size: 12px;
}
img {
max-width: 100%;
}
}
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment