1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915 |
- import React, { Component } from 'react';
- import { Link } from 'react-router-dom';
- import './index.less';
- import { Icon, Popover } from 'antd';
- import FileUpload from '@src/components/FileUpload';
- import Page from '@src/containers/Page';
- import Assets from '@src/components/Assets';
- import { asyncSMessage } from '@src/services/AsyncTools';
- import { formatDate, formatSeconds, formatPercent, getMap } from '@src/services/Tools';
- import UserLayout from '../../../layouts/User';
- import Button from '../../../components/Button';
- import ProgressText from '../../../components/ProgressText';
- import IconButton from '../../../components/IconButton';
- import { Icon as GIcon } from '../../../components/Icon';
- import menu from '../index';
- import Tabs from '../../../components/Tabs';
- import UserTable from '../../../components/UserTable';
- import More from '../../../components/More';
- import Modal from '../../../components/Modal';
- import DatePlane from '../../../components/Date';
- import Note from '../../../components/Note';
- import { FinishModal, CommentModal, CourseNoteModal } from '../../../components/OtherModal';
- import { My } from '../../../stores/my';
- import { User } from '../../../stores/user';
- import { Question } from '../../../stores/question';
- import { Order } from '../../../stores/order';
- import { Common } from '../../../stores/common';
- export default class extends Page {
- initState() {
- return {
- tab: 'online',
- status: 'all',
- };
- }
- formatRecord(row) {
- if (row.useEndTime) {
- if (row.isSuspend && !row.restoreTime) {
- row.status = 'suspend';
- } else if (new Date(row.useEndTime).getTime() < new Date().getTime()) {
- row.status = 'end';
- } else {
- row.status = 'ing';
- }
- } else {
- row.status = 'not';
- }
- row.paperMap = {};
- row.appointmentPaperMap = {};
- if (row.papers) {
- row.papers.forEach(paper => {
- if (paper.courseNo) row.paperMap[paper.courseNo] = paper;
- if (paper.appointment) row.appointmentPaperMap[paper.appointment] = paper;
- });
- }
- row.progressMap = {};
- if (row.progress) {
- row.progress.forEach(progress => {
- row.progressMap[progress.courseNoId] = progress;
- });
- }
- row.recordMap = {};
- if (row.records) {
- row.records.forEach(record => {
- row.recordMap[record.courseNoId] = record;
- });
- }
- row.courseNoMap = {};
- row.courseTime = 0;
- if (row.courseNos) {
- row.courseNos.forEach(no => {
- row.courseNoMap[no.id] = no;
- row.courseTime += no.time;
- no.paper = row.paperMap[no.no];
- no.progress = row.progressMap[no.id];
- no.record = row.recordMap[no.id];
- });
- }
- if (row.currentNo) {
- row.currentCourseNo = row.courseNoMap[row.currentNo];
- } else {
- row.currentNo = 0;
- }
- // 如果已经最新预约结束,则添加一个空记录作为最新预约
- if (row.appointments) {
- row.appointments.forEach(r => {
- r.paper = row.appointmentPaperMap[r.id];
- r.noteList = (row.comments || []).filter(c => c.type === 'note' && c.appointmentId === r.id);
- r.supplyList = (row.comments || []).filter(c => c.type === 'supply' && c.appointmentId === r.id);
- });
- // 是否是最后一课时,是否过预约时间
- const last = row.appointments.length - 1;
- const appointment = row.appointments[last];
- if (appointment) {
- if (new Date(appointment.endTime).getTime() < new Date().getTime()) {
- // row.status = 'end';
- if (row.number !== row.appointments.length) {
- row.appointments.push([{}]);
- }
- }
- }
- }
- row.days = new Date(row.userEndTime);
- return row;
- }
- initData() {
- const data = Object.assign(this.state, this.state.search);
- data.filterMap = this.state.search;
- if (data.order) {
- data.sortMap = { [data.order]: data.direction };
- }
- this.setState(data);
- let isUsed = null;
- let isEnd = null;
- switch (data.status) {
- case 'learning':
- isUsed = true;
- isEnd = false;
- break;
- case 'end':
- isUsed = true;
- isEnd = true;
- break;
- case 'nouse':
- isUsed = false;
- isEnd = false;
- break;
- case 'all':
- default:
- }
- My.listCourse(Object.assign({ courseModule: data.tab }, this.state.search, { isUsed, isEnd })).then(result => {
- result.list = result.list.map(row => {
- return this.formatRecord(row);
- });
- this.setState({ list: result.list, total: result.total, page: data.page });
- });
- }
- onAction() { }
- onTabChange(tab) {
- const data = { tab };
- this.refreshQuery(data);
- }
- onStatusChange(status) {
- this.search({ status });
- }
- openTime(record) {
- if (record.courseTimeMap) {
- this.setState({ data: record, showTime: true });
- return;
- }
- My.timeCourse(record.id).then(result => {
- const courseMap = {};
- const previewMap = {};
- const stopMap = {};
- result.forEach(row => {
- const date = formatDate(row.day, 'YYYY-MM-DD');
- if (row.type === 'stop') {
- stopMap[date] = true;
- } else if (row.type === 'preview') {
- previewMap[date] = true;
- } else if (row.type === 'course') {
- courseMap[date] = true;
- }
- });
- record.courseTimeMap = courseMap;
- record.previewTimeMap = previewMap;
- record.stopTimeMap = stopMap;
- this.setState({ data: record, showTime: true });
- });
- }
- refreshDetail(recordId) {
- My.detailCourse(recordId).then(result => {
- let { list } = this.state;
- list = list.map(row => {
- if (row.id === recordId) return this.formatRecord(result);
- return row;
- });
- this.setState({ list });
- });
- }
- refreshNote(recordId) {
- let { list } = this.state;
- const [record] = list.filter(row => row.id === recordId);
- if (!record) return Promise.reject(new Error('记录错误'));
- return My.listCourseNote({ courseId: record.productId, page: 1, size: record.courseNos.length })
- .then((result) => {
- list = list.map(row => {
- if (row.id === recordId) {
- row.noteMap = getMap(result.list, 'courseNoId');
- }
- return row;
- });
- this.setState({ list });
- });
- }
- suspend() {
- const { suspend } = this.state;
- My.suspendCourse(suspend.id)
- .then(() => {
- asyncSMessage('停课成功');
- this.setState({ showSuspend: false });
- this.refreshDetail(suspend.id);
- })
- .catch(err => {
- asyncSMessage(err.message, 'error');
- });
- }
- restore() {
- const { restore } = this.state;
- My.restoreCourse(restore.id)
- .then(() => {
- asyncSMessage('恢复成功');
- this.setState({ showRestore: false });
- this.refreshDetail(restore.id);
- })
- .catch(err => {
- asyncSMessage(err.message, 'error');
- });
- }
- submitAppointmentComment(data, type) {
- data.type = type;
- if (data.id) {
- My.editAppointmentComment(data).then(() => {
- this.refreshDetail(data.recordId);
- });
- } else {
- My.addAppointmentComment(data).then(() => {
- this.refreshDetail(data.recordId);
- });
- }
- }
- deleteAppointmentComment(row) {
- My.delAppointmentComment(row.id).then(() => {
- this.refreshDetail(row.recordId);
- });
- }
- submitQuestionFile(data) {
- My.uploadAppointmentQuestion(data).then(() => {
- this.refreshDetail(data.recordId);
- });
- }
- setCCTalkName(recordId, cctalkname) {
- My.setCCTalkName(recordId, cctalkname).then(() => {
- this.refreshDetail(recordId);
- });
- }
- open(recordId) {
- Order.useRecord(recordId).then(() => {
- this.refreshDetail(recordId);
- }).catch((err) => {
- asyncSMessage(err.message, 'error');
- });
- }
- closeCommentTips(recordId) {
- My.courseCommentTips(recordId);
- }
- uploadNote(file) {
- const { note = {} } = this.state;
- Common.uploadImage(file).then(result => {
- note.file = result.url;
- note.name = file.name;
- this.setState({ note });
- });
- }
- uploadSupply(file) {
- const { supply = {} } = this.state;
- Common.uploadImage(file).then(result => {
- supply.file = result.url;
- supply.name = file.name;
- this.setState({ supply });
- });
- }
- renderView() {
- const { config } = this.props;
- return <UserLayout active={config.key} menu={menu} center={this.renderDetail()} />;
- }
- renderDetail() {
- const {
- tab,
- status,
- showTips,
- showTime,
- showSuspend,
- showRestore,
- showUploadNote,
- showUploadSupply,
- showSupply,
- showNote,
- showCourseNote,
- showComment,
- showFinish,
- comment = {},
- data = {},
- note = {},
- supply = {},
- appointment = {},
- } = this.state;
- return (
- <div className="detail-layout">
- <div hidden={!showTips} className="tip">
- <div className="text">理清备考思路,避开常见误区,让学习的每一分钟发光发热!</div>
- <a href="" target="_blank">
- 去填写 >
- </a>
- <Icon type="close-circle" theme="filled" onClick={() => this.setState({ showTips: false })} />
- </div>
- <Tabs
- type="division"
- theme="theme"
- size="small"
- space={2.5}
- width={100}
- active={tab}
- tabs={[{ key: 'online', title: '在线课程' }, { key: 'vs', title: '1V1私教' }]}
- onChange={key => this.onTabChange(key)}
- />
- <Tabs
- type="tag"
- theme="white"
- size="small"
- space={5}
- width={54}
- active={status}
- tabs={[
- { key: 'all', title: '全部' },
- { key: 'nouse', title: '未开通' },
- { key: 'learning', title: '学习中' },
- { key: 'end', title: '已结束' },
- ]}
- onChange={key => this.onStatusChange(key)}
- />
- {this[`renderTab${tab}`]()}
- <Modal
- show={showTime}
- className="clock-modal"
- title="打卡表"
- width={460}
- onClose={() => this.setState({ showTime: false })}
- >
- <div>
- <div className="d-i-b w-3">
- <div className="t-2 t-s-14">听课频率</div>
- <div className="t-4 t-s-18">{data.currentNo ? parseInt(data.totalDays / data.currentNo, 10) : 0}天/课时</div>
- </div>
- <div className="d-i-b w-3">
- <div className="t-2 t-s-14">作业完成度</div>
- <div className="t-4 t-s-18">{data.previewProgress || 0}%</div>
- </div>
- </div>
- <div className="b-b m-t-1 m-b-1" />
- <div className="m-b-1">
- <div className="tag d-i-b t-s-16">
- <i style={{ background: '#6865FD' }} />
- 听课
- </div>
- <div className="tag d-i-b t-s-16">
- <i style={{ background: '#4299FF' }} />
- 预习
- </div>
- <div className="tag d-i-b t-s-16">
- <i style={{ background: '#E7E7E7' }} />
- 停课
- </div>
- </div>
- <div style={{ position: 'relative' }}>
- <DatePlane
- hideInput
- show={showTime}
- onChange={() => { }}
- disabledDate={current => {
- const date = current.format('YYYY-MM-DD');
- return data.stopTimeMap[date];
- }}
- dateRender={current => {
- const date = current.format('YYYY-MM-DD');
- return (
- <div className="ant-calendar-date">
- {current.get('date')}
- {data.courseTimeMap[date] && <i className="s1" style={{ background: '#6865FD' }} />}
- {data.previewTimeMap[date] && <i className="s2" style={{ background: '#4299FF' }} />}
- </div>
- );
- }}
- checkRefresh={(date, refresh) => {
- setTimeout(() => {
- refresh();
- }, 2000);
- return true;
- }}
- /></div>
- <div className="t-2 t-s-12">*听课频率≤2天/课时,作业完成度≥90%,课程有效期可延长7-10天。</div>
- </Modal>
- <Modal
- show={showSuspend}
- title="申请停课"
- width={630}
- confirmText="立即停课"
- onConfirm={() => this.suspend()}
- onCancel={() => this.setState({ showSuspend: false })}
- >
- <div className="t-2 t-s-18">最长停课周期为1个月,到期后系统自动恢复至“学习中”状态。</div>
- <div className="t-2 t-s-18">每门课程只有一次申请机会,是否需要停课?</div>
- <div style={{ bottom: 20, left: 0 }} className="p-a t-3 t-s-14">
- *停课不影响听课频率的计算;
- </div>
- <div style={{ bottom: 0, left: 0 }} className="p-a t-3 t-s-14">
- {' '}
- 停课期间可随时恢复学习。
- </div>
- </Modal>
- <Modal
- show={showRestore}
- title="恢复学习"
- width={630}
- confirmText="立即恢复"
- onConfirm={() => this.restore()}
- onCancel={() => this.setState({ showRestore: false })}
- >
- <div className="t-2 t-s-18">恢复学习后,本课程的停课功能将无法使用。是否恢复学习?</div>
- </Modal>
- <Modal
- show={showUploadNote}
- title="上传笔记"
- width={630}
- confirmText="提交"
- onConfirm={() => this.submitAppointmentComment(note, 'note')}
- onCancel={() => this.setState({ showUploadNote: false, note: {} })}
- >
- <textarea
- className="b-c-1 w-10 p-10 m-b-1"
- rows={6}
- value={note.content}
- placeholder="请输入留言内容。"
- onChange={e => {
- note.content = e.target.value;
- this.setState({ note });
- }}
- />
- <div className={`t-c drag-upload ${this.state.draging ? 'draging' : ''}`}>
- <Button theme="file">上传文件</Button>
- <span className="m-l-1 t-3 t-s-14">
- {note.file ? `上传文件:${note.name} 成功` : '支持 docx, xls, PDF, rar, zip, PNG, JPG 等类型的文件'}
- </span>
- <div className="fixed">
- <span className="f-w-b t-s-18">放开文件立刻上传</span>
- </div>
- <FileUpload
- type="none"
- onDragEnter={() => this.setState({ draging: true })}
- onDragLeave={() => this.setState({ draging: false })}
- onUpload={({ file }) => {
- Common.upload(file).then(result => {
- note.file = result.url;
- note.name = file.name;
- this.setState({ note });
- });
- }}
- />
- </div>
- <div className="b-b m-t-2" />
- </Modal>
- <Modal
- show={showNote}
- title="课后笔记"
- width={500}
- height={500}
- onClose={() => this.setState({ showNote: false })}
- >
- {appointment.noteList &&
- appointment.noteList.map(row => {
- return <Note user={this.props.user} teacher={data.teacher} data={row} />;
- })}
- </Modal>
- <Modal
- show={showSupply}
- title="课后留言"
- width={500}
- height={500}
- onClose={() => this.setState({ showSupply: false })}
- >
- {appointment.supplyList &&
- appointment.supplyList.map(row => {
- return <Note user={this.props.user} teacher={data.teacher} data={row} />;
- })}
- </Modal>
- <Modal
- show={showUploadSupply}
- title="上传留言"
- width={630}
- confirmText="提交"
- onConfirm={() => this.submitAppointmentComment(supply, 'supply')}
- onCancel={() => this.setState({ showUploadSupply: false, supply: {} })}
- >
- <textarea
- className="b-c-1 w-10 p-10 m-b-1"
- rows={6}
- value={supply.content}
- placeholder="请输入留言内容。"
- onChange={e => {
- supply.content = e.target.value;
- this.setState({ supply });
- }}
- />
- <div className={`t-c drag-upload ${this.state.draging ? 'draging' : ''}`}>
- <Button theme="file">上传文件</Button>
- <span className="m-l-1 t-3 t-s-14">
- {supply.file ? `上传文件:${supply.name} 成功` : '支持 docx, xls, PDF, rar, zip, PNG, JPG 等类型的文件'}
- </span>
- <div className="fixed">
- <span className="f-w-b t-s-18">放开文件立刻上传</span>
- </div>
- <FileUpload
- type="none"
- onDragEnter={() => this.setState({ draging: true })}
- onDragLeave={() => this.setState({ draging: false })}
- onUpload={({ file }) => {
- Common.upload(file).then(result => {
- supply.file = result.url;
- supply.name = file.name;
- this.setState({ supply });
- });
- }}
- />
- </div>
- <div className="b-b m-t-2" />
- </Modal>
- <CommentModal
- show={showComment}
- defaultData={comment}
- onConfirm={() => this.setState({ showComment: false, comment: {}, showFinish: true })}
- onCancel={() => this.setState({ showComment: false, comment: {} })}
- onClose={() => this.setState({ showComment: false, comment: {} })}
- />
- <FinishModal
- show={showFinish}
- onConfirm={() => this.setState({ showFinish: false })}
- />
- <CourseNoteModal getContainer={() => document.body} show={showCourseNote} defaultData={note} course={data.course} courseNos={data.courseNos} noteMap={data.noteMap} onConfirm={() => {
- this.setState({ showCourseNote: false });
- this.refreshNote();
- }} onCancel={() => this.setState({ showCourseNote: false })} />
- </div>
- );
- }
- renderTabonline() {
- const { list = [] } = this.state;
- return list.map(item => {
- return (
- <CourseOnline
- data={item}
- user={this.props.user}
- refreshDetail={recordId => {
- this.refreshDetail(recordId);
- }}
- onRestore={() => {
- this.setState({ showRestore: true, restore: item });
- }}
- onSuspend={() => {
- this.setState({ showSuspend: true, suspend: item });
- }}
- onTime={() => {
- this.openTime(item);
- }}
- onComment={() => {
- this.setState({ showComment: true, comment: { channel: 'course-video', position: item.course.id } });
- }}
- onNote={(courseNo) => {
- let handler = Promise.resolve();
- if (!item.noteMap) {
- handler = this.refreshNote(item.id);
- }
- handler.then(() => {
- this.setState({ showCourseNote: true, note: item.noteMap[courseNo.id], data: item });
- });
- }}
- closeCommentTips={() => this.closeCommentTips(item.id)}
- />
- );
- });
- }
- renderTabvs() {
- const { list = [] } = this.state;
- return list.map(item => {
- return (
- <CourseVs
- data={item}
- user={this.props.user}
- refreshDetail={recordId => {
- this.refreshDetail(recordId);
- }}
- onRestore={() => {
- this.setState({ showRestore: true, restore: item });
- }}
- onSuspend={() => {
- this.setState({ showSuspend: true, suspend: item });
- }}
- onComment={() => {
- this.setState({ showComment: true, comment: { channel: 'course-vs', position: item.course.id } });
- }}
- closeCommentTips={() => this.closeCommentTips(item.id)}
- onUploadNote={(appointment, row) => {
- this.setState({ showUploadNote: true, appointment, data: item, note: row || {} });
- }}
- onUploadSupply={(appointment, row) => {
- this.setState({ showUploadSupply: true, appointment, data: item, supply: row || {} });
- }}
- onDeleteNote={(appointment, row) => this.deleteAppointmentComment(row)}
- onDeleteSupply={(appointment, row) => this.deleteAppointmentComment(row)}
- onNote={appointment => this.setState({ showNote: true, appointment, data: item })}
- onSupply={appointment => this.setState({ showSupply: true, appointment, data: item })}
- onUploadQuestion={(appointment, file, name) => {
- this.submitQuestionFile({
- id: appointment.id,
- recordId: appointment.recordId,
- questionFile: file,
- questionFileName: name,
- });
- }}
- setCCTalkName={(appointment, cctalkName) => this.setCCTalkName(appointment.recordId, cctalkName)}
- />
- );
- });
- }
- }
- class CourseOnline extends Component {
- constructor(props) {
- super(props);
- this.columns = [
- {
- title: '学习内容',
- key: 'title',
- render: (text, record) => {
- return <a href={`/course/detail/${record.courseId}?no=${record.no}`} target="_blank">课时 {record.no}: {text}</a>;
- },
- },
- {
- title: '预习作业',
- key: 'paper',
- render: (text, record) => {
- const { paper = {} } = record;
- const progress = paper.report ? formatPercent(paper.report.userNumber, paper.report.questionNumber) : 0;
- const times = paper.paper ? paper.paper.resetTimes : 0;
- return (
- <div>
- <div className="v-a-m d-i-b">
- <ProgressText width={50} size="small" times={times} progress={progress} unit="次" />
- </div>
- {!paper.report && (
- <IconButton
- className="m-l-2"
- type="start"
- tip="Start"
- onClick={() => {
- User.needLogin().then(() => {
- Question.startLink('preview', paper);
- });
- }}
- />
- )}
- {paper.report && !paper.report.isFinish && (
- <IconButton
- className="m-l-2"
- type="continue"
- tip="Continue"
- onClick={() => {
- User.needLogin().then(() => {
- Question.continueLink('preview', paper);
- });
- }}
- />
- )}
- {paper.report && (
- <IconButton
- className="m-l-2"
- type="restart"
- tip="Restart"
- onClick={() => {
- User.needLogin().then(() => {
- Question.restart('preview', paper);
- });
- }}
- />
- )}
- {paper.report && !!paper.report.isFinish && (
- <IconButton
- className="m-l-5"
- type="report"
- tip="Report"
- onClick={() => {
- User.needLogin().then(() => {
- Question.reportLink('preview', paper);
- });
- }}
- />
- )}
- </div>
- );
- },
- },
- {
- title: '进度',
- key: 'progress',
- width: 70,
- render: (text, record) => {
- const { progress } = record;
- return progress ? `${progress.progress}%` : '0%';
- },
- },
- {
- title: '最近学习',
- key: 'lastTime',
- width: 105,
- render: (text, rr) => {
- const { record } = rr;
- return record && formatDate(record.createTime, 'YYYY-MM-DD HH:mm:ss');
- },
- },
- {
- title: '笔记',
- key: 'note',
- width: 70,
- render: (text, record) => {
- return <GIcon name="note" active={record.note} onClick={() => {
- this.onNote(record);
- }} />;
- },
- },
- {
- title: '问答',
- key: 'ask',
- width: 70,
- render: (text, record) => {
- return (
- <Link to={`/course/answer/${record.courseId}?tab=my&courseNoId=${record.id}`}>{`${record.answerNumber ||
- 0}/${record.askNumber || 0}`}</Link>
- );
- },
- },
- ];
- this.state = { open: props.data.status === 'ing' };
- }
- open(recordId) {
- Order.useRecord(recordId).then(() => {
- this.props.refreshDetail(recordId);
- }).catch((err) => {
- asyncSMessage(err.message, 'error');
- });
- }
- onNote(record) {
- const { onNote } = this.props;
- onNote(record);
- }
- render() {
- const { data = {} } = this.props;
- switch (data.status) {
- case 'ing':
- return this.renderIng();
- case 'not':
- return this.renderNot();
- case 'end':
- return this.renderEnd();
- case 'suspend':
- return this.renderSuspend();
- default:
- return <div />;
- }
- }
- renderIng() {
- const { data, onTime, onComment, onSuspend } = this.props;
- const { open } = this.state;
- return (
- <div className="course-item ing">
- <div className="title">
- <div className="tag">学习中</div>
- <div className="text">{data.course.title}</div>
- <div className="right">
- <More
- menu={[{ label: '评价', key: 'comment' }, { label: '停课', key: 'suspend' }]}
- onClick={value => {
- const { key } = value;
- if (key === 'comment') {
- onComment();
- } else if (key === 'suspend') {
- onSuspend();
- }
- }}
- />
- </div>
- </div>
- {data.currentCourseNo && (
- <div
- className="continue"
- onClick={() => {
- linkTo(`/course/detail/${data.course.id}`);
- }}
- >
- <Assets name="notice" />
- 继续学习:课时 {data.currentNo}:{data.currentCourseNo.title}
- </div>
- )}
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.course.teacher}</div>
- <div className="t1">有效期</div>
- <div className="t2">{data.useExpireDays}Days</div>
- </div>
- </div>
- <div className="right">
- <div className="item" onClick={() => {
- openLink(`/course/detail/${data.course.id}?no=${data.currentNo}`);
- }}>
- <GIcon name="speed-block" active noHover />
- <div className="text">
- <span>{data.currentNo}</span>/{(data.courseNos || []).length}
- </div>
- </div>
- <div className="item" onClick={() => {
- openLink(`/course/answer/${data.course.id}`);
- }}>
- <GIcon name="question-block" active noHover />
- <div className="text">
- <span>{data.answerNumber}</span>/{data.askNumber}
- </div>
- </div>
- <div className="item" onClick={() => onTime()}>
- <GIcon name="clockin-block" active noHover />
- <div className="text">
- <span>{formatSeconds(data.totalTime)}</span> {data.previewProgress || 0}%
- </div>
- </div>
- <div className="item" onClick={() => {
- openLink(`/course/note/${data.course.id}`);
- }}>
- <GIcon name="note-block" active noHover />
- <div className="text">{data.noteNumber}</div>
- </div>
- </div>
- <div className="open">
- <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
- </div>
- </div>
- {open && this.renderTable()}
- </div>
- );
- }
- renderNot() {
- const { data } = this.props;
- return (
- <div className="course-item not">
- <div className="title">
- <div className="tag">未开通</div>
- <div className="text">{data.course.title}</div>
- </div>
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.course.teacher}</div>
- <div>
- <div className="d-i-b m-r-2">
- <div className="t-2">课时</div>
- <div className="t-1 t-s-16">{(data.courseNos || []).length}</div>
- </div>
- <div className="d-i-b">
- <div className="t-2">总时长</div>
- <div className="t-1 t-s-16">{formatSeconds(data.time || data.courseTime)}</div>
- </div>
- </div>
- </div>
- </div>
- <div className="right t-c">
- <div className="text">请于 {formatDate(data.endTime, 'YYYY-MM-DD')} 前开通</div>
- <Button
- size="lager"
- radius
- onClick={() => {
- this.open(data.id);
- }}
- >
- 立即开通
- </Button>
- </div>
- </div>
- </div>
- );
- }
- renderEnd() {
- const { data, onTime, onComment } = this.props;
- const { open } = this.state;
- return (
- <div className="course-item end">
- <div className="title">
- <div className="tag">已结束</div>
- <div className="text">{data.course.title}</div>
- <div className="right">
- <More
- menu={[{ label: '评价', key: 'comment' }]}
- onClick={value => {
- const { key } = value;
- if (key === 'comment') {
- onComment();
- }
- }}
- />
- </div>
- </div>
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.course.teacher}</div>
- <div className="t1">有效期</div>
- <div className="t-s-12">
- {formatDate(data.useStartTime, 'YYYY-MM-DD')}
- <br />至{formatDate(data.useEndTime, 'YYYY-MM-DD')}
- </div>
- </div>
- </div>
- <div className="right">
- <div className="item">
- <GIcon name="question-block" active noHover />
- <div className="text">
- <span>{data.answerNumber}</span>/{data.askNumber}
- </div>
- </div>
- <div className="item" onClick={() => onTime()}>
- <GIcon name="clockin-block" active noHover />
- <div className="text">
- <span>{formatSeconds(data.totalTime)}</span> {data.previewProgress || 0}%
- </div>
- </div>
- <div className="item">
- <GIcon name="note-block" active noHover />
- <div className="text">{data.noteNumber}</div>
- </div>
- {data.courseAward > 0 && (
- <div className="item">
- <GIcon name="gift-block" active />
- <div className="text">赠送{data.courseAward}天</div>
- </div>
- )}
- </div>
- <div className="open">
- <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
- </div>
- </div>
- {open && this.renderTable()}
- </div>
- );
- }
- renderSuspend() {
- const { data, onTime, onRestore, onComment } = this.props;
- const { open } = this.state;
- return (
- <div className="course-item end">
- <div className="title">
- <div className="tag">已停课</div>
- <div className="text">
- {data.course.title}
- <Button size="small" radius onClick={() => onRestore()}>
- 恢复上课
- </Button>
- </div>
- <div className="t-s-12">
- <span className="t-3">申请时间:</span>
- <span className="t-2 m-r-1">{formatDate(data.suspendTime, 'YYYY-MM-DD HH:mm:ss')}</span>
- <span className="t-3">已停课:</span>
- <span>{parseInt((new Date().getTime() - new Date(data.suspendTime).getTime()) / 86400000, 10)}Days/30</span>
- </div>
- <div className="right">
- <More
- menu={[{ label: '评价', key: 'comment' }]}
- onClick={value => {
- const { key } = value;
- if (key === 'comment') {
- onComment();
- }
- }}
- />
- </div>
- </div>
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.course.teacher}</div>
- <div className="t1">有效期</div>
- <div className="t2">{data.useExpireDays}Days</div>
- </div>
- </div>
- <div className="right">
- <div className="item">
- <GIcon name="speed-block" noHover />
- <div className="text">
- <span>{data.currentNo}</span>/{(data.courseNos || []).length}
- </div>
- </div>
- <div className="item">
- <GIcon name="question-block" active noHover />
- <div className="text">
- <span>{data.answerNumber}</span>/{data.askNumber}
- </div>
- </div>
- <div className="item" onClick={() => onTime()}>
- <GIcon name="clockin-block" active noHover />
- <div className="text">
- <span>{formatSeconds(data.totalTime)}</span> {data.previewProgress || 0}%
- </div>
- </div>
- <div className="item">
- <GIcon name="note-block" active noHover />
- <div className="text">{data.noteNumber}</div>
- </div>
- </div>
- <div className="open">
- <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
- </div>
- </div>
- {open && this.renderTable()}
- </div>
- );
- }
- renderTable() {
- const { data = {} } = this.props;
- const { courseNos = [] } = data;
- return <UserTable size="small" columns={this.columns} data={courseNos || []} />;
- }
- }
- const titleMap = {
- 1: '预约时间',
- 2: '答疑文档',
- 3: '上课',
- 4: '课后笔记',
- 5: '课后补充',
- 6: '备考信息',
- 7: '完成作业',
- };
- const iconMap = {
- 1: 'time-icon',
- 2: 'QA-icon',
- 3: 'class-icon',
- 4: 'note-icon',
- 5: 'supplement-icon',
- 6: 'information-icon',
- 7: 'homework-icon',
- };
- const statusMap = {
- 1: appointment => {
- if (!appointment.id) return 'end';
- return '';
- },
- 2: appointment => {
- if (!appointment.questionFile) return 'not';
- return '';
- },
- 3: (appointment, data) => {
- if (!data.cctalkName) return 'not';
- // if (new Date(appointment.endTime).getTime() > new Date()) return 'not';
- return '';
- },
- 4: appointment => {
- if (!appointment.noteList || appointment.noteList.length === 0) return 'not';
- return '';
- },
- 5: appointment => {
- if (!appointment.supplyList || appointment.supplyList.length === 0) return 'not';
- return '';
- },
- 6: () => {
- return '';
- },
- 7: appointment => {
- const { paper = {} } = appointment;
- if (!paper.report || formatPercent(paper.report.userNumber, paper.report.questionNumber) < 100) return 'not';
- return '';
- },
- };
- class CourseVs extends Component {
- constructor(props) {
- super(props);
- this.columns = {
- system: [
- { title: '学习内容', key: 'title' },
- {
- title: '预习作业',
- key: 'paper',
- render: text => {
- text = text || {};
- const progress = text.report ? formatPercent(text.report.userNumber, text.report.questionNumber) : 0;
- const times = text.paper ? text.paper.resetTimes : 0;
- return (
- <div>
- <div className="v-a-m d-i-b">
- <ProgressText width={50} size="small" times={times} progress={progress} unit="次" />
- </div>
- {!text.report && (
- <IconButton
- className="m-l-2"
- type="start"
- tip="Start"
- onClick={() => {
- User.needLogin().then(() => {
- Question.startLink('preview', text);
- });
- }}
- />
- )}
- {text.report && !text.report.isFinish && (
- <IconButton
- className="m-l-2"
- type="continue"
- tip="Continue"
- onClick={() => {
- User.needLogin().then(() => {
- Question.continueLink('preview', text);
- });
- }}
- />
- )}
- {text.report && !!text.report.isFinish && (
- <IconButton
- className="m-l-2"
- type="restart"
- tip="Restart"
- onClick={() => {
- User.needLogin().then(() => {
- Question.restart('preview', text);
- });
- }}
- />
- )}
- {text.report && !!text.report.isFinish && (
- <IconButton
- className="m-l-5"
- type="report"
- tip="Report"
- onClick={() => {
- User.needLogin().then(() => {
- Question.reportLink('preview', text);
- });
- }}
- />
- )}
- </div>
- );
- },
- },
- {
- title: '授课时间',
- key: 'time',
- render: (text, record) => {
- return (
- <div className="sub">
- <div className="t-2 t-s-12">{formatDate(record.startTime, 'YYYY-MM-DD')}</div>
- <div className="t-6 t-s-12">
- {formatDate(record.startTime, 'HH:mm:ss')} ~ {formatDate(record.endTime, 'HH:mm:ss')}
- </div>
- </div>
- );
- },
- },
- {
- title: '课后笔记',
- key: 'note',
- render: (text, record) => {
- return record.noteList && record.noteList.length > 0 ? (
- <a onClick={() => this.props.onNote(record)}>查看</a>
- ) : (<span>查看</span>);
- },
- },
- {
- title: '课后补充',
- key: 'supply',
- render: (text, record) => {
- return record.supplyList && record.supplyList.length > 0 ? (
- <a onClick={() => this.props.onSupply(record)}>查看</a>
- ) : (<span>查看</span>);
- },
- },
- ],
- answer: [
- { title: '学习内容', key: 'title' },
- {
- title: '答疑文档',
- key: 'questionFile',
- render: (text, record) => {
- return (
- <a href={text} target="_blank">
- {record.questionFileName}
- </a>
- );
- },
- },
- {
- title: '授课时间',
- key: 'time',
- render: (text, record) => {
- return `${formatDate(record.startTime, 'YYYY-MM-DD HH:mm:ss')} ~ ${formatDate(record.endTime, 'HH:mm:ss')}`;
- },
- },
- {
- title: '课后补充',
- key: 'supply',
- render: (text, record) => {
- return record.supplyList ? <a onClick={() => this.props.onSupply(record)}>查看</a> : <span>查看</span>;
- },
- },
- ],
- };
- this.listMap = {
- novice: [1, 3],
- coach: [1, 6, 3],
- system: [1, 7, 3, 4],
- answer: [1, 2, 3],
- };
- if (!props.data.appointments) {
- props.data.appointments = [];
- }
- if (!props.data.teacher) {
- props.data.teacher = {};
- }
- const index = props.data.appointments.length - 1;
- this.state = {
- open: props.data.status === 'ing',
- tab: 'ing',
- index,
- list: this.listMap[this.props.data.course.vsType],
- showTips:
- props.data.commentTips === 0 &&
- (props.data.appointments.length === Math.ceil(props.data.number / 2) ||
- props.data.appointments.length === props.data.number),
- };
- }
- closeCommentTips() {
- My.courseCommentTips(this.props.data.id).then(() => {
- this.setState({ showTips: false });
- });
- }
- render() {
- const { data = {} } = this.props;
- switch (data.status) {
- case 'ing':
- return this.renderIng();
- case 'not':
- return this.renderNot();
- case 'end':
- return this.renderEnd();
- case 'suspend':
- return this.renderSuspend();
- default:
- return <div />;
- }
- }
- renderIng() {
- const { data, onComment, closeCommentTips } = this.props;
- const { tab, showTips, open } = this.state;
- return (
- <div className="education-item ing">
- <div className="title">
- <div className="tag">学习中</div>
- <div className="text">
- {data.course.title}
- {data.vsNo > 0 ? `V${data.vsNo}` : ''}
- {data.number > 0 ? `(${data.number}课时)` : ''}
- </div>
- <div className="right">
- <More
- menu={[{ label: '评价', key: 'comment' }, { label: '停课', key: 'suspend' }]}
- onClick={value => {
- const { key } = value;
- if (key === 'comment') {
- onComment();
- }
- }}
- />
- </div>
- </div>
- {showTips && (
- <div className="continue">
- <Icon className="close m-r-5 t-3" type="close-circle" theme="filled" onClick={() => closeCommentTips()} />
- 课程已过半,可以来写写评价啦<a onClick={() => onComment()}>去写评价 ></a>
- </div>
- )}
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.teacher.realname}</div>
- <div className="t1">有效期</div>
- <div className="t2">{data.useExpireDays}Days</div>
- </div>
- </div>
- <div className="right">
- <div className="item">
- <GIcon name="speed-block" active noHover />
- <div className="text">
- <span>{data.appointments.length}</span>/{data.number}
- </div>
- </div>
- <div className="item">
- <GIcon name="time-block" active noHover />
- <div className="text">
- <span>{data.appointments.length > 0 ? parseInt(data.totalDays / data.appointments.length, 10) : 0}</span>天/课时
- </div>
- </div>
- </div>
- <div className="open">
- <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
- </div>
- </div>
- {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && (
- <Tabs
- className="t-l"
- type="line"
- theme="theme"
- size="small"
- width={80}
- active={tab}
- tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
- onChange={key => this.setState({ tab: key })}
- />
- )}
- {open && (tab === 'ing' ? this.renderTimeLine() : this.renderTable())}
- </div>
- );
- }
- renderNot() {
- const { data } = this.props;
- return (
- <div className="education-item not">
- <div className="title">
- <div className="tag">未开通</div>
- <div className="text">
- {data.course.title}
- {data.vsNo > 0 ? `V${data.vsNo}` : ''}
- {data.number > 0 ? `(${data.number}课时)` : ''}
- </div>
- </div>
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.teacher.realname}</div>
- <div>
- <div className="d-i-b m-r-2">
- <div className="t-2">课时</div>
- <div className="t-1 t-s-16">{data.number}</div>
- </div>
- <div className="d-i-b">
- <div className="t-2">总时长</div>
- <div className="t-1 t-s-16">{data.number}Hours</div>
- </div>
- </div>
- </div>
- </div>
- <div className="right">
- <div className="qr-code">
- <Assets name="qrcode" src={data.teacher.qr} />
- <div className="i">
- <div className="t1">请尽快与老师预约上课时间</div>
- <div className="t2">请于 {formatDate(data.endTime, 'YYYY-MM-DD')} 前开通课程</div>
- </div>
- </div>
- </div>
- </div>
- {/* {this.renderTimeLine()} */}
- </div>
- );
- }
- renderEnd() {
- const { data, onComment, closeCommentTips } = this.props;
- const { open, tab, showTips } = this.state;
- return (
- <div className="education-item end">
- <div className="title">
- <div className="tag">已结课</div>
- <div className="text">
- {data.course.title}
- {data.vsNo > 0 ? `V${data.vsNo}` : ''}
- {data.number > 0 ? `(${data.number}课时)` : ''}
- </div>
- <div className="right">
- <More
- menu={[{ label: '评价', key: 'comment' }]}
- onClick={value => {
- const { key } = value;
- if (key === 'comment') {
- onComment();
- }
- }}
- />
- </div>
- </div>
- {showTips && (
- <div className="continue">
- <Icon className="close m-r-5 t-3" type="close-circle" theme="filled" onClick={() => closeCommentTips()} />
- 课程已结束,可以来写写评价啦<a onClick={() => onComment()}>去写评价 ></a>
- </div>
- )}
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.teacher.realname}</div>
- <div className="t1">有效期</div>
- <div className="t2">{data.useExpireDays}Days</div>
- </div>
- </div>
- <div className="right">
- <div className="item">
- <GIcon name="speed-block" active noHover />
- <div className="text">
- <span>{data.appointments.length}</span>/{data.number}
- </div>
- </div>
- <div className="item">
- <GIcon name="time-block" active noHover />
- <div className="text">
- <span>{data.appointments.length > 0 ? parseInt(data.totalDays / data.appointments.length, 10) : 0}</span>天/课时
- </div>
- </div>
- </div>
- <div className="open">
- <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
- </div>
- </div>
- {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && (
- <Tabs
- className="t-l"
- type="line"
- theme="theme"
- size="small"
- width={80}
- active={tab}
- tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
- onChange={key => this.setState({ tab: key })}
- />
- )}
- {open && (tab === 'ing' ? this.renderTimeLine() : this.renderTable())}
- </div>
- );
- }
- renderSuspend() {
- const { data, onRestore, onComment } = this.props;
- return (
- <div className="education-item end">
- <div className="title">
- <div className="tag">已停课</div>
- <div className="text">
- {data.course.title}
- {data.vsNo > 0 ? `V${data.vsNo}` : ''}
- {data.number > 0 ? `(${data.number}课时)` : ''}
- <Button size="small" onClick={() => onRestore()}>
- 恢复上课
- </Button>
- </div>
- <div className="t-s-12">
- <span className="t-3">申请时间:</span>
- <span className="t-2 m-r-1">{formatDate(data.suspendTime, 'YYYY-MM-DD HH:mm:ss')}</span>
- <span className="t-3">已停课:</span>
- <span>{parseInt((new Date().getTime() - new Date(data.suspendTime).getTime()) / 86400000, 10)}Days/30</span>
- </div>
- <div className="right">
- <More
- menu={[{ label: '评价', key: 'comment' }]}
- onClick={value => {
- const { key } = value;
- if (key === 'comment') {
- onComment();
- }
- }}
- />
- </div>
- </div>
- <div className="detail">
- <div className="left">
- <Assets name="sun_blue" src={data.course.cover} />
- <div className="info">
- <div className="t1">授课老师</div>
- <div className="t2">{data.teacher.realname}</div>
- <div className="t1">有效期</div>
- <div className="t2">{data.useExpireDays}Days</div>
- </div>
- </div>
- <div className="right">
- <div className="item">
- <GIcon name="speed-block" active noHover />
- <div className="text">
- <span>{data.appointments.length}</span>/{data.number}
- </div>
- </div>
- <div className="item">
- <GIcon name="time-block" active noHover />
- <div className="text">
- <span>{data.appointments.length > 0 ? parseInt(data.totalDays / data.appointments.length, 10) : 0}</span>天/课时
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- }
- renderTimeLine() {
- const { data = {}, onUploadNote, onUploadSupply, onUploadQuestion, setCCTalkName } = this.props;
- const { list = [], index } = this.state;
- const appointment = data.appointments[index] || {};
- let status = '';
- return [
- <div className="class-hour">
- {data.number > 1 && (
- <div className="text">
- 课时 {appointment.no}:{appointment.title}
- </div>
- )}
- {data.number > 1 && (
- <div className="right">
- <GIcon name="prev" onClick={() => this.setState({ index: index === 0 ? index : index - 1 })} />
- <span>上一课时</span>
- <span>下一课时</span>
- <GIcon
- name="next"
- onClick={() => this.setState({ index: index >= data.appointments.length - 1 ? index : index + 1 })}
- />
- </div>
- )}
- </div>,
- <div className="time-line">
- {list.map(item => {
- if (status === '') {
- // 上一阶段完成
- status = statusMap[item](appointment, data);
- } else {
- // 上一阶段未完成
- status = 'end';
- }
- return (
- <TimeLineItem
- type={`${item}`}
- user={this.props.user}
- appointment={appointment}
- data={data}
- status={status}
- onUploadNote={onUploadNote}
- onUploadSupply={onUploadSupply}
- onUploadQuestion={onUploadQuestion}
- setCCTalkName={setCCTalkName}
- />
- );
- })}
- </div>,
- ];
- }
- renderTable() {
- const { data = {} } = this.props;
- const { appointments = [] } = data;
- return (
- <UserTable size="small" columns={this.columns[data.course.vsType]} data={appointments.filter(row => row.id)} />
- );
- }
- }
- class TimeLineItem extends Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
- onClick(key) {
- const { onClick } = this.props;
- const { status } = this.props;
- if (status === 'not') return;
- if (onClick) onClick(key);
- }
- render() {
- const { type } = this.props;
- const { status } = this.props;
- return (
- <div className={`time-line-item ${status}`}>
- <div className="icon-title">
- <GIcon name={iconMap[type]} active={!status} noHover />
- <div className="title">{titleMap[type]}</div>
- </div>
- <div className="time-line-detail">{this.renderDetail()}</div>
- </div>
- );
- }
- renderDetail() {
- const {
- data = {},
- appointment = {},
- type,
- onUploadNote,
- onUploadSupply,
- onDeleteNote,
- onDeleteSupply,
- onUploadQuestion,
- setCCTalkName,
- } = this.props;
- const { status } = this.props;
- const { paper } = appointment;
- switch (type) {
- case '1':
- switch (status) {
- case 'end':
- case 'not':
- return (
- <span>
- 请尽快与老师预约上课时间,老师微信:{data.teacher.wechat}扫码加微信{' '}
- <Popover content={<Assets name="qrcode" src={data.teacher.qr} />}>
- <span>
- <Assets className="m-l-1" name="erweima" />
- </span>
- </Popover>
- </span>
- );
- default:
- return (
- <span>
- {formatDate(appointment.startTime, 'YYYY-MM-DD HH:mm:ss')} ~{' '}
- {formatDate(appointment.endTime, 'HH:mm:ss')}
- </span>
- );
- }
- case '2':
- switch (status) {
- case 'end':
- return <span className="link">点此上传</span>;
- case 'not':
- return (
- <FileUpload
- onUpload={file => {
- return Common.upload({ file }).then(result => onUploadQuestion(appointment, result.url, file.name));
- }}
- >
- <span className="link">点此上传</span>
- </FileUpload>
- );
- default:
- return (
- <a href={appointment.questionFile} target="_blank">
- {appointment.questionFileName || '文件'}
- </a>
- );
- }
- case '3':
- switch (status) {
- case 'end':
- return data.cctalkName ? (
- <span>
- CCtalk 频道号 :{appointment.cctalkChannel}{' '}
- <a className="link" href="" target="_black">
- CC talk使用手册
- </a>
- </span>
- ) : (<div>
- <input
- style={{ width: 200 }}
- className="b-c-1 p-l-1 p-r-1 t-s-12 m-r-1"
- placeholder="请输入CCtalk用户名查看授课频道"
- onChange={e => {
- this.setState({ cctalkName: e.target.value });
- }}
- />
- <Button size="small" radius disabled>
- 提交
- </Button>
- </div>);
- case 'not':
- return data.cctalkName ? (
- <span>
- CCtalk 频道号 :{appointment.cctalkChannel}{' '}
- <a className="link" href="" target="_black">
- CC talk使用手册
- </a>
- </span>
- ) : (<div>
- <input
- style={{ width: 200 }}
- className="b-c-1 p-l-1 p-r-1 t-s-12 m-r-1"
- placeholder="请输入CCtalk用户名查看授课频道"
- onChange={e => {
- this.setState({ cctalkName: e.target.value });
- }}
- />
- <Button
- size="small"
- radius
- onClick={() => {
- if (this.state.cctalkName) setCCTalkName(appointment, this.state.cctalkName);
- }}
- >
- 提交
- </Button>
- </div>);
- default:
- return (
- <span>
- CCtalk 频道号 :{appointment.cctalkChannel}{' '}
- <a className="link" href="" target="_black">
- CC talk使用手册
- </a>
- </span>
- );
- }
- case '4':
- switch (status) {
- case 'end':
- return <span className="link">点此上传</span>;
- case 'not':
- return (
- <span
- className="link"
- onClick={() => {
- onUploadNote(appointment, { appointmentId: appointment.id, recordId: appointment.recordId });
- }}
- >
- 点此上传
- </span>
- );
- default:
- return (
- <div>
- <div>
- <span
- className="link"
- onClick={() => {
- onUploadNote(appointment, { appointmentId: appointment.id, recordId: appointment.recordId });
- }}
- >
- 点此上传
- </span>
- </div>
- <div className="note-list">
- {appointment.noteList.map(row => {
- return (
- <Note
- user={this.props.user}
- teacher={data.teacher}
- data={row}
- reply={!row.userId}
- actionList={
- row.userId ? [{ key: 'edit', label: '编辑' }, { key: 'delete', label: '删除' }] : null
- }
- onAction={key => {
- switch (key) {
- case 'edit':
- onUploadNote(appointment, row);
- break;
- case 'delete':
- onDeleteNote(appointment, row);
- break;
- case 'reply':
- onUploadNote(appointment, {
- parentId: row.id,
- appointmentId: appointment.id,
- recordId: appointment.recordId,
- });
- break;
- default:
- }
- }}
- />
- );
- })}
- </div>
- </div>
- );
- }
- case '5':
- switch (status) {
- case 'end':
- return <span className="link">写留言</span>;
- case 'not':
- return (
- <span
- className="link"
- onClick={() => {
- onUploadSupply(appointment, { appointmentId: appointment.id, recordId: appointment.recordId });
- }}
- >
- 写留言
- </span>
- );
- default:
- return (
- <div>
- <div>
- <span
- className="link"
- onClick={() => {
- onUploadSupply(appointment, { appointmentId: appointment.id, recordId: appointment.recordId });
- }}
- >
- 写留言
- </span>
- </div>
- <div className="note-list">
- {appointment.supplyList.map(row => {
- return (
- <Note
- user={this.props.user}
- teacher={data.teacher}
- data={row}
- reply={!row.userId}
- actionList={
- row.userId ? [{ key: 'edit', label: '编辑' }, { key: 'delete', label: '删除' }] : null
- }
- onAction={key => {
- switch (key) {
- case 'edit':
- onUploadSupply(appointment, row);
- break;
- case 'delete':
- onDeleteSupply(appointment, row);
- break;
- case 'reply':
- onUploadSupply(appointment, {
- parentId: row.id,
- appointmentId: appointment.id,
- recordId: appointment.recordId,
- });
- break;
- default:
- }
- }}
- />
- );
- })}
- </div>
- </div>
- );
- }
- case '6':
- return [
- <div>
- <span>基本情况</span>
- <a href={status !== 'end' ? '' : ''} className="link">
- 填写
- </a>
- </div>,
- <div>
- <span>备考细节</span>
- <a href={status !== 'end' ? '' : ''} className="link">
- 填写
- </a>
- </div>,
- ];
- case '7':
- return (
- <ProgressText
- progress={paper ? formatPercent(paper.report.userNumber, paper.report.questionNumber) : 0}
- size="small"
- />
- );
- default:
- return <div />;
- }
- }
- }
|