浏览代码

feat(front): 机经

Go 5 年之前
父节点
当前提交
e0a7f7d34e
共有 55 个文件被更改,包括 1185 次插入358 次删除
  1. 37 0
      front/project/admin/routes/setting/time/page.js
  2. 2 2
      front/project/admin/routes/textbook/topic/page.js
  3. 9 9
      front/project/admin/routes/textbook/topicDetail/page.js
  4. 8 0
      front/project/admin/stores/system.js
  5. 3 0
      front/project/h5/routes/textbook/detail/page.js
  6. 8 6
      front/project/www/components/Date/index.js
  7. 1 1
      front/project/www/components/Date/index.less
  8. 6 6
      front/project/www/components/Item/index.js
  9. 9 2
      front/project/www/components/Login/index.js
  10. 1 1
      front/project/www/components/Other/index.js
  11. 25 11
      front/project/www/components/OtherModal/index.js
  12. 2 2
      front/project/www/components/UserPagination/index.js
  13. 1 1
      front/project/www/routes/my/tools/page.js
  14. 329 30
      front/project/www/routes/textbook/main/page.js
  15. 1 1
      front/project/www/routes/textbook/topic/index.js
  16. 109 14
      front/project/www/routes/textbook/topic/page.js
  17. 1 1
      front/project/www/routes/textbook/topicDetail/index.js
  18. 91 30
      front/project/www/routes/textbook/topicDetail/page.js
  19. 81 7
      front/project/www/routes/textbook/year/page.js
  20. 7 7
      front/project/www/static/login.html
  21. 3 3
      front/project/www/stores/my.js
  22. 10 6
      front/project/www/stores/textbook.js
  23. 5 7
      front/project/www/stores/user.js
  24. 1 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java
  25. 12 12
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookTopic.java
  26. 16 16
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserTextbookEnroll.java
  27. 12 12
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserTextbookFeedback.java
  28. 2 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookTopicMapper.xml
  29. 2 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserTextbookEnrollMapper.xml
  30. 2 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserTextbookFeedbackMapper.xml
  31. 9 0
      server/data/src/main/java/com/qxgmat/data/relation/UserOrderRecordRelationMapper.java
  32. 2 5
      server/data/src/main/java/com/qxgmat/data/relation/UserTextbookEnrollRelationMapper.java
  33. 9 10
      server/data/src/main/java/com/qxgmat/data/relation/entity/TextbookEnrollNumberRelation.java
  34. 37 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserOrderRecordRelationMapper.xml
  35. 16 12
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserTextbookEnrollRelationMapper.xml
  36. 5 4
      server/data/src/main/resources/db/migration/V1__init_table.sql
  37. 17 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  38. 5 5
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/TextbookController.java
  39. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  40. 78 50
      server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java
  41. 9 9
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/TextbookTopicInfoDto.java
  42. 36 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/TextbookEnrollTimeExtendDto.java
  43. 5 5
      server/gateway-api/src/main/java/com/qxgmat/dto/request/TextbookEnrollDto.java
  44. 9 9
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserTextbookFeedbackDto.java
  45. 13 20
      server/gateway-api/src/main/java/com/qxgmat/dto/response/TextbookEnrollTimeDto.java
  46. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageExtendService.java
  47. 4 2
      server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java
  48. 91 6
      server/gateway-api/src/main/java/com/qxgmat/service/extend/TextbookService.java
  49. 10 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ToolsService.java
  50. 2 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookLibraryHistoryService.java
  51. 2 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookLibraryService.java
  52. 16 12
      server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookTopicService.java
  53. 5 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderRecordService.java
  54. 6 10
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserTextbookEnrollService.java
  55. 1 1
      server/tools/src/main/java/com/nuliji/tools/Tools.java

+ 37 - 0
front/project/admin/routes/setting/time/page.js

@@ -78,6 +78,9 @@ export default class extends Page {
     if (tab === 'paper') {
     if (tab === 'paper') {
       return this.refreshExercisePaperAuto();
       return this.refreshExercisePaperAuto();
     }
     }
+    if (tab === 'textbook') {
+      return this.refreshTextbookConfig();
+    }
     return Promise.reject();
     return Promise.reject();
   }
   }
 
 
@@ -132,6 +135,15 @@ export default class extends Page {
     });
     });
   }
   }
 
 
+  refreshTextbookConfig() {
+    return System.getTextbookConfig().then((result) => {
+      this.setState({ textbookConfig: result || {} });
+
+      const { form } = this.props;
+      form.setFieldsValue(flattenObject(result, 'textbookConfig'));
+    });
+  }
+
   structExercise() {
   structExercise() {
     return Exercise.allStruct().then(result => {
     return Exercise.allStruct().then(result => {
       const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; return row; });
       const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; return row; });
@@ -356,6 +368,28 @@ export default class extends Page {
     </Form>;
     </Form>;
   }
   }
 
 
+  renderTextbookConfig() {
+    const { getFieldDecorator } = this.props.form;
+    return <Form>
+      <Row>
+        <Col span={12}>
+          <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='每月基础人数'>
+            {getFieldDecorator('textbookConfig.use_number', {
+              rules: [
+                { required: true, message: '输入每月基础人数' },
+              ],
+            })(
+              <InputNumber placeholder='请输入每月基础人数' onChange={(value) => {
+                this.changeValue('textbookConfig', 'use_number', value);
+              }} style={{ width: '200px' }} />,
+            )}
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form>;
+  }
+
+
   renderExamination() {
   renderExamination() {
     return <TableLayout
     return <TableLayout
       columns={this.examinationColumns}
       columns={this.examinationColumns}
@@ -386,6 +420,9 @@ export default class extends Page {
         <Tabs.TabPane tab="组卷" key="paper">
         <Tabs.TabPane tab="组卷" key="paper">
           {this.renderExercisePaperAuto()}
           {this.renderExercisePaperAuto()}
         </Tabs.TabPane>
         </Tabs.TabPane>
+        <Tabs.TabPane tab="机经" key="textbook">
+          {this.renderTextbookConfig()}
+        </Tabs.TabPane>
       </Tabs>
       </Tabs>
       {tab !== 'examination' && <Row type="flex" justify="center">
       {tab !== 'examination' && <Row type="flex" justify="center">
         <Col>
         <Col>

+ 2 - 2
front/project/admin/routes/textbook/topic/page.js

@@ -30,7 +30,7 @@ export default class extends Page {
       },
       },
     }];
     }];
     this.filterForm = [{
     this.filterForm = [{
-      key: 'questionSubject',
+      key: 'textbookSubject',
       type: 'select',
       type: 'select',
       name: '单项',
       name: '单项',
       select: TextbookSubject,
       select: TextbookSubject,
@@ -52,7 +52,7 @@ export default class extends Page {
     }];
     }];
     this.columns = [{
     this.columns = [{
       title: '单项',
       title: '单项',
-      dataIndex: 'questionSubject',
+      dataIndex: 'textbookSubject',
       render: (text) => {
       render: (text) => {
         return TextbookSubjectMap[text] || '';
         return TextbookSubjectMap[text] || '';
       },
       },

+ 9 - 9
front/project/admin/routes/textbook/topicDetail/page.js

@@ -16,7 +16,7 @@ import { Textbook } from '../../../stores/textbook';
 export default class extends Page {
 export default class extends Page {
   init() {
   init() {
     this.filterForm = [{
     this.filterForm = [{
-      key: 'questionSubject',
+      key: 'testbookSubject',
       type: 'select',
       type: 'select',
       name: '单项',
       name: '单项',
       select: TextbookSubject,
       select: TextbookSubject,
@@ -55,8 +55,8 @@ export default class extends Page {
   }
   }
 
 
   refreshLibrary() {
   refreshLibrary() {
-    const { libraryId, questionSubject } = this.state.search;
-    Textbook.getNextTopic({ libraryId, questionSubject }).then(result => {
+    const { libraryId, testbookSubject } = this.state.search;
+    Textbook.getNextTopic({ libraryId, testbookSubject }).then(result => {
       this.setState({ no: result });
       this.setState({ no: result });
       this.addTopic();
       this.addTopic();
     });
     });
@@ -94,8 +94,8 @@ export default class extends Page {
         const data = form.getFieldsValue();
         const data = form.getFieldsValue();
         let handler;
         let handler;
         if (!this.params.id) {
         if (!this.params.id) {
-          const { libraryId, questionSubject } = this.state.search;
-          handler = Promise.all([data.topic.filter(row => row).map((row, index) => Textbook.addTopic(Object.assign({ libraryId, questionSubject }, row, { isOld: row.isOld ? 1 : 0, no: this.state.no + index })))]);
+          const { libraryId, textbookSubject } = this.state.search;
+          handler = Promise.all([data.topic.filter(row => row).map((row, index) => Textbook.addTopic(Object.assign({ libraryId, textbookSubject }, row, { isOld: row.isOld ? 1 : 0, no: this.state.no + index })))]);
         } else {
         } else {
           handler = Textbook.editTopic(Object.assign({ id: this.params.id }, data.topic[0], { isOld: data.topic[0].isOld }));
           handler = Textbook.editTopic(Object.assign({ id: this.params.id }, data.topic[0], { isOld: data.topic[0].isOld }));
         }
         }
@@ -111,7 +111,7 @@ export default class extends Page {
     });
     });
   }
   }
 
 
-  renderInfo(index, questionSubject, no) {
+  renderInfo(index, textbookSubject, no) {
     const { getFieldDecorator } = this.props.form;
     const { getFieldDecorator } = this.props.form;
     return <Block flex>
     return <Block flex>
       <Row>
       <Row>
@@ -136,7 +136,7 @@ export default class extends Page {
                   message: '请选择',
                   message: '请选择',
                 }],
                 }],
               })(
               })(
-                questionSubject === 'quant' ? <Select select={TextbookType} /> : <Input />,
+                textbookSubject === 'quant' ? <Select select={TextbookType} /> : <Input />,
               )}
               )}
             </Form.Item>
             </Form.Item>
           </Col>
           </Col>
@@ -189,7 +189,7 @@ export default class extends Page {
           this.search(data);
           this.search(data);
         }} />
         }} />
     </Block>
     </Block>
-      {keys.map((key, index) => this.renderInfo(key, this.state.search.questionSubject, this.state.no + index))}
+      {keys.map((key, index) => this.renderInfo(key, this.state.search.textbookSubject, this.state.no + index))}
       {this.state.no && <Row type="flex" justify="center">
       {this.state.no && <Row type="flex" justify="center">
         <Col>
         <Col>
           <Form.Item>
           <Form.Item>
@@ -203,7 +203,7 @@ export default class extends Page {
   }
   }
 
 
   renderEdit() {
   renderEdit() {
-    return this.renderInfo(0, this.state.data.questionSubject, this.state.data.no);
+    return this.renderInfo(0, this.state.data.textbookSubject, this.state.data.no);
   }
   }
 
 
   renderView() {
   renderView() {

+ 8 - 0
front/project/admin/stores/system.js

@@ -93,6 +93,14 @@ export default class SystemStore extends BaseStore {
     return this.apiPut('/setting/textbook_time', params);
     return this.apiPut('/setting/textbook_time', params);
   }
   }
 
 
+  getTextbookConfig() {
+    return this.apiGet('/setting/textbook_config');
+  }
+
+  setTextbookConfig(params) {
+    return this.apiPut('/setting/textbook_config', params);
+  }
+
   getExaminationTime() {
   getExaminationTime() {
     return this.apiGet('/setting/examination_time');
     return this.apiGet('/setting/examination_time');
   }
   }

+ 3 - 0
front/project/h5/routes/textbook/detail/page.js

@@ -50,6 +50,9 @@ export default class extends Page {
   initData() {
   initData() {
     Textbook.getInfo()
     Textbook.getInfo()
       .then(result => {
       .then(result => {
+        if (!result.hasService) {
+          linkTo('/textbook');
+        }
         this.setState(result);
         this.setState(result);
       });
       });
     const { subject } = this.params;
     const { subject } = this.params;

+ 8 - 6
front/project/www/components/Date/index.js

@@ -98,7 +98,8 @@ export class TwoDate extends Component {
   }
   }
 
 
   onLeftSelect(date) {
   onLeftSelect(date) {
-    const { onChange } = this.props;
+    const { onChange, startDate } = this.props;
+    if (startDate && date.isBefore(startDate)) return;
     this.setState({
     this.setState({
       value: date,
       value: date,
       leftValue: date,
       leftValue: date,
@@ -108,7 +109,8 @@ export class TwoDate extends Component {
   }
   }
 
 
   onRightSelect(date) {
   onRightSelect(date) {
-    const { onChange } = this.props;
+    const { onChange, endDate } = this.props;
+    if (endDate && date.isAfter(endDate)) return;
     this.setState({
     this.setState({
       value: date,
       value: date,
       rightValue: date,
       rightValue: date,
@@ -131,7 +133,7 @@ export class TwoDate extends Component {
           <Icon type="left" onClick={() => this.onLeftSelect(leftValue.clone().subtract(1, 'month'))} />
           <Icon type="left" onClick={() => this.onLeftSelect(leftValue.clone().subtract(1, 'month'))} />
         </div>
         </div>
         <span>{leftValue.year()}年 </span>
         <span>{leftValue.year()}年 </span>
-        <span>{leftValue.month()}月 </span>
+        <span>{leftValue.month() + 1}月 </span>
         <span className="t-4">{extendInfo && extendInfo(leftValue)}</span>
         <span className="t-4">{extendInfo && extendInfo(leftValue)}</span>
       </div>
       </div>
     );
     );
@@ -143,14 +145,14 @@ export class TwoDate extends Component {
     return (
     return (
       <div className="t-c">
       <div className="t-c">
         <span>{rightValue.year()}年 </span>
         <span>{rightValue.year()}年 </span>
-        <span>{rightValue.month()}月 </span>
+        <span>{rightValue.month() + 1}月 </span>
         <span className="t-4">{extendInfo && extendInfo(rightValue)}</span>
         <span className="t-4">{extendInfo && extendInfo(rightValue)}</span>
         <div style={{ right: 15, top: 0 }} className="p-a">
         <div style={{ right: 15, top: 0 }} className="p-a">
-          <Icon type="right" onClick={() => this.onRightSelect(rightValue.clone().add(1, 'year'))} />
+          <Icon type="right" onClick={() => this.onRightSelect(rightValue.clone().add(1, 'month'))} />
           <Icon
           <Icon
             className="m-l-5"
             className="m-l-5"
             type="double-right"
             type="double-right"
-            onClick={() => this.onRightSelect(rightValue.clone().add(1, 'month'))}
+            onClick={() => this.onRightSelect(rightValue.clone().add(1, 'year'))}
           />
           />
         </div>
         </div>
       </div>
       </div>

+ 1 - 1
front/project/www/components/Date/index.less

@@ -204,7 +204,7 @@
   .ant-fullcalendar-last-month-btn-day,
   .ant-fullcalendar-last-month-btn-day,
   .ant-fullcalendar-next-month-btn-day {
   .ant-fullcalendar-next-month-btn-day {
     .ant-fullcalendar-value {
     .ant-fullcalendar-value {
-      color: rgba(0, 0, 0, .65) !important;
+      color: rgba(0, 0, 0, .25) !important;
       background: #fff !important;
       background: #fff !important;
     }
     }
   }
   }

+ 6 - 6
front/project/www/components/Item/index.js

@@ -1,7 +1,7 @@
 import React, { Component } from 'react';
 import React, { Component } from 'react';
 import './index.less';
 import './index.less';
 import Assets from '@src/components/Assets';
 import Assets from '@src/components/Assets';
-import { getMap, formatSeconds } from '@src/services/Tools';
+import { getMap, formatSeconds, formatDate } from '@src/services/Tools';
 import Button from '../Button';
 import Button from '../Button';
 import More from '../More';
 import More from '../More';
 import { Order } from '../../stores/order';
 import { Order } from '../../stores/order';
@@ -292,17 +292,17 @@ export class TextbookItem extends Component {
   }
   }
 
 
   render() {
   render() {
-    const { data = {} } = this.props;
+    const { data = {}, menu, onClick, onMenuClick } = this.props;
     return (
     return (
       <div className="textbook-item">
       <div className="textbook-item">
-        <Assets src={data.src} className="m-b-5" />
+        <Assets name="sun_blue" className="m-b-5" onClick={() => onClick()} />
         <div className="t-6 t-s-14 m-b-5">
         <div className="t-6 t-s-14 m-b-5">
-          已更新至 <span className="t-4">30</span> 题
+          已更新至 <span className="t-4">{data.number}</span> 题
         </div>
         </div>
         <div className="t-6 t-s-12 m-b-1">
         <div className="t-6 t-s-12 m-b-1">
-          2019-08-31 09:26:13{' '}
+          {formatDate(data.time, 'YYYY-MM-DD HH:mm:ss')}
           <div className="f-r">
           <div className="f-r">
-            <More />
+            <More menu={menu} onClick={onMenuClick} />
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>

+ 9 - 2
front/project/www/components/Login/index.js

@@ -36,7 +36,11 @@ export default class Login extends Component {
       },
       },
       false,
       false,
     );
     );
-    if (!props.user.login) {
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (nextProps.user.needLogin && !this.init) {
+      this.init = true;
       Main.getContract('register')
       Main.getContract('register')
         .then(result => {
         .then(result => {
           this.setState({ registerContract: result });
           this.setState({ registerContract: result });
@@ -101,7 +105,10 @@ export default class Login extends Component {
       } else {
       } else {
         this.setState({ type: BIND_PHONE });
         this.setState({ type: BIND_PHONE });
       }
       }
-    });
+    })
+      .catch(err => {
+        this.setState({ type: BIND_WX_ERROR, wechatError: err.message });
+      });
   }
   }
 
 
   scanBind(code) {
   scanBind(code) {

+ 1 - 1
front/project/www/components/Other/index.js

@@ -94,7 +94,7 @@ export class AnswerCarousel extends Component {
               })}
               })}
             </Carousel>
             </Carousel>
           )}
           )}
-          <div className="fixed" />
+          {!tabs && <div className="fixed" />}
           <Assets name="footer_next_highlight_1" className="next" onClick={() => this.onNext()} />
           <Assets name="footer_next_highlight_1" className="next" onClick={() => this.onNext()} />
           <Assets name="footer_previous_highlight_1" className="prev" onClick={() => this.onPrev()} />
           <Assets name="footer_previous_highlight_1" className="prev" onClick={() => this.onPrev()} />
         </div>
         </div>

+ 25 - 11
front/project/www/components/OtherModal/index.js

@@ -8,7 +8,7 @@ import Assets from '@src/components/Assets';
 import scale from '@src/services/Scale';
 import scale from '@src/services/Scale';
 import { asyncSMessage } from '@src/services/AsyncTools';
 import { asyncSMessage } from '@src/services/AsyncTools';
 import { SelectInput, VerificationInput, Input } from '../Login';
 import { SelectInput, VerificationInput, Input } from '../Login';
-import { MobileArea, TextbookFeedbackTarget } from '../../../Constant';
+import { MobileArea, TextbookFeedbackTarget, TextbookSubject } from '../../../Constant';
 import Invite from '../Invite';
 import Invite from '../Invite';
 import Modal from '../Modal';
 import Modal from '../Modal';
 import { Common } from '../../stores/common';
 import { Common } from '../../stores/common';
@@ -17,7 +17,7 @@ import { My } from '../../stores/my';
 import Select from '../Select';
 import Select from '../Select';
 import { formatDate, getMap } from '../../../../src/services/Tools';
 import { formatDate, getMap } from '../../../../src/services/Tools';
 
 
-const TextbookFeedbackTargetMap = getMap(TextbookFeedbackTarget, 'value', 'label');
+const TextbookFeedbackTargetMap = getMap(TextbookFeedbackTarget, 'value', 'tip');
 
 
 export class BindPhone extends Component {
 export class BindPhone extends Component {
   constructor(props) {
   constructor(props) {
@@ -932,7 +932,21 @@ export class CourseNoteModal extends Component {
 export class TextbookFeedbackModal extends Component {
 export class TextbookFeedbackModal extends Component {
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
-    this.state = { data: {} };
+    this.state = {
+      data: {},
+      targetList: TextbookFeedbackTarget.map(row => {
+        return {
+          title: row.label,
+          key: row.value,
+        };
+      }),
+      textbookSubject: TextbookSubject.map(row => {
+        return {
+          title: row.label,
+          key: row.value,
+        };
+      }),
+    };
   }
   }
 
 
   componentWillReceiveProps(nextProps) {
   componentWillReceiveProps(nextProps) {
@@ -946,7 +960,7 @@ export class TextbookFeedbackModal extends Component {
     const { data } = this.state;
     const { data } = this.state;
     if (!data.content) return;
     if (!data.content) return;
     if (data.target !== 'new' && !data.no) return;
     if (data.target !== 'new' && !data.no) return;
-    My.addTextbookFeedback(data.questionSubject, data.target, data.no, data.content).then(() => {
+    My.addTextbookFeedback(data.textbookSubject, data.target, data.no, data.content).then(() => {
       if (onConfirm) onConfirm();
       if (onConfirm) onConfirm();
       this.setState({ data: {} });
       this.setState({ data: {} });
     });
     });
@@ -960,7 +974,7 @@ export class TextbookFeedbackModal extends Component {
 
 
   render() {
   render() {
     const { show } = this.props;
     const { show } = this.props;
-    const { data } = this.state;
+    const { data, targetList, textbookSubject } = this.state;
     return (
     return (
       <Modal
       <Modal
         show={show}
         show={show}
@@ -971,20 +985,20 @@ export class TextbookFeedbackModal extends Component {
       >
       >
         <div className="t-2 t-s-16 m-b-1">
         <div className="t-2 t-s-16 m-b-1">
           机经类别: <Select
           机经类别: <Select
-            value={data.questionSubject}
+            value={data.textbookSubject}
             theme="white"
             theme="white"
-            list={[{ title: '数学机经', key: 'quant' }, { title: '逻辑机经', key: 'rc' }, { title: '阅读机经', key: 'ir' }]}
+            list={textbookSubject}
             onChange={(value) => {
             onChange={(value) => {
-              data.questionSubject = value;
+              data.textbookSubject = value;
               this.setState({ data });
               this.setState({ data });
             }}
             }}
           />
           />
           反馈类型: <Select
           反馈类型: <Select
             value={data.target}
             value={data.target}
             theme="white"
             theme="white"
-            list={TextbookFeedbackTarget}
-            onChange={(value) => {
-              data.target = value;
+            list={targetList}
+            onChange={({ key }) => {
+              data.target = key;
               this.setState({ data });
               this.setState({ data });
             }}
             }}
           />
           />

+ 2 - 2
front/project/www/components/UserPagination/index.js

@@ -30,8 +30,8 @@ export default class extends Component {
               size="small"
               size="small"
               theme="white"
               theme="white"
               value={current}
               value={current}
-              list={[...Array(all)].map((key, index) => ({ title: `第${index + 1}页`, key: index + 1 }))}
-              onChange={key => this.onChangePage(key)}
+              list={all > 0 ? [...Array(all)].map((key, index) => ({ title: `第${index + 1}页`, key: index + 1 })) : []}
+              onChange={({ key }) => this.onChangePage(key)}
             />
             />
           </div>
           </div>
         )}
         )}

+ 1 - 1
front/project/www/routes/my/tools/page.js

@@ -573,7 +573,7 @@ export default class extends Page {
             {list.map(item => {
             {list.map(item => {
               return (
               return (
                 <div className="data-item">
                 <div className="data-item">
-                  <Assets name="sun_blue" />
+                  <Assets name="sun_blue" onClick={() => linkTo(`/textbook/topic/list/${item.subject}`)} />
                   <div className="title">
                   <div className="title">
                     已更新至<b>{item.num}</b>题
                     已更新至<b>{item.num}</b>题
                   </div>
                   </div>

+ 329 - 30
front/project/www/routes/textbook/main/page.js

@@ -3,42 +3,304 @@ import { Link } from 'react-router-dom';
 import './index.less';
 import './index.less';
 import Page from '@src/containers/Page';
 import Page from '@src/containers/Page';
 import Assets from '@src/components/Assets';
 import Assets from '@src/components/Assets';
+import { getMap, formatDate } from '@src/services/Tools';
+import { CommentModal, FaqModal, TextbookFeedbackModal, FinishModal } from '../../../components/OtherModal';
 import { CommentFalls, AnswerCarousel, Consultation, Contact } from '../../../components/Other';
 import { CommentFalls, AnswerCarousel, Consultation, Contact } from '../../../components/Other';
+import Modal from '../../../components/Modal';
 import Footer from '../../../components/Footer';
 import Footer from '../../../components/Footer';
 import Button from '../../../components/Button';
 import Button from '../../../components/Button';
 import UserTable from '../../../components/UserTable';
 import UserTable from '../../../components/UserTable';
 import Tabs from '../../../components/Tabs';
 import Tabs from '../../../components/Tabs';
 import { TextbookItem } from '../../../components/Item';
 import { TextbookItem } from '../../../components/Item';
 import { TwoDate } from '../../../components/Date';
 import { TwoDate } from '../../../components/Date';
+import { Main } from '../../../stores/main';
+import { Textbook } from '../../../stores/textbook';
+import { Order } from '../../../stores/order';
+import { User } from '../../../stores/user';
+import { TextbookFeedbackTarget } from '../../../../Constant';
+
+const textbookHistoryColumns = [
+  {
+    title: '更新时间',
+    key: 'createTime',
+    width: 120,
+    render: (text) => {
+      return <div className="sub">
+        <div className="t-2 t-s-12">{text.split(' ')[0]}</div>
+        <div className="t-6 t-s-12">{text.split(' ')[1]}</div>
+      </div>;
+    },
+  },
+  { title: '版本', key: 'version', width: 120 },
+  { title: '更新内容', key: 'content', width: 330 },
+];
 
 
 export default class extends Page {
 export default class extends Page {
   initState() {
   initState() {
     return {
     return {
-      list: [{}, {}, {}],
+      tab: 'baselibrary',
+      list: [],
+      enroll: {},
+      load: 0,
     };
     };
   }
   }
 
 
+  init() {
+    this.enrollMap = {};
+    this.libraryMap = {};
+    Main.getBase()
+      .then(result => {
+        this.setState({ base: result });
+      });
+
+    Textbook.getInfo().then((result) => {
+      const { latest } = result;
+      result.day = parseInt((new Date().getTime() - new Date(result.latest.startDate).getTime()) / 86400000, 10);
+
+      result.expireDay =
+        result.expireTime && parseInt((new Date(result.expireTime).getTime() - new Date().getTime()) / 86400000, 10);
+
+      const list = [];
+
+      list.push({ subject: 'quant', number: latest.quantNumber, time: latest.quantTime, version: latest.quantVersion });
+      list.push({ subject: 'rc', number: latest.rcNumber, time: latest.rcTime, version: latest.rcVersion });
+      list.push({ subject: 'ir', number: latest.irNumber, time: latest.irTime, version: latest.irVersion });
+      this.setState({ data: result, list });
+    });
+  }
+
+  initData() {
+    this.refreshFaqs(this.state.tab);
+    this.refreshComments();
+    const start = new Date();
+    start.setMinutes(0, 0, 0);
+    start.setHours(0);
+    start.setDate(1);
+    start.setMonth(start.getMonth() - 2);
+    const end = new Date();
+    end.setMinutes(0, 0, 0);
+    end.setHours(0);
+    end.setDate(1);
+    end.setMonth(end.getMonth() + 4);
+    const startDate = formatDate(start, 'YYYY-MM-DD');
+    const endDate = formatDate(end, 'YYYY-MM-DD');
+    this.refreshEnroll(startDate, endDate);
+    this.setState({ startDate, endDate });
+
+    const nowYear = new Date().getFullYear();
+    this.refreshYear(nowYear);
+    if (nowYear > start.getFullYear()) {
+      this.refreshYear(nowYear - 1);
+    }
+  }
+
+  refreshFaqs(tab) {
+    Main.listFaq({ page: 1, size: 1000, channel: `library-${tab}` })
+      .then((result => {
+        this.setState({ faqs: result.list });
+      }));
+  }
+
+  refreshComments() {
+    Main.listComment({ page: 1, size: 1000, channel: 'library' })
+      .then(result => {
+        this.setState({ comments: result.list });
+      });
+  }
+
+  refreshEnroll(startDate, endDate) {
+    const month = formatDate(new Date(), 'YYYY-MM');
+    Textbook.listEnroll(startDate, endDate)
+      .then(result => {
+        result.times = result.times.map(row => {
+          row.month = formatDate(row.month, 'YYYY-MM');
+          if (row.month === month) {
+            // 本月机经开通人数
+            this.setState({ useNumber: row.useNumber });
+          }
+          return row;
+        });
+        this.enrollMap = getMap(result.times, 'month');
+        if (result.date) {
+          const d = new Date(result.date);
+          result.dateF = formatDate(d, 'YYYY-MM-DD');
+          result.day = parseInt((d.getTime() - new Date().getTime()) / 86400000, 10);
+        }
+        this.setState({ enroll: result, load: this.state.load + 1 });
+      });
+  }
+
+  refreshYear(year) {
+    Textbook.listYear(year)
+      .then(result => {
+        result = result.map(row => {
+          row.day = formatDate(row.startDate, 'YYYY-MM-DD');
+          this.libraryMap[row.day] = row;
+          return row;
+        });
+        this.setState({ library: result, load: this.state.load + 1 });
+      });
+  }
+
+  textbookHistory({ page, size, subject }) {
+    this.setState({ subject });
+    Textbook.allHistory(subject).then(result => {
+      this.setState({
+        showUpdate: true,
+        updateList: result.map(row => {
+          row.version = row[`${subject}Version`];
+          row.content = row[`${subject}Content`];
+          row.createTime = formatDate(row.createTime, 'YYYY-MM-DD HH:mm:ss');
+          return row;
+        }),
+        // 不显示分页
+        updateTotal: 0,
+        maxHeight: 730,
+        updatePage: page,
+        updateData: { page, size, subject, columns: textbookHistoryColumns, type: 'textbook' },
+      });
+    });
+  }
+
+  enroll() {
+    const { date, enroll } = this.state;
+    if (enroll.date) return;
+    if (!date) {
+      this.setState({ showWarn: true, warn: { title: '报名', content: '请先选择报考日期' } });
+      return;
+    }
+    User.needLogin()
+      .then(() => {
+        Textbook.enroll(date.format('YYYY-MM-DD'))
+          .then(() => {
+            enroll.date = new Date(date);
+            enroll.dateF = date.format('YYYY-MM-DD');
+            enroll.day = parseInt((enroll.date.getTime() - new Date().getTime()) / 86400000, 10);
+            this.setState({ showWarn: true, warn: { title: '报名', content: `已报考${formatDate(date, 'YYYY-MM-DD')}` } });
+            this.setState({ enroll });
+          });
+      });
+  }
+
+  unEnroll() {
+    const { enroll } = this.state;
+    if (!enroll.date) return;
+    User.needLogin()
+      .then(() => {
+        Textbook.unEnroll()
+          .then(() => {
+            this.setState({ enroll: {} });
+          });
+      });
+  }
+
+  onTabChange(key) {
+    this.refreshFaqs(key);
+    this.setState({ tab: key });
+  }
+
+  open(recordId) {
+    User.needLogin()
+      .then(() => {
+        Order.useRecord(recordId)
+          .then(() => {
+            this.refresh();
+          });
+      });
+  }
+
+  buy() {
+    User.needLogin()
+      .then(() => {
+        return Order.speedPay({ productType: 'service', service: 'textbook' });
+      })
+      .then((order) => {
+        return User.needPay(order);
+      })
+      .then(() => {
+        this.refresh();
+      });
+  }
+
   renderView() {
   renderView() {
+    const { data = {}, base = {}, tab, faqs = [], comments = [], showFaq, faq = {}, showFinish, showComment, comment = {}, showUpdate, updateData = {}, updateList = [], updateTotal, maxHeight, showFeedback, feedback = {}, showWarn, warn = {} } = this.state;
     return (
     return (
       <div>
       <div>
         {this.renderDate()}
         {this.renderDate()}
-        {this.renderLog()}
-        {this.renderCompare()}
-        {this.renderList()}
+        {!data.hasService && data.unUseRecord && this.renderLog()}
+        {!data.hasService && !data.unUseRecord && this.renderCompare()}
+        {data.hasService && this.renderList()}
         <AnswerCarousel
         <AnswerCarousel
           hideBtn
           hideBtn
-          tabActive={'1'}
-          tabs={[{ title: '换库知识', key: '1' }, { title: '机经知识', key: '2' }, { title: '千行机经', key: '3' }]}
+          tabActive={tab}
+          list={faqs}
+          tabs={[{ title: '换库知识', key: 'baselibrary' }, { title: '机经知识', key: 'basetextbook' }, { title: '千行机经', key: 'qxtextbook' }]}
+          onTabChange={(key) => this.onTabChange(key)}
         />
         />
-        <CommentFalls />
+        <CommentFalls list={comments} />
         <Consultation />
         <Consultation />
-        <Contact />
+        <Contact data={base.contact} />
         <Footer />
         <Footer />
+
+        <Modal show={showWarn} title={warn.title} confirmText="好的,知道了" btnAlign="center" onConfirm={() => this.setState({ showWarn: false })}>
+          <div className="t-2 t-s-18">{warn.content}</div>
+        </Modal>,
+        <Modal
+          show={showUpdate}
+          maskClosable
+          close={false}
+          body={false}
+          width={630}
+          onClose={() => this.setState({ showUpdate: false, updateList: [] })}
+        >
+          <UserTable
+            size="small"
+            theme="top"
+            columns={updateData.columns}
+            data={updateList}
+            current={updateData.page}
+            pageSize={updateData.size}
+            onChange={page => {
+              updateData.page = page;
+              if (updateData.type === 'data') {
+                this.dataHistory(updateData);
+              } else if (updateData.type === 'textbook') {
+                this.textbookHistory(updateData);
+              } else if (updateData.type === 'record') {
+                this.recordList(updateData);
+              }
+            }}
+            total={updateTotal}
+            maxHeight={maxHeight}
+          />
+        </Modal>
+        <TextbookFeedbackModal
+          show={showFeedback}
+          defaultData={feedback}
+          onConfirm={() => this.setState({ showFeedback: false, showFinish: true })}
+          onCancel={() => this.setState({ showFeedback: false })}
+          onClose={() => this.setState({ showFeedback: false })}
+        />
+        <CommentModal
+          show={showComment}
+          defaultData={comment}
+          onConfirm={() => this.setState({ showComment: false, showFinish: true })}
+          onCancel={() => this.setState({ showComment: false })}
+          onClose={() => this.setState({ showComment: false })}
+        />
+        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false })} onConfirm={() => this.setState({ showFaq: false, showFinish: true })} />
+        <FinishModal
+          getContainer={() => document.getElementById(this.video.state.id)}
+          show={showFinish}
+          onConfirm={() => this.setState({ showFinish: false })}
+        />
       </div>
       </div>
     );
     );
   }
   }
 
 
   renderDate() {
   renderDate() {
+    const { data, enroll = {}, useNumber, startDate, endDate, load } = this.state;
+    const { latest = {}, day } = data;
     return (
     return (
       <div className="date-layout">
       <div className="date-layout">
         <div className="content">
         <div className="content">
@@ -47,31 +309,55 @@ export default class extends Page {
               <span className="today">今日</span>
               <span className="today">今日</span>
               <span className="type-1">换库</span>
               <span className="type-1">换库</span>
               <span className="type-2">考试日</span>
               <span className="type-2">考试日</span>
-              <Button size="small" radius>
+              {enroll.date && <span>
+                {enroll.day > 0 ? `距离考试还有${enroll.day}天` : `距离考试已过去${enroll.day * -1}天`}
+              </span>}
+              {enroll.date && <Button size="small" radius onClick={() => this.unEnroll()}>
+                取消报考
+              </Button>}
+              {!enroll.date && <Button size="small" radius onClick={() => this.enroll()}>
                 我已报考
                 我已报考
-              </Button>
-              <Link to="" className="f-r">
+              </Button>}
+              <Link to="/textbook/year" className="f-r">
                 按年份查看 >
                 按年份查看 >
               </Link>
               </Link>
             </div>
             </div>
             <TwoDate
             <TwoDate
-              getType={date => (date.date() === 1 ? 'type-1' : 'type-2')}
-              extendInfo={date => `${date.month()}人`}
-              onChange={() => {}}
+              key={load}
+              startDate={startDate}
+              endDate={endDate}
+              getType={date => {
+                const d = date.format('YYYY-MM-DD');
+                if (enroll.date && d === enroll.dateF) {
+                  return 'type-2';
+                }
+                if (this.libraryMap[d]) {
+                  return 'type-1';
+                }
+                return null;
+              }}
+              extendInfo={date => {
+                const d = date.format('YYYY-MM');
+                return `${this.enrollMap[d] ? this.enrollMap[d].enrollNumber : 0}人`;
+              }}
+              onChange={(date) => this.setState({ date })}
             />
             />
           </div>
           </div>
           <div style={{ width: 275 }} className="b f-r p-20">
           <div style={{ width: 275 }} className="b f-r p-20">
             <div className="t-13 t-s-16">最近换库</div>
             <div className="t-13 t-s-16">最近换库</div>
             <Assets name="" />
             <Assets name="" />
-            <div className="t-13 t-s-32 t-c">2019-07-22</div>
+            <div className="t-13 t-s-32 t-c">{latest.startDate ? formatDate(latest.startDate, 'YYYY-MM-DD') : ''}</div>
             <div className="t-13 t-c t-s-16">
             <div className="t-13 t-c t-s-16">
-              已换库 <span className="t-4">10</span> 天
+              已换库 <span className="t-4">{day}</span> 天
             </div>
             </div>
             <div className="m-t-2 t-c">
             <div className="m-t-2 t-c">
-              <Button width={100} radius size="lager">
+              <Button width={100} radius size="lager" onClick={() => User.needLogin().then(() => linkTo('/my/tools?tab=textbook'))}>
                 我的机经
                 我的机经
               </Button>
               </Button>
             </div>
             </div>
+            <div className="m-t-2 t-13 t-c t-s-14">
+              本月共{useNumber || 0}人使用机经
+            </div>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -84,7 +370,24 @@ export default class extends Page {
       <div className="list-layout">
       <div className="list-layout">
         <div className="content">
         <div className="content">
           {list.map(item => {
           {list.map(item => {
-            return <TextbookItem data={item} />;
+            return <TextbookItem
+              data={item}
+              menu={[
+                { label: '更新', key: 'update' },
+                { label: '反馈', key: 'feedback' },
+                { label: '评价', key: 'comment' },
+              ]}
+              onClick={() => linkTo(`/textbook/topic/list/${item.subject}`)}
+              onMenuClick={value => {
+                const { key } = value;
+                if (key === 'comment') {
+                  this.setState({ showComment: true, comment: { channel: 'library' } });
+                } else if (key === 'update') {
+                  this.textbookHistory({ page: 1, size: 100, subject: item.subject });
+                } else if (key === 'feedback') {
+                  this.setState({ showFeedback: true, feedback: { questionSubject: item.subject, target: TextbookFeedbackTarget[0].value } });
+                }
+              }} />;
           })}
           })}
         </div>
         </div>
       </div>
       </div>
@@ -92,6 +395,7 @@ export default class extends Page {
   }
   }
 
 
   renderLog() {
   renderLog() {
+    const { data, subject, updateList } = this.state;
     return (
     return (
       <div className="table-layout">
       <div className="table-layout">
         <div className="content">
         <div className="content">
@@ -99,8 +403,9 @@ export default class extends Page {
             <span className="d-i-b t-1 t-s-18">更新日志</span>
             <span className="d-i-b t-1 t-s-18">更新日志</span>
             <Tabs
             <Tabs
               type="text"
               type="text"
-              tabs={[{ title: '数学', key: '1' }, { title: '阅读RC', key: '2' }, { title: '逻辑RC', key: '3' }]}
-              active="1"
+              tabs={[{ title: '数学', key: 'quant' }, { title: '阅读RC', key: 'rc' }, { title: '逻辑IR', key: 'ir' }]}
+              active={subject}
+              onTabChange={(key) => this.textbookHistory({ subject: key })}
             />
             />
           </div>
           </div>
           <UserTable
           <UserTable
@@ -110,15 +415,9 @@ export default class extends Page {
               { title: '版本', key: 'version' },
               { title: '版本', key: 'version' },
               { title: '更新内容', key: 'content' },
               { title: '更新内容', key: 'content' },
             ]}
             ]}
-            data={[
-              {
-                date: '2019-07-12 \n 11:38:51',
-                version: '数学机经-版本 7',
-                content: '新增 7 道数学机经;补充第 23 题条件;\n 更新第 54题解析和答案',
-              },
-            ]}
+            data={updateList}
           />
           />
-          <Assets name="textbook_banner" />
+          <Assets name="textbook_banner" onClick={() => this.open(data.unUseRecord.id)} />
         </div>
         </div>
       </div>
       </div>
     );
     );
@@ -129,10 +428,10 @@ export default class extends Page {
       <div className="compare-layout">
       <div className="compare-layout">
         <div className="t-14 t-c t-s-32 m-b-2">让机经帮上忙,而不是帮倒忙!</div>
         <div className="t-14 t-c t-s-32 m-b-2">让机经帮上忙,而不是帮倒忙!</div>
         <div className="t-c m-b-2">
         <div className="t-c m-b-2">
-          <Button width={100} size="lager" radius className="m-r-2">
+          <Button width={100} size="lager" radius className="m-r-2" onClick={() => this.buy()}>
             立刻购买
             立刻购买
           </Button>
           </Button>
-          <Button width={100} size="lager" radius className="m-l-2">
+          <Button width={100} size="lager" radius className="m-l-2" onClick={() => linkTo('/examination?tab1=textbook')}>
             试用往期
             试用往期
           </Button>
           </Button>
         </div>
         </div>

+ 1 - 1
front/project/www/routes/textbook/topic/index.js

@@ -1,5 +1,5 @@
 export default {
 export default {
-  path: '/textbook/topic',
+  path: '/textbook/topic/list/:subject',
   key: 'textbook-topic',
   key: 'textbook-topic',
   title: '机经目录',
   title: '机经目录',
   needLogin: false,
   needLogin: false,

+ 109 - 14
front/project/www/routes/textbook/topic/page.js

@@ -1,46 +1,141 @@
 import React from 'react';
 import React from 'react';
+import { Link } from 'react-router-dom';
 import './index.less';
 import './index.less';
 import Page from '@src/containers/Page';
 import Page from '@src/containers/Page';
 import Footer from '../../../components/Footer';
 import Footer from '../../../components/Footer';
 import { Contact } from '../../../components/Other';
 import { Contact } from '../../../components/Other';
 import Select from '../../../components/Select';
 import Select from '../../../components/Select';
 import UserTable from '../../../components/UserTable';
 import UserTable from '../../../components/UserTable';
+import { Textbook } from '../../../stores/textbook';
+import { Main } from '../../../stores/main';
+import { TextbookSubject, TextbookQuality, TextbookType } from '../../../../Constant';
+import { getMap, formatDate } from '../../../../../src/services/Tools';
+
+const TextbookSubjectMap = getMap(TextbookSubject, 'value', 'label');
+const TextbookQualityMap = getMap(TextbookQuality, 'value', 'label');
+const TextbookTypeMap = getMap(TextbookType, 'value', 'label');
 
 
 export default class extends Page {
 export default class extends Page {
+  initState() {
+    return {
+      subject: TextbookSubject[0].value,
+      textbookSubject: TextbookSubject.map(row => {
+        return {
+          title: row.label,
+          key: row.value,
+        };
+      }),
+      textbookQuality: TextbookQuality.map(row => {
+        return {
+          title: row.label,
+          key: row.value,
+        };
+      }),
+      textbookType: TextbookType.map(row => {
+        return {
+          title: row.label,
+          key: row.value,
+        };
+      }),
+    };
+  }
+
+  init() {
+    Main.getBase()
+      .then(result => {
+        this.setState({ base: result });
+      });
+    Textbook.getInfo()
+      .then(result => {
+        if (!result.hasService) {
+          linkTo('/textbook');
+        }
+        this.setState({ data: result });
+      });
+  }
+
+  initData() {
+    const { subject } = this.params;
+    const data = Object.assign(this.state, this.state.search);
+    if (data.order) {
+      data.sortMap = { [data.order]: data.direction };
+    }
+    data.filterMap = this.state.search;
+    this.setState(data);
+    Textbook.listTopic(Object.assign({ latest: true, subject, order: 'no', direction: 'desc' }, this.state.search, { isOld: !!this.state.search.month }))
+      .then(result => {
+        if (this.state.search.page === 1) {
+          result.list = result.list.map(row => {
+            row.new = '';
+            return row;
+          });
+        }
+        this.setState({ list: result.list, total: result.total });
+      });
+  }
+
+  filter(data) {
+    this.search(data);
+  }
+
+  changeSubject(subject) {
+    linkTo(`/textbook/topic/list/${subject}`);
+  }
+
   renderView() {
   renderView() {
+    const { subject } = this.params;
+    const { base = {}, textbookSubject, textbookQuality, textbookType, keyword, quality, month, data = {}, list = [], page, total } = this.state;
+    const { latest = {} } = data;
     return (
     return (
       <div>
       <div>
         <div className="top content t-8">
         <div className="top content t-8">
-          机经 > 本期机经 > <span className="t-1">逻辑</span>
-          <Select className="f-r m-t-1" size="small" theme="white" value={'1'} list={[{ title: '123', key: '1' }]} />
+          机经 > 本期机经 > <span className="t-1">{TextbookSubjectMap[subject]}</span>
+          <Select className="f-r m-t-1" size="small" theme="white" value={subject} list={textbookSubject} onChange={({ key }) => this.changeSubject(key)} />
         </div>
         </div>
         <div className="center content">
         <div className="center content">
           <div className="t-1 t-s-18 m-b-1">
           <div className="t-1 t-s-18 m-b-1">
-            【逻辑】0515 起逻辑机经整理
+            【{TextbookSubjectMap[subject]}】{latest.startDate && formatDate(latest.startDate, 'MMDD')} 起{TextbookSubjectMap[subject]}机经整理
+            <Select className="f-r m-l-1" size="small" theme="default" value={quality} placeholder={'机经质量'} list={textbookQuality} onChange={({ key }) => this.filter({ quality: key })} />
             <Select
             <Select
               className="f-r m-l-1"
               className="f-r m-l-1"
               size="small"
               size="small"
               theme="default"
               theme="default"
-              value={'1'}
-              list={[{ title: '123', key: '1' }]}
+              value={month}
+              list={[{ title: '本月', key: '' }, { title: '考古', key: '1' }]}
+              onChange={({ key }) => this.filter({ month: key })}
             />
             />
-            <Select className="f-r" size="small" theme="default" value={'1'} list={[{ title: '123', key: '1' }]} />
+            {subject === 'quant' && <Select
+              className="f-r m-l-1"
+              size="small"
+              theme="default"
+              value={keyword}
+              list={textbookType}
+              placeholder={'题型'}
+              onChange={({ key }) => this.filter({ keyword: key })}
+            />}
           </div>
           </div>
           <UserTable
           <UserTable
             size="small"
             size="small"
-            data={[{}, {}, {}]}
-            current={1}
-            pageSize={20}
-            total={100}
+            data={list}
+            current={page}
+            pageSize={this.state.search.size}
+            total={total}
             jump
             jump
             columns={[
             columns={[
-              { title: '文章编号', key: '1', sort: true },
-              { title: '关键词', key: '2' },
-              { title: '机经质量', key: '3' },
+              {
+                title: '文章编号',
+                key: 'no',
+                sort: true,
+                render: (text) => {
+                  return <Link to={`/textbook/topic/detail/${subject}?no=${text}`}>{text}</Link>;
+                },
+              },
+              { title: '关键词', key: 'keyword', render: (text) => (subject === 'quant' ? TextbookTypeMap[text] : text) },
+              { title: '机经质量', key: 'quality', render: (text) => TextbookQualityMap[text] || '' },
             ]}
             ]}
           />
           />
         </div>
         </div>
-        <Contact />
+        <Contact data={base.contact} />
         <Footer />
         <Footer />
       </div>
       </div>
     );
     );

+ 1 - 1
front/project/www/routes/textbook/topicDetail/index.js

@@ -1,5 +1,5 @@
 export default {
 export default {
-  path: '/textbook/topic/detail',
+  path: '/textbook/topic/detail/:subject',
   key: 'textbook-topic-detail',
   key: 'textbook-topic-detail',
   title: '机经内容页',
   title: '机经内容页',
   needLogin: false,
   needLogin: false,

+ 91 - 30
front/project/www/routes/textbook/topicDetail/page.js

@@ -7,16 +7,68 @@ import { Contact } from '../../../components/Other';
 import Select from '../../../components/Select';
 import Select from '../../../components/Select';
 import Modal from '../../../components/Modal';
 import Modal from '../../../components/Modal';
 import { Button } from '../../../components/Button';
 import { Button } from '../../../components/Button';
+import { Textbook } from '../../../stores/textbook';
+import { My } from '../../../stores/my';
+import { Main } from '../../../stores/main';
+import { User } from '../../../stores/user';
+import { TextbookSubject, TextbookQuality, TextbookType } from '../../../../Constant';
+import { getMap, formatDate } from '../../../../../src/services/Tools';
+
+const TextbookSubjectMap = getMap(TextbookSubject, 'value', 'label');
+const TextbookQualityMap = getMap(TextbookQuality, 'value', 'label');
+const TextbookTypeMap = getMap(TextbookType, 'value', 'label');
 
 
 export default class extends Page {
 export default class extends Page {
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
-    this.state = { open: false, showTip: true };
     this.keyMap = {};
     this.keyMap = {};
     window.onkeydown = this.onKeydown.bind(this);
     window.onkeydown = this.onKeydown.bind(this);
     window.onkeyup = this.onKeyup.bind(this);
     window.onkeyup = this.onKeyup.bind(this);
   }
   }
 
 
+  initState() {
+    const { info = {} } = this.props.user;
+    return {
+      open: false,
+      showTip: !info.textbookTips,
+      subject: TextbookSubject[0].value,
+      textbookSubject: TextbookSubject.map(row => {
+        return {
+          title: row.label,
+          key: row.value,
+        };
+      }),
+    };
+  }
+
+  init() {
+    Main.getBase()
+      .then(result => {
+        this.setState({ base: result });
+      });
+  }
+
+  initData() {
+    Textbook.getInfo()
+      .then(result => {
+        if (!result.hasService) {
+          linkTo('/textbook');
+        }
+        this.setState({ data: result });
+        console.log(this.state);
+        this.refreshItem(this.state.search.no || 1);
+      });
+  }
+
+  refreshItem(no) {
+    const { subject } = this.params;
+    const { data } = this.state;
+    Textbook.noTopic(data.latest.id, subject, no)
+      .then(result => {
+        this.setState({ item: result });
+      });
+  }
+
   onKeydown(e) {
   onKeydown(e) {
     let active = false;
     let active = false;
     if (this.keyMap[e.keyCode]) return false;
     if (this.keyMap[e.keyCode]) return false;
@@ -69,30 +121,54 @@ export default class extends Page {
     this.setState({ open: !this.state.open });
     this.setState({ open: !this.state.open });
   }
   }
 
 
-  onNext() {}
+  onNext() {
+    const { subject } = this.params;
+    const { item, data } = this.state;
+    const no = item.no + 1;
+    if (no > data.latest[`${subject}Number`]) return;
+    this.refreshItem(no);
+  }
+
+  onPrev() {
+    const { item } = this.state;
+    const no = item.no - 1;
+    if (no === 0) return;
+    this.refreshItem(no);
+  }
+
+  closeTips() {
+    this.setState({ showTip: false });
+    My.textbookTips()
+      .then(() => {
+        User.infoHandle({ textbookTips: 1 });
+      });
+  }
 
 
-  onPrev() {}
+  changeSubject(subject) {
+    linkTo(`/textbook/topic/list/${subject}`);
+  }
 
 
   renderView() {
   renderView() {
-    const { showTip } = this.state;
+    const { showTip, base = {}, subject, data = {}, textbookSubject } = this.state;
+    const { latest = {} } = data;
     return (
     return (
       <div>
       <div>
         <div className="top content t-8">
         <div className="top content t-8">
-          机经 > 本期机经 > <span className="t-1">逻辑</span>
-          <Select className="f-r m-t-1" size="small" theme="white" value={'1'} list={[{ title: '123', key: '1' }]} />
+          机经 > 本期机经 > <span className="t-1">{TextbookSubjectMap[subject]}</span>
+          <Select className="f-r m-t-1" size="small" theme="white" value={subject} list={textbookSubject} onChange={({ key }) => this.changeSubject(key)} />
         </div>
         </div>
         <div className="center content">
         <div className="center content">
-          <div className="t-1 t-s-18 m-b-1">【逻辑】0515 起逻辑机经整理</div>
+          【{TextbookSubjectMap[subject]}】{latest.startDate && formatDate(latest.startDate, 'MMDD')} 起{TextbookSubjectMap[subject]}机经整理
           {this.renderDetail()}
           {this.renderDetail()}
           <Assets className="prev" name="footer_previous_highlight_1" onClick={() => this.onPrev()} />
           <Assets className="prev" name="footer_previous_highlight_1" onClick={() => this.onPrev()} />
           <Assets className="next" name="footer_next_highlight_1" onClick={() => this.onNext()} />
           <Assets className="next" name="footer_next_highlight_1" onClick={() => this.onNext()} />
         </div>
         </div>
-        <Contact />
+        <Contact data={base.contact} />
         <Footer />
         <Footer />
         <Modal
         <Modal
           show={showTip}
           show={showTip}
           title="提示"
           title="提示"
-          onConfirm={() => this.setState({ showTip: false })}
+          onConfirm={() => this.closeTips()}
           confirmText="好的,知道了"
           confirmText="好的,知道了"
           btnAlign="center"
           btnAlign="center"
         >
         >
@@ -104,36 +180,21 @@ export default class extends Page {
   }
   }
 
 
   renderDetail() {
   renderDetail() {
-    const { open } = this.state;
+    const { open, subject, item = {} } = this.state;
     return (
     return (
       <div className="detail">
       <div className="detail">
         <div className="m-b-1">
         <div className="m-b-1">
-          <span className="t-1 t-s-18 m-r-1">NO.34 题目题目题目</span>
-          <span className="t-3 t-s-12">2019-02-21 19:19:20</span>
+          <span className="t-1 t-s-18 m-r-1">NO.{item.no} {subject === 'quant' ? TextbookTypeMap[item.keyword] : item.keyword}</span>
+          <span className="t-3 t-s-12 m-r-1">{TextbookQualityMap[item.quality]}</span>
+          <span className="t-3 t-s-12 m-r-1">{item.createTime && formatDate(item.createTime, 'YYYY-MM-DD HH:mm:ss')}</span>
           <Button radius className="f-r" onClick={() => this.onOpen()}>
           <Button radius className="f-r" onClick={() => this.onOpen()}>
             {open ? '收起' : '展开'}解析
             {open ? '收起' : '展开'}解析
           </Button>
           </Button>
         </div>
         </div>
-        <div className="t-2 t-s-16 m-b-2">
-          GMAT考试由分析写作、推理、数学和语文四部分组成。分别为: a)分析性写作评价(Analytical Writing
-          Assessment)A:GMAT考试由分析写作、推理、数学和语文四部分组成。分别为: a)分析性写作评价(Analytical Writing
-          Assessment)GMAT考试由分析写作、推理、数学和语文四部分组成。分别为: a)分析性写作评价(Analytical Writing
-          Assessment)A:GMAT考试由分析写作、推理、数学和语文四部分组成。分别为: a)分析性写作评价(Analytical Writing
-          Assessment)A:GMAT考试由分析写作、推理、数学和语文四部分组成。分别为: a)分析性写作评价
-        </div>
+        <div className="t-2 t-s-16 m-b-2" dangerouslySetInnerHTML={{ __html: item.detail }} />
         <div hidden={!open} className="p-20 b-c-3">
         <div hidden={!open} className="p-20 b-c-3">
           <div className="t t-1 t-s-16 f-w-b m-b-5">官方解析</div>
           <div className="t t-1 t-s-16 f-w-b m-b-5">官方解析</div>
-          <div className="t-1 t-s-16">
-            A.By whom they were supposedly named is a passive construction that is unnecessarily indirect and wordy,
-            especially immediately following another passive construction; the singular its does not agree with the
-            plural antecedent the Glass House Mountains. B.This version of the sentence loses the causal connection,
-            failing to explain why James Cook gave the mountains their particular name. C.As the object of a preposition
-            and not the subject of the clause, James Cook does not work as the noun that the verbal phrase beginning
-            with naming can describe; the preposition since loses the important causal logic of the sentence. D.Correct.
-            This concise sentence uses active- voice construction in the relative clause and maintains agreement between
-            the pronoun their and its antecedent. E The pronoun it does not agree with the plural Mountains and the
-            following pronoun their.
-          </div>
+          <div className="t-1 t-s-16" dangerouslySetInnerHTML={{ __html: item.content }} />
         </div>
         </div>
       </div>
       </div>
     );
     );

+ 81 - 7
front/project/www/routes/textbook/year/page.js

@@ -5,30 +5,104 @@ import Footer from '../../../components/Footer';
 import { Contact } from '../../../components/Other';
 import { Contact } from '../../../components/Other';
 import Select from '../../../components/Select';
 import Select from '../../../components/Select';
 import UserTable from '../../../components/UserTable';
 import UserTable from '../../../components/UserTable';
+import { Textbook } from '../../../stores/textbook';
+import { Main } from '../../../stores/main';
+import { TextbookMinYear, TextbookSubject } from '../../../../Constant';
+import { formatDate } from '../../../../../src/services/Tools';
 
 
 export default class extends Page {
 export default class extends Page {
+  initState() {
+    const yearList = [];
+    const nowYear = new Date().getFullYear();
+    for (let i = TextbookMinYear; i <= nowYear; i += 1) {
+      yearList.push({
+        title: i.toString(),
+        key: i.toString(),
+      });
+    }
+    return {
+      subject: TextbookSubject[0].value,
+      year: nowYear,
+      yearList,
+      textbookSubject: TextbookSubject.map(row => {
+        return {
+          title: row.label,
+          key: row.value,
+        };
+      }),
+    };
+  }
+
+  init() {
+    Main.getBase()
+      .then(result => {
+        this.setState({ base: result });
+      });
+  }
+
+  initData() {
+    const data = Object.assign(this.state, this.state.search);
+    if (data.order) {
+      data.sortMap = { [data.order]: data.direction };
+    }
+    data.filterMap = this.state.search;
+    this.setState(data);
+    Textbook.getInfo()
+      .then(result => {
+        this.setState(result);
+      });
+    console.log(this.state);
+    this.refreshYear(this.state.year);
+  }
+
+  refreshYear(year) {
+    this.setState({ year });
+    Textbook.listYear(year)
+      .then((list) => {
+        const monthMap = {};
+        let lastTime = null;
+        list.forEach((row) => {
+          const d = new Date(row.startDate);
+          const month = d.getMonth() + 1;
+          row.month = month;
+          if (lastTime) {
+            row.period = parseInt((d.getTime() - lastTime.getTime()) / 86400000, 10) - 1;
+          } else {
+            row.period = 0;
+          }
+          lastTime = d;
+          if (!monthMap[month]) {
+            monthMap[month] = [];
+          }
+          monthMap[month].push(d.getDate());
+        });
+        this.setState({ monthMap, list });
+      });
+  }
+
   renderView() {
   renderView() {
+    const { base = {}, yearList, year, monthMap, list } = this.state;
     return (
     return (
       <div>
       <div>
         <div className="top content t-8">
         <div className="top content t-8">
-          机经 > 本期机经 > <span className="t-1">逻辑</span>
-          <Select className="f-r m-t-1" size="small" theme="white" value={'1'} list={[{ title: '123', key: '1' }]} />
+          机经 > <span className="t-1">按年份查询</span>
         </div>
         </div>
         <div className="center content">
         <div className="center content">
           <div className="t-1 t-s-18 m-b-1">
           <div className="t-1 t-s-18 m-b-1">
             GMAT历年换库记录
             GMAT历年换库记录
-            <Select className="f-r" size="small" theme="default" value={'1'} list={[{ title: '123', key: '1' }]} />
+            <Select className="f-r" size="small" theme="default" value={year} placeholder={'年份'} list={yearList} onChange={({ key }) => this.refreshYear(key)} />
           </div>
           </div>
           <UserTable
           <UserTable
             size="small"
             size="small"
+            data={list}
             columns={[
             columns={[
-              { title: '更新时间', key: '1' },
-              { title: '间隔天数', key: '2' },
-              { title: '当月换库次数(次)', key: '3' },
+              { title: '更新时间', key: 'startDate', render: (text) => formatDate(text, 'YYYY-MM-DD') },
+              { title: '间隔天数', key: 'period' },
+              { title: '当月换库次数(次)', key: 'month', render: (text) => (monthMap[text] ? monthMap[text].length : 0) },
             ]}
             ]}
           />
           />
         </div>
         </div>
-        <Contact />
+        <Contact data={base.contact} />
         <Footer />
         <Footer />
       </div>
       </div>
     );
     );

+ 7 - 7
front/project/www/static/login.html

@@ -206,14 +206,14 @@
     window.top.postMessage('code:' + code, '*');
     window.top.postMessage('code:' + code, '*');
   } else {
   } else {
     document.getElementById('loading').style.display = 'none';
     document.getElementById('loading').style.display = 'none';
+    new WxLogin({
+      id: 'root',
+      self_redirect: true,
+      appid: getQuery('appid'),
+      scope: 'snsapi_login',
+      redirect_uri: getQuery('redirectUri') + '/login.html',
+    });
   }
   }
-  new WxLogin({
-    id: 'root',
-    self_redirect: true,
-    appid: getQuery('appid'),
-    scope: 'snsapi_login',
-    redirect_uri: getQuery('redirectUri') + '/login.html',
-  });
 </script>
 </script>
 
 
 </html>
 </html>

+ 3 - 3
front/project/www/stores/my.js

@@ -381,13 +381,13 @@ export default class MyStore extends BaseStore {
 
 
   /**
   /**
    * 添加机经反馈
    * 添加机经反馈
-   * @param {*} questionSubject
+   * @param {*} textbookSubject
    * @param {*} target
    * @param {*} target
    * @param {*} no
    * @param {*} no
    * @param {*} content
    * @param {*} content
    */
    */
-  addTextbookFeedback(questionSubject, target, no, content) {
-    return this.apiPost('/my/feedback/textbook', { questionSubject, target, no, content });
+  addTextbookFeedback(textbookSubject, target, no, content) {
+    return this.apiPost('/my/feedback/textbook', { textbookSubject, target, no, content });
   }
   }
 
 
   /**
   /**

+ 10 - 6
front/project/www/stores/textbook.js

@@ -34,20 +34,24 @@ export default class TextbookStore extends BaseStore {
     return this.apiGet('/textbook/topic/no', { libraryId, subject, no });
     return this.apiGet('/textbook/topic/no', { libraryId, subject, no });
   }
   }
 
 
-  listTopic(page, size, latest, qualitys, isOld, order, direction) {
-    return this.apiGet('/textbook/topic/list', { page, size, latest, qualitys, isOld, order, direction });
+  listTopic({ page, size, latest, subject, keyword, quality, isOld, order, direction }) {
+    return this.apiGet('/textbook/topic/list', { page, size, latest, subject, keyword, quality, isOld, order, direction });
   }
   }
 
 
   subscribe(subscribe) {
   subscribe(subscribe) {
     return this.apiPost('/textbook/subscribe', { subscribe });
     return this.apiPost('/textbook/subscribe', { subscribe });
   }
   }
 
 
-  enroll(month) {
-    return this.apiPost('/textbook/enroll', { month });
+  enroll(date) {
+    return this.apiPost('/textbook/enroll', { date });
   }
   }
 
 
-  listEnroll(year) {
-    return this.apiGet('/textbook/enroll/list', { year });
+  unEnroll() {
+    return this.apiPost('/textbook/enroll/cancel');
+  }
+
+  listEnroll(startDate, endDate) {
+    return this.apiGet('/textbook/enroll/list', { startDate, endDate });
   }
   }
 }
 }
 
 

+ 5 - 7
front/project/www/stores/user.js

@@ -76,13 +76,11 @@ export default class UserStore extends BaseStore {
   }
   }
 
 
   initAfter() {
   initAfter() {
-    if (this.state.login || this.adminLogin) {
-      this.refreshToken().then(() => {
-        if (this.adminLogin) {
-          window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
-        }
-      });
-    }
+    this.refreshToken().then(() => {
+      if (this.adminLogin) {
+        window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
+      }
+    });
   }
   }
 
 
   needPay(order) {
   needPay(order) {

+ 1 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java

@@ -31,6 +31,7 @@ public enum SettingKey {
     SENTENCE_INFO("sentence_info"), // 长难句信息
     SENTENCE_INFO("sentence_info"), // 长难句信息
     WECHAT_INFO("wechat_info"), // 微信公众号信息
     WECHAT_INFO("wechat_info"), // 微信公众号信息
     READY_READ("ready_read"), // 推荐阅读设置
     READY_READ("ready_read"), // 推荐阅读设置
+    TEXTBOOK_CONFIG("textbook_config"), // 机经设置信息
 
 
     BASE("base"), // 基础设置
     BASE("base"), // 基础设置
     TIPS("tips"); // 页面提示信息
     TIPS("tips"); // 页面提示信息

+ 12 - 12
server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookTopic.java

@@ -20,8 +20,8 @@ public class TextbookTopic implements Serializable {
     /**
     /**
      * 学科
      * 学科
      */
      */
-    @Column(name = "`question_subject`")
-    private String questionSubject;
+    @Column(name = "`textbook_subject`")
+    private String textbookSubject;
 
 
     /**
     /**
      * 题目序号
      * 题目序号
@@ -102,19 +102,19 @@ public class TextbookTopic implements Serializable {
     /**
     /**
      * 获取学科
      * 获取学科
      *
      *
-     * @return question_subject - 学科
+     * @return textbook_subject - 学科
      */
      */
-    public String getQuestionSubject() {
-        return questionSubject;
+    public String getTextbookSubject() {
+        return textbookSubject;
     }
     }
 
 
     /**
     /**
      * 设置学科
      * 设置学科
      *
      *
-     * @param questionSubject 学科
+     * @param textbookSubject 学科
      */
      */
-    public void setQuestionSubject(String questionSubject) {
-        this.questionSubject = questionSubject;
+    public void setTextbookSubject(String textbookSubject) {
+        this.textbookSubject = textbookSubject;
     }
     }
 
 
     /**
     /**
@@ -261,7 +261,7 @@ public class TextbookTopic implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", id=").append(id);
         sb.append(", libraryId=").append(libraryId);
         sb.append(", libraryId=").append(libraryId);
-        sb.append(", questionSubject=").append(questionSubject);
+        sb.append(", textbookSubject=").append(textbookSubject);
         sb.append(", no=").append(no);
         sb.append(", no=").append(no);
         sb.append(", keyword=").append(keyword);
         sb.append(", keyword=").append(keyword);
         sb.append(", quality=").append(quality);
         sb.append(", quality=").append(quality);
@@ -306,10 +306,10 @@ public class TextbookTopic implements Serializable {
         /**
         /**
          * 设置学科
          * 设置学科
          *
          *
-         * @param questionSubject 学科
+         * @param textbookSubject 学科
          */
          */
-        public Builder questionSubject(String questionSubject) {
-            obj.setQuestionSubject(questionSubject);
+        public Builder textbookSubject(String textbookSubject) {
+            obj.setTextbookSubject(textbookSubject);
             return this;
             return this;
         }
         }
 
 

+ 16 - 16
server/data/src/main/java/com/qxgmat/data/dao/entity/UserTextbookEnroll.java

@@ -18,10 +18,10 @@ public class UserTextbookEnroll implements Serializable {
     private Integer userId;
     private Integer userId;
 
 
     /**
     /**
-     * 报名月份
+     * 报名日期
      */
      */
-    @Column(name = "`month`")
-    private Date month;
+    @Column(name = "`date`")
+    private Date date;
 
 
     @Column(name = "`create_time`")
     @Column(name = "`create_time`")
     private Date createTime;
     private Date createTime;
@@ -61,21 +61,21 @@ public class UserTextbookEnroll implements Serializable {
     }
     }
 
 
     /**
     /**
-     * 获取报名月份
+     * 获取报名日期
      *
      *
-     * @return month - 报名月份
+     * @return date - 报名日期
      */
      */
-    public Date getMonth() {
-        return month;
+    public Date getDate() {
+        return date;
     }
     }
 
 
     /**
     /**
-     * 设置报名月份
+     * 设置报名日期
      *
      *
-     * @param month 报名月份
+     * @param date 报名日期
      */
      */
-    public void setMonth(Date month) {
-        this.month = month;
+    public void setDate(Date date) {
+        this.date = date;
     }
     }
 
 
     /**
     /**
@@ -100,7 +100,7 @@ public class UserTextbookEnroll implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
         sb.append(", userId=").append(userId);
-        sb.append(", month=").append(month);
+        sb.append(", date=").append(date);
         sb.append(", createTime=").append(createTime);
         sb.append(", createTime=").append(createTime);
         sb.append("]");
         sb.append("]");
         return sb.toString();
         return sb.toString();
@@ -136,12 +136,12 @@ public class UserTextbookEnroll implements Serializable {
         }
         }
 
 
         /**
         /**
-         * 设置报名月份
+         * 设置报名日期
          *
          *
-         * @param month 报名月份
+         * @param date 报名日期
          */
          */
-        public Builder month(Date month) {
-            obj.setMonth(month);
+        public Builder date(Date date) {
+            obj.setDate(date);
             return this;
             return this;
         }
         }
 
 

+ 12 - 12
server/data/src/main/java/com/qxgmat/data/dao/entity/UserTextbookFeedback.java

@@ -20,8 +20,8 @@ public class UserTextbookFeedback implements Serializable {
     /**
     /**
      * 学科
      * 学科
      */
      */
-    @Column(name = "`question_subject`")
-    private String questionSubject;
+    @Column(name = "`textbook_subject`")
+    private String textbookSubject;
 
 
     /**
     /**
      * 题目序号
      * 题目序号
@@ -111,19 +111,19 @@ public class UserTextbookFeedback implements Serializable {
     /**
     /**
      * 获取学科
      * 获取学科
      *
      *
-     * @return question_subject - 学科
+     * @return textbook_subject - 学科
      */
      */
-    public String getQuestionSubject() {
-        return questionSubject;
+    public String getTextbookSubject() {
+        return textbookSubject;
     }
     }
 
 
     /**
     /**
      * 设置学科
      * 设置学科
      *
      *
-     * @param questionSubject 学科
+     * @param textbookSubject 学科
      */
      */
-    public void setQuestionSubject(String questionSubject) {
-        this.questionSubject = questionSubject;
+    public void setTextbookSubject(String textbookSubject) {
+        this.textbookSubject = textbookSubject;
     }
     }
 
 
     /**
     /**
@@ -292,7 +292,7 @@ public class UserTextbookFeedback implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
         sb.append(", userId=").append(userId);
-        sb.append(", questionSubject=").append(questionSubject);
+        sb.append(", textbookSubject=").append(textbookSubject);
         sb.append(", no=").append(no);
         sb.append(", no=").append(no);
         sb.append(", topicId=").append(topicId);
         sb.append(", topicId=").append(topicId);
         sb.append(", libraryId=").append(libraryId);
         sb.append(", libraryId=").append(libraryId);
@@ -338,10 +338,10 @@ public class UserTextbookFeedback implements Serializable {
         /**
         /**
          * 设置学科
          * 设置学科
          *
          *
-         * @param questionSubject 学科
+         * @param textbookSubject 学科
          */
          */
-        public Builder questionSubject(String questionSubject) {
-            obj.setQuestionSubject(questionSubject);
+        public Builder textbookSubject(String textbookSubject) {
+            obj.setTextbookSubject(textbookSubject);
             return this;
             return this;
         }
         }
 
 

+ 2 - 2
server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookTopicMapper.xml

@@ -7,7 +7,7 @@
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="library_id" jdbcType="INTEGER" property="libraryId" />
     <result column="library_id" jdbcType="INTEGER" property="libraryId" />
-    <result column="question_subject" jdbcType="VARCHAR" property="questionSubject" />
+    <result column="textbook_subject" jdbcType="VARCHAR" property="textbookSubject" />
     <result column="no" jdbcType="INTEGER" property="no" />
     <result column="no" jdbcType="INTEGER" property="no" />
     <result column="keyword" jdbcType="VARCHAR" property="keyword" />
     <result column="keyword" jdbcType="VARCHAR" property="keyword" />
     <result column="quality" jdbcType="VARCHAR" property="quality" />
     <result column="quality" jdbcType="VARCHAR" property="quality" />
@@ -26,7 +26,7 @@
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `library_id`, `question_subject`, `no`, `keyword`, `quality`, `is_old`, `create_time`, 
+    `id`, `library_id`, `textbook_subject`, `no`, `keyword`, `quality`, `is_old`, `create_time`, 
     `update_time`
     `update_time`
   </sql>
   </sql>
   <sql id="Blob_Column_List">
   <sql id="Blob_Column_List">

+ 2 - 2
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserTextbookEnrollMapper.xml

@@ -7,13 +7,13 @@
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
-    <result column="month" jdbcType="TIMESTAMP" property="month" />
+    <result column="date" jdbcType="TIMESTAMP" property="date" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   </resultMap>
   <sql id="Base_Column_List">
   <sql id="Base_Column_List">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `user_id`, `month`, `create_time`
+    `id`, `user_id`, `date`, `create_time`
   </sql>
   </sql>
 </mapper>
 </mapper>

+ 2 - 2
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserTextbookFeedbackMapper.xml

@@ -7,7 +7,7 @@
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
-    <result column="question_subject" jdbcType="VARCHAR" property="questionSubject" />
+    <result column="textbook_subject" jdbcType="VARCHAR" property="textbookSubject" />
     <result column="no" jdbcType="INTEGER" property="no" />
     <result column="no" jdbcType="INTEGER" property="no" />
     <result column="topic_id" jdbcType="INTEGER" property="topicId" />
     <result column="topic_id" jdbcType="INTEGER" property="topicId" />
     <result column="library_id" jdbcType="INTEGER" property="libraryId" />
     <result column="library_id" jdbcType="INTEGER" property="libraryId" />
@@ -27,7 +27,7 @@
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `user_id`, `question_subject`, `no`, `topic_id`, `library_id`, `manager_id`, 
+    `id`, `user_id`, `textbook_subject`, `no`, `topic_id`, `library_id`, `manager_id`, 
     `target`, `create_time`, `status`, `handle_time`
     `target`, `create_time`, `status`, `handle_time`
   </sql>
   </sql>
   <sql id="Blob_Column_List">
   <sql id="Blob_Column_List">

+ 9 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserOrderRecordRelationMapper.java

@@ -3,6 +3,7 @@ package com.qxgmat.data.relation;
 import com.qxgmat.data.dao.entity.UserCollectQuestion;
 import com.qxgmat.data.dao.entity.UserCollectQuestion;
 import com.qxgmat.data.dao.entity.UserOrderRecord;
 import com.qxgmat.data.dao.entity.UserOrderRecord;
 import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
 import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
+import com.qxgmat.data.relation.entity.MonthNumberRelation;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Param;
 
 
 import java.util.Collection;
 import java.util.Collection;
@@ -43,4 +44,12 @@ public interface UserOrderRecordRelationMapper {
     List<CourseStudentNumberRelation> groupByTime(
     List<CourseStudentNumberRelation> groupByTime(
             @Param("ids") Collection ids
             @Param("ids") Collection ids
     );
     );
+
+    List<MonthNumberRelation> groupByMonth(
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            @Param("productType") String productType,
+            @Param("productId") Integer productId,
+            @Param("service") String service
+    );
 }
 }

+ 2 - 5
server/data/src/main/java/com/qxgmat/data/relation/UserTextbookEnrollRelationMapper.java

@@ -1,11 +1,8 @@
 package com.qxgmat.data.relation;
 package com.qxgmat.data.relation;
 
 
-import com.qxgmat.data.dao.entity.UserOrderRecord;
-import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
-import com.qxgmat.data.relation.entity.TextbookEnrollNumberRelation;
+import com.qxgmat.data.relation.entity.MonthNumberRelation;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Param;
 
 
-import java.util.Collection;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
@@ -13,7 +10,7 @@ import java.util.List;
  */
  */
 public interface UserTextbookEnrollRelationMapper {
 public interface UserTextbookEnrollRelationMapper {
 
 
-    List<TextbookEnrollNumberRelation> groupByMonth(
+    List<MonthNumberRelation> groupByMonth(
             @Param("startTime") String startTime,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime
             @Param("endTime") String endTime
     );
     );

+ 9 - 10
server/data/src/main/java/com/qxgmat/data/relation/entity/TextbookEnrollNumberRelation.java

@@ -1,24 +1,23 @@
 package com.qxgmat.data.relation.entity;
 package com.qxgmat.data.relation.entity;
 
 
 import javax.persistence.Column;
 import javax.persistence.Column;
-import java.util.Date;
 
 
 /**
 /**
  * Created by gaojie on 2017/11/9.
  * Created by gaojie on 2017/11/9.
  */
  */
-// 备考统计
-public class TextbookEnrollNumberRelation {
+// 月份统计
+public class MonthNumberRelation {
 
 
     /**
     /**
      * 数字字段
      * 数字字段
      */
      */
-    @Column(name = "`id`")
-    private Date month;
+    @Column(name = "`month`")
+    private Integer month;
 
 
     /**
     /**
      * 统计值
      * 统计值
      */
      */
-    @Column(name = "`user_id`")
+    @Column(name = "`number`")
     private Integer number;
     private Integer number;
 
 
     public Integer getNumber() {
     public Integer getNumber() {
@@ -29,11 +28,11 @@ public class TextbookEnrollNumberRelation {
         this.number = number;
         this.number = number;
     }
     }
 
 
-    public Date getMonth() {
-        return month;
+    public void setMonth(Integer month) {
+        this.month = month;
     }
     }
 
 
-    public void setMonth(Date month) {
-        this.month = month;
+    public Integer getMonth() {
+        return month;
     }
     }
 }
 }

+ 37 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserOrderRecordRelationMapper.xml

@@ -14,6 +14,14 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="number" jdbcType="INTEGER" property="number" />
     <id column="number" jdbcType="INTEGER" property="number" />
   </resultMap>
   </resultMap>
+
+  <resultMap id="MonthMap" type="com.qxgmat.data.relation.entity.MonthNumberRelation">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="month" jdbcType="INTEGER" property="month" />
+    <id column="number" jdbcType="INTEGER" property="number" />
+  </resultMap>
   <sql id="Id_Column_List">
   <sql id="Id_Column_List">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
@@ -36,6 +44,35 @@
   </select>
   </select>
 
 
   <!--
   <!--
+    统计人数
+  -->
+  <select id="groupByMonth" resultMap="MonthMap">
+    select
+    count(`id`) as `number`, `month`
+    from (
+    select uor.`id` as `id`, CONVERT(date_format(uor.`use_time`, '%m'), UNSIGNED) as `month`
+    from `user_order_record` uor
+    where 1
+    <if test="startTime != null">
+      and uor.`use_time` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and uor.`use_time` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+    <if test="productType != null">
+      and uor.`product_type` = #{productType,jdbcType=VARCHAR}
+    </if>
+    <if test="productId != null">
+      and uor.`product_id` = #{productId,jdbcType=VARCHAR}
+    </if>
+    <if test="service != null">
+      and uor.`service` = #{service,jdbcType=VARCHAR}
+    </if>
+    ) as s
+    group by `month`
+  </select>
+
+  <!--
     获取用户学习记录
     获取用户学习记录
   -->
   -->
   <select id="listWithStudyAdmin" resultMap="IdMap">
   <select id="listWithStudyAdmin" resultMap="IdMap">

+ 16 - 12
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserTextbookEnrollRelationMapper.xml

@@ -7,11 +7,11 @@
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
   </resultMap>
   </resultMap>
-  <resultMap id="NumberMap" type="com.qxgmat.data.relation.entity.TextbookEnrollNumberRelation">
+  <resultMap id="MonthMap" type="com.qxgmat.data.relation.entity.MonthNumberRelation">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    <id column="month" jdbcType="TIMESTAMP" property="month" />
+    <id column="month" jdbcType="INTEGER" property="month" />
     <id column="number" jdbcType="INTEGER" property="number" />
     <id column="number" jdbcType="INTEGER" property="number" />
   </resultMap>
   </resultMap>
   <sql id="Id_Column_List">
   <sql id="Id_Column_List">
@@ -24,17 +24,21 @@
   <!--
   <!--
     统计报名人数
     统计报名人数
   -->
   -->
-  <select id="groupByMonth" resultMap="NumberMap">
+  <select id="groupByMonth" resultMap="MonthMap">
     select
     select
-    count(ute.`id`) as `number`, ute.`month` as `month`
-    from `user_textbook_enrool` ute
-    where 1
-    <if test="startTime != null">
-      and ute.`month` &gt; #{startTime,jdbcType=VARCHAR}
-    </if>
-    <if test="endTime != null">
-      and ute.`month` &lt; #{endTime,jdbcType=VARCHAR}
-    </if>
+    count(`id`) as `number`, `month`
+    from (
+      select ute.`id` as `id`, CONVERT(date_format(ute.`date`, '%m'), UNSIGNED) as `month`
+      from `user_textbook_enroll` ute
+      where 1
+      <if test="startTime != null">
+        and ute.`date` &gt; #{startTime,jdbcType=VARCHAR}
+      </if>
+      <if test="endTime != null">
+        and ute.`date` &lt; #{endTime,jdbcType=VARCHAR}
+      </if>
+    ) as s
+    group by `month`
   </select>
   </select>
 
 
 </mapper>
 </mapper>

+ 5 - 4
server/data/src/main/resources/db/migration/V1__init_table.sql

@@ -734,7 +734,8 @@ VALUES
 	(22,'sentence_info','{}'),
 	(22,'sentence_info','{}'),
 	(23,'wechat_info','{}'),
 	(23,'wechat_info','{}'),
 	(24,'ready_read','{}'),
 	(24,'ready_read','{}'),
-	(25,'base','{}');
+	(25,'base','{}'),
+	(26,'textbook_config','{}');
 
 
 CREATE TABLE textbook_library (
 CREATE TABLE textbook_library (
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
@@ -895,7 +896,7 @@ CREATE TABLE textbook_question (
 CREATE TABLE textbook_topic (
 CREATE TABLE textbook_topic (
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   library_id int(11) unsigned NOT NULL COMMENT '换库表',
   library_id int(11) unsigned NOT NULL COMMENT '换库表',
-  question_subject varchar(20) NOT NULL DEFAULT '' COMMENT '学科',
+  textbook_subject varchar(20) NOT NULL DEFAULT '' COMMENT '学科',
   no int(11) unsigned NOT NULL DEFAULT '0' COMMENT '题目序号',
   no int(11) unsigned NOT NULL DEFAULT '0' COMMENT '题目序号',
   keyword varchar(255) DEFAULT NULL COMMENT '关键词',
   keyword varchar(255) DEFAULT NULL COMMENT '关键词',
   quality varchar(20) DEFAULT NULL COMMENT '质量',
   quality varchar(20) DEFAULT NULL COMMENT '质量',
@@ -905,7 +906,7 @@ CREATE TABLE textbook_topic (
   create_time datetime DEFAULT NULL,
   create_time datetime DEFAULT NULL,
   update_time datetime DEFAULT NULL,
   update_time datetime DEFAULT NULL,
   PRIMARY KEY (id),
   PRIMARY KEY (id),
-  KEY library_id (library_id,question_subject)
+  KEY library_id (library_id,textbook_subject)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='机经-题目';
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='机经-题目';
 
 
 CREATE TABLE user (
 CREATE TABLE user (
@@ -1466,7 +1467,7 @@ CREATE TABLE user_service (
 CREATE TABLE user_textbook_enroll (
 CREATE TABLE user_textbook_enroll (
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   user_id int(11) unsigned NOT NULL COMMENT '用户ID',
   user_id int(11) unsigned NOT NULL COMMENT '用户ID',
-  month datetime DEFAULT NULL COMMENT '报名月份',
+  date datetime DEFAULT NULL COMMENT '报名日期',
   create_time datetime DEFAULT NULL,
   create_time datetime DEFAULT NULL,
   PRIMARY KEY (id),
   PRIMARY KEY (id),
   KEY user_id (user_id,month)
   KEY user_id (user_id,month)

+ 17 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java

@@ -264,6 +264,23 @@ public class SettingController {
         return ResponseHelp.success(entity.getValue());
         return ResponseHelp.success(entity.getValue());
     }
     }
 
 
+    @RequestMapping(value = "/textbook_config", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改机经设置", httpMethod = "PUT")
+    private Response<Boolean> editTextbookConfig(@RequestBody @Validated JSONObject dto){
+        Setting entity = settingService.getByKey(SettingKey.TEXTBOOK_CONFIG);
+        entity.setValue(dto);
+        settingService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/textbook_config", method = RequestMethod.GET)
+    @ApiOperation(value = "获取机经配置", httpMethod = "GET")
+    private Response<JSONObject> getTextbookConfig(){
+        Setting entity = settingService.getByKey(SettingKey.TEXTBOOK_CONFIG);
+
+        return ResponseHelp.success(entity.getValue());
+    }
+
     @RequestMapping(value = "/score_switch", method = RequestMethod.PUT)
     @RequestMapping(value = "/score_switch", method = RequestMethod.PUT)
     @ApiOperation(value = "修改分数开关", httpMethod = "PUT")
     @ApiOperation(value = "修改分数开关", httpMethod = "PUT")
     private Response<Boolean> editScoreSwitch(@RequestBody @Validated JSONObject dto){
     private Response<Boolean> editScoreSwitch(@RequestBody @Validated JSONObject dto){

+ 5 - 5
server/gateway-api/src/main/java/com/qxgmat/controller/admin/TextbookController.java

@@ -220,7 +220,7 @@ public class TextbookController {
     public Response<TextbookTopic> addTopic(@RequestBody @Validated TextbookTopic dto, HttpServletRequest request) {
     public Response<TextbookTopic> addTopic(@RequestBody @Validated TextbookTopic dto, HttpServletRequest request) {
         TextbookTopic entity = Transform.convert(dto, TextbookTopic.class);
         TextbookTopic entity = Transform.convert(dto, TextbookTopic.class);
         entity = textbookTopicService.add(entity);
         entity = textbookTopicService.add(entity);
-        textbookService.updateLibraryNo(entity.getLibraryId(), entity.getQuestionSubject());
+        textbookService.updateLibraryNo(entity.getLibraryId(), entity.getTextbookSubject());
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(Transform.convert(entity, TextbookTopic.class));
         return ResponseHelp.success(Transform.convert(entity, TextbookTopic.class));
     }
     }
@@ -230,7 +230,7 @@ public class TextbookController {
     public Response<Boolean> editTopic(@RequestBody @Validated TextbookTopic dto, HttpServletRequest request) {
     public Response<Boolean> editTopic(@RequestBody @Validated TextbookTopic dto, HttpServletRequest request) {
         TextbookTopic entity = Transform.convert(dto, TextbookTopic.class);
         TextbookTopic entity = Transform.convert(dto, TextbookTopic.class);
         entity = textbookTopicService.edit(entity);
         entity = textbookTopicService.edit(entity);
-        textbookService.updateLibraryNo(entity.getLibraryId(), entity.getQuestionSubject());
+        textbookService.updateLibraryNo(entity.getLibraryId(), entity.getTextbookSubject());
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
@@ -240,7 +240,7 @@ public class TextbookController {
     public Response<Boolean> deleteTopic(@RequestParam int id, HttpServletRequest request) {
     public Response<Boolean> deleteTopic(@RequestParam int id, HttpServletRequest request) {
         TextbookTopic entity = textbookTopicService.get(id);
         TextbookTopic entity = textbookTopicService.get(id);
         textbookTopicService.delete(id);
         textbookTopicService.delete(id);
-        textbookService.updateLibraryNo(entity.getLibraryId(), entity.getQuestionSubject());
+        textbookService.updateLibraryNo(entity.getLibraryId(), entity.getTextbookSubject());
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
@@ -254,8 +254,8 @@ public class TextbookController {
 
 
     @RequestMapping(value = "/topic/next", method = RequestMethod.GET)
     @RequestMapping(value = "/topic/next", method = RequestMethod.GET)
     @ApiOperation(value = "获取机经题目下一题序号", httpMethod = "GET")
     @ApiOperation(value = "获取机经题目下一题序号", httpMethod = "GET")
-    public Response<Integer> nextTopic(@RequestParam int libraryId, @RequestParam String questionSubject, HttpSession session) {
-        TextbookTopic entity = textbookTopicService.lastByLibrary(libraryId, questionSubject);
+    public Response<Integer> nextTopic(@RequestParam int libraryId, @RequestParam String textbookSubject, HttpSession session) {
+        TextbookTopic entity = textbookTopicService.lastByLibrary(libraryId, textbookSubject);
         Integer no = 1;
         Integer no = 1;
         if (entity != null){
         if (entity != null){
             no += entity.getNo();
             no += entity.getNo();

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -1530,7 +1530,7 @@ public class MyController {
         entity.setUserId(user.getId());
         entity.setUserId(user.getId());
         entity.setStatus(0);
         entity.setStatus(0);
         if (entity.getNo() != null && entity.getNo() > 0){
         if (entity.getNo() != null && entity.getNo() > 0){
-            TextbookTopic textbookTopic = textbookTopicService.getByNo(entity.getLibraryId(), entity.getQuestionSubject(), entity.getNo());
+            TextbookTopic textbookTopic = textbookTopicService.getByNo(entity.getLibraryId(), entity.getTextbookSubject(), entity.getNo());
             entity.setTopicId(textbookTopic.getId());
             entity.setTopicId(textbookTopic.getId());
         }
         }
         userTextbookFeedbackService.add(entity);
         userTextbookFeedbackService.add(entity);

+ 78 - 50
server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java

@@ -4,22 +4,19 @@ import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
 import com.nuliji.tools.*;
 import com.nuliji.tools.exception.AuthException;
 import com.nuliji.tools.exception.AuthException;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.ParameterException;
-import com.qxgmat.data.constants.enums.QuestionSubject;
 import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.ServiceKey;
+import com.qxgmat.data.constants.enums.TextbookSubject;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
 import com.qxgmat.data.constants.enums.module.PaperOrigin;
 import com.qxgmat.data.constants.enums.module.PaperOrigin;
+import com.qxgmat.data.constants.enums.module.ProductType;
 import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
-import com.qxgmat.data.relation.entity.TextbookEnrollNumberRelation;
-import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
-import com.qxgmat.dto.extend.UserPaperBaseExtendDto;
-import com.qxgmat.dto.extend.UserReportExtendDto;
-import com.qxgmat.dto.extend.UserServiceRecordExtendDto;
-import com.qxgmat.dto.extend.UserTextbookGroupExtendDto;
+import com.qxgmat.data.relation.entity.MonthNumberRelation;
+import com.qxgmat.dto.extend.*;
 import com.qxgmat.dto.request.TextbookEnrollDto;
 import com.qxgmat.dto.request.TextbookEnrollDto;
 import com.qxgmat.dto.request.TextbookSubscribeDto;
 import com.qxgmat.dto.request.TextbookSubscribeDto;
 import com.qxgmat.dto.response.TextbookEnrollTimeDto;
 import com.qxgmat.dto.response.TextbookEnrollTimeDto;
@@ -33,6 +30,7 @@ import com.qxgmat.service.UserServiceService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.extend.QuestionFlowService;
 import com.qxgmat.service.extend.QuestionFlowService;
 import com.qxgmat.service.extend.TextbookService;
 import com.qxgmat.service.extend.TextbookService;
+import com.qxgmat.service.extend.ToolsService;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
@@ -43,6 +41,7 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSession;
 import java.text.DateFormat;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
@@ -103,6 +102,9 @@ public class TextbookController
     private TextbookService textbookService;
     private TextbookService textbookService;
 
 
     @Autowired
     @Autowired
+    private ToolsService toolsService;
+
+    @Autowired
     private UserTextbookEnrollService userTextbookEnrollService;
     private UserTextbookEnrollService userTextbookEnrollService;
 
 
     @RequestMapping(value = "/progress", method = RequestMethod.GET)
     @RequestMapping(value = "/progress", method = RequestMethod.GET)
@@ -224,13 +226,9 @@ public class TextbookController
             dto.setStartTime(userService != null ? userService.getStartTime() : null);
             dto.setStartTime(userService != null ? userService.getStartTime() : null);
             dto.setExpireTime(userService != null ? userService.getExpireTime() : null);
             dto.setExpireTime(userService != null ? userService.getExpireTime() : null);
         }
         }
-        if (!dto.getHasService()){
-            // 移除数据
-            latest.setRc("");
-            latest.setIr("");
-            latest.setQuant("");
-        }
+        textbookService.refreshLibraryResource(user, latest);
         TextbookLibrary second = textbookLibraryService.getSecond();
         TextbookLibrary second = textbookLibraryService.getSecond();
+        textbookService.refreshLibraryResource(user, second);
         dto.setSecond(second);
         dto.setSecond(second);
 
 
         return ResponseHelp.success(dto);
         return ResponseHelp.success(dto);
@@ -241,6 +239,7 @@ public class TextbookController
     public Response<List<TextbookLibrary>> year(
     public Response<List<TextbookLibrary>> year(
             @RequestParam(required = false) String year,
             @RequestParam(required = false) String year,
             HttpSession session) {
             HttpSession session) {
+        User user = (User) shiroHelp.getLoginUser();
         Date start;
         Date start;
         try {
         try {
             start = DateFormat.getDateInstance().parse(String.format("%s-01-01", year));
             start = DateFormat.getDateInstance().parse(String.format("%s-01-01", year));
@@ -249,7 +248,7 @@ public class TextbookController
         }
         }
         Date end = Tools.addYear(start, 1);
         Date end = Tools.addYear(start, 1);
         List<TextbookLibrary> libraryList = textbookLibraryService.listByTime(start, end);
         List<TextbookLibrary> libraryList = textbookLibraryService.listByTime(start, end);
-
+        textbookService.refreshLibraryResource(user, libraryList);
         return ResponseHelp.success(libraryList);
         return ResponseHelp.success(libraryList);
     }
     }
 
 
@@ -265,12 +264,13 @@ public class TextbookController
         if (!userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK)){
         if (!userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK)){
             throw new ParameterException("没有机经查看权限");
             throw new ParameterException("没有机经查看权限");
         }
         }
-        if (QuestionSubject.ValueOf(subject) == null){
+        if (TextbookSubject.ValueOf(subject) == null){
             throw new ParameterException("科目错误");
             throw new ParameterException("科目错误");
         }
         }
         TextbookLibrary library = textbookLibraryService.getLatest();
         TextbookLibrary library = textbookLibraryService.getLatest();
-        List<TextbookLibraryHistory> p = textbookLibraryHistoryService.allByLibraryAndSubject(library.getId(), QuestionSubject.ValueOf(subject));
+        List<TextbookLibraryHistory> p = textbookLibraryHistoryService.allByLibraryAndSubject(library.getId(), TextbookSubject.ValueOf(subject));
 
 
+        textbookService.refreshHistoryResource(user, p);
         return ResponseHelp.success(p);
         return ResponseHelp.success(p);
     }
     }
 
 
@@ -298,9 +298,10 @@ public class TextbookController
     public Response<PageMessage<TextbookTopic>> listTopic(
     public Response<PageMessage<TextbookTopic>> listTopic(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) boolean latest,
+            @RequestParam(required = false) boolean latest,
             @RequestParam(required = true) String subject,
             @RequestParam(required = true) String subject,
-            @RequestParam(required = false) String[] qualitys,
+            @RequestParam(required = false) String keyword,
+            @RequestParam(required = false) String quality,
             @RequestParam(required = false) Boolean isOld,
             @RequestParam(required = false) Boolean isOld,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             @RequestParam(required = false, defaultValue = "desc") String direction,
@@ -320,7 +321,7 @@ public class TextbookController
             library = textbookLibraryService.getSecond();
             library = textbookLibraryService.getSecond();
         }
         }
 
 
-        Page<TextbookTopic> p = textbookTopicService.list(page, size, library.getId(), QuestionSubject.ValueOf(subject), qualitys, isOld, order, DirectionStatus.ValueOf(direction));
+        Page<TextbookTopic> p = textbookTopicService.list(page, size, library.getId(), TextbookSubject.ValueOf(subject), keyword, quality, isOld, order, DirectionStatus.ValueOf(direction));
 
 
         return ResponseHelp.success(p, page, size, p.getTotal());
         return ResponseHelp.success(p, page, size, p.getTotal());
     }
     }
@@ -398,55 +399,82 @@ public class TextbookController
         if (user == null){
         if (user == null){
             throw new AuthException("请先登录");
             throw new AuthException("请先登录");
         }
         }
-        textbookService.enroll(user.getId(), dto.getMonth());
+        textbookService.enroll(user.getId(), dto.getDate());
+
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/enroll/cancel", method = RequestMethod.POST)
+    @ApiOperation(value = "取消报名", notes = "取消报名", httpMethod = "POST")
+    public Response<Boolean> cancelEnroll()  {
+        User user = (User) shiroHelp.getLoginUser();
+        if (user == null){
+            throw new AuthException("请先登录");
+        }
+        textbookService.unEnroll(user.getId());
 
 
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 
 
     @RequestMapping(value = "/enroll/list", method = RequestMethod.GET)
     @RequestMapping(value = "/enroll/list", method = RequestMethod.GET)
     @ApiOperation(value = "报名记录", notes = "报名记录", httpMethod = "GET")
     @ApiOperation(value = "报名记录", notes = "报名记录", httpMethod = "GET")
-    public Response<List<TextbookEnrollTimeDto>> enroll(
-            @RequestParam(required = false) String year,
+    public Response<TextbookEnrollTimeDto> enrollList(
+            @RequestParam(required = true) String startDate,
+            @RequestParam(required = true) String endDate,
             HttpSession session) {
             HttpSession session) {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
+        Date end;
         Date start;
         Date start;
-        try {
-            start = DateFormat.getDateInstance().parse(String.format("%s-01-01", year));
-        } catch (ParseException e) {
+        try{
+            SimpleDateFormat sdf =   new SimpleDateFormat("yyyy-MM-dd");
+            end = sdf.parse(endDate);
+            start = sdf.parse(startDate);
+        }catch (Exception e){
             throw new ParameterException("日期格式错误");
             throw new ParameterException("日期格式错误");
         }
         }
-        Date end = Tools.addYear(start, 1);
+        Integer useNumber = toolsService.getTextbookUseNumber();
+        if (useNumber == null){
+            useNumber = 0;
+        }
+
+        TextbookEnrollTimeDto dto = new TextbookEnrollTimeDto();
 
 
-        List<TextbookEnrollNumberRelation> relations = userTextbookEnrollService.groupByMonth(start.toString(), end.toString());
-        Map<Integer, Integer> monthMap = new HashMap<>();
-        for(TextbookEnrollNumberRelation relation : relations){
-            int month = Tools.monthNumber(relation.getMonth());
-            monthMap.put(month, relation.getNumber());
+        List<MonthNumberRelation> enrollRelation = userTextbookEnrollService.groupByMonth(startDate, endDate);
+        Map<Integer, Integer> enrollMonthMap = new HashMap<>();
+        for(MonthNumberRelation relation : enrollRelation){
+            int month = relation.getMonth();
+            enrollMonthMap.put(month, relation.getNumber());
         }
         }
 
 
-        Map<Integer, Boolean> enrollMap = new HashMap<>();
+        List<MonthNumberRelation> recordRelation = userOrderRecordService.groupByMonth(startDate, endDate, ProductType.SERVICE, null, ServiceKey.TEXTBOOK);
+        Map<Integer, Integer> recordMonthMap = new HashMap<>();
+        for(MonthNumberRelation relation : recordRelation){
+            int month = relation.getMonth();
+            recordMonthMap.put(month, relation.getNumber());
+        }
+
+        // 获取用户报考日期
         if(user != null){
         if(user != null){
-            List<UserTextbookEnroll> enrolls = userTextbookEnrollService.allByUser(user.getId(), start.toString(), end.toString());
-            for(UserTextbookEnroll enroll : enrolls){
-                int month = Tools.monthNumber(enroll.getMonth());
-                enrollMap.put(month, true);
+            UserTextbookEnroll enroll = userTextbookEnrollService.getByUser(user.getId());
+            if (enroll != null){
+                dto.setDate(enroll.getDate());
             }
             }
         }
         }
 
 
-        List<TextbookEnrollTimeDto> dtos = new ArrayList<>();
-        Date now = Tools.addMonth(new Date(), 1);
-        Date monthTime = start;
-        while(monthTime.before(now)){
-            int month = Tools.monthNumber(monthTime);
-            int number = monthMap.getOrDefault(month, 0);
-            boolean status = enrollMap.getOrDefault(month, false);
-            TextbookEnrollTimeDto dto = new TextbookEnrollTimeDto();
-            dto.setMonth(monthTime);
-            dto.setNumber(number);
-            dto.setStatus(status);
-
-            monthTime = Tools.addMonth(monthTime, 1);
+        List<TextbookEnrollTimeExtendDto> dtos = new ArrayList<>();
+        while(start.before(end)){
+            int month = Tools.monthNumber(start);
+            int enrollNumber = enrollMonthMap.getOrDefault(month, 0);
+            int recordNumber = recordMonthMap.getOrDefault(month, 0);
+            TextbookEnrollTimeExtendDto extendDto = new TextbookEnrollTimeExtendDto();
+            extendDto.setMonth(start);
+            extendDto.setEnrollNumber(enrollNumber);
+            extendDto.setUseNumber(recordNumber + useNumber);
+            dtos.add(extendDto);
+
+            start = Tools.addMonth(start, 1);
         }
         }
-        return ResponseHelp.success(dtos);
+        dto.setTimes(dtos);
+        return ResponseHelp.success(dto);
     }
     }
 }
 }

+ 9 - 9
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/TextbookTopicInfoDto.java

@@ -14,7 +14,7 @@ public class TextbookTopicInfoDto {
 
 
     private TextbookLibraryExtendDto library;
     private TextbookLibraryExtendDto library;
 
 
-    private String questionSubject;
+    private String textbookSubject;
 
 
     private Integer no;
     private Integer no;
 
 
@@ -52,14 +52,6 @@ public class TextbookTopicInfoDto {
         this.library = library;
         this.library = library;
     }
     }
 
 
-    public String getQuestionSubject() {
-        return questionSubject;
-    }
-
-    public void setQuestionSubject(String questionSubject) {
-        this.questionSubject = questionSubject;
-    }
-
     public Integer getNo() {
     public Integer getNo() {
         return no;
         return no;
     }
     }
@@ -107,4 +99,12 @@ public class TextbookTopicInfoDto {
     public void setUpdateTime(Date updateTime) {
     public void setUpdateTime(Date updateTime) {
         this.updateTime = updateTime;
         this.updateTime = updateTime;
     }
     }
+
+    public String getTextbookSubject() {
+        return textbookSubject;
+    }
+
+    public void setTextbookSubject(String textbookSubject) {
+        this.textbookSubject = textbookSubject;
+    }
 }
 }

+ 36 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/TextbookEnrollTimeExtendDto.java

@@ -0,0 +1,36 @@
+package com.qxgmat.dto.extend;
+
+
+import java.util.Date;
+
+public class TextbookEnrollTimeExtendDto {
+    private Date month;
+
+    private Integer enrollNumber;
+
+    private Integer useNumber;
+
+    public Date getMonth() {
+        return month;
+    }
+
+    public void setMonth(Date month) {
+        this.month = month;
+    }
+
+    public Integer getEnrollNumber() {
+        return enrollNumber;
+    }
+
+    public void setEnrollNumber(Integer enrollNumber) {
+        this.enrollNumber = enrollNumber;
+    }
+
+    public Integer getUseNumber() {
+        return useNumber;
+    }
+
+    public void setUseNumber(Integer useNumber) {
+        this.useNumber = useNumber;
+    }
+}

+ 5 - 5
server/gateway-api/src/main/java/com/qxgmat/dto/request/TextbookEnrollDto.java

@@ -3,13 +3,13 @@ package com.qxgmat.dto.request;
 import java.util.Date;
 import java.util.Date;
 
 
 public class TextbookEnrollDto {
 public class TextbookEnrollDto {
-    private Date month;
+    private Date date;
 
 
-    public Date getMonth() {
-        return month;
+    public Date getDate() {
+        return date;
     }
     }
 
 
-    public void setMonth(Date month) {
-        this.month = month;
+    public void setDate(Date date) {
+        this.date = date;
     }
     }
 }
 }

+ 9 - 9
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserTextbookFeedbackDto.java

@@ -5,7 +5,7 @@ import com.qxgmat.data.dao.entity.UserTextbookFeedback;
 
 
 @Dto(entity = UserTextbookFeedback.class)
 @Dto(entity = UserTextbookFeedback.class)
 public class UserTextbookFeedbackDto {
 public class UserTextbookFeedbackDto {
-    private String questionSubject;
+    private String textbookSubject;
 
 
     private Integer no;
     private Integer no;
 
 
@@ -29,14 +29,6 @@ public class UserTextbookFeedbackDto {
         this.content = content;
         this.content = content;
     }
     }
 
 
-    public String getQuestionSubject() {
-        return questionSubject;
-    }
-
-    public void setQuestionSubject(String questionSubject) {
-        this.questionSubject = questionSubject;
-    }
-
     public Integer getNo() {
     public Integer getNo() {
         return no;
         return no;
     }
     }
@@ -44,4 +36,12 @@ public class UserTextbookFeedbackDto {
     public void setNo(Integer no) {
     public void setNo(Integer no) {
         this.no = no;
         this.no = no;
     }
     }
+
+    public String getTextbookSubject() {
+        return textbookSubject;
+    }
+
+    public void setTextbookSubject(String textbookSubject) {
+        this.textbookSubject = textbookSubject;
+    }
 }
 }

+ 13 - 20
server/gateway-api/src/main/java/com/qxgmat/dto/response/TextbookEnrollTimeDto.java

@@ -1,36 +1,29 @@
 package com.qxgmat.dto.response;
 package com.qxgmat.dto.response;
 
 
 
 
+import com.qxgmat.dto.extend.TextbookEnrollTimeExtendDto;
+
 import java.util.Date;
 import java.util.Date;
+import java.util.List;
 
 
 public class TextbookEnrollTimeDto {
 public class TextbookEnrollTimeDto {
-    private Date month;
-
-    private Integer number;
-
-    private Boolean status;
+    private Date date;
 
 
-    public Date getMonth() {
-        return month;
-    }
-
-    public void setMonth(Date month) {
-        this.month = month;
-    }
+    private List<TextbookEnrollTimeExtendDto> times;
 
 
-    public Integer getNumber() {
-        return number;
+    public List<TextbookEnrollTimeExtendDto> getTimes() {
+        return times;
     }
     }
 
 
-    public void setNumber(Integer number) {
-        this.number = number;
+    public void setTimes(List<TextbookEnrollTimeExtendDto> times) {
+        this.times = times;
     }
     }
 
 
-    public Boolean getStatus() {
-        return status;
+    public Date getDate() {
+        return date;
     }
     }
 
 
-    public void setStatus(Boolean status) {
-        this.status = status;
+    public void setDate(Date date) {
+        this.date = date;
     }
     }
 }
 }

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageExtendService.java

@@ -775,7 +775,7 @@ public class MessageExtendService {
         Map<String, String> map = new HashMap<>();
         Map<String, String> map = new HashMap<>();
         map.put("time", getTime(textbookFeedback.getCreateTime()));
         map.put("time", getTime(textbookFeedback.getCreateTime()));
         map.put("content", textbookFeedback.getContent());
         map.put("content", textbookFeedback.getContent());
-        map.put("subject", QuestionSubject.ValueOf(textbookFeedback.getQuestionSubject()).title);
+        map.put("subject", TextbookSubject.ValueOf(textbookFeedback.getTextbookSubject()).title);
         map.put("no", String.valueOf(textbookFeedback.getNo()));
         map.put("no", String.valueOf(textbookFeedback.getNo()));
         FeedbackTarget target = FeedbackTarget.ValueOf(textbookFeedback.getTarget());
         FeedbackTarget target = FeedbackTarget.ValueOf(textbookFeedback.getTarget());
         map.put("target", target.title);
         map.put("target", target.title);

+ 4 - 2
server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java

@@ -698,8 +698,10 @@ public class OrderFlowService {
                 userService = userServiceService.edit(userService);
                 userService = userServiceService.edit(userService);
             }
             }
             if (serviceKey == ServiceKey.TEXTBOOK){
             if (serviceKey == ServiceKey.TEXTBOOK){
-                // 自动报名: 使用机经的后10天所在月份
-                textbookService.enroll(record.getUserId(), Tools.addDate(new Date(), 10));
+//                // 自动报名: 使用机经的后10天所在月份
+//                textbookService.enroll(record.getUserId(), Tools.addDate(new Date(), 10));
+                // 重置机经页面tips
+                usersService.edit(User.builder().id(record.getUserId()).textbookTips(0).build());
             }
             }
 
 
             record.setUseStartTime(startTime);
             record.setUseStartTime(startTime);

+ 91 - 6
server/gateway-api/src/main/java/com/qxgmat/service/extend/TextbookService.java

@@ -1,6 +1,8 @@
 package com.qxgmat.service.extend;
 package com.qxgmat.service.extend;
 
 
 import com.nuliji.tools.Tools;
 import com.nuliji.tools.Tools;
+import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.TextbookSubject;
 import com.qxgmat.data.constants.enums.TextbookSubject;
 import com.qxgmat.data.constants.enums.logic.SentenceLogic;
 import com.qxgmat.data.constants.enums.logic.SentenceLogic;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
@@ -8,6 +10,7 @@ import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.constants.enums.module.QuestionNoModule;
 import com.qxgmat.data.constants.enums.module.QuestionNoModule;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
 import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
+import com.qxgmat.service.UserServiceService;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.service.inline.*;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
@@ -15,9 +18,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
 import java.text.SimpleDateFormat;
 import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 @Service
 @Service
@@ -50,6 +51,9 @@ public class TextbookService {
     @Resource
     @Resource
     private TextbookTopicService textbookTopicService;
     private TextbookTopicService textbookTopicService;
 
 
+    @Resource
+    private UserServiceService userServiceService;
+
     /**
     /**
      * 报名
      * 报名
      * @param userId
      * @param userId
@@ -57,18 +61,30 @@ public class TextbookService {
      */
      */
     @Transactional
     @Transactional
     public void enroll(Integer userId, Date date){
     public void enroll(Integer userId, Date date){
-        date = Tools.month(date);
-        UserTextbookEnroll in = userTextbookEnrollService.get(userId, date.toString());
+        UserTextbookEnroll in = userTextbookEnrollService.getByUser(userId);
         if (in != null){
         if (in != null){
             return;
             return;
         }
         }
         userTextbookEnrollService.add(UserTextbookEnroll.builder()
         userTextbookEnrollService.add(UserTextbookEnroll.builder()
                 .userId(userId)
                 .userId(userId)
-                .month(date)
+                .date(date)
                 .build());
                 .build());
     }
     }
 
 
     /**
     /**
+     * 取消报名
+     * @param userId
+     */
+    @Transactional
+    public void unEnroll(Integer userId){
+        UserTextbookEnroll in = userTextbookEnrollService.getByUser(userId);
+        if (in == null){
+            return;
+        }
+        userTextbookEnrollService.delete(in.getId());
+    }
+
+    /**
      * 添加新一期的换库
      * 添加新一期的换库
      * @param entity
      * @param entity
      * @return
      * @return
@@ -188,6 +204,75 @@ public class TextbookService {
         }
         }
     }
     }
 
 
+    /**
+     * 根据用户权限更新资源信息
+     * @param user
+     * @param textbookLibrary
+     */
+    public void refreshLibraryResource(User user, TextbookLibrary textbookLibrary){
+        // 处理权限
+        if (user != null){
+            if (!userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK)){
+                // 移除数据
+                textbookLibrary.setRc("");
+                textbookLibrary.setIr("");
+                textbookLibrary.setQuant("");
+            }
+        }else{
+            textbookLibrary.setRc("");
+            textbookLibrary.setIr("");
+            textbookLibrary.setQuant("");
+        }
+    }
+
+    /**
+     * 根据用户权限更新资源信息
+     * @param user
+     * @param textbookLibraryList
+     */
+    public void refreshLibraryResource(User user, List<TextbookLibrary> textbookLibraryList){
+        // 处理权限
+        if (user != null){
+            if (!userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK)) {
+                for (TextbookLibrary textbookLibrary : textbookLibraryList) {
+                    textbookLibrary.setRc("");
+                    textbookLibrary.setIr("");
+                    textbookLibrary.setQuant("");
+                }
+            }
+        }else{
+            for(TextbookLibrary textbookLibrary : textbookLibraryList){
+                textbookLibrary.setRc("");
+                textbookLibrary.setIr("");
+                textbookLibrary.setQuant("");
+            }
+        }
+    }
+
+
+    /**
+     * 根据用户权限更新资源信息
+     * @param user
+     * @param textbookLibraryHistoryList
+     */
+    public void refreshHistoryResource(User user, List<TextbookLibraryHistory> textbookLibraryHistoryList){
+        // 处理权限
+        if (user != null){
+            if (!userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK)) {
+                for (TextbookLibraryHistory history : textbookLibraryHistoryList) {
+                    history.setRc("");
+                    history.setIr("");
+                    history.setQuant("");
+                }
+            }
+        }else{
+            for(TextbookLibraryHistory history : textbookLibraryHistoryList){
+                history.setRc("");
+                history.setIr("");
+                history.setQuant("");
+            }
+        }
+    }
     private void addQuestionToPaper(TextbookLibrary library, TextbookQuestion question, TextbookLogic logic){
     private void addQuestionToPaper(TextbookLibrary library, TextbookQuestion question, TextbookLogic logic){
         String prefixTitle = generatePrefixTitle(library);
         String prefixTitle = generatePrefixTitle(library);
         // 获取最后一个paper
         // 获取最后一个paper

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/ToolsService.java

@@ -592,4 +592,14 @@ public class ToolsService {
             return info.getIntValue("price");
             return info.getIntValue("price");
         }
         }
     }
     }
+
+    /**
+     * 获取机经每月基础使用人数
+     * @return
+     */
+    public Integer getTextbookUseNumber(){
+        Setting setting = settingService.getByKey(SettingKey.TEXTBOOK_CONFIG);
+        JSONObject value = setting.getValue();
+        return value.getInteger("use_number");
+    }
 }
 }

+ 2 - 2
server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookLibraryHistoryService.java

@@ -5,7 +5,7 @@ import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.constants.enums.QuestionSubject;
+import com.qxgmat.data.constants.enums.TextbookSubject;
 import com.qxgmat.data.dao.TextbookLibraryHistoryMapper;
 import com.qxgmat.data.dao.TextbookLibraryHistoryMapper;
 import com.qxgmat.data.dao.TextbookLibraryMapper;
 import com.qxgmat.data.dao.TextbookLibraryMapper;
 import com.qxgmat.data.dao.entity.TextbookLibrary;
 import com.qxgmat.data.dao.entity.TextbookLibrary;
@@ -42,7 +42,7 @@ public class TextbookLibraryHistoryService extends AbstractService {
         return page(()->select(textbookLibraryHistoryMapper, example), page, size);
         return page(()->select(textbookLibraryHistoryMapper, example), page, size);
     }
     }
 
 
-    public List<TextbookLibraryHistory> allByLibraryAndSubject(Integer libraryId, QuestionSubject subject){
+    public List<TextbookLibraryHistory> allByLibraryAndSubject(Integer libraryId, TextbookSubject subject){
         Example example = new Example(TextbookLibraryHistory.class);
         Example example = new Example(TextbookLibraryHistory.class);
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()

+ 2 - 1
server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookLibraryService.java

@@ -82,9 +82,10 @@ public class TextbookLibraryService extends AbstractService {
         Example example = new Example(TextbookLibrary.class);
         Example example = new Example(TextbookLibrary.class);
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()
-                .andLessThanOrEqualTo("startDate", startTime)
+                .andGreaterThanOrEqualTo("startDate", startTime)
                 .andLessThan("startDate", endTime)
                 .andLessThan("startDate", endTime)
         );
         );
+        example.orderBy("id").asc();
         return select(textbookLibraryMapper, example);
         return select(textbookLibraryMapper, example);
     }
     }
 
 

+ 16 - 12
server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookTopicService.java

@@ -5,13 +5,11 @@ import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.constants.enums.QuestionSubject;
+import com.qxgmat.data.constants.enums.TextbookSubject;
 import com.qxgmat.data.constants.enums.TopicQuality;
 import com.qxgmat.data.constants.enums.TopicQuality;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.TextbookTopicMapper;
 import com.qxgmat.data.dao.TextbookTopicMapper;
-import com.qxgmat.data.dao.UserTextbookFeedbackMapper;
 import com.qxgmat.data.dao.entity.TextbookTopic;
 import com.qxgmat.data.dao.entity.TextbookTopic;
-import com.qxgmat.data.dao.entity.UserTextbookFeedback;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
@@ -29,12 +27,12 @@ public class TextbookTopicService extends AbstractService {
     @Resource
     @Resource
     private TextbookTopicMapper textbookTopicMapper;
     private TextbookTopicMapper textbookTopicMapper;
 
 
-    public Page<TextbookTopic> listAdmin(int page, int pageSize, String questionType, Number libraryId, String keyword, TopicQuality quality, String order, DirectionStatus direction){
+    public Page<TextbookTopic> listAdmin(int page, int pageSize, String textbookSubject, Number libraryId, String keyword, TopicQuality quality, String order, DirectionStatus direction){
         Example example = new Example(TextbookTopic.class);
         Example example = new Example(TextbookTopic.class);
-        if (questionType!=null){
+        if (textbookSubject!=null){
             example.and(
             example.and(
                     example.createCriteria()
                     example.createCriteria()
-                            .andEqualTo("questionType", questionType)
+                            .andEqualTo("textbookSubject", textbookSubject)
             );
             );
         }
         }
         if (libraryId!=null){
         if (libraryId!=null){
@@ -76,23 +74,29 @@ public class TextbookTopicService extends AbstractService {
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()
                         .andEqualTo("libraryId", libraryId)
                         .andEqualTo("libraryId", libraryId)
-                        .andEqualTo("questionSubject", questionSubject)
+                        .andEqualTo("textbookSubject", questionSubject)
         );
         );
         example.orderBy("no").desc();
         example.orderBy("no").desc();
         return one(textbookTopicMapper, example);
         return one(textbookTopicMapper, example);
     }
     }
 
 
-    public Page<TextbookTopic> list(int page, int size, Integer libraryId, QuestionSubject subject, String[] qualitys, Boolean isOld, String order, DirectionStatus direction){
+    public Page<TextbookTopic> list(int page, int size, Integer libraryId, TextbookSubject subject, String keyword, String quality, Boolean isOld, String order, DirectionStatus direction){
         Example example = new Example(TextbookTopic.class);
         Example example = new Example(TextbookTopic.class);
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()
                 .andEqualTo("libraryId", libraryId)
                 .andEqualTo("libraryId", libraryId)
-                .andEqualTo("questionSubject", subject.key)
+                .andEqualTo("textbookSubject", subject.key)
         );
         );
-        if (qualitys != null){
+        if (keyword != null){
             example.and(
             example.and(
                     example.createCriteria()
                     example.createCriteria()
-                    .andIn("quality", Arrays.stream(qualitys).collect(Collectors.toList()))
+                            .andEqualTo("keyword", keyword)
+            );
+        }
+        if (quality != null){
+            example.and(
+                    example.createCriteria()
+                    .andEqualTo("quality", quality)
             );
             );
         }
         }
         if (isOld != null){
         if (isOld != null){
@@ -122,7 +126,7 @@ public class TextbookTopicService extends AbstractService {
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()
                         .andEqualTo("libraryId", libraryId)
                         .andEqualTo("libraryId", libraryId)
-                        .andEqualTo("questionSubject", subject)
+                        .andEqualTo("textbookSubject", subject)
                         .andEqualTo("no", no)
                         .andEqualTo("no", no)
         );
         );
         return one(textbookTopicMapper, example);
         return one(textbookTopicMapper, example);

+ 5 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderRecordService.java

@@ -17,6 +17,7 @@ import com.qxgmat.data.dao.entity.UserOrder;
 import com.qxgmat.data.dao.entity.UserOrderRecord;
 import com.qxgmat.data.dao.entity.UserOrderRecord;
 import com.qxgmat.data.relation.UserOrderRecordRelationMapper;
 import com.qxgmat.data.relation.UserOrderRecordRelationMapper;
 import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
 import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
+import com.qxgmat.data.relation.entity.MonthNumberRelation;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
@@ -157,6 +158,10 @@ public class UserOrderRecordService extends AbstractService {
         return select(userOrderRecordMapper, example);
         return select(userOrderRecordMapper, example);
     }
     }
 
 
+    public List<MonthNumberRelation> groupByMonth(String startTime, String endTime, ProductType productType, Integer productId, ServiceKey serviceKey){
+        return userOrderRecordRelationMapper.groupByMonth(startTime, endTime, productType != null ? productType.key : null, productId, serviceKey != null ? serviceKey.key : null);
+    }
+
     /**
     /**
      * 列出购买资料的记录
      * 列出购买资料的记录
      * @param page
      * @param page

+ 6 - 10
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserTextbookEnrollService.java

@@ -5,18 +5,15 @@ import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.dao.TextbookLibraryHistoryMapper;
 import com.qxgmat.data.dao.UserTextbookEnrollMapper;
 import com.qxgmat.data.dao.UserTextbookEnrollMapper;
-import com.qxgmat.data.dao.entity.TextbookLibraryHistory;
 import com.qxgmat.data.dao.entity.UserTextbookEnroll;
 import com.qxgmat.data.dao.entity.UserTextbookEnroll;
 import com.qxgmat.data.relation.UserTextbookEnrollRelationMapper;
 import com.qxgmat.data.relation.UserTextbookEnrollRelationMapper;
-import com.qxgmat.data.relation.entity.TextbookEnrollNumberRelation;
+import com.qxgmat.data.relation.entity.MonthNumberRelation;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.List;
 import java.util.List;
 
 
@@ -35,23 +32,22 @@ public class UserTextbookEnrollService extends AbstractService {
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()
                         .andEqualTo("userId", userId)
                         .andEqualTo("userId", userId)
-                        .andGreaterThanOrEqualTo("month", startTime)
-                        .andLessThan("month", endTime)
+                        .andGreaterThanOrEqualTo("date", startTime)
+                        .andLessThan("date", endTime)
         );
         );
-        example.orderBy("month").asc();
+        example.orderBy("date").asc();
         return select(userTextbookEnrollMapper, example);
         return select(userTextbookEnrollMapper, example);
     }
     }
 
 
-    public List<TextbookEnrollNumberRelation> groupByMonth(String startTime, String endTime){
+    public List<MonthNumberRelation> groupByMonth(String startTime, String endTime){
         return userTextbookEnrollRelationMapper.groupByMonth(startTime, endTime);
         return userTextbookEnrollRelationMapper.groupByMonth(startTime, endTime);
     }
     }
 
 
-    public UserTextbookEnroll get(Integer userId, String month){
+    public UserTextbookEnroll getByUser(Integer userId){
         Example example = new Example(UserTextbookEnroll.class);
         Example example = new Example(UserTextbookEnroll.class);
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()
                         .andEqualTo("userId", userId)
                         .andEqualTo("userId", userId)
-                        .andEqualTo("month", month)
         );
         );
         return one(userTextbookEnrollMapper, example);
         return one(userTextbookEnrollMapper, example);
     }
     }

+ 1 - 1
server/tools/src/main/java/com/nuliji/tools/Tools.java

@@ -274,7 +274,7 @@ public class Tools {
     public static int monthNumber(Date date){
     public static int monthNumber(Date date){
         Calendar calendar = Calendar.getInstance();
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(date);
         calendar.setTime(date);
-        return calendar.get(Calendar.MONTH);
+        return calendar.get(Calendar.MONTH) + 1;
     }
     }
 
 
     public static Date month(Date date){
     public static Date month(Date date){