123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 |
- import React from 'react';
- import { Link } from 'react-router-dom';
- import moment from 'moment';
- import { Form, Input, Button, Row, Col, InputNumber, Upload, DatePicker, Checkbox, Icon } from 'antd';
- import './index.less';
- import Editor from '@src/components/Editor';
- import Page from '@src/containers/Page';
- import Block from '@src/components/Block';
- import TreeSelect from '@src/components/TreeSelect';
- import Select from '@src/components/Select';
- import EditTableCell from '@src/components/EditTableCell';
- import Radio from '@src/components/Radio';
- import ActionLayout from '@src/layouts/ActionLayout';
- import TableLayout from '@src/layouts/TableLayout';
- // import FileUpload from '@src/components/FileUpload';
- import { formatFormError, formatSeconds, formatTreeData, getMap } from '@src/services/Tools';
- import { asyncSMessage } from '@src/services/AsyncTools';
- import { CrowdList, CourseStatus, CourseVideoType } from '../../../../Constant';
- import { Course } from '../../../stores/course';
- import { System } from '../../../stores/system';
- import { Exercise } from '../../../stores/exercise';
- const CourseStatusMap = getMap(CourseStatus, 'value', 'label');
- export default class extends Page {
- init() {
- this.exerciseMap = {};
- this.actionList = [{
- key: 'add',
- type: 'primary',
- name: '上传视频',
- render: (item) => {
- return <Upload
- showUploadList={false}
- beforeUpload={(file) => System.uploadVideo(file).then((result) => {
- return Course.addNo({ courseId: this.params.id, resource: result.url, time: result.time, title: file.name.split('.')[0] });
- }).then(() => {
- this.refreshNo();
- })}
- >
- <Button>{item.name}</Button>
- </Upload>;
- },
- }];
- this.noColumns = [{
- title: '课程序号',
- dataIndex: 'no',
- }, {
- title: '名称',
- dataIndex: 'title',
- render: (text, record) => {
- return <EditTableCell value={text} onChange={(v) => {
- this.changeNo('title', record, v);
- }} />;
- },
- }, {
- title: '时长',
- dataIndex: 'time',
- render: (text) => {
- return formatSeconds(text);
- },
- }, {
- title: '视频地址',
- dataIndex: 'resource',
- render: (text) => {
- return <a href={text} target='_blank'>访问</a>;
- },
- }, {
- title: '试用视频',
- dataIndex: 'isTrail',
- render: (text, record) => {
- return <div>
- <Checkbox checked={!!text} onChange={(v) => {
- this.changeNo('isTrail', record, v.target.checked ? 1 : 0);
- }} />
- {text > 0 && <InputNumber value={record.startTrail} onChange={(v) => {
- this.changeNo('startTrail', record, v);
- }} />}
- {text > 0 && <InputNumber value={record.endTrail} onChange={(v) => {
- this.changeNo('endTrail', record, v);
- }} />}
- {text > 0 && <Upload
- showUploadList={false}
- beforeUpload={(file) => System.uploadVideo(file).then((result) => {
- return this.changeNo('trailResource', record, result.url);
- })}
- >
- <Button>上传视频{record.trailResource ? '(已上传)' : ''}</Button>
- </Upload>}
- </div>;
- },
- }, {
- title: '操作',
- dataIndex: 'handler',
- render: (text, record) => {
- const { total } = this.state;
- return <div className="table-button">
- {record.no > 1 && (
- <a onClick={() => {
- this.changeNo('no', record, record.no - 1);
- }}>上移</a>
- )}
- {record.no <= total && (
- <a onClick={() => {
- this.changeNo('no', record, record.no + 1);
- }}>下移</a>
- )}
- {(
- <a onClick={() => {
- this.delNo(record.id);
- }}>删除</a>
- )}
- </div>;
- },
- }];
- this.timeColumns = [{
- title: '时间段',
- dataIndex: 'time',
- render: (text, record) => {
- return <DatePicker.RangePicker value={[record.startTime, record.endTime]} onChange={(value) => {
- this.changeTime(record.id, { startTime: value[0], endTime: value[1] });
- }} />;
- },
- }, {
- title: '学员数量',
- dataIndex: 'studentNumber',
- render: (text, record) => {
- return <Link to={`/course/student/${this.params.id}?timeId=${record.id}`}>{text || 0}</Link>;
- },
- }, {
- title: '状态',
- dataIndex: 'status',
- render: (text, record) => {
- let status = 0;
- const start = new Date(record.startTime);
- const end = new Date(record.endTime);
- if (new Date().getTime() > start.getTime()) {
- status = 1;
- if (new Date().getTime() > end.getTime()) {
- status = 2;
- }
- }
- return CourseStatusMap[status] || status;
- },
- }];
- Exercise.courseStruct().then((result) => {
- const list = result.map(row => { row.title = `${row.titleZh}`; row.value = row.id; return row; });
- const tree = formatTreeData(list, 'id', 'title', 'parentId');
- this.exerciseMap = getMap(result.map(row => {
- row.title = `${row.titleZh}`;
- row.value = row.id;
- return row;
- }), 'id');
- this.setState({ exercise: tree });
- });
- }
- initData() {
- const { id } = this.params;
- const { module } = this.state.search;
- let handler;
- if (id) {
- handler = Course.get({ id });
- } else {
- handler = Promise.resolve({ structId: '', courseModule: module, expireDays: 180 });
- }
- handler
- .then(result => {
- this.setState({ module: result.courseModule });
- const { form } = this.props;
- result.structId = `${result.structId}`;
- form.setFieldsValue(result);
- if (id) {
- switch (result.courseModule) {
- case 'video':
- this.refreshNo();
- break;
- case 'online':
- this.refreshTime();
- break;
- default:
- }
- }
- this.setState({ data: result });
- });
- }
- refreshNo() {
- const { id } = this.params;
- Course.allNo({ courseId: id }).then(result => {
- this.setState({ list: result, total: result.length, no: true });
- });
- }
- changeNo(field, record, value) {
- Course.editNo({ id: record.id, [field]: value, courseId: record.courseId }).then(() => {
- this.refreshNo();
- });
- }
- delNo(id) {
- Course.delNo({ id }).then(() => {
- this.refreshNo();
- });
- }
- refreshTime() {
- const { id } = this.params;
- Course.listTime({ courseId: id }).then(result => {
- result.list = result.list.map(row => {
- row.startTime = moment(row.startTime);
- row.endTime = moment(row.endTime);
- return row;
- });
- this.setState({ list: result.list, total: result.total, time: true });
- });
- }
- changeTime(id, data) {
- data.id = id;
- Course.editTime(data).then(() => {
- this.refreshTime();
- });
- }
- submit() {
- const { form } = this.props;
- const { module } = this.state;
- form.validateFields((err) => {
- if (!err) {
- const data = form.getFieldsValue();
- data.parentStructId = this.exerciseMap[data.structId] ? this.exerciseMap[data.structId].parentId : 0;
- data.extend = this.exerciseMap[data.structId] ? this.exerciseMap[data.structId].extend : '';
- let handler;
- if (data.id) {
- handler = Course.edit(data);
- } else {
- data.courseModule = module;
- handler = Course.add(data);
- }
- handler.then((result) => {
- asyncSMessage('保存成功');
- if (data.id) {
- linkTo(`/course/detail/${data.id}`);
- } else {
- linkTo(`/course/detail/${result.id}`);
- }
- }).catch((e) => {
- if (e.result) form.setFields(formatFormError(data, e.result));
- });
- }
- });
- }
- renderVideo() {
- const { exercise, data } = this.state;
- const { getFieldDecorator, getFieldValue, setFieldsValue } = this.props.form;
- const structIdConfig = {
- rules: [{
- required: true, message: '请选择学科',
- }],
- };
- if (data.structId) {
- structIdConfig.initialValue = data.structId;
- }
- const cover = getFieldValue('cover');
- return <Block>
- <Form>
- {getFieldDecorator('id')(<input hidden />)}
- {exercise && data && <Form.Item key={data.structId} labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
- {getFieldDecorator('structId', structIdConfig)(
- <TreeSelect treeData={exercise} />,
- )}
- </Form.Item>}
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='类型'>
- {getFieldDecorator('videoType', {
- rules: [
- { required: true, message: '请选择' },
- ],
- })(
- <Select select={CourseVideoType} />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='适合人群'>
- {getFieldDecorator('crowd', {
- rules: [
- { required: true, message: '请选择' },
- ],
- })(
- <Radio select={CrowdList} />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='定价'>
- {getFieldDecorator('price', {
- rules: [
- { required: true, message: '请输入价格' },
- ],
- })(
- <InputNumber placeholder='请输入' />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程名称'>
- {getFieldDecorator('title', {
- rules: [
- { required: true, message: '请输入课程名称' },
- ],
- })(
- <Input placeholder='请输入课程名称' />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='开通有效期'>
- {getFieldDecorator('expireDays', {
- rules: [
- { required: true, message: '请输入有效期' },
- ],
- })(
- <InputNumber placeholder='天' min={0} />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='使用有效期'>
- {getFieldDecorator('useExpireDays', {
- rules: [
- { required: true, message: '请输入有效期' },
- ],
- })(
- <InputNumber placeholder='天' min={0} />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='教师'>
- {getFieldDecorator('teacher', {
- rules: [
- { required: true, message: '请输入教师' },
- ],
- })(
- <Input placeholder='请输入教师' />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程封面'>
- {getFieldDecorator('cover', {
- rules: [
- { required: true, message: '上传图片' },
- ],
- })(
- <Upload
- listType="picture-card"
- showUploadList={false}
- beforeUpload={(file) => System.uploadImage(file).then((result) => {
- setFieldsValue({ cover: result.url });
- return Promise.reject();
- })}
- >
- {cover ? <img src={cover} alt="avatar" /> : <div>
- <Icon type={this.state.loading ? 'loading' : 'plus'} />
- <div className="ant-upload-text">Upload</div>
- </div>}
- </Upload>,
- )}
- </Form.Item>
- </Form>
- </Block>;
- }
- renderNo() {
- const { no } = this.state;
- if (!no) return null;
- return <Block>
- <h1>上传正式视频</h1>
- <ActionLayout
- itemList={this.actionList}
- selectedKeys={this.state.selectedKeys}
- onAction={key => this.onAction(key)}
- />
- <TableLayout
- columns={this.noColumns}
- list={this.state.list}
- pagination={false}
- loading={this.props.core.loading}
- onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
- onSelect={(keys, rows) => this.tableSelect(keys, rows)}
- selectedKeys={this.state.selectedKeys}
- />
- </Block>;
- }
- renderInfoVideo() {
- const { getFieldDecorator } = this.props.form;
- return <Block flex>
- <h1>课程介绍</h1>
- <Form>
- <Form.Item label='老师资历'>
- {getFieldDecorator('teacherContent', {
- })(
- <Editor placeholder='输入内容' />,
- )}
- </Form.Item>
- <Form.Item label='基本参数'>
- {getFieldDecorator('baseContent', {
- })(
- <Editor placeholder='输入内容' />,
- )}
- </Form.Item>
- <Form.Item label='授课内容'>
- {getFieldDecorator('courseContent', {
- })(
- <Editor placeholder='输入内容' />,
- )}
- </Form.Item>
- <Form.Item label='授课重点'>
- {getFieldDecorator('pointContent', {
- })(
- <Editor placeholder='输入内容' />,
- )}
- </Form.Item>
- <Form.Item label='适合人群'>
- {getFieldDecorator('crowdContent', {
- })(
- <Editor placeholder='输入内容' />,
- )}
- </Form.Item>
- </Form>
- </Block>;
- }
- renderSyllabus() {
- const { getFieldDecorator } = this.props.form;
- return <Block flex>
- <Form>
- <Form.Item label='授课大纲'>
- {getFieldDecorator('syllabusContent', {
- })(
- <Editor placeholder='输入内容' />,
- )}
- </Form.Item>
- </Form>
- </Block>;
- }
- renderPromote() {
- const { getFieldDecorator } = this.props.form;
- return <Block flex>
- <Form>
- <Form.Item label='优惠信息'>
- {getFieldDecorator('promoteContent', {
- })(
- <Editor placeholder='输入内容' />,
- )}
- </Form.Item>
- </Form>
- </Block>;
- }
- renderOnline() {
- const { exercise, data } = this.state;
- const { getFieldDecorator } = this.props.form;
- const structIdConfig = {
- rules: [{
- required: true, message: '请选择学科',
- }],
- };
- if (data.structId) {
- structIdConfig.initialValue = data.structId;
- }
- return <Block>
- <Form>
- {getFieldDecorator('id')(<input hidden />)}
- {exercise && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
- {getFieldDecorator('structId', structIdConfig)(
- <TreeSelect treeData={exercise} />,
- )}
- </Form.Item>}
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程名称'>
- {getFieldDecorator('title', {
- rules: [
- { required: true, message: '请输入课程名称' },
- ],
- })(
- <Input placeholder='请输入课程名称' />,
- )}
- </Form.Item>
- <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问权限延迟'>
- {getFieldDecorator('askExtendDays', {
- rules: [
- { required: true, message: '请输入扩展天数' },
- ],
- })(
- <InputNumber placeholder='天' />,
- )}
- </Form.Item>
- </Form>
- </Block>;
- }
- renderTime() {
- const { time, timerange } = this.state;
- if (!time) return null;
- return <Block>
- <h1>课时管理</h1>
- <TableLayout
- columns={this.timeColumns}
- list={this.state.list}
- pagination={false}
- loading={this.props.core.loading}
- onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
- onSelect={(keys, rows) => this.tableSelect(keys, rows)}
- selectedKeys={this.state.selectedKeys}
- />
- <Row>
- <Col span={8}>
- <Form.Item>
- <DatePicker.RangePicker value={timerange} onChange={(value) => {
- this.setState({ timerange: value });
- }} />
- </Form.Item>
- </Col>
- <Col span={1}>
- <Form.Item>
- <Button onClick={() => {
- Course.addTime({ courseId: this.params.id, startTime: timerange[0], endTime: timerange[1] }).then(() => {
- this.refreshTime();
- this.setState({ timerange: null });
- });
- }}>添加</Button>
- </Form.Item>
- </Col>
- </Row>
- </Block>;
- }
- renderContent() {
- switch (this.state.module) {
- case 'online':
- return [this.renderOnline(), this.renderTime()];
- case 'video':
- return [this.renderVideo(), this.renderNo(), this.renderInfoVideo(), this.renderSyllabus(), this.renderPromote()];
- default:
- return <div />;
- }
- }
- renderView() {
- return <div flex>
- {this.renderContent()}
- <Row type="flex" justify="center">
- <Col>
- <Button type="primary" onClick={() => {
- this.submit();
- }}>保存</Button>
- </Col>
- </Row>
- </div>;
- }
- }
|