page.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import React from 'react';
  2. import { Link } from 'react-router-dom';
  3. import { Button, Modal, Form, Icon, Upload } from 'antd';
  4. import './index.less';
  5. import Page from '@src/containers/Page';
  6. import Block from '@src/components/Block';
  7. import FilterLayout from '@src/layouts/FilterLayout';
  8. import ActionLayout from '@src/layouts/ActionLayout';
  9. import TableLayout from '@src/layouts/TableLayout';
  10. import { formatTreeData, getMap } from '@src/services/Tools';
  11. import { asyncSMessage } from '@src/services/AsyncTools';
  12. import { CourseModule, CourseVideoType } from '../../../../Constant';
  13. import { System } from '../../../stores/system';
  14. import { Course } from '../../../stores/course';
  15. import { Exercise } from '../../../stores/exercise';
  16. const CourseModuleMap = getMap(CourseModule, 'value', 'label');
  17. const CourseVideoTypeMap = getMap(CourseVideoType, 'value', 'label');
  18. export default class extends Page {
  19. init() {
  20. this.exerciseMap = {};
  21. this.filterForm = [
  22. {
  23. key: 'structId',
  24. type: 'tree',
  25. allowClear: true,
  26. tree: [],
  27. name: '学科',
  28. placeholder: '标题或正文',
  29. }, {
  30. key: 'courseModule',
  31. type: 'select',
  32. name: '课程种类',
  33. allowClear: true,
  34. select: CourseModule,
  35. placeholder: '请输入',
  36. },
  37. ];
  38. this.actionList = [{
  39. key: 'info',
  40. name: '首页视频',
  41. }, {
  42. key: 'addVideo',
  43. type: 'primary',
  44. name: '创建视频课程',
  45. render: (item) => {
  46. return <Link to='/course/detail?module=video'><Button type='primary'>{item.name}</Button></Link>;
  47. },
  48. }, {
  49. key: 'addOnline',
  50. type: 'primary',
  51. name: '创建小班课程',
  52. render: (item) => {
  53. return <Link to='/course/detail?module=online'><Button type='primary'>{item.name}</Button></Link>;
  54. },
  55. }, {
  56. key: 'addVs',
  57. type: 'primary',
  58. name: '编辑1vs1课程',
  59. render: (item) => {
  60. return <Link to='/course/vs'><Button type='primary'>{item.name}</Button></Link>;
  61. },
  62. }];
  63. this.columns = [{
  64. title: '课程种类',
  65. dataIndex: 'courseModule',
  66. render: (text) => {
  67. return CourseModuleMap[text] || text;
  68. },
  69. }, {
  70. title: '学科',
  71. dataIndex: 'structId',
  72. render: (text, record) => {
  73. return `${record.parentStructId ? `${this.exerciseMap[record.parentStructId]}-` : ''}${this.exerciseMap[record.structId]}`;
  74. },
  75. }, {
  76. title: '类型',
  77. dataIndex: 'videoType',
  78. render: (text) => {
  79. return CourseVideoTypeMap[text] || text;
  80. },
  81. }, {
  82. title: '课程名称',
  83. dataIndex: 'title',
  84. }, {
  85. title: '售价',
  86. dataIndex: 'price',
  87. }, {
  88. title: '试听人数',
  89. dataIndex: 'trailNumber',
  90. }, {
  91. title: '购买数量(含套餐)',
  92. dataIndex: 'saleNumber',
  93. render: (text, record) => {
  94. return text + record.packageSaleNumber;
  95. },
  96. }, {
  97. title: '操作',
  98. dataIndex: 'handler',
  99. render: (text, record) => {
  100. return <div className="table-button">
  101. {<Link to={`/course/detail/${record.id}`}>编辑</Link>}
  102. {(record.courseModule === 'online') && <Link to={`/course/student/${record.id}`}>查看学员</Link>}
  103. </div>;
  104. },
  105. }];
  106. System.getCourseIndex().then(result => {
  107. return this.refreshInfo(result);
  108. }).then(() => {
  109. this.initData();
  110. });
  111. Exercise.courseStruct().then((result) => {
  112. const list = result.map(row => { row.title = `${row.titleZh}`; row.value = row.id; return row; });
  113. this.filterForm[0].tree = formatTreeData(list, 'id', 'title', 'parentId');
  114. this.exerciseMap = getMap(result.map(row => {
  115. row.title = `${row.titleZh}`;
  116. row.value = row.id;
  117. return row;
  118. }), 'id', 'title');
  119. this.setState({ exercise: result });
  120. });
  121. }
  122. initData() {
  123. Course.list(Object.assign({ excludeVs: true }, this.state.search)).then(result => {
  124. this.setTableData(result.list, result.total);
  125. });
  126. }
  127. refreshInfo(result) {
  128. this.setState({ info: result });
  129. }
  130. infoAction() {
  131. const { info = {} } = this.state;
  132. this.open(info);
  133. }
  134. changeInfo(field, value) {
  135. const { detail } = this.state;
  136. detail[field] = value;
  137. this.setState({ detail });
  138. }
  139. submitInfo() {
  140. const { detail } = this.state;
  141. System.setCourseIndex(detail).then(() => {
  142. asyncSMessage('保存成功');
  143. this.close(false, 'detail');
  144. return this.refreshInfo(detail);
  145. });
  146. }
  147. renderView() {
  148. const { exercise } = this.state;
  149. return <Block flex>
  150. {exercise && <FilterLayout
  151. show
  152. itemList={this.filterForm}
  153. data={this.state.search}
  154. onChange={data => {
  155. data.page = 1;
  156. this.search(data);
  157. }} />}
  158. <ActionLayout
  159. itemList={this.actionList}
  160. selectedKeys={this.state.selectedKeys}
  161. onAction={key => this.onAction(key)}
  162. />
  163. <TableLayout
  164. columns={this.tableSort(this.columns)}
  165. list={this.state.list}
  166. pagination={this.state.page}
  167. loading={this.props.core.loading}
  168. onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
  169. onSelect={(keys, rows) => this.tableSelect(keys, rows)}
  170. selectedKeys={this.state.selectedKeys}
  171. />
  172. {this.state.detail && <Modal visible closable title='数据管理' onCancel={() => {
  173. this.close(false, 'detail');
  174. }} onOk={() => {
  175. if (this.props.core.loading) return;
  176. this.submitInfo();
  177. }}>
  178. <Form>
  179. {this.state.uploadErr}
  180. <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 10 }} label={'在线课程'} help={this.state.onlineErr}>
  181. <Upload
  182. accept={'.mp4'}
  183. listType="picture-card"
  184. showUploadList={false}
  185. beforeUpload={(file) => System.uploadVideo(file).then((result) => {
  186. this.changeInfo('onlineVideo', result.url);
  187. }).catch(err => {
  188. this.setState({ onlineErr: err.message });
  189. })}
  190. >
  191. {this.state.detail.onlineVideo ? <div>
  192. <Icon type={this.props.core.loading ? 'loading' : 'plus'} />
  193. <div className="ant-upload-text">已上传</div>
  194. </div> : <div><Icon type={this.props.core.loading ? 'loading' : 'plus'} /><div className="ant-upload-text">Upload</div></div>}
  195. </Upload>
  196. {this.state.detail.onlineVideo && <a href={this.state.detail.onlineVideo} target='_blank'>访问</a>}
  197. </Form.Item>
  198. <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 10 }} label={'1v1课程'} help={this.state.vsErr}>
  199. <Upload
  200. accept={'.mp4'}
  201. listType="picture-card"
  202. showUploadList={false}
  203. beforeUpload={(file) => System.uploadVideo(file).then((result) => {
  204. this.changeInfo('vsVideo', result.url);
  205. }).catch(err => {
  206. this.setState({ vsErr: err.message });
  207. })}
  208. >
  209. {this.state.detail.vsVideo ? <div>
  210. <Icon type={this.props.core.loading ? 'loading' : 'plus'} />
  211. <div className="ant-upload-text">已上传</div>
  212. </div> : <div><Icon type={this.props.core.loading ? 'loading' : 'plus'} /><div className="ant-upload-text">Upload</div></div>}
  213. </Upload>
  214. {this.state.detail.vsVideo && <a href={this.state.detail.vsVideo} target='_blank'>访问</a>}
  215. </Form.Item>
  216. </Form>
  217. </Modal>}
  218. </Block>;
  219. }
  220. }