CoursewareCreate.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. import React, { Component } from 'react';
  2. import pathToRegexp from 'path-to-regexp';
  3. import { connect } from 'dva';
  4. import { routerRedux } from 'dva/router';
  5. import { Form, Modal, Card, Button, Input, Radio, Switch } from 'antd';
  6. import RBVideoPlayer from '../../../components/RBVideoPlayer/index';
  7. import RBDragSortTable from '../../../components/RBDragSortTable/index';
  8. import Selector from '../../../components/RBTableSelector/Selector';
  9. import FooterToolbar from '../../../components/FooterToolbar/index';
  10. import { RESOURCE_VIDEO } from '../../../utils/config';
  11. import {
  12. genAbsolutePicUrl,
  13. renderStatus,
  14. statusToBool,
  15. boolToStatus,
  16. } from '../../../utils/utils';
  17. import styles from './CoursewareCreate.less';
  18. const fieldLabels = {
  19. code: '课件编号',
  20. title: '课件名称',
  21. category: '环节名称',
  22. digest: '课件简述',
  23. resourceList: '资源列表',
  24. status: '课件状态',
  25. };
  26. const formItemLayout = {
  27. labelCol: {
  28. xs: { span: 24 },
  29. sm: { span: 2 },
  30. },
  31. wrapperCol: {
  32. xs: { span: 24 },
  33. sm: { span: 14 },
  34. md: { span: 12 },
  35. },
  36. };
  37. @connect(({ loading, courseware, resource }) => ({
  38. resource,
  39. courseware,
  40. loading: loading.models.resource,
  41. submitting: loading.models.courseware,
  42. }))
  43. @Form.create()
  44. export default class CoursewareCreatePage extends Component {
  45. state = {
  46. modalSelectorDestroy: true,
  47. resourceType: 'Picture',
  48. };
  49. componentWillMount() {
  50. // 进入页面前清空下model中state内容,防止上次内容造成干扰
  51. const match = pathToRegexp('/product/courseware/create').exec(this.props.location.pathname);
  52. if (match) {
  53. this.cleanPageState();
  54. }
  55. }
  56. componentDidMount() {
  57. // 组件挂载完成,检查是否是编辑操作,决定是否加载该课件数据
  58. const matchId = this.isEdit();
  59. if (matchId) {
  60. this.props.dispatch({
  61. type: 'courseware/fetchCoursewareItem',
  62. payload: { id: matchId },
  63. });
  64. }
  65. }
  66. isEdit = () => {
  67. const { location } = this.props;
  68. const match = pathToRegexp('/product/courseware/edit/:id').exec(location.pathname);
  69. if (match) {
  70. return match[1];
  71. }
  72. return false;
  73. }
  74. cleanPageState = () => {
  75. this.props.dispatch({
  76. type: 'courseware/cleanItemState',
  77. payload: {},
  78. });
  79. }
  80. selectorDataFetcher = (params) => {
  81. const { resourceType } = this.state;
  82. if (resourceType === 'Picture') {
  83. this.props.dispatch({
  84. type: 'resource/fetchImageList',
  85. payload: params,
  86. });
  87. }
  88. if (resourceType === 'Video') {
  89. this.props.dispatch({
  90. type: 'resource/fetchVideoList',
  91. payload: params,
  92. });
  93. }
  94. }
  95. handleSelectorModalShow = () => {
  96. this.setState({
  97. modalSelectorDestroy: false,
  98. });
  99. this.selectorDataFetcher();
  100. }
  101. handleSelectorCancel = () => {
  102. this.setState({
  103. modalSelectorDestroy: true,
  104. });
  105. }
  106. handleSelectorFinish = (rows) => {
  107. this.setState({
  108. modalSelectorDestroy: true,
  109. });
  110. this.props.dispatch({
  111. type: 'courseware/fixResourceList',
  112. payload: rows,
  113. });
  114. }
  115. handleSelectorChange = (params) => {
  116. this.selectorDataFetcher(params);
  117. }
  118. handleRadioChange = (e) => {
  119. this.setState({
  120. resourceType: e.target.value,
  121. }, () => this.selectorDataFetcher());
  122. }
  123. handleDragSortTableChange = (rows) => {
  124. this.props.dispatch({
  125. type: 'courseware/fixResourceList',
  126. payload: rows,
  127. });
  128. }
  129. handlePageBack = () => {
  130. this.props.dispatch(routerRedux.push({
  131. pathname: '/product/courseware',
  132. state: this.props.location.state,
  133. }));
  134. }
  135. handlePageSubmit = (e) => {
  136. e.preventDefault();
  137. this.props.form.validateFieldsAndScroll((err, values) => {
  138. if (!err) {
  139. const { status, ...rest } = values;
  140. values = { status: boolToStatus(status), ...rest };
  141. const { courseware } = this.props;
  142. const { currentItem } = courseware;
  143. const { resourceList } = currentItem;
  144. let resourceIdList;
  145. if (resourceIdList) {
  146. resourceIdList = resourceList.map(item => item.id);
  147. }
  148. const matchId = this.isEdit();
  149. if (matchId) {
  150. const params = {
  151. id: matchId,
  152. resourceList: resourceIdList,
  153. ...values,
  154. };
  155. this.props.dispatch({
  156. type: 'courseware/updateCoursewareItem',
  157. payload: params,
  158. states: this.props.location.state,
  159. });
  160. } else {
  161. const params = {
  162. resourceList: resourceIdList,
  163. ...values,
  164. };
  165. this.props.dispatch({
  166. type: 'courseware/createCoursewareItem',
  167. payload: params,
  168. states: this.props.location.state,
  169. });
  170. }
  171. }
  172. });
  173. }
  174. render() {
  175. const { submitting, courseware, form, loading, resource } = this.props;
  176. const { modalSelectorDestroy, resourceType } = this.state;
  177. const { getFieldDecorator } = form;
  178. const { currentItem } = courseware;
  179. const { code, title, digest, category, status, resourceList = [] } = currentItem;
  180. const imageColumns = [{
  181. title: '图片',
  182. dataIndex: 'path',
  183. key: 1,
  184. render: text => (
  185. <div className={styles.picture}>
  186. <img src={genAbsolutePicUrl(text)} alt="" />
  187. </div>
  188. ),
  189. width: '10%',
  190. }, {
  191. title: '编号',
  192. dataIndex: 'code',
  193. key: 2,
  194. width: '20%',
  195. }, {
  196. title: '名称',
  197. dataIndex: 'name',
  198. key: 3,
  199. width: '30%',
  200. }, {
  201. title: '格式',
  202. dataIndex: 'format',
  203. key: 4,
  204. }, {
  205. title: '状态',
  206. dataIndex: 'status',
  207. key: 5,
  208. render: text => renderStatus(text),
  209. }];
  210. const renderCardName = () => {
  211. return (
  212. <div className={styles.cardName}>
  213. <span>
  214. <a onClick={this.handleSelectorModalShow}>资源列表</a>
  215. </span>
  216. </div>
  217. );
  218. };
  219. const renderModalTitle = () => {
  220. return (
  221. <Radio.Group
  222. value={resourceType}
  223. onChange={this.handleRadioChange}
  224. className={styles.radio}
  225. >
  226. <Radio.Button value="Picture">图片</Radio.Button>
  227. <Radio.Button value="Video">视频</Radio.Button>
  228. </Radio.Group>
  229. );
  230. };
  231. // 根据选定的资源列表类型决定渲染样式
  232. const renderResourceList = () => {
  233. if (!resourceList.length) {
  234. return (
  235. <h3 style={{ color: 'red' }}>你还未选择任何资源,请点击上方"资源列表"进行选择!</h3>
  236. );
  237. } else if (resourceList[0].type === RESOURCE_VIDEO) {
  238. const videoItem = resourceList[0];
  239. return (
  240. <div className={styles.video}>
  241. <RBVideoPlayer
  242. width="100%"
  243. height="100%"
  244. url={videoItem.url}
  245. isM3U8={videoItem.format === 'm3u8'}
  246. />
  247. </div>
  248. );
  249. } else {
  250. return (
  251. <RBDragSortTable
  252. columns={imageColumns}
  253. data={resourceList}
  254. onChange={this.handleDragSortTableChange}
  255. />
  256. );
  257. }
  258. };
  259. return (
  260. <div>
  261. <Card title="基础信息" style={{ marginBottom: 16 }}>
  262. <Form>
  263. <Form.Item hasFeedback label={fieldLabels.code} {...formItemLayout}>
  264. {getFieldDecorator('code', {
  265. rules: [
  266. {
  267. required: true, message: '请填写课件编号',
  268. }, {
  269. pattern: /^[a-zA-Z0-9|-]+$/g, message: '编号包含非法字符',
  270. },
  271. ],
  272. initialValue: code,
  273. })(
  274. <Input
  275. placeholder="请输入(课件一旦创建完成,编号不可修改)"
  276. disabled={!!this.isEdit()}
  277. />
  278. )}
  279. </Form.Item>
  280. <Form.Item hasFeedback label={fieldLabels.title} {...formItemLayout}>
  281. {getFieldDecorator('title', {
  282. rules: [{ required: true, message: '请填写课件名称' }],
  283. initialValue: title,
  284. })(
  285. <Input placeholder="请输入" />
  286. )}
  287. </Form.Item>
  288. <Form.Item hasFeedback label={fieldLabels.category} {...formItemLayout}>
  289. {getFieldDecorator('category', {
  290. initialValue: category,
  291. })(
  292. <Input placeholder="请输入" />
  293. )}
  294. </Form.Item>
  295. <Form.Item label={fieldLabels.digest} {...formItemLayout}>
  296. {getFieldDecorator('digest', {
  297. initialValue: digest,
  298. })(
  299. <Input.TextArea rows={4} placeholder="请输入" />
  300. )}
  301. </Form.Item>
  302. <Form.Item label={fieldLabels.status} {...formItemLayout}>
  303. {getFieldDecorator('status', {
  304. valuePropName: 'checked',
  305. initialValue: statusToBool(status),
  306. })(
  307. <Switch
  308. checkedChildren="正常"
  309. unCheckedChildren="删除"
  310. />
  311. )}
  312. </Form.Item>
  313. </Form>
  314. </Card>
  315. <Card title={renderCardName()} style={{ marginBottom: 70 }}>
  316. {renderResourceList()}
  317. {!modalSelectorDestroy && (
  318. <Modal
  319. visible
  320. width={1100}
  321. footer={null}
  322. title={renderModalTitle()}
  323. maskClosable={false}
  324. onCancel={this.handleSelectorCancel}
  325. >
  326. <Selector
  327. multiple={resourceType === 'Picture'}
  328. loading={loading}
  329. selectorName={resourceType}
  330. list={resource.list}
  331. pageNo={resource.pageNo}
  332. pageSize={resource.pageSize}
  333. totalSize={resource.totalSize}
  334. onCancel={this.handleSelectorCancel}
  335. onChange={this.handleSelectorChange}
  336. onFinish={this.handleSelectorFinish}
  337. />
  338. </Modal>
  339. )}
  340. </Card>
  341. <FooterToolbar style={{ width: '100%' }}>
  342. <Button
  343. onClick={this.handlePageBack}
  344. style={{ marginRight: 10 }}
  345. >取消
  346. </Button>
  347. <Button
  348. type="primary"
  349. loading={submitting}
  350. onClick={this.handlePageSubmit}
  351. >提交
  352. </Button>
  353. </FooterToolbar>
  354. </div>
  355. );
  356. }
  357. }