Преглед изворни кода

添加用户配置,标签配置,推荐配置

sophieChenyx пре 6 година
родитељ
комит
f385ff746a
48 измењених фајлова са 828 додато и 358 уклоњено
  1. 0 3
      .webpackrc
  2. 2 2
      package.json
  3. 4 0
      src/common/menu.js
  4. 11 0
      src/common/router.js
  5. 1 12
      src/components/AXItem/PictureItem.js
  6. 12 0
      src/components/AXTableSelector/columnsMap.js
  7. 2 2
      src/components/AXUpload/index.js
  8. 2 2
      src/components/SiderMenu/SiderMenu.js
  9. 9 4
      src/index.less
  10. 37 18
      src/models/resource.js
  11. 21 3
      src/models/shelves.js
  12. 2 2
      src/models/terminal.js
  13. 7 7
      src/routes/Campus/CampusCreate.js
  14. 46 9
      src/routes/Document/DocumentPlatform.js
  15. 1 1
      src/routes/Frontend/Recommend/RecommendCourse.js
  16. 10 19
      src/routes/Frontend/Recommend/RecommendPoster.js
  17. 8 6
      src/routes/Frontend/Tag/TagCreate.js
  18. 20 21
      src/routes/Frontend/TagGroup/TagGroupCreate.js
  19. 12 12
      src/routes/Merchant/MerchantList.js
  20. 11 12
      src/routes/Product/Course/CourseCreate.js
  21. 21 6
      src/routes/Product/Courseware/CoursewareCreate.js
  22. 0 14
      src/routes/Product/Courseware/CoursewareCreate.less
  23. 7 8
      src/routes/Product/Lesson/LessonCreate.js
  24. 0 15
      src/routes/Product/Lesson/LessonCreate.less
  25. 1 5
      src/routes/Product/Package/PackageCreate.js
  26. 6 6
      src/routes/Product/Support/SupportCreate.js
  27. 188 0
      src/routes/Resource/AudioBook/AudioBookCreate.js
  28. 212 0
      src/routes/Resource/AudioBook/AudioBookList.js
  29. 25 0
      src/routes/Resource/AudioBook/AudioBookList.less
  30. 1 2
      src/routes/Resource/Picture/PictureCardList.js
  31. 6 17
      src/routes/Resource/Picture/PictureEdit.js
  32. 2 17
      src/routes/Resource/Picture/PictureList.js
  33. 5 16
      src/routes/Resource/Picture/PictureSingleUpload.js
  34. 11 22
      src/routes/Resource/Picture/PictureTableList.js
  35. 8 22
      src/routes/Resource/Video/VideoCreate.js
  36. 14 25
      src/routes/Resource/Video/VideoTableList.js
  37. 2 10
      src/routes/Shelves/ShelvesCreate.js
  38. 7 3
      src/routes/Shelves/ShelvesEdit.js
  39. 45 6
      src/routes/Shelves/ShelvesList.js
  40. 5 4
      src/routes/Shelves/TableForm.js
  41. 1 1
      src/routes/System/CmsUser/CmsUserCreate.js
  42. 1 1
      src/routes/Terminal/User/TerminalCreate.js
  43. 1 1
      src/routes/Terminal/User/TerminalList.js
  44. 2 2
      src/routes/Trade/Order/OrderCreate.js
  45. 23 5
      src/services/resource.js
  46. 1 1
      src/theme.js
  47. 7 7
      src/utils/config.js
  48. 8 7
      src/utils/utils.js

+ 0 - 3
.webpackrc

@@ -3,9 +3,6 @@
   "extraBabelPlugins": [
     ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": true }]
   ],
-  "define": {
-    "process.env.API": "DEV"
-  },
   "env": {
     "development": {
       "extraBabelPlugins": [

+ 2 - 2
package.json

@@ -6,8 +6,8 @@
   "scripts": {
     "precommit": "npm run lint-staged",
     "start": "cross-env DISABLE_ESLINT=true roadhog dev",
-    "start:no-proxy": "cross-env API=DEV NO_PROXY=true DISABLE_ESLINT=true roadhog dev",
-    "build": "cross-env API=PRO DISABLE_ESLINT=true roadhog build",
+    "start:no-proxy": "cross-env NO_PROXY=true DISABLE_ESLINT=true roadhog dev",
+    "build": "cross-env NODE_ENV=production DISABLE_ESLINT=true roadhog build",
     "site": "roadhog-api-doc static && gh-pages -d dist",
     "analyze": "cross-env ANALYZE=true roadhog build",
     "lint:style": "stylelint \"src/**/*.less\" --syntax less",

+ 4 - 0
src/common/menu.js

@@ -29,6 +29,10 @@ const menuData = () => {
       name: '视频管理',
       path: 'video',
       icon: 'video-camera',
+    }, {
+      name: '有声读物',
+      path: 'audiobook',
+      icon: 'notification',
     }],
     authority: ['admin', 'platform'],
   }, {

+ 11 - 0
src/common/router.js

@@ -133,6 +133,17 @@ export const getRouterData = (app) => {
       component: dynamicWrapper(app, ['resource'], () => import('../routes/Resource/Video/VideoCreate')),
       name: '编辑视频',
     },
+    '/resource/audiobook': {
+      component: dynamicWrapper(app, ['resource'], () => import('../routes/Resource/AudioBook/AudioBookList')),
+    },
+    '/resource/audiobook-create': {
+      component: dynamicWrapper(app, ['resource'], () => import('../routes/Resource/AudioBook/AudioBookCreate')),
+      name: '创建有声读物',
+    },
+    '/resource/audiobook-edit/:id': {
+      component: dynamicWrapper(app, ['resource'], () => import('../routes/Resource/AudioBook/AudioBookCreate')),
+      name: '编辑有声读物',
+    },
     // 系统管理相关路由注册
     '/system/cms-user': {
       component: dynamicWrapper(app, ['cmsUser'], () => import('../routes/System/CmsUser')),

+ 1 - 12
src/components/AXItem/PictureItem.js

@@ -8,10 +8,6 @@ class PictureItem extends Component {
     const { item, onSelectChange } = this.props;
     onSelectChange(item.id, e.target.checked);
   };
-  handleItemDelete = () => {
-    const { item, onDelete } = this.props;
-    onDelete(item.id);
-  };
   handleItemEdit = () => {
     const { item, onEdit } = this.props;
     onEdit(item);
@@ -33,10 +29,10 @@ class PictureItem extends Component {
           className={styles.checkbox}
           onChange={this.handleItemChecked}
         />
+        {/* 不需删除功能 */}
         <Icon
           type="close-square-o"
           className={styles.removeIcon}
-          onClick={this.handleItemDelete}
         />
         <div className={styles.metaData}>
           {code}
@@ -50,13 +46,6 @@ class PictureItem extends Component {
             onClick={this.handleItemEdit}
           >编辑
           </Button>
-          <Button
-            size="small"
-            type="primary"
-            icon="delete"
-            onClick={this.handleItemDelete}
-          >删除
-          </Button>
         </div>
       </Card>
     );

+ 12 - 0
src/components/AXTableSelector/columnsMap.js

@@ -90,6 +90,18 @@ const clMap = {
       render: text => renderVideoQuality(text),
     }],
   },
+  AudioBook: {
+    columns: [{
+      title: '有声读物编号',
+      key: 1,
+      dataIndex: 'code',
+      width: '40%',
+    }, {
+      title: '有声读物名称',
+      key: 2,
+      dataIndex: 'name',
+    }],
+  },
   Courseware: {
     columns: [{
       title: '课件编号',

+ 2 - 2
src/components/AXUpload/index.js

@@ -182,13 +182,13 @@ class Uploader extends Component {
             <Icon type="inbox" />
           </p>
           <p className={styles.dragText}>点击或者拖拽图片到此区域进行上传</p>
-          <p className={styles.dragHint}>{`支持jpg/png图片格式,大小需小于${Hotax.FILE_MAX_SIZE}M`}</p>
+          <p className={styles.dragHint}>{`支持jpg/png/svg等图片格式,大小需小于${Hotax.FILE_MAX_SIZE}M`}</p>
         </Upload.Dragger>
         <Modal
           visible={previewVisible}
           footer={null}
           onCancel={this.handleCancelPreview}
-          width={650}
+          width={1100}
         >
           <img src={previewImg} alt="" style={{ width: '100%', marginTop: 20 }} />
         </Modal>

+ 2 - 2
src/components/SiderMenu/SiderMenu.js

@@ -168,7 +168,7 @@ export default class SiderMenu extends PureComponent {
     const { collapsed, onCollapse } = this.props;
     onCollapse(!collapsed);
     this.triggerResizeEvent();
-  }
+  };
   @Debounce(600)
   triggerResizeEvent() { // eslint-disable-line
     const event = document.createEvent('HTMLEvents');
@@ -197,7 +197,7 @@ export default class SiderMenu extends PureComponent {
       item =>
         key && (item.key === key || item.path === key),
     );
-  }
+  };
   handleOpenChange = (openKeys) => {
     const lastOpenKey = openKeys[openKeys.length - 1];
     const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1;

+ 9 - 4
src/index.less

@@ -60,7 +60,7 @@ body {
   .ant-tag {
     width: 137px;
     text-align: center;
-    margin-top: 5px;
+    margin-top: 8px !important;
     height: 25px;
     line-height: 25px;
   }
@@ -72,21 +72,26 @@ body {
 
 // 自定义全局样式
 :global(.editBtn) {
-  margin-right: 10px;
   background: @primary-color !important;
   color: #fff !important;
 }
 :global(.delBtn) {
+  margin-left: 10px;
   background: #f5222d !important;
   color: #fff !important;
 }
+:global(.recBtn) {
+  margin-left: 10px;
+  background: #13c2c2 !important;
+  color: #fff !important;
+}
 :global(.depositBtn) {
-  margin-right: 10px;
+  margin-left: 10px;
   background: #a0d911 !important;
   color: #fff !important;
 }
 :global(.playBtn) {
-  margin-right: 10px;
+  margin-left: 10px;
   background: #36cfc9 !important;
   color: #fff !important;
 }

+ 37 - 18
src/models/resource.js

@@ -2,10 +2,12 @@ import { routerRedux } from 'dva/router';
 import { message } from 'antd';
 import {
   createResource,
-  deleteResource,
   updateResource,
+  createAudioBook,
+  updateAudioBook,
   queryImageResource,
   queryVideoResource,
+  queryAudioBookResource,
 } from '../services/resource';
 
 export default {
@@ -47,6 +49,20 @@ export default {
         });
       }
     },
+    *fetchAudioBookList({ payload }, { call, put }) {
+      const response = yield call(queryAudioBookResource, payload);
+      if (response.success) {
+        yield put({
+          type: 'querySuccess',
+          payload: {
+            list: response.data.list || [],
+            pageSize: response.data.pageSize,
+            totalSize: response.data.totalSize,
+            pageNo: response.data.pageNo,
+          },
+        });
+      }
+    },
     *createImage({ payload }, { call, put }) {
       const response = yield call(createResource, payload);
       if (response && response.success) {
@@ -61,6 +77,7 @@ export default {
     *createVideo({ payload, states }, { call, put }) {
       const response = yield call(createResource, payload);
       if (response && response.success) {
+        message.success('创建视频成功');
         yield put(
           routerRedux.push({
             pathname: '/resource/video',
@@ -69,6 +86,18 @@ export default {
         );
       }
     },
+    *createAudioBook({ payload, states }, { call, put }) {
+      const response = yield call(createAudioBook, payload);
+      if (response && response.success) {
+        message.success('创建有声读物成功');
+        yield put(
+          routerRedux.push({
+            pathname: '/resource/audiobook',
+            state: states,
+          })
+        );
+      }
+    },
     *updateImage({ payload, states }, { call, put }) {
       const response = yield call(updateResource, payload);
       if (response && response.success) {
@@ -89,24 +118,14 @@ export default {
         }));
       }
     },
-    *deleteImage({ payload, states }, { call, put }) {
-      const response = yield call(deleteResource, payload);
+    *updateAudioBook({ payload, states }, { call, put }) {
+      const response = yield call(updateAudioBook, payload);
       if (response && response.success) {
-        message.success('删除图片成功');
-        yield put({
-          type: 'fetchImageList',
-          payload: states,
-        });
-      }
-    },
-    *deleteVideo({ payload, states }, { call, put }) {
-      const response = yield call(deleteResource, payload);
-      if (response && response.success) {
-        message.success('删除视频成功');
-        yield put({
-          type: 'fetchVideoList',
-          payload: states,
-        });
+        message.success('修改有声读物成功');
+        yield put(routerRedux.push({
+          pathname: '/resource/audiobook',
+          state: states,
+        }));
       }
     },
   },

+ 21 - 3
src/models/shelves.js

@@ -117,16 +117,26 @@ export default {
         }));
       }
     },
-    *deleteItem({ payload }, { call }) {
+    *deleteItem({ payload, states }, { call, put }) {
       const response = yield call(deleteItem, payload);
       if (response.success) {
         message.success('下架成功');
+        const { scene, Queryers } = states;
+        yield put({
+          type: `fetch${scene}ItemList`,
+          payload: Queryers,
+        });
       }
     },
-    *recoverItem({ payload }, { call }) {
+    *recoverItem({ payload, states }, { call, put }) {
       const response = yield call(recoverItem, payload);
       if (response.success) {
-        message.success('恢复上架成功');
+        const { scene, Queryers } = states;
+        message.success('上架成功');
+        yield put({
+          type: `fetch${scene}ItemList`,
+          payload: Queryers,
+        });
       }
     },
     *createItemPrice({ payload, states }, { call, put }) {
@@ -178,6 +188,14 @@ export default {
         ...action.payload,
       };
     },
+    cleanListState(state) {
+      return {
+        ...state,
+        list: [],
+        pageSize: 15,
+        pageNo: 1,
+      };
+    },
     cleanItemState(state) {
       return {
         ...state,

+ 2 - 2
src/models/terminal.js

@@ -139,11 +139,11 @@ export default {
       if (response.success) {
         message.success('账号已成功解绑');
         yield put({
-          type: 'fetchSpecialTerminalList',
+          type: 'fetchTerminalList',
           payload: states.Queryers,
         });
       }
-    }
+    },
   },
 
   reducers: {

+ 7 - 7
src/routes/Campus/CampusCreate.js

@@ -73,7 +73,7 @@ export default class CampusCreatePage extends PureComponent {
       return match[1];
     }
     return false;
-  }
+  };
   handleMerchantSelectorModalShow = () => {
     this.setState({
       merchantSelectorDestroy: false,
@@ -82,7 +82,7 @@ export default class CampusCreatePage extends PureComponent {
       type: 'merchant/fetchMerchantList',
       payload: {},
     });
-  }
+  };
   handleMerchantSelectorFinish = (rows) => {
     this.setState({
       merchantSelectorDestroy: true,
@@ -109,7 +109,7 @@ export default class CampusCreatePage extends PureComponent {
       type: 'merchant/fetchMerchantList',
       payload: params,
     });
-  }
+  };
   handlePageSubmit = () => {
     this.props.form.validateFieldsAndScroll((error, values) => {
       if (!error) {
@@ -143,13 +143,13 @@ export default class CampusCreatePage extends PureComponent {
         }
       }
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/campus/list',
       state: this.props.location.state,
     }));
-  }
+  };
 
   render() {
     const { merchantSelectorDestroy } = this.state;
@@ -161,7 +161,7 @@ export default class CampusCreatePage extends PureComponent {
     const renderCityName = () => {
       const { provinceCode, cityName } = currentItem;
       if (!provinceCode && !cityName) {
-
+        return null;
       } else {
         return [
           provinceCodeToName(provinceCode),
@@ -242,7 +242,7 @@ export default class CampusCreatePage extends PureComponent {
           <Form>
             <Form.Item
               {...formItemLayout}
-              label={!this.isEdit() ? <a onClick={this.handleMerchantSelectorModalShow}>所属厂商</a> : '所属厂商'}
+              label={!this.isEdit() ? <Button size="small" type="primary" onClick={this.handleMerchantSelectorModalShow}>所属厂商</Button> : '所属厂商'}
             >
               <List
                 bordered

+ 46 - 9
src/routes/Document/DocumentPlatform.js

@@ -8,7 +8,7 @@ const { Description } = DescriptionList;
 
 const resourceQAList = [{
   question: '图片的创建与编辑',
-  answer: '操作:"资源管理 > 图片管理 > 新建/编辑",正确填写图片的编号和名称后方可选择待上传图片;',
+  answer: '操作:"基础资源 > 图片管理 > 新建/编辑",正确填写图片的编号和名称后方可选择待上传图片;',
   note: '注意:图片编号应满足格式限制,不填写或者格式错误禁止上传图片',
   imgList: [
     'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/document/image/1/15279977811093052.png',
@@ -16,11 +16,19 @@ const resourceQAList = [{
   ],
 }, {
   question: '视频的创建与编辑',
-  answer: '操作:"资源管理 > 视频管理 > 新建/编辑",正确填写视频相关信息',
+  answer: '操作:"基础资源 > 视频管理 > 新建/编辑",正确填写视频相关信息',
   note: '注意:视频编号、名称、路径、类型、清晰度、格式为必填项',
   imgList: [
     'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/document/video/1/15280080455214642.png',
   ],
+}, {
+  question: '有声读物的创建与编辑',
+  answer: '操作:"基础资源 > 有声读物 > 新建/编辑",正确填写有声读物的相关信息',
+  note: '注意:有声读物编号、有声读物名称、音频路径、音频格式为必填项,上传图片有且仅支持一张图片的上传和选择',
+  imgList: [
+    'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/0000111/15290356776645389.png',
+    'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/haha/15290357830402821.png',
+  ],
 }];
 const productQAList = [{
   question: '课件的创建及编辑',
@@ -43,13 +51,37 @@ const shelvesQAList = [{
     'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/document/shelves/2/15280127974934585.png',
   ],
 }];
-const otherQAList = [{
-  question: '如何调整某入口下侧边栏目顺序',
-  answer: '操作:"前端配置 > 首页入口 > 编辑标签组",在编辑页面找到该入口下所有栏目表格,拖动或者点击进行排序',
+const frontConfig = [{
+  question: '首页入口',
+  answer: '操作:"前端配置 > 首页入口 > 新建/编辑",可以新建/编辑 标签组到对应的渠道',
+  note: '在编辑页面找到该入口下 标签列表 表格,拖动或者点击进行排序,即可对该标签组下的标签进行排序',
+  imgList: [
+    'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/notes1/15290475537003780.png',
+    'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/notes02/15290476539697182.png',
+  ],
+}, {
+  question: '栏目类型',
+  answer: '操作:"前端配置 > 栏目类型 > 新建/编辑",可以新建/编辑 标签类',
+  note: '在编辑页面找到该入口下 标签列表 表格,拖动或者点击进行排序,即可对该标签类下的标签进行排序',
+}, {
+  question: '侧边栏目',
+  answer: '操作:"前端配置 > 侧边栏目 > 新建/编辑",可以新建/编辑 标签',
+  note: '在编辑页面找到该入口下 标签列表 表格,拖动或者点击进行排序,即可对该标签下的相关产品进行排序',
+  imgList: [
+    'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/notes003/15290489273706567.png',
+    'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/notes004/15290489908065769.png',
+  ],
 }, {
-  question: '如何调整某栏目下的课程排序',
-  answer: '操作:"前端配置 > 栏目管理 > 编辑标签", 在编辑页面找到已关联的产品后拖动或者上移/下移进行课程排序',
-  note: '注意:此处点击关联产品可批量进行课程与栏目关联操作',
+  question: '推荐内容',
+  answer: '操作:"前端配置 > 推荐内容 > 课程/海报",可以对 推荐位置 课程/海报 进行修改和设置',
+  note: '从课程资源选取课程到推荐课程位置,从图片资源选取图片到 轮播图中的滚动海报位置',
+  imgList: [
+    'http://efunimgs.oss-cn-beijing.aliyuncs.com/resources/notes005/15290494850684261.png',
+  ],
+}];
+const otherQAList = [{
+  question: '欢迎联系开发组团队,我们将及时反馈您的问题 ╰( ̄▽ ̄)╭',
+  answer: '更多功能即将上线 d=====( ̄▽ ̄*)b',
 }];
 
 function FAQComponent({ sort, bigTitle, qaList }) {
@@ -102,11 +134,16 @@ export default class PlatformDocument extends PureComponent {
         />
         <FAQComponent
           sort={3}
-          bigTitle="产品上架"
+          bigTitle="产品出售"
           qaList={shelvesQAList}
         />
         <FAQComponent
           sort={4}
+          bigTitle="前端配置"
+          qaList={frontConfig}
+        />
+        <FAQComponent
+          sort={5}
           bigTitle="其他问题"
           qaList={otherQAList}
         />

+ 1 - 1
src/routes/Frontend/Recommend/RecommendCourse.js

@@ -119,7 +119,7 @@ export default class RecommendCourseEditPage extends Component {
     return (
       <div>
         <Card
-          title={<a onClick={this.handleSelectorModalShow}>选择课程</a>}
+          title={<Button type="primary" onClick={this.handleSelectorModalShow}>选择课程</Button>}
           style={{ marginBottom: 70 }}
         >
           <AXDragSortTable

+ 10 - 19
src/routes/Frontend/Recommend/RecommendPoster.js

@@ -11,16 +11,6 @@ import {
 import bitmap from '../../../assets/bitmap.png';
 import styles from './RecommendPoster.less';
 
-function dataSort(array) {
-  if (!array || !Array.isArray(array)) {
-    return array;
-  }
-  const sorted = array.sort((a, b) => {
-    return a.sort - b.sort;
-  });
-  return sorted;
-}
-
 @connect(({ loading, merchant, shelves, resource }) => ({
   shelves,
   merchant,
@@ -97,10 +87,10 @@ export default class RecommendPosterEditPage extends Component {
       type: 'merchant/deleteMerchantPosterItem',
       payload: { posterId },
     });
-  }
+  };
   /**
    * 5.编辑一条海报
-   * @param postId
+   * @param posterId
    */
   handlePosterItemEdit = (posterId) => {
     const newData = [...this.props.merchant.posterList];
@@ -117,6 +107,7 @@ export default class RecommendPosterEditPage extends Component {
   /**
    * 6.控制模态框的展现
    * @param {String} flag
+   * @param {String} posterId
    */
   handleSelectorModalShow = (flag, posterId) => {
     this.setState({
@@ -172,8 +163,8 @@ export default class RecommendPosterEditPage extends Component {
     const originalData = [...this.props.merchant.posterList];
     const newData = originalData.map((data) => {
       if (flag === 'product' && data.id === currentEditPosterId) {
-        const { id, name, code, type } = rows[0];
-        return { ...data, type, name, code, pid: id };
+        const { pid, name, code, type } = rows[0];
+        return { ...data, type, name, code, pid };
       }
       if (flag === 'resource' && data.id === currentEditPosterId) {
         const { path } = rows[0];
@@ -308,7 +299,7 @@ export default class RecommendPosterEditPage extends Component {
       key: 3,
       render: (_, record) => {
         // 将产品信息渲染成一个小表格
-        const { id, type, name, code, isEdit, isNew } = record;
+        const { id, code, name, type, product, isEdit, isNew } = record;
         const columns = [{
           dataIndex: 'label',
           width: '40%',
@@ -319,15 +310,15 @@ export default class RecommendPosterEditPage extends Component {
         const data = [{
           key: 'name',
           label: '产品名称',
-          value: name,
+          value: name || (product || {}).name,
         }, {
           key: 'code',
           label: '产品编号',
-          value: code,
+          value: code || (product || {}).code,
         }, {
           key: 'type',
           label: '产品类型',
-          value: renderProductType(type),
+          value: renderProductType(type || (product || {}).type),
         }];
         return (
           <div className={styles.product}>
@@ -491,7 +482,7 @@ export default class RecommendPosterEditPage extends Component {
           <Table
             pagination={false}
             loading={mLoading}
-            dataSource={dataSort(posterList)}
+            dataSource={posterList}
             columns={posterColumns}
             rowKey={record => record.id}
             className={styles.posterTable}

+ 8 - 6
src/routes/Frontend/Tag/TagCreate.js

@@ -267,7 +267,13 @@ export default class TagCreatePage extends Component {
       width: '10%',
       align: 'left',
       render: (text, record) => (
-        <a onClick={() => this.handleTagMetaSelectorModalShow(record.key)}>{text}</a>
+        <Button
+          size="small"
+          type="primary"
+          style={{ width: 90 }}
+          onClick={() => this.handleTagMetaSelectorModalShow(record.key)}
+        >{text}
+        </Button>
       ),
     }, {
       dataIndex: 'value',
@@ -398,11 +404,7 @@ export default class TagCreatePage extends Component {
     };
     const renderProductCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleShelvesSelectorModalShow}>关联产品</a>
-          </span>
-        </div>
+        <Button type="primary" onClick={this.handleShelvesSelectorModalShow}>关联产品</Button>
       );
     };
     return (

+ 20 - 21
src/routes/Frontend/TagGroup/TagGroupCreate.js

@@ -7,8 +7,6 @@ import { renderStatus, statusToBool, boolToStatus } from '../../../utils/utils';
 import AXDragSortTable from '../../../components/AXDragSortTable';
 import Selector from '../../../components/AXTableSelector/Selector';
 import FooterToolbar from '../../../components/FooterToolbar';
-import styles from './TagGroupCreate.less';
-
 
 const formItemLayout = {
   labelCol: {
@@ -55,13 +53,13 @@ export default class TagCreatePage extends Component {
       return match[1];
     }
     return false;
-  }
+  };
   cleanPageState=() => {
     this.props.dispatch({
       type: 'tagGroup/cleanItemState',
       payload: {},
     });
-  }
+  };
   selectorDataFetcher=(name, params) => {
     switch (name) {
       case 'Merchant':
@@ -79,21 +77,21 @@ export default class TagCreatePage extends Component {
       default:
         break;
     }
-  }
+  };
   handleMerchantSelectorModalShow = () => {
     this.setState({
       merchantSelectorDestroy: false,
     });
     this.selectorDataFetcher('Merchant');
-  }
+  };
   handleMerchantSelectorChange = (params) => {
     this.selectorDataFetcher('Merchant', params);
-  }
+  };
   handleMerchantSelectorCancel = () => {
     this.setState({
       merchantSelectorDestroy: true,
     });
-  }
+  };
   handleMerchantSelectorFinish = (rows) => {
     this.setState({
       merchantSelectorDestroy: true,
@@ -109,19 +107,19 @@ export default class TagCreatePage extends Component {
         merchantName: name,
       },
     });
-  }
+  };
   handleDragSortTableChange = (rows) => {
     this.props.dispatch({
       type: 'tagGroup/fixCurrentItem',
       payload: { tagList: rows },
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/frontend/tagGroup',
       state: this.props.location.state,
     }));
-  }
+  };
   handlePageSubmit = (e) => {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
@@ -159,7 +157,7 @@ export default class TagCreatePage extends Component {
         }
       }
     });
-  }
+  };
 
   render() {
     const { form, submitting, mLoading, merchant, tagGroup } = this.props;
@@ -220,11 +218,12 @@ export default class TagCreatePage extends Component {
     };
     const renderMerchantCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a disabled={!!this.isEdit()} onClick={this.handleMerchantSelectorModalShow}>所属渠道</a>
-          </span>
-        </div>
+        <Button
+          type="primary"
+          disabled={!!this.isEdit()}
+          onClick={this.handleMerchantSelectorModalShow}
+        >所属渠道
+        </Button>
       );
     };
     return (
@@ -238,7 +237,7 @@ export default class TagCreatePage extends Component {
                   {
                     required: true, message: '请填写标签组编号',
                   }, {
-                    pattern: /^[a-zA-Z0-9|_|-]+$/g, message: '编号包含非法字符',
+                    pattern: /^[a-zA-Z0-9_-]+$/g, message: '编号包含非法字符',
                   },
                 ],
                 initialValue: code,
@@ -279,15 +278,15 @@ export default class TagCreatePage extends Component {
           {!merchantSelectorDestroy && getMerchantModal()}
         </Card>
         {/* 标签排序Card */}
-        {this.isEdit() &&
-          <Card title="标签列表" style={{marginBottom: 70}}>
+        {this.isEdit() && (
+          <Card title="标签列表" style={{ marginBottom: 70 }}>
             <AXDragSortTable
               data={tagList}
               columns={tagColumns}
               onChange={this.handleDragSortTableChange}
             />
           </Card>
-        }
+        )}
         <FooterToolbar style={{ width: '100%' }}>
           <Button
             onClick={this.handlePageBack}

+ 12 - 12
src/routes/Merchant/MerchantList.js

@@ -34,7 +34,7 @@ export default class MerchantListPage extends Component {
       pathname: '/merchant/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
@@ -48,13 +48,13 @@ export default class MerchantListPage extends Component {
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/merchant/edit/${item.id}`,
       state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'merchant/fetchMerchantList',
@@ -64,16 +64,16 @@ export default class MerchantListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleDepositOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/merchant/deposit/${item.id}`,
       state: { ...this.state, currentItem: item },
     }));
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, merchant } = this.props;
@@ -85,6 +85,12 @@ export default class MerchantListPage extends Component {
           <Authorized authority="admin" noMatch={null}>
             <Button
               size="small"
+              className="editBtn"
+              onClick={() => this.handleEditOperation(item)}
+            >编辑
+            </Button>
+            <Button
+              size="small"
               className="depositBtn"
               onClick={() => this.handleDepositOperation(item)}
             >充值
@@ -92,12 +98,6 @@ export default class MerchantListPage extends Component {
           </Authorized>
           <Button
             size="small"
-            className="editBtn"
-            onClick={() => this.handleEditOperation(item)}
-          >编辑
-          </Button>
-          <Button
-            size="small"
             className="delBtn"
             onClick={() => this.handleDeleteOperation(item)}
           >删除

+ 11 - 12
src/routes/Product/Course/CourseCreate.js

@@ -407,23 +407,22 @@ export default class CourseItemCreatePage extends Component {
         </Modal>
       );
     };
-
     const renderLessonCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={() => this.handleSelectorModalShow('lesson')}>课列表</a>
-          </span>
-        </div>
+        <Button
+          type="primary"
+          onClick={() => this.handleSelectorModalShow('lesson')}
+        >课列表
+        </Button>
       );
     };
     const renderSupportCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={() => this.handleSelectorModalShow('support')}>配套列表</a>
-          </span>
-        </div>
+        <Button
+          type="primary"
+          onClick={() => this.handleSelectorModalShow('support')}
+        >配套列表
+        </Button>
       );
     };
     const renderCoverCardName = () => {
@@ -540,7 +539,7 @@ export default class CourseItemCreatePage extends Component {
           </Form>
         </Card>
         {/* 封面及背景图选择Card */}
-        <Card title="封面 | 背景" style={{ marginBottom: 16 }}>
+        <Card title="封面|背景" style={{ marginBottom: 16 }}>
           <Row gutter={16}>
             <Col
               md={{ span: 9, offset: 1 }}

+ 21 - 6
src/routes/Product/Courseware/CoursewareCreate.js

@@ -91,6 +91,12 @@ export default class CoursewareCreatePage extends Component {
         payload: params,
       });
     }
+    if (resourceType === 'AudioBook') {
+      this.props.dispatch({
+        type: 'resource/fetchAudioBookList',
+        payload: params,
+      });
+    }
   };
   handleSelectorModalShow = () => {
     this.setState({
@@ -197,6 +203,14 @@ export default class CoursewareCreatePage extends Component {
               <img src={genAbsolutePicUrl(text)} alt="" />
             </div>
           );
+        } else if (type === Hotax.RESOURCE_AUDIOBOOK) {
+          const { img } = record;
+          const { path } = img || {};
+          return (
+            <div className={styles.picture}>
+              <img src={genAbsolutePicUrl(path)} alt="" />
+            </div>
+          );
         } else {
           return (
             <div className={styles.video}>
@@ -244,11 +258,11 @@ export default class CoursewareCreatePage extends Component {
 
     const renderCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleSelectorModalShow}>资源列表</a>
-          </span>
-        </div>
+        <Button
+          type="primary"
+          onClick={this.handleSelectorModalShow}
+        >资源列表
+        </Button>
       );
     };
     const renderModalTitle = () => {
@@ -259,6 +273,7 @@ export default class CoursewareCreatePage extends Component {
         >
           <Radio.Button value="Picture">图片</Radio.Button>
           <Radio.Button value="Video">视频</Radio.Button>
+          <Radio.Button value="AudioBook">有声读物</Radio.Button>
         </Radio.Group>
       );
     };
@@ -345,7 +360,7 @@ export default class CoursewareCreatePage extends Component {
               onCancel={this.handleSelectorCancel}
             >
               <Selector
-                multiple={resourceType === 'Picture'}
+                multiple={resourceType === 'Picture' || resourceType === 'AudioBook'}
                 loading={loading}
                 selectorName={resourceType}
                 list={resource.list}

+ 0 - 14
src/routes/Product/Courseware/CoursewareCreate.less

@@ -1,19 +1,5 @@
 @import "../../../../node_modules/antd/lib/style/themes/default.less";
 
-.cardName {
-  & > span {
-    display: inline-block;
-    height: 24px;
-    padding: 0 7px;
-    vertical-align: bottom;
-  }
-  :global {
-    .ant-btn-primary {
-      margin-left: 10px;
-    }
-  }
-}
-
 .picture {
   position: relative;
   vertical-align: middle;

+ 7 - 8
src/routes/Product/Lesson/LessonCreate.js

@@ -3,11 +3,10 @@ import pathToRegexp from 'path-to-regexp';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Form, Modal, Card, Button, Input, Switch } from 'antd';
-import AXDragSortTable from '../../../components/AXDragSortTable/index';
+import AXDragSortTable from '../../../components/AXDragSortTable';
 import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar/index';
+import FooterToolbar from '../../../components/FooterToolbar';
 import { renderStatus, statusToBool, boolToStatus } from '../../../utils/utils';
-import styles from './LessonCreate.less';
 
 const fieldLabels = {
   code: '课编号',
@@ -199,11 +198,11 @@ export default class LessonCreatePage extends Component {
 
     const renderCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleSelectorModalShow}>课件列表</a>
-          </span>
-        </div>
+        <Button
+          type="primary"
+          onClick={this.handleSelectorModalShow}
+        >课件列表
+        </Button>
       );
     };
     return (

+ 0 - 15
src/routes/Product/Lesson/LessonCreate.less

@@ -1,15 +0,0 @@
-@import "../../../../node_modules/antd/lib/style/themes/default.less";
-
-.cardName {
-  & > span {
-    display: inline-block;
-    height: 24px;
-    padding: 0 7px;
-    vertical-align: bottom;
-  }
-  :global {
-    .ant-btn-primary {
-      margin-left: 10px;
-    }
-  }
-}

+ 1 - 5
src/routes/Product/Package/PackageCreate.js

@@ -298,11 +298,7 @@ export default class PackageCreatePage extends Component {
 
     const renderCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleSelectorModalShow}>课程配套</a>
-          </span>
-        </div>
+        <Button type="primary" onClick={this.handleSelectorModalShow}>课程配套</Button>
       );
     };
     const renderModalTitle = () => {

+ 6 - 6
src/routes/Product/Support/SupportCreate.js

@@ -327,11 +327,11 @@ export default class SupportCreatePage extends Component {
 
     const renderSupportCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={() => this.handleSelectorModalShow('support')}>相关配套</a>
-          </span>
-        </div>
+        <Button
+          type="primary"
+          onClick={() => this.handleSelectorModalShow('support')}
+        >相关配套
+        </Button>
       );
     };
     const renderCoverCardName = () => {
@@ -440,7 +440,7 @@ export default class SupportCreatePage extends Component {
           </Form>
         </Card>
         {/* 封面及走马灯选择Card */}
-        <Card title="封面 | 图册" style={{ marginBottom: 16 }}>
+        <Card title="封面|图册" style={{ marginBottom: 16 }}>
           <Row gutter={16}>
             <Col
               md={{ span: 10, offset: 1 }}

+ 188 - 0
src/routes/Resource/AudioBook/AudioBookCreate.js

@@ -0,0 +1,188 @@
+import React, { PureComponent } from 'react';
+import { Card, Form, Input, Button } from 'antd';
+import { connect } from 'dva';
+import { routerRedux } from 'dva/router';
+import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
+import Uploader from '../../../components/AXUpload';
+import { Hotax } from '../../../utils/config';
+
+const formItemLayout = {
+  labelCol: {
+    xs: { span: 24 },
+    sm: { span: 6 },
+  },
+  wrapperCol: {
+    xs: { span: 24 },
+    sm: { span: 14 },
+    md: { span: 12 },
+  },
+};
+const submitFormLayout = {
+  wrapperCol: {
+    xs: { span: 24, offset: 0 },
+    sm: { span: 12, offset: 6 },
+  },
+};
+
+function getFileObject(params) {
+  if (!params) { return; }
+  const { img } = params;
+  const { format, ...rest } = img || {};
+  return { ...rest, type: `image/${format}` };
+}
+
+@Form.create()
+@connect(({ loading }) => ({
+  submitting: loading.models.resource,
+}))
+export default class AudioBookCreatePage extends PureComponent {
+  constructor(props) {
+    super(props);
+    const { state } = props.location;
+    const { audioBookItem } = state || {};
+    this.state = {
+      fileList: audioBookItem ? [getFileObject(audioBookItem)] : [],
+      ...(audioBookItem || {}),
+    };
+  }
+  handleOnChangeEvent = (fileList) => {
+    this.setState({ fileList });
+    return fileList;
+  };
+  handlePageBack = () => {
+    const { UIParams, Queryers } = this.props.location.state || {};
+    this.props.dispatch(
+      routerRedux.push({
+        pathname: '/resource/audiobook',
+        state: {
+          UIParams,
+          Queryers,
+        },
+      })
+    );
+  };
+  handlePageSubmit = (e) => {
+    e.preventDefault();
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        const { id, img, audio } = this.state;
+        const { audioPath, audioFormat, fileList, ...params } = values;
+        // 1.提取图片信息
+        let newImg = {};
+        if (Array.isArray(this.state.fileList) && this.state.fileList.length) {
+          const { path, type, size, url } = this.state.fileList[0];
+          newImg = {
+            ...img,
+            url,
+            path,
+            size,
+            format: type ? type.split('/')[1] : '',
+            type: Hotax.RESOURCE_IMAGE,
+            status: (img || {}).status ? img.status : Hotax.STATUS_NORMAL,
+          };
+        }
+        // 2.提取音频信息
+        const newAudio = {
+          ...audio,
+          path: audioPath,
+          format: audioFormat,
+          type: Hotax.RESOURCE_AUDIO,
+          status: (audio || {}).status ? audio.status : Hotax.STATUS_NORMAL,
+        };
+        // 3.需提交的数据
+        const newParams = {
+          ...params,
+          img: newImg,
+          audio: newAudio,
+          status: Hotax.STATUS_NORMAL,
+        };
+        const { UIParams, Queryers } = this.props.location.state || {};
+        if (id) {
+          this.props.dispatch({
+            type: 'resource/updateAudioBook',
+            payload: { id, ...newParams },
+            states: { UIParams, Queryers },
+          });
+        } else {
+          this.props.dispatch({
+            type: 'resource/createAudioBook',
+            payload: newParams,
+            states: { UIParams, Queryers },
+          });
+        }
+      }
+    });
+  };
+  render() {
+    const { form, submitting } = this.props;
+    const { getFieldDecorator } = form;
+    const { fileList, code, name, audio } = this.state;
+
+    return (
+      <PageHeaderLayout>
+        <Card>
+          <Form onSubmit={this.handlePageSubmit}>
+            <Form.Item label="有声读物编号" hasFeedback {...formItemLayout}>
+              {getFieldDecorator('code', {
+                rules: [{
+                  required: true, message: '编号不能为空!',
+                }, {
+                  pattern: /^[a-zA-Z0-9|-]+$/ig, message: '编号格式错误!',
+                }],
+                initialValue: code,
+              })(
+                <Input />
+              )}
+            </Form.Item>
+            <Form.Item label="有声读物名称" hasFeedback {...formItemLayout}>
+              {getFieldDecorator('name', {
+                rules: [{ required: true, message: '名称不能为空!' }],
+                initialValue: name,
+              })(
+                <Input />
+              )}
+            </Form.Item>
+            <Form.Item label="上传配图" {...formItemLayout}>
+              {getFieldDecorator('fileList', {
+                getValueFromEvent: this.handleOnChangeEvent,
+              })(
+                <Uploader
+                  fileList={fileList}
+                  accept="image"
+                  multiple={false}
+                  totalLimit={1}
+                />
+              )}
+            </Form.Item>
+            <Form.Item label="音频路径" {...formItemLayout}>
+              {getFieldDecorator('audioPath', {
+                rules: [{ required: true, message: '音频路径不能为空!' }],
+                initialValue: (audio || {}).path,
+              })(
+                <Input />
+              )}
+            </Form.Item>
+            <Form.Item label="音频格式" {...formItemLayout}>
+              {getFieldDecorator('audioFormat', {
+                rules: [{ required: true, message: '音频格式不能为空!' }],
+                initialValue: (audio || {}).format || 'mp3',
+              })(
+                <Input disabled />
+              )}
+            </Form.Item>
+            <Form.Item {...submitFormLayout} style={{ marginTop: 32 }}>
+              <Button onClick={this.handlePageBack}>取消</Button>
+              <Button
+                type="primary"
+                htmlType="submit"
+                loading={submitting}
+                style={{ marginLeft: 8 }}
+              >提交
+              </Button>
+            </Form.Item>
+          </Form>
+        </Card>
+      </PageHeaderLayout>
+    );
+  }
+}

+ 212 - 0
src/routes/Resource/AudioBook/AudioBookList.js

@@ -0,0 +1,212 @@
+/* eslint-disable no-prototype-builtins,jsx-a11y/media-has-caption */
+import React, { Component } from 'react';
+import moment from 'moment';
+import { connect } from 'dva';
+import { routerRedux } from 'dva/router';
+import { Card, Button, message } from 'antd';
+import Ellipsis from '../../../components/Ellipsis';
+import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
+import { StandardTableList } from '../../../components/AXList';
+import { addRowKey, genAbsolutePicUrl } from '../../../utils/utils';
+import styles from './AudioBookList.less';
+
+const Message = message;
+
+function deleteBlankKey(obj) {
+  if (!(typeof obj === 'object')) {
+    return;
+  }
+  const newObj = { ...obj };
+  for (const key in newObj) {
+    if (newObj.hasOwnProperty(key) && !newObj[key]) {
+      delete newObj[key];
+    }
+  }
+  return newObj;
+}
+function genAudioBook(obj = {}) {
+  const { id, code, name, img, audio, status } = obj;
+  return {
+    id,
+    code,
+    name,
+    status,
+    img: img || {},
+    audio: audio || {},
+  };
+}
+
+@connect(({ loading, resource }) => ({
+  resource,
+  loading: loading.models.resource,
+}))
+export default class AudioBookListPage extends Component {
+  constructor(props) {
+    super(props);
+    const { state } = props.location;
+    this.state = {
+      UIParams: (state || {}).UIParams, // 组件的状态参数
+      Queryers: (state || {}).Queryers, // 查询的条件参数
+    };
+  }
+  componentWillMount() {
+    this.props.dispatch({
+      type: 'resource/clearState',
+    });
+  }
+  componentDidMount() {
+    this.props.dispatch({
+      type: 'resource/fetchAudioBookList',
+      payload: { ...this.state.Queryers },
+    });
+  }
+  // 创建有声读物(增)
+  handleCreateOperation = () => {
+    const { UIParams, Queryers } = this.state;
+    this.props.dispatch(
+      routerRedux.push({
+        pathname: '/resource/audiobook-create',
+        state: { UIParams, Queryers },
+      })
+    );
+  };
+  // 修改有声读物(改)
+  handleUpdateOperation = (item) => {
+    const { UIParams, Queryers } = this.state;
+    this.props.dispatch(
+      routerRedux.push({
+        pathname: `/resource/audiobook-edit/${item.id}`,
+        state: { UIParams, Queryers, audioBookItem: genAudioBook(item) },
+      })
+    );
+  };
+  // 查询有声读物(查)
+  handleFilterOperation = (params, states) => {
+    const newParams = deleteBlankKey(params);
+    this.props.dispatch({
+      type: 'resource/fetchAudioBookList',
+      payload: newParams,
+    });
+    this.setState({
+      UIParams: states,
+      Queryers: newParams,
+    });
+  };
+  // TODO: 批量操作
+  handleBatchOperation = () => {
+    Message.info('暂不支持批量操作!');
+  };
+
+  render() {
+    const { loading, resource } = this.props;
+    const { list, totalSize, pageSize, pageNo } = resource;
+    const pagination = {
+      pageNo,
+      pageSize,
+      totalSize,
+    };
+    const batchActions = [{
+      key: 'delete',
+      name: '批量删除',
+    }, {
+      key: 'edit',
+      name: '批量编辑',
+    }];
+    const basicSearch = {
+      keys: [{
+        name: '有声读物名称',
+        field: 'name',
+      }, {
+        name: '有声读物编号',
+        field: 'code',
+      }],
+    };
+    const columns = [{
+      title: '有声读物编号',
+      key: 1,
+      dataIndex: 'code',
+      width: '18%',
+      render: text => (
+        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
+      ),
+    }, {
+      title: '有声读物名称',
+      key: 2,
+      dataIndex: 'name',
+      width: '20%',
+      render: text => (
+        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
+      ),
+    }, {
+      title: '有声读物配图',
+      key: 3,
+      dataIndex: 'img',
+      width: '20%',
+      render: (text) => {
+        const { path } = text || {};
+        return (
+          <div className={styles.picWrapper}>
+            <img src={genAbsolutePicUrl(path)} alt="thumb" />
+          </div>
+        );
+      },
+    }, {
+      title: '有声读物音频',
+      key: 4,
+      dataIndex: 'audio',
+      width: '20%',
+      render: (text) => {
+        const { url } = text || {};
+        return (
+          <div className={styles.audioWrapper}>
+            <audio controls src={url}>浏览器暂不支持播放</audio>
+          </div>
+        );
+      },
+    }, {
+      title: '修改时间',
+      key: 5,
+      dataIndex: 'gmtModified',
+      render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
+      width: '17%',
+    }, {
+      title: '操作',
+      key: 6,
+      dataIndex: 'operation',
+      render: (_, record) => (
+        <Button
+          size="small"
+          type="primary"
+          className="editBtn"
+          onClick={() => this.handleUpdateOperation(record)}
+        >编辑
+        </Button>
+      ),
+      width: '5%',
+      align: 'right',
+    }];
+    return (
+      <PageHeaderLayout>
+        <Card bordered={false}>
+          <StandardTableList
+            columns={columns}
+            loading={loading}
+            dataSource={addRowKey(list)}
+            header={{
+              basicSearch,
+              onFilterClick: this.handleFilterOperation,
+              onCreateClick: this.handleCreateOperation,
+            }}
+            footer={{
+              pagination,
+              batchActions,
+              onBatchClick: this.handleBatchOperation,
+            }}
+            keepUIState={{ ...this.state.UIParams }}
+            showStatusSelect={false}
+          />
+        </Card>
+      </PageHeaderLayout>
+    );
+  }
+}

+ 25 - 0
src/routes/Resource/AudioBook/AudioBookList.less

@@ -0,0 +1,25 @@
+@import "../../../../node_modules/antd/lib/style/themes/default.less";
+
+.picWrapper {
+  position: relative;
+  vertical-align: middle;
+  text-align: center;
+  width: 90px;
+  height: 128px;
+  line-height: 128px;
+  img {
+    max-height: 100%;
+    max-width: 100%;
+    vertical-align: middle;
+    height: auto;
+  }
+}
+
+.audioWrapper {
+  width: 180px;
+  height: 35px;
+  audio {
+    width: 100%;
+    height: 100%;
+  }
+}

+ 1 - 2
src/routes/Resource/Picture/PictureCardList.js

@@ -4,7 +4,7 @@ import { StandardCardList } from '../../../components/AXList';
 
 function PictureCardList({
   UIParams, dataSource, loading, totalSize, pageSize, pageNo,
-  onFilterClick, onCreateClick, onBatchClick, onDeleteClick, onEditClick,
+  onFilterClick, onCreateClick, onBatchClick, onEditClick,
 }) {
   const batchActions = [{
     key: 'delete',
@@ -36,7 +36,6 @@ function PictureCardList({
       header={{ basicSearch, onFilterClick, onCreateClick }}
       footer={{ pagination, batchActions, onBatchClick }}
       grid={{ gutter: 16, xxl: 12, xl: 6, lg: 4, md: 3, sm: 2, xs: 1 }}
-      onDelete={onDeleteClick}
       onEdit={onEditClick}
     />
   );

+ 6 - 17
src/routes/Resource/Picture/PictureEdit.js

@@ -1,10 +1,10 @@
 import React, { PureComponent } from 'react';
-import { Card, Form, Input, Button, Switch } from 'antd';
+import { Card, Form, Input, Button } from 'antd';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import Uploader from '../../../components/AXUpload';
+import { Hotax } from '../../../utils/config';
 import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
-import { boolToStatus, statusToBool } from '../../../utils/utils';
 
 const formItemLayout = {
   labelCol: {
@@ -53,11 +53,11 @@ export default class PictureSingleUpload extends PureComponent {
     return fileList;
   };
   handlePageBack = () => {
-    const { UIParams, Queryers } = this.props.location.state || {};
+    const { UIParams, Queryers, isCard } = this.props.location.state || {};
     this.props.dispatch(
       routerRedux.push({
         pathname: '/resource/picture',
-        state: { UIParams, Queryers },
+        state: { UIParams, Queryers, isCard },
       })
     );
   };
@@ -66,13 +66,13 @@ export default class PictureSingleUpload extends PureComponent {
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
         const { id, type, UIParams, Queryers } = this.props.location.state || {};
-        const { fileList, status, ...params } = values;
+        const { fileList, ...params } = values;
         if (Array.isArray(fileList) && fileList.length) {
           params.url = fileList[0].url;
         }
         params.id = id;
         params.type = type;
-        params.status = boolToStatus(status);
+        params.status = Hotax.STATUS_NORMAL;
         this.props.dispatch({
           type: 'resource/updateImage',
           payload: params,
@@ -145,17 +145,6 @@ export default class PictureSingleUpload extends PureComponent {
                 <Input disabled />
               )}
             </Form.Item>
-            <Form.Item label="图片状态" {...formItemLayout}>
-              {getFieldDecorator('status', {
-                valuePropName: 'checked',
-                initialValue: statusToBool(status),
-              })(
-                <Switch
-                  checkedChildren="启用"
-                  unCheckedChildren="不启用"
-                />
-              )}
-            </Form.Item>
             <Form.Item {...submitFormLayout} style={{ marginTop: 32 }}>
               <Button onClick={this.handlePageBack}>取消</Button>
               <Button

+ 2 - 17
src/routes/Resource/Picture/PictureList.js

@@ -1,7 +1,7 @@
 import React, { Component } from 'react';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
-import { Card, Modal, Button, message } from 'antd';
+import { Card, Button, message } from 'antd';
 import PictureCardList from './PictureCardList';
 import PictureTableList from './PictureTableList';
 import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
@@ -19,7 +19,7 @@ export default class PictureListPage extends Component {
     this.state = {
       UIParams: (state || {}).UIParams, // 组件的状态参数
       Queryers: (state || {}).Queryers, // 查询的条件参数
-      isCard: false,
+      isCard: (state || {}).isCard || false,
     };
   }
   componentWillMount() {
@@ -45,20 +45,6 @@ export default class PictureListPage extends Component {
       })
     );
   };
-  // 删除图片(删)
-  handleDeleteOperation = (item) => {
-    Modal.confirm({
-      okText: '确定',
-      cancelText: '取消',
-      title: '您确定要删除这张图片吗?',
-      onOk: () => {
-        this.props.dispatch({
-          type: 'resource/deleteImage',
-          payload: { id: item.id },
-        });
-      },
-    });
-  };
   // 修改图片(改)
   handleEditOperation = (data) => {
     this.props.dispatch(
@@ -99,7 +85,6 @@ export default class PictureListPage extends Component {
       UIParams,
       dataSource: list,
       onCreateClick: this.handleCreateOperation,
-      onDeleteClick: this.handleDeleteOperation,
       onEditClick: this.handleEditOperation,
       onFilterClick: this.handleFilterOperation,
       onBatchClick: this.handleBatchOperation,

+ 5 - 16
src/routes/Resource/Picture/PictureSingleUpload.js

@@ -1,9 +1,8 @@
 import React, { PureComponent, Fragment } from 'react';
-import { Form, Input, Button, Switch, Alert } from 'antd';
+import { Form, Input, Button, Alert } from 'antd';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import Uploader from '../../../components/AXUpload';
-import { boolToStatus } from '../../../utils/utils';
 import { Hotax } from '../../../utils/config';
 
 const formItemLayout = {
@@ -45,11 +44,12 @@ export default class PictureSingleUpload extends PureComponent {
     return fileList;
   };
   handlePageBack = () => {
-    const { UIParams, Queryers } = this.props.location.state || {};
+    const { UIParams, Queryers, isCard } = this.props.location.state || {};
     this.props.dispatch(
       routerRedux.push({
         pathname: '/resource/picture',
         state: {
+          isCard,
           UIParams,
           Queryers,
         },
@@ -60,12 +60,12 @@ export default class PictureSingleUpload extends PureComponent {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
-        const { fileList, status, ...params } = values;
+        const { fileList, ...params } = values;
         if (Array.isArray(fileList) && fileList.length) {
           params.url = fileList[0].url;
         }
-        params.status = boolToStatus(status);
         params.type = Hotax.RESOURCE_IMAGE;
+        params.status = Hotax.STATUS_NORMAL;
         this.props.dispatch({
           type: 'resource/createImage',
           payload: params,
@@ -150,17 +150,6 @@ export default class PictureSingleUpload extends PureComponent {
             <Input disabled />
           )}
         </Form.Item>
-        <Form.Item label="图片状态" {...formItemLayout}>
-          {getFieldDecorator('status', {
-            valuePropName: 'checked',
-            initialValue: true,
-          })(
-            <Switch
-              checkedChildren="启用"
-              unCheckedChildren="不启用"
-            />
-          )}
-        </Form.Item>
         <Form.Item {...submitFormLayout} style={{ marginTop: 32 }}>
           <Button onClick={this.handlePageBack}>取消</Button>
           <Button

+ 11 - 22
src/routes/Resource/Picture/PictureTableList.js

@@ -1,13 +1,13 @@
 import React from 'react';
 import moment from 'moment';
 import { Button } from 'antd';
-import { renderStatus, addRowKey, genAbsolutePicUrl } from '../../../utils/utils';
+import { addRowKey, genAbsolutePicUrl } from '../../../utils/utils';
 import { StandardTableList } from '../../../components/AXList';
 import styles from './PictureTableList.less';
 
 function PictureTableList({
   UIParams, dataSource, loading, totalSize, pageSize, pageNo,
-  onFilterClick, onCreateClick, onBatchClick, onDeleteClick, onEditClick,
+  onFilterClick, onCreateClick, onBatchClick, onEditClick,
 }) {
   const batchActions = [{
     key: 'delete',
@@ -55,12 +55,6 @@ function PictureTableList({
           onClick={() => onEditClick(item)}
         >编辑
         </Button>
-        <Button
-          size="small"
-          className="delBtn"
-          onClick={() => onDeleteClick(item)}
-        >删除
-        </Button>
       </div>
     );
   };
@@ -69,41 +63,35 @@ function PictureTableList({
     key: 1,
     dataIndex: 'path',
     render: text => renderThumbPic(genAbsolutePicUrl(text)),
-    width: '15%',
+    width: '20%',
   }, {
     title: '名称/编号',
     key: 2,
     dataIndex: 'meta',
     render: (_, record) => renderMetaData(record),
-    width: '27%',
+    width: '25%',
   }, {
     title: '格式',
     key: 3,
     dataIndex: 'format',
-    width: '10%',
+    width: '13%',
   }, {
     title: '大小(Byte)',
     key: 4,
     dataIndex: 'size',
-    width: '10%',
-  }, {
-    title: '状态',
-    key: 5,
-    dataIndex: 'status',
-    render: text => renderStatus(text),
-    width: '8%',
+    width: '12%',
   }, {
     title: '更新日期',
-    key: 6,
+    key: 5,
     dataIndex: 'gmtModified',
     render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
-    width: '17%',
+    width: '20%',
   }, {
     title: '操作',
-    key: 7,
+    key: 6,
     dataIndex: 'action',
     render: (_, record) => renderActions(record),
-    width: '13%',
+    width: '10%',
     align: 'right',
   }];
 
@@ -115,6 +103,7 @@ function PictureTableList({
       keepUIState={{ ...UIParams }}
       header={{ basicSearch, onFilterClick, onCreateClick }}
       footer={{ pagination, batchActions, onBatchClick }}
+      showStatusSelect={false}
     />
   );
 }

+ 8 - 22
src/routes/Resource/Video/VideoCreate.js

@@ -1,12 +1,10 @@
 import React, { PureComponent } from 'react';
 import pathToRegexp from 'path-to-regexp';
-import { Card, Form, Radio, Input, Button, Switch } from 'antd';
+import { Card, Form, Radio, Input, Button } from 'antd';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
-import {
-  resourceTypes, resourceQuality, boolToStatus, statusToBool,
-} from '../../../utils/utils';
+import { resourceTypes, resourceQuality } from '../../../utils/utils';
 import { Hotax } from '../../../utils/config';
 
 const formItemLayout = {
@@ -54,19 +52,18 @@ export default class VideoCreatePage extends PureComponent {
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
         const { UIParams, Queryers } = this.props.location.state || {};
-        const { status, ...params } = values;
         const matchId = this.isEdit();
         if (matchId) {
           this.props.dispatch({
             type: 'resource/updateVideo',
-            payload: { id: matchId, status: boolToStatus(status), ...params },
+            payload: { id: matchId, status: Hotax.STATUS_NORMAL, ...values },
             states: { UIParams, Queryers },
           });
           return;
         }
         this.props.dispatch({
           type: 'resource/createVideo',
-          payload: { status: boolToStatus(status), ...params },
+          payload: { status: Hotax.STATUS_NORMAL, ...values },
           states: { UIParams, Queryers },
         });
       }
@@ -76,7 +73,7 @@ export default class VideoCreatePage extends PureComponent {
     const { form, submitting, location } = this.props;
     const { getFieldDecorator } = form;
     const { state = {} } = location;
-    const { code, name, size, type, path, rate, quality, status, format } = state;
+    const { code, name, size, type, path, rate, quality, format } = state;
 
     return (
       <PageHeaderLayout>
@@ -117,7 +114,7 @@ export default class VideoCreatePage extends PureComponent {
                 rules: [{ required: true, message: '资源类型不能为空' }],
                 initialValue: type || Hotax.RESOURCE_VIDEO,
               })(
-                <Radio.Group>
+                <Radio.Group disabled>
                   {
                     Object.keys(resourceTypes).map(key =>
                       (
@@ -137,7 +134,7 @@ export default class VideoCreatePage extends PureComponent {
                 rules: [{ required: true, message: '清晰度为必选项' }],
                 initialValue: quality || Hotax.QUALITY_HIGH,
               })(
-                <Radio.Group>
+                <Radio.Group disabled>
                   {
                     Object.keys(resourceQuality).map(key =>
                       (
@@ -157,7 +154,7 @@ export default class VideoCreatePage extends PureComponent {
                 rules: [{ required: true, message: '视频格式不能为空' }],
                 initialValue: format || 'm3u8',
               })(
-                <Input placeholder="请填写" />
+                <Input disabled placeholder="请填写" />
               )}
             </Form.Item>
             <Form.Item label="视频码流" {...formItemLayout}>
@@ -174,17 +171,6 @@ export default class VideoCreatePage extends PureComponent {
                 <Input placeholder="请填写" addonAfter="字节" />
               )}
             </Form.Item>
-            <Form.Item label="视频状态" {...formItemLayout}>
-              {getFieldDecorator('status', {
-                valuePropName: 'checked',
-                initialValue: statusToBool(status),
-              })(
-                <Switch
-                  checkedChildren="正常"
-                  unCheckedChildren="删除"
-                />
-              )}
-            </Form.Item>
             <Form.Item {...submitFormLayout} style={{ marginTop: 32 }}>
               <Button onClick={this.handlePageBack}>取消</Button>
               <Button

+ 14 - 25
src/routes/Resource/Video/VideoTableList.js

@@ -4,11 +4,11 @@ import { Modal, Button } from 'antd';
 import { StandardTableList } from '../../../components/AXList';
 import AXVideoPlayer from '../../../components/AXVideoPlayer';
 import Ellipsis from '../../../components/Ellipsis';
-import { renderStatus, renderVideoQuality } from '../../../utils/utils';
+import { resourceQuality } from '../../../utils/utils';
 
 function VideoTableList({
   UIParams, dataSource, loading, totalSize, pageSize, pageNo, modalDestroy, currentItem,
-  onCreateClick, onDeleteClick, onUpdateClick, onFilterClick, onBatchClick, onModalCreate,
+  onCreateClick, onUpdateClick, onFilterClick, onBatchClick, onModalCreate,
   onModalDestroy,
 }) {
   const pagination = {
@@ -44,7 +44,7 @@ function VideoTableList({
     title: '视频名称',
     key: 2,
     dataIndex: 'name',
-    width: '23%',
+    width: '30%',
     render: text => (
       <Ellipsis tooltip lines={1}>{text}</Ellipsis>
     ),
@@ -57,26 +57,20 @@ function VideoTableList({
     title: '质量',
     key: 4,
     dataIndex: 'quality',
-    render: text => renderVideoQuality(text),
-    width: '8%',
-  }, {
-    title: '状态',
-    key: 5,
-    dataIndex: 'status',
-    render: text => renderStatus(text),
-    width: '8%',
+    render: text => resourceQuality[text],
+    width: '10%',
   }, {
     title: '修改时间',
-    key: 6,
+    key: 5,
     dataIndex: 'gmtModified',
     render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
-    width: '17%',
+    width: '15%',
   }, {
     title: '操作',
-    key: 8,
+    key: 6,
     dataIndex: 'operation',
     render: (_, record) => renderActions(record),
-    width: '19%',
+    width: '20%',
     align: 'right',
   }];
   const renderActions = (item) => {
@@ -85,22 +79,16 @@ function VideoTableList({
         <Button
           size="small"
           type="primary"
-          className="playBtn"
-          onClick={() => onModalCreate(item)}
-        >播放
-        </Button>
-        <Button
-          size="small"
-          type="primary"
           className="editBtn"
           onClick={() => onUpdateClick(item)}
         >编辑
         </Button>
         <Button
           size="small"
-          className="delBtn"
-          onClick={() => onDeleteClick(item)}
-        >删除
+          type="primary"
+          className="playBtn"
+          onClick={() => onModalCreate(item)}
+        >播放
         </Button>
       </div>
     );
@@ -114,6 +102,7 @@ function VideoTableList({
         keepUIState={{ ...UIParams }}
         header={{ basicSearch, onFilterClick, onCreateClick }}
         footer={{ pagination, batchActions, onBatchClick }}
+        showStatusSelect={false}
       />
       {!modalDestroy && (
         <Modal

+ 2 - 10
src/routes/Shelves/ShelvesCreate.js

@@ -242,20 +242,12 @@ export default class ShelvesCreatePage extends Component {
     // render card title
     const renderProductCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleProductSelectorModalShow}>{`选择${productNameMap[scene]}`}</a>
-          </span>
-        </div>
+        <Button type="primary" onClick={this.handleProductSelectorModalShow}>{`选择${productNameMap[scene]}`}</Button>
       );
     };
     const renderMerchantCardName = () => {
       return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleMerchantSelectorModalShow}>选择渠道</a>
-          </span>
-        </div>
+        <Button type="primary" onClick={this.handleMerchantSelectorModalShow}>选择渠道</Button>
       );
     };
 

+ 7 - 3
src/routes/Shelves/ShelvesEdit.js

@@ -23,18 +23,22 @@ export default class ShelvesEdit extends Component {
     super(props);
     const { location } = props;
     const { state } = location;
-    const { merchantId, pid, productType } = state;
+    const { merchantId, pid } = state;
     const match = pathToRegexp('/shelves/:type/edit').exec(location.pathname);
     const type = match[1];
     this.state = {
       pid,
       merchantId,
-      productType,
       scene: type,
       tagSelectorDestroy: true,
       resourceSelectorDestroy: true,
     };
   }
+  componentWillMount() {
+    this.props.dispatch({
+      type: 'shelves/cleanItemState',
+    });
+  }
   componentDidMount() {
     const { merchantId, pid } = this.state;
     this.props.dispatch({
@@ -182,7 +186,7 @@ export default class ShelvesEdit extends Component {
       <div>
         <Card title="价格管理" style={{ marginBottom: 16 }}>
           {getFieldDecorator('goods', {
-            initialValue: addRowKey(goods),
+            initialValue: (!goods || !goods.length) ? null : addRowKey(goods),
           })(
             <TableForm
               loading={submitting}

+ 45 - 6
src/routes/Shelves/ShelvesList.js

@@ -6,6 +6,7 @@ import { routerRedux } from 'dva/router';
 import { Card, Modal, Button, message } from 'antd';
 import { StandardTableList } from '../../components/AXList';
 import Ellipsis from '../../components/Ellipsis';
+import { Hotax } from '../../utils/config';
 import { renderStatus, addRowKey } from '../../utils/utils';
 
 const Message = message;
@@ -33,6 +34,11 @@ export default class ShelvesListPage extends Component {
       Queryers: (state || {}).Queryers, // 查询的条件参数
     };
   }
+  componentWillMount() {
+    this.props.dispatch({
+      type: 'shelves/cleanListState',
+    });
+  }
   componentDidMount() {
     const { scene } = this.state;
     this.props.dispatch({
@@ -70,6 +76,28 @@ export default class ShelvesListPage extends Component {
     });
   };
   /**
+   * 恢复某渠道的一个产品
+   * @param item
+   */
+  handleRecoverOperation = (item) => {
+    Modal.confirm({
+      okText: '确定',
+      cancelText: '取消',
+      title: '你确定要上架该产品吗?',
+      onOk: () => {
+        this.props.dispatch({
+          type: 'shelves/recoverItem',
+          payload: {
+            pid: item.pid,
+            merchantId: item.merchantId,
+            status: Hotax.STATUS_NORMAL,
+          },
+          states: this.state,
+        });
+      },
+    });
+  };
+  /**
    * 跳转到编辑界面
    * @param {Object} item
    */
@@ -121,12 +149,23 @@ export default class ShelvesListPage extends Component {
             onClick={() => this.handleEditOperation(item)}
           >编辑
           </Button>
-          <Button
-            size="small"
-            className="delBtn"
-            onClick={() => this.handleDeleteOperation(item)}
-          >下架
-          </Button>
+          {item.status === Hotax.STATUS_NORMAL ?
+            (
+              <Button
+                size="small"
+                className="delBtn"
+                onClick={() => this.handleDeleteOperation(item)}
+              >下架
+              </Button>
+            ) : (
+              <Button
+                size="small"
+                className="recBtn"
+                onClick={() => this.handleRecoverOperation(item)}
+              >上架
+              </Button>
+            )
+          }
         </div>
       );
     };

+ 5 - 4
src/routes/Shelves/TableForm.js

@@ -19,13 +19,13 @@ export default class TableForm extends PureComponent {
     super(props);
 
     this.state = {
-      data: props.value,
+      data: null,
       loading: props.loading,
       currentKey: null,
     };
   }
   componentWillReceiveProps(nextProps) {
-    if ('value' in nextProps && (!this.props.value || !this.props.value.length) ) {
+    if ('value' in nextProps && !this.state.data) {
       this.setState({
         data: nextProps.value,
       });
@@ -62,7 +62,7 @@ export default class TableForm extends PureComponent {
     }
   }
   newPrice = () => {
-    const newData = this.state.data.map(item => ({ ...item }));
+    const newData = this.state.data ? this.state.data.map(item => ({ ...item })) : [];
     newData.push({
       key: `NEW_TEMP_ID_${this.index}`,
       cpPrice: '',
@@ -112,7 +112,8 @@ export default class TableForm extends PureComponent {
       return;
     }
     const target = this.getRowByKey(key) || {};
-    if (!target.chargeUnit || !target.cpPrice || !target.merchantPrice || !target.terminalPrice) {
+    if (!target.chargeUnit || (typeof target.cpPrice !== 'number')
+      || (typeof target.merchantPrice !== 'number') || (typeof target.terminalPrice !== 'number')) {
       message.error('请填写完整价格信息');
       e.target.focus();
       return;

+ 1 - 1
src/routes/System/CmsUser/CmsUserCreate.js

@@ -209,7 +209,7 @@ export default class CmsUserCreatePage extends PureComponent {
           <Form>
             <Form.Item
               {...formItemLayout}
-              label={<a onClick={this.handleMerchantSelectorModalShow}>选择厂商</a>}
+              label={<Button size="small" type="primary" onClick={this.handleMerchantSelectorModalShow}>选择厂商</Button>}
             >
               <List
                 bordered

+ 1 - 1
src/routes/Terminal/User/TerminalCreate.js

@@ -154,7 +154,7 @@ export default class TerminalCreatePage extends PureComponent {
           <Form>
             <Form.Item
               {...formItemLayout}
-              label={<a onClick={this.handleCampusSelectorModalShow}>选择校区</a>}
+              label={<Button size="small" type="primary" onClick={this.handleCampusSelectorModalShow}>选择校区</Button>}
             >
               <List
                 bordered

+ 1 - 1
src/routes/Terminal/User/TerminalList.js

@@ -206,7 +206,7 @@ export default class TerminalListPage extends Component {
             ) : (
               <Button
                 size="small"
-                className="delBtn"
+                className="recBtn"
                 onClick={() => this.handleRecoverOperation(item)}
               >解禁
               </Button>

+ 2 - 2
src/routes/Trade/Order/OrderCreate.js

@@ -276,7 +276,7 @@ export default class OrderCreatePage extends Component {
           <Form>
             <Form.Item
               {...formItemLayout}
-              label={<a onClick={this.handleTerminalSelectorModalShow}>选择终端</a>}
+              label={<Button size="small" type="primary" onClick={this.handleTerminalSelectorModalShow}>选择终端</Button>}
             >
               <List
                 bordered
@@ -581,7 +581,7 @@ export default class OrderCreatePage extends Component {
       }];
       return (
         <Card
-          title={<a onClick={this.handleGoodsSelectorModalShow}>选择商品</a>}
+          title={<Button type="primary" onClick={this.handleGoodsSelectorModalShow}>选择商品</Button>}
           style={{ marginTop: 10, marginBottom: 70 }}
         >
           <Table

+ 23 - 5
src/services/resource.js

@@ -21,6 +21,15 @@ export async function queryVideoResource(params) {
   return request(`${api.resource}?${stringify(newParams)}`);
 }
 
+export async function queryAudioBookResource(params) {
+  const newParams = {
+    pageSize: Hotax.PAGE_SIZE,
+    ...params,
+    type: Hotax.RESOURCE_AUDIOBOOK,
+  };
+  return request(`${api.resource}?${stringify(newParams)}`);
+}
+
 export async function queryOssSignature(params) {
   const signature = getSignature();
   const expireTime = Math.floor(((new Date()).getTime() / 1000) + 5).toString();
@@ -41,17 +50,26 @@ export async function createResource(params) {
   return request(`${api.resourceItem}`, options);
 }
 
-export async function deleteResource(params) {
+export async function updateResource(params) {
   const options = {
-    method: 'DELETE',
+    method: 'PUT',
+    body: params,
   };
-  return request(`${api.resourceItem}/${params.id}`, options);
+  return request(`${api.resourceItem}`, options);
 }
 
-export async function updateResource(params) {
+export async function createAudioBook(params) {
+  const options = {
+    method: 'POST',
+    body: params,
+  };
+  return request(`${api.audiobookItem}`, options);
+}
+
+export async function updateAudioBook(params) {
   const options = {
     method: 'PUT',
     body: params,
   };
-  return request(`${api.resourceItem}`, options);
+  return request(`${api.audiobookItem}`, options);
 }

+ 1 - 1
src/theme.js

@@ -3,5 +3,5 @@ module.exports = {
   'primary-color': '#09c',
   'border-radius-base': '0',
   'font-family': '"Helvetica Neue", Helvetica, Arial, sans-serif',
-  'table-header-bg': '#dadada',
+  'table-header-bg': '#f5f6fa',
 };

+ 7 - 7
src/utils/config.js

@@ -7,6 +7,7 @@ Hotax.RESOURCE_VIDEO = 0;
 Hotax.RESOURCE_AUDIO = 1;
 Hotax.RESOURCE_LIVE = 2;
 Hotax.RESOURCE_IMAGE = 3;
+Hotax.RESOURCE_AUDIOBOOK = 4;
 
 // 清晰度类型 <流畅|标清|高清|超清>
 Hotax.QUALITY_FLUENT = 'fluent';
@@ -70,15 +71,13 @@ Hotax.PAGE_SIZE = 20;
 // 上传文件最大尺寸
 Hotax.FILE_MAX_SIZE = 5; // Index max size should below 5M
 // 项目名称
-Hotax.PROJECT_NAME = 'Hotax';
+Hotax.PROJECT_NAME = 'Taurus';
 // 版权声明
 Hotax.CopyRight = '2017-2020 领教信息科技有限公司';
-// 接口地址(本地)
-Hotax.API_HOST_LOC = 'http://192.168.1.40:8500';
 // 接口地址(测试)
 Hotax.API_HOST_DEV = 'http://tt-cms.api.ai160.com';
 // 接口地址(线上)
-Hotax.API_HOST_PRO = 'http://cms.lingjiao.cn/api/v1';
+Hotax.API_HOST_PRO = '/api';
 // oss存储地址
 Hotax.OSS_HOST = 'http://efunimgs.oss-cn-beijing.aliyuncs.com';
 /********************* 常量定义结束 **********************/
@@ -89,6 +88,7 @@ const apiObj = {
   userLogout: '/logout',
   resource: '/resource/list',
   resourceItem: '/resource',
+  audiobookItem: '/resource/audioImg',
   signature: '/oss/signature',
   merchant: '/merchant/list',
   merchantItem: '/merchant',
@@ -141,9 +141,9 @@ const apiObj = {
 function apiFormatter() {
   // 根据环境变量选取接口地址
   let prefix = '';
-  if (process.env.API === 'LOC') {
-    prefix = Hotax.API_HOST_LOC;
-  } else if (process.env.API === 'PRO') {
+  if (process.env.NODE_ENV === 'development') {
+    prefix = Hotax.API_HOST_DEV;
+  } else if (process.env.NODE_ENV === 'production') {
     prefix = Hotax.API_HOST_PRO;
   } else {
     prefix = Hotax.API_HOST_DEV;

+ 8 - 7
src/utils/utils.js

@@ -39,6 +39,8 @@ const ProvinceCodes = {
   81: '香港特别行政区',
   82: '澳门特别行政区',
   99: '海外',
+  // 43湖南校区编号超过99,省份代码顺延为90
+  90: '湖南省',
 };
 
 export function fixedZero(val) {
@@ -202,10 +204,8 @@ export function addRowKey(data) {
   if (!data) {
     return [];
   }
-  return data.map((val) => {
-    const item = val;
-    item.key = item.id;
-    return item;
+  return data.map((item) => {
+    return { key: item.id, ...item };
   });
 }
 
@@ -324,7 +324,7 @@ export function renderProductType(type) {
   } else if (type === Hotax.PRODUCT_PACKAGE) {
     return '套餐包';
   } else {
-    return '未知';
+    return '';
   }
 }
 
@@ -352,9 +352,8 @@ export function provinceNameToCode(pname) {
   const match = Object.keys(ProvinceCodes).filter((code) => {
     if (ProvinceCodes[code] === pname) {
       return true;
-    } else {
-      return false;
     }
+    return false;
   });
   return match[0];
 }
@@ -449,6 +448,8 @@ export function getResourceTypeName(type) {
       return '音频';
     case Hotax.RESOURCE_IMAGE:
       return '图片';
+    case Hotax.RESOURCE_AUDIOBOOK:
+      return '有声读物';
     default:
       return '';
   }