page.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import React from 'react';
  2. import { Form, Input, Button, Row, Col, InputNumber } from 'antd';
  3. import './index.less';
  4. import Editor from '@src/components/Editor';
  5. import Page from '@src/containers/Page';
  6. import Block from '@src/components/Block';
  7. import Select from '@src/components/Select';
  8. // import FileUpload from '@src/components/FileUpload';
  9. import { formatFormError, getMap } from '@src/services/Tools';
  10. import { asyncSMessage } from '@src/services/AsyncTools';
  11. import { Sentence } from '../../../stores/sentence';
  12. import config from './index';
  13. export default class extends Page {
  14. constructor(props) {
  15. super(props);
  16. this.preview = null;
  17. this.structMap = {};
  18. this.partList = [];
  19. this.pageLine = 100;
  20. const { id } = this.params;
  21. if (id) {
  22. config.title = '编辑长难句文章';
  23. } else {
  24. config.title = '添加长难句文章';
  25. }
  26. }
  27. init() {
  28. Sentence.getStruct().then(result => {
  29. return this.refreshStruct(result);
  30. });
  31. }
  32. refreshStruct(result) {
  33. result = result || {};
  34. result.chapters = result.chapters || [];
  35. const chapters = result.chapters.map((row, index) => { row.value = index + 1; return row; }).filter(row => !row.exercise);
  36. this.structMap = getMap(chapters, 'value');
  37. this.setState({ struct: result, chapters });
  38. }
  39. refreshPart(chapter) {
  40. const { form } = this.props;
  41. const { id } = this.params;
  42. Sentence.listArticle({ chapter }).then(result => {
  43. this.partList = result.list.map(row => row.part);
  44. if (id) {
  45. this.partList = this.partList.filter(row => row !== this.data.part);
  46. }
  47. form.validateFields(['part'], { force: true });
  48. });
  49. }
  50. initData() {
  51. const { id } = this.params;
  52. const { form } = this.props;
  53. let handler;
  54. if (id) {
  55. handler = Sentence.getArticle({ id }).then((result) => {
  56. if (result.chapter === 0) {
  57. // 前言模式
  58. this.setState({ mode: 'introduction' });
  59. } else {
  60. this.refreshPart(result.chapter);
  61. }
  62. return result;
  63. });
  64. } else {
  65. const { i } = this.state.search;
  66. if (i) {
  67. this.setState({ mode: 'introduction' });
  68. // 查询前言对应的id
  69. handler = Sentence.listArticle({ chapter: 0 })
  70. .then(result => {
  71. if (result.total > 0) {
  72. return result.list[0];
  73. }
  74. return { part: 1, chapter: 0, title: '前言' };
  75. });
  76. } else {
  77. handler = Promise.resolve({ part: 1 });
  78. }
  79. }
  80. handler
  81. .then(result => {
  82. this.data = result;
  83. this.content = result.content || '';
  84. form.setFieldsValue(result);
  85. });
  86. }
  87. computePages() {
  88. if (!this.preview) return 0;
  89. this.preview.style.display = 'block';
  90. const lines = this.preview.clientHeight / 20;
  91. this.preview.style.display = 'none';
  92. return Math.ceil(lines / this.pageLine);
  93. }
  94. submit() {
  95. const { form } = this.props;
  96. form.validateFields((err) => {
  97. if (!err) {
  98. const data = form.getFieldsValue();
  99. data.isTrail = data.isTrail ? 1 : 0;
  100. data.pages = this.computePages();
  101. let handler;
  102. if (data.id) {
  103. handler = Sentence.editArticle(data);
  104. } else {
  105. handler = Sentence.addArticle(data);
  106. }
  107. handler.then(() => {
  108. asyncSMessage('保存成功');
  109. goBack();
  110. }).catch((e) => {
  111. if (e.result) form.setFields(formatFormError(data, e.result));
  112. });
  113. }
  114. });
  115. }
  116. changeContent(content) {
  117. this.content = content;
  118. if (this.preview) {
  119. this.preview.innerHTML = content;
  120. }
  121. }
  122. renderIntroduction() {
  123. const { getFieldDecorator } = this.props.form;
  124. return <Block>
  125. <Form>
  126. {getFieldDecorator('id')(<input hidden />)}
  127. {getFieldDecorator('chapter')(<input hidden />)}
  128. {getFieldDecorator('part')(<input hidden />)}
  129. <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='前言名称'>
  130. {getFieldDecorator('title')(
  131. <Input placeholder='请输入名称' />,
  132. )}
  133. </Form.Item>
  134. </Form>
  135. </Block>;
  136. }
  137. renderBase() {
  138. const { getFieldDecorator } = this.props.form;
  139. return <Block>
  140. <Form>
  141. {getFieldDecorator('id')(<input hidden />)}
  142. <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='Chapter'>
  143. {getFieldDecorator('chapter', {
  144. rules: [
  145. { required: true, message: '请选择章节' },
  146. ],
  147. })(
  148. <Select select={this.state.chapters} placeholder='请选择章节' onChange={(v) => {
  149. this.refreshPart(v);
  150. }} />,
  151. )}
  152. </Form.Item>
  153. <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='Part'>
  154. {getFieldDecorator('part', {
  155. rules: [
  156. { required: true, message: '请输入Part' },
  157. {
  158. validator: (rule, value, callback) => {
  159. if (this.partList.indexOf(value) >= 0) callback('该part已被使用');
  160. else callback();
  161. },
  162. },
  163. ],
  164. })(
  165. <InputNumber min={1} precision={0} formatter={(v) => parseInt(v, 10) || 1} />,
  166. )}
  167. </Form.Item>
  168. <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='名称'>
  169. {getFieldDecorator('title', {
  170. rules: [
  171. { required: true, message: '请输入名称' },
  172. ],
  173. })(
  174. <Input placeholder='请输入名称' />,
  175. )}
  176. </Form.Item>
  177. {/* <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='开放试用'>
  178. <Row>
  179. <Col span={4}>
  180. {getFieldDecorator('isTrail', {
  181. valuePropName: 'checked',
  182. })(
  183. <Switch checkedChildren='on' unCheckedChildren='off' />,
  184. )}
  185. </Col>
  186. <Col span={3}>
  187. <Form.Item>
  188. {getFieldDecorator('trailStart')(
  189. <InputNumber disabled={!getFieldValue('isTrail')} min={1} precision={0} formatter={(v) => parseInt(v, 10) || 1} />,
  190. )}
  191. </Form.Item>
  192. </Col>
  193. <Col span={1}>至</Col>
  194. <Col span={3}>
  195. <Form.Item>
  196. {getFieldDecorator('trailEnd')(
  197. <InputNumber disabled={!getFieldValue('isTrail')} min={1} precision={0} formatter={(v) => parseInt(v, 10) || 1} />,
  198. )}
  199. </Form.Item>
  200. </Col>
  201. </Row>
  202. </Form.Item> */}
  203. </Form>
  204. </Block>;
  205. }
  206. renderContent() {
  207. const { getFieldDecorator } = this.props.form;
  208. return <Block flex>
  209. <Form>
  210. <Form.Item label='文章录入'>
  211. {getFieldDecorator('content', {
  212. })(
  213. <Editor placeholder='输入内容'
  214. onChange={(value) => {
  215. this.changeContent(value);
  216. }} />,
  217. )}
  218. </Form.Item>
  219. </Form>
  220. <div ref={(ref) => {
  221. if (ref) {
  222. this.preview = ref;
  223. this.preview.style.display = 'none';
  224. this.changeContent(this.content);
  225. }
  226. }} className='simulation' />
  227. </Block>;
  228. }
  229. renderView() {
  230. const { mode } = this.state;
  231. return <div flex>
  232. {mode === 'introduction' ? this.renderIntroduction() : this.renderBase()}
  233. {this.renderContent()}
  234. <Row type="flex" justify="center">
  235. <Col>
  236. <Button type="primary" onClick={() => {
  237. this.submit();
  238. }}>保存</Button>
  239. </Col>
  240. </Row>
  241. </div>;
  242. }
  243. }