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

[update] 优化代码,调整部分交互样式

zhanghe пре 6 година
родитељ
комит
d3d7ff82cb
90 измењених фајлова са 1662 додато и 4190 уклоњено
  1. 0 1
      .webpackrc
  2. 5 11
      package.json
  3. 0 43
      src/assets/logo.svg
  4. 141 234
      src/common/menu.js
  5. 32 14
      src/common/router.js
  6. 1 1
      src/components/AXCityCascader/index.js
  7. 24 23
      src/components/AXDragSortTable/index.js
  8. 3 3
      src/components/AXItem/PictureItem.js
  9. 0 1
      src/components/AXItem/PictureItem.less
  10. 16 16
      src/components/AXList/StandardCardList.js
  11. 17 17
      src/components/AXList/StandardTableList.js
  12. 2 2
      src/components/AXRemoteSelect/index.js
  13. 8 8
      src/components/AXSelectTable/RBSingleSelectTable.js
  14. 0 0
      src/components/AXSelectTable/AXSingleSelectTable.less
  15. 7 7
      src/components/AXTableSelector/MultipleSelectTable.js
  16. 21 16
      src/components/AXTableSelector/Selector.js
  17. 2 2
      src/components/AXTableSelector/SingleSelectTable.js
  18. 12 0
      src/components/AXTableSelector/columnsMap.js
  19. 6 10
      src/components/AXUpload/index.js
  20. 7 0
      src/index.less
  21. 1 1
      src/layouts/BasicLayout.js
  22. 0 2
      src/models/campus.js
  23. 3 3
      src/models/courseware.js
  24. 3 3
      src/models/lesson.js
  25. 8 8
      src/models/product.js
  26. 103 0
      src/models/tagType.js
  27. 2 2
      src/routes/Dashboard/SnapshotList.js
  28. 163 84
      src/routes/Frontend/Tag/TagCreate.js
  29. 19 14
      src/routes/Frontend/Tag/TagList.js
  30. 311 0
      src/routes/Frontend/TagType/TagTypeCreate.js
  31. 32 46
      src/routes/Shelves/Package/PackageList.js
  32. 2 2
      src/routes/Shelves/Course/index.js
  33. 7 7
      src/routes/Merchant/MerchantCreate.js
  34. 56 15
      src/routes/Product/Course/CourseCreate.js
  35. 52 37
      src/routes/Product/Courseware/CoursewareCreate.js
  36. 2 11
      src/routes/Product/Courseware/CoursewareCreate.less
  37. 16 9
      src/routes/Product/Courseware/CoursewareList.js
  38. 43 25
      src/routes/Product/Lesson/LessonCreate.js
  39. 16 9
      src/routes/Product/Lesson/LessonList.js
  40. 70 52
      src/routes/Product/Package/PackageCreate.js
  41. 5 5
      src/routes/Product/Package/PackageList.js
  42. 92 88
      src/routes/Product/Support/SupportCreate.js
  43. 5 5
      src/routes/Product/Support/SupportList.js
  44. 21 25
      src/routes/Product/Training/TrainingCreate.js
  45. 5 5
      src/routes/Product/Training/TrainingList.js
  46. 7 7
      src/routes/Resource/Picture/PictureMultipleUpload.js
  47. 3 3
      src/routes/Resource/Picture/PictureUploadResult.js
  48. 1 1
      src/routes/Resource/Video/VideoCreate.js
  49. 7 7
      src/routes/Resource/Video/VideoPlayList.js
  50. 19 19
      src/routes/Resource/Video/VideoTableList.js
  51. 0 37
      src/routes/Result/Error.js
  52. 0 78
      src/routes/Result/Success.js
  53. 0 9
      src/routes/Result/Success.test.js
  54. 0 294
      src/routes/Shelves/Course/CourseCreate.js
  55. 0 29
      src/routes/Shelves/Course/CourseCreate.less
  56. 0 179
      src/routes/Shelves/Course/CourseList.js
  57. 0 323
      src/routes/Shelves/Course/TableForm.js
  58. 0 291
      src/routes/Shelves/Package/PackageCreate.js
  59. 0 29
      src/routes/Shelves/Package/PackageCreate.less
  60. 0 224
      src/routes/Shelves/Package/PackageEdit.js
  61. 0 326
      src/routes/Shelves/Package/TableForm.js
  62. 0 8
      src/routes/Shelves/Package/TableForm.less
  63. 49 33
      src/routes/Shelves/Support/SupportCreate.js
  64. 0 6
      src/routes/Shelves/Training/TrainingCreate.less
  65. 18 13
      src/routes/Shelves/Course/CourseEdit.js
  66. 56 21
      src/routes/Shelves/Support/SupportList.js
  67. 0 29
      src/routes/Shelves/Support/SupportCreate.less
  68. 0 225
      src/routes/Shelves/Support/SupportEdit.js
  69. 0 297
      src/routes/Shelves/Support/TableForm.js
  70. 0 13
      src/routes/Shelves/Support/TableForm.less
  71. 0 33
      src/routes/Shelves/Support/index.js
  72. 20 15
      src/routes/Shelves/Training/TableForm.js
  73. 0 0
      src/routes/Shelves/TableForm.less
  74. 0 13
      src/routes/Shelves/Training/TableForm.less
  75. 0 291
      src/routes/Shelves/Training/TrainingCreate.js
  76. 0 225
      src/routes/Shelves/Training/TrainingEdit.js
  77. 0 179
      src/routes/Shelves/Training/TrainingList.js
  78. 0 33
      src/routes/Shelves/Training/index.js
  79. 10 4
      src/routes/Shelves/Package/index.js
  80. 0 1
      src/routes/System/CmsUser/CmsUserCreate.less
  81. 5 5
      src/routes/System/CmsUser/CmsUserEdit.js
  82. 5 1
      src/routes/System/CmsUser/CmsUserList.js
  83. 5 5
      src/routes/Terminal/User/TerminalCreate.js
  84. 0 1
      src/routes/Terminal/User/TerminalCreate.less
  85. 5 5
      src/routes/Terminal/User/TerminalEdit.js
  86. 12 5
      src/routes/Terminal/User/TerminalList.js
  87. 5 5
      src/routes/User/Login.js
  88. 38 0
      src/services/tagType.js
  89. 9 0
      src/utils/config.js
  90. 47 1
      src/utils/utils.js

+ 0 - 1
.webpackrc

@@ -5,7 +5,6 @@
     ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": true }]
   ],
   "define": {
-    "process.env.ROLE": "PLATFORM",
     "process.env.API": "DEV"
   },
   "env": {

+ 5 - 11
package.json

@@ -1,18 +1,13 @@
 {
-  "name": "ant-design-pro",
-  "version": "1.1.0",
-  "description": "An out-of-box UI solution for enterprise applications",
+  "name": "Hotax",
+  "version": "3.0.1",
+  "description": "Enterprise applications - Content Manage System",
   "private": true,
   "scripts": {
     "precommit": "npm run lint-staged",
     "start": "cross-env DISABLE_ESLINT=true roadhog dev",
-    "start:platform": "cross-env ROLE=PLATFORM API=DEV NO_PROXY=true DISABLE_ESLINT=true roadhog dev",
-    "start:channel": "cross-env ROLE=CHANNEL API=DEV NO_PROXY=true DISABLE_ESLINT=true roadhog dev",
-    "start:cp": "cross-env ROLE=CP API=DEV NO_PROXY=true DISABLE_ESLINT=true roadhog dev",
-    "build": "cross-env DISABLE_ESLINT=true roadhog build",
-    "build:platform": "cross-env ROLE=PLATFORM API=PRO roadhog build",
-    "build:channel": "cross-env ROLE=CHANNEL API=PRO roadhog build",
-    "build:cp": "cross-env ROLE=CP API=PRO roadhog build",
+    "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",
     "site": "roadhog-api-doc static && gh-pages -d dist",
     "analyze": "cross-env ANALYZE=true roadhog build",
     "lint:style": "stylelint \"src/**/*.less\" --syntax less",
@@ -37,7 +32,6 @@
     "enquire-js": "^0.1.1",
     "fastclick": "^1.0.6",
     "hls.js": "^0.9.1",
-    "immutability-helper": "^2.6.6",
     "lodash": "^4.17.4",
     "lodash-decorators": "^4.4.1",
     "moment": "^2.19.1",

Разлика између датотеке није приказан због своје велике величине
+ 0 - 43
src/assets/logo.svg


+ 141 - 234
src/common/menu.js

@@ -3,241 +3,148 @@ import { isUrl } from '../utils/utils';
 import AXIcon from '../components/AXIcon';
 
 const menuData = () => {
-  if (process.env.ROLE === 'PLATFORM') {
-    return [{
-      name: '统计概览',
-      icon: 'dashboard',
-      path: 'dashboard',
-      children: [{
-      //   name: '营销统计',
-      //   path: 'analysis',
-      //   icon: <AXIcon type="monitor" />,
-      // }, {
-        name: '销售详情',
-        path: 'sold',
-        icon: <AXIcon type="action" />,
-      }],
-      authority: ['admin', 'platform'],
-    }, {
-      name: '基础资源',
-      icon: 'folder',
-      path: 'resource',
-      children: [{
-        name: '图库管理',
-        path: 'picture',
-        icon: 'file-jpg',
-      }, {
-        name: '视频管理',
-        path: 'video',
-        icon: 'video-camera',
-      }],
-      authority: ['admin', 'platform'],
-    }, {
-      name: '产品加工',
-      icon: 'appstore-o',
-      path: 'product',
-      children: [{
-        name: '制作课件',
-        path: 'courseware',
-      }, {
-        name: '制作课',
-        path: 'lesson',
-      }, {
-        name: '制作课程',
-        path: 'course',
-      }, {
-        name: '制作配套',
-        path: 'support',
-      }, {
-        name: '制作师训',
-        path: 'training',
-      }, {
-        name: '制作套餐包',
-        path: 'package',
-      }],
-      authority: ['admin', 'platform'],
-    }, {
-      name: '产品出售',
-      icon: 'shop',
-      path: 'shelves',
-      children: [{
-        name: '上架课程',
-        path: 'course',
-      }, {
-        name: '上架配套',
-        path: 'support',
-      }, {
-        name: '上架师训',
-        path: 'training',
-      }, {
-        name: '上架套餐包',
-        path: 'package',
-      }],
-      authority: ['admin', 'platform'],
-    }, {
-      name: '前端配置',
-      icon: 'android-o',
-      path: 'frontend',
-      children: [{
-        name: '首页入口',
-        path: 'tagGroup',
-      }, {
-        name: '侧边栏目',
-        path: 'tag',
-      }, {
-        name: '推荐内容',
-        path: 'recommend',
-      }],
-      authority: ['admin', 'platform'],
-    }, {
-      name: '交易管理',
-      icon: 'trademark',
-      path: 'trade',
-      children: [{
-        name: '购物车',
-        icon: 'shopping-cart',
-        path: 'shopcart',
-      }, {
-        name: '订单列表',
-        icon: <AXIcon type="order" />,
-        path: 'order',
-      }],
-      authority: ['admin', 'platform'],
-    }, {
-      name: '厂商管理',
-      icon: 'team',
-      path: 'merchant',
-      children: [{
-        name: '商户列表',
-        path: 'list',
-      }],
-      authority: ['admin', 'platform'],
-    }, {
-      name: '校区管理',
-      icon: <AXIcon type="campus" />,
-      path: 'campus',
-      children: [{
-        name: '校区列表',
-        path: 'list',
-      }],
-      authority: ['admin', 'platform', 'channel'],
-    }, {
-      name: '终端管理',
-      path: 'terminal',
-      icon: <AXIcon type="terminal" />,
-      children: [{
-        name: '终端用户',
-        path: 'user',
-      }, {
-        name: '白名单',
-        path: 'whitelist',
-      }],
-      authority: ['admin', 'platform', 'channel'],
-    }, {
-      name: '系统管理',
-      path: 'system',
-      icon: <AXIcon type="systemuser" />,
-      children: [{
-        name: '系统用户',
-        path: 'cms-user',
-      }],
-      authority: 'admin',
-    }];
-  } else if (process.env.ROLE === 'CHANNEL') {
-    return [{
-      name: '统计概览',
-      icon: 'dashboard',
-      path: 'dashboard',
-      children: [{
-        name: '运行监控',
-        path: 'analysis',
-        icon: <AXIcon type="apprun" />,
-      }, {
-        name: '营销统计',
-        path: 'monitor',
-        icon: <AXIcon type="monitor" />,
-      }, {
-        name: '行为分析',
-        path: 'workplace',
-        icon: <AXIcon type="action" />,
-      }],
-    }, {
-      name: '产品库',
-      icon: 'shop',
-      path: 'goods',
-      children: [{
-        name: '虚拟课程',
-        path: 'virtual',
-      }, {
-        name: '实体物品',
-        path: 'entity',
-      }, {
-        name: '打包套装',
-        path: 'package',
-      }],
-    }, {
-      name: '订单系统',
-      icon: 'trademark',
-      path: 'trade',
-      children: [{
-        name: '购物车',
-        icon: 'shopping-cart',
-        path: 'shopcart',
-      }, {
-        name: '订单列表',
-        icon: <AXIcon type="order" />,
-      }],
-    }, {
-      name: '校区管理',
-      icon: <AXIcon type="campus" />,
-      path: 'campus',
-    }, {
+  return [{
+    name: '统计概览',
+    icon: 'dashboard',
+    path: 'dashboard',
+    children: [{
+    //   name: '营销统计',
+    //   path: 'analysis',
+    //   icon: <AXIcon type="monitor" />,
+    // }, {
+      name: '销售详情',
+      path: 'sold',
+      icon: <AXIcon type="action" />,
+    }],
+    authority: ['admin', 'platform'],
+  }, {
+    name: '基础资源',
+    icon: 'folder',
+    path: 'resource',
+    children: [{
+      name: '图库管理',
+      path: 'picture',
+      icon: 'file-jpg',
+    }, {
+      name: '视频管理',
+      path: 'video',
+      icon: 'video-camera',
+    }],
+    authority: ['admin', 'platform'],
+  }, {
+    name: '产品加工',
+    icon: 'appstore-o',
+    path: 'product',
+    children: [{
+      name: '制作课件',
+      path: 'courseware',
+    }, {
+      name: '制作课',
+      path: 'lesson',
+    }, {
+      name: '制作课程',
+      path: 'course',
+    }, {
+      name: '制作配套',
+      path: 'support',
+    }, {
+      name: '制作师训',
+      path: 'training',
+    }, {
+      name: '制作套餐包',
+      path: 'package',
+    }],
+    authority: ['admin', 'platform'],
+  }, {
+    name: '产品出售',
+    icon: 'shop',
+    path: 'shelves',
+    children: [{
+      name: '上架课程',
+      path: 'course',
+    }, {
+      name: '上架配套',
+      path: 'support',
+    }, {
+      name: '上架师训',
+      path: 'training',
+    }, {
+      name: '上架套餐包',
+      path: 'package',
+    }],
+    authority: ['admin', 'platform'],
+  }, {
+    name: '前端配置',
+    icon: 'android-o',
+    path: 'frontend',
+    children: [{
+      name: '首页入口',
+      path: 'tagGroup',
+    }, {
+      name: '栏目类型',
+      path: 'tagType',
+    }, {
+      name: '侧边栏目',
+      path: 'tag',
+    }, {
+      name: '推荐内容',
+      path: 'recommend',
+    }],
+    authority: ['admin', 'platform'],
+  }, {
+    name: '交易管理',
+    icon: 'trademark',
+    path: 'trade',
+    children: [{
+      name: '购物车',
+      icon: 'shopping-cart',
+      path: 'shopcart',
+    }, {
+      name: '订单列表',
+      icon: <AXIcon type="order" />,
+      path: 'order',
+    }],
+    authority: ['admin', 'platform'],
+  }, {
+    name: '厂商管理',
+    icon: 'team',
+    path: 'merchant',
+    children: [{
+      name: '商户列表',
+      path: 'list',
+    }],
+    authority: ['admin', 'platform'],
+  }, {
+    name: '校区管理',
+    icon: <AXIcon type="campus" />,
+    path: 'campus',
+    children: [{
+      name: '校区列表',
+      path: 'list',
+    }],
+    authority: ['admin', 'platform', 'channel'],
+  }, {
+    name: '终端管理',
+    path: 'terminal',
+    icon: <AXIcon type="terminal" />,
+    children: [{
       name: '终端用户',
-      path: 'terminal',
-      icon: <AXIcon type="terminal" />,
-    }, {
-      name: '账户信息',
-      icon: 'team',
-      path: 'merchant',
-    }];
-  } else if (process.env.ROLE === 'CP') {
-    return [{
-      name: '统计概览',
-      icon: 'dashboard',
-      path: 'dashboard',
-      children: [{
-        name: '营销统计',
-        path: 'monitor',
-        icon: <AXIcon type="monitor" />,
-      }],
-    }, {
-      name: '产品库',
-      icon: 'shop',
-      path: 'goods',
-      children: [{
-        name: '虚拟课程',
-        path: 'virtual',
-      }, {
-        name: '实体物品',
-        path: 'entity',
-      }, {
-        name: '打包套装',
-        path: 'package',
-      }],
-    }, {
-      name: '订单系统',
-      icon: 'trademark',
-      path: 'trade',
-      children: [{
-        name: '订单列表',
-        icon: <AXIcon type="order" />,
-      }],
-    }, {
-      name: '账户信息',
-      icon: 'team',
-      path: 'merchant',
-    }];
-  }
+      path: 'user',
+    }, {
+      name: '白名单',
+      path: 'whitelist',
+    }],
+    authority: ['admin', 'platform', 'channel'],
+  }, {
+    name: '系统管理',
+    path: 'system',
+    icon: <AXIcon type="systemuser" />,
+    children: [{
+      name: '系统用户',
+      path: 'cms-user',
+    }],
+    authority: 'admin',
+  }];
 };
 
 function formatter(data, parentPath = '/', parentAuthority) {

+ 32 - 14
src/common/router.js

@@ -246,46 +246,52 @@ export const getRouterData = (app) => {
     },
     // 产品出售相关路由注册
     '/shelves/course': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Course')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves')),
     },
     '/shelves/course/list': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Course/CourseList')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesList')),
     },
     '/shelves/course/create': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Course/CourseCreate')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesCreate')),
     },
     '/shelves/course/edit': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Course/CourseEdit')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesEdit')),
     },
     '/shelves/support': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Support')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves')),
     },
     '/shelves/support/list': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Support/SupportList')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesList')),
     },
     '/shelves/support/create': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Support/SupportCreate')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesCreate')),
     },
     '/shelves/support/edit': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Support/SupportEdit')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesEdit')),
     },
     '/shelves/training': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Training')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves')),
     },
     '/shelves/training/list': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Training/TrainingList')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesList')),
+    },
+    '/shelves/training/create': {
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesCreate')),
+    },
+    '/shelves/training/edit': {
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesEdit')),
     },
     '/shelves/package': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Package')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves')),
     },
     '/shelves/package/list': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Package/PackageList')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesList')),
     },
     '/shelves/package/create': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Package/PackageCreate')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesCreate')),
     },
     '/shelves/package/edit': {
-      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/Package/PackageEdit')),
+      component: dynamicWrapper(app, ['shelves'], () => import('../routes/Shelves/ShelvesEdit')),
     },
     // 前端管理相关路由注册
     '/frontend/tagGroup': {
@@ -300,6 +306,18 @@ export const getRouterData = (app) => {
     '/frontend/tagGroup/edit/:id': {
       component: dynamicWrapper(app, ['tagGroup', 'merchant'], () => import('../routes/Frontend/TagGroup/TagGroupCreate')),
     },
+    '/frontend/tagType': {
+      component: dynamicWrapper(app, ['tagType'], () => import('../routes/Frontend/TagType')),
+    },
+    '/frontend/tagType/list': {
+      component: dynamicWrapper(app, ['tagType'], () => import('../routes/Frontend/TagType/TagTypeList')),
+    },
+    '/frontend/tagType/create': {
+      component: dynamicWrapper(app, ['tagType', 'merchant'], () => import('../routes/Frontend/TagType/TagTypeCreate')),
+    },
+    '/frontend/tagType/edit/:id': {
+      component: dynamicWrapper(app, ['tagType', 'merchant'], () => import('../routes/Frontend/TagType/TagTypeCreate')),
+    },
     '/frontend/tag': {
       component: dynamicWrapper(app, ['tag'], () => import('../routes/Frontend/Tag')),
     },

+ 1 - 1
src/components/AXCityCascader/index.js

@@ -13,7 +13,7 @@ class AXCityCascader extends PureComponent {
   };
   handleOnChange = (value) => {
     this.props.onChange(value);
-  }
+  };
   render() {
     const { value, placeholder } = this.props;
     return (

+ 24 - 23
src/components/AXDragSortTable/index.js

@@ -1,64 +1,65 @@
+/* eslint-disable no-param-reassign,prefer-destructuring */
 import React, { PureComponent } from 'react';
 import { Table, Button } from 'antd';
 import { DragDropContext, DragSource, DropTarget } from 'react-dnd';
 import HTML5Backend from 'react-dnd-html5-backend';
-import update from 'immutability-helper';
 import styles from './index.less';
 
 class AXDragSortTable extends PureComponent {
   handleMoveRow = (dragIndex, hoverIndex) => {
     const { data, onChange } = this.props;
-    let newData = data;
+    const newData = data;
     newData[dragIndex] = newData.splice(hoverIndex, 1, newData[dragIndex])[0];
     onChange(newData);
-  }
+  };
   swapper = (arr, targetIndex, currentIndex) => {
-    let tmpArray = [...arr];
+    const tmpArray = [...arr];
     tmpArray[currentIndex] = tmpArray.splice(targetIndex, 1, tmpArray[currentIndex])[0];
     return tmpArray;
-  }
+  };
   handleMoveUp = (data, index) => {
     if (index === 0) {
       return;
     }
     this.props.onChange(this.swapper(data, index - 1, index));
-  }
+  };
   handleMoveDown = (data, index) => {
-    if (index === data.length -1) {
+    if (index === data.length - 1) {
       return;
     }
     this.props.onChange(this.swapper(data, index + 1, index));
-  }
+  };
   handleRemove = (data, index) => {
-    let tmpArray = [...data];
+    const tmpArray = [...data];
     tmpArray.splice(index, 1);
     this.props.onChange(tmpArray);
-  }
+  };
 
   render() {
     const { data, columns } = this.props;
 
-    let addExtraDatas = (data) => {
-      const newData = data.map((item, index) => ({
+    const addExtraDatas = (originalData) => {
+      return (originalData || []).map((item, index) => ({
         ...item,
         key: item.id ? item.id : index + 1,
         _location: index + 1,
       }));
-      return newData;
-    }
+    };
 
-    let addExtraColumns = (columns) => {
+    const addExtraColumns = (newColumns) => {
       const headColumn = {
         title: '位置',
         dataIndex: '_location',
         key: '+01',
         width: 60,
+        align: 'center',
       };
       const tailColumn = {
         title: '操作',
         dataIndex: '_operation',
         key: '-01',
         width: 190,
+        align: 'right',
         render: (text, record, index) => (
           <div className={styles.operation}>
             <span>
@@ -80,7 +81,7 @@ class AXDragSortTable extends PureComponent {
             <span>
               <Button
                 size="small"
-                style={{background: '#f5222d', color: '#fff'}}
+                style={{ background: '#f5222d', color: '#fff' }}
                 onClick={() => this.handleRemove(data, index)}
               >删除
               </Button>
@@ -88,10 +89,10 @@ class AXDragSortTable extends PureComponent {
           </div>
         ),
       };
-      return [headColumn, ...columns, tailColumn];
-    }
+      return [headColumn, ...newColumns, tailColumn];
+    };
 
-    let dragDirection = (
+    const dragDirection = (
       dragIndex,
       hoverIndex,
       initialClientOffset,
@@ -106,7 +107,7 @@ class AXDragSortTable extends PureComponent {
       if (dragIndex > hoverIndex && hoverClientY < hoverMiddleY) {
         return 'upward';
       }
-    }
+    };
 
     let BodyRow = (props) => {
       const {
@@ -122,7 +123,7 @@ class AXDragSortTable extends PureComponent {
       } = props;
       const style = { ...restProps.style, cursor: 'move' };
 
-      let className = restProps.className;
+      let { className } = restProps;
       if (isOver && initialClientOffset) {
         const direction = dragDirection(
           dragRow.index,
@@ -186,12 +187,12 @@ class AXDragSortTable extends PureComponent {
     const components = {
       body: {
         row: BodyRow,
-      }
+      },
     };
 
     return (
       <Table
-        bordered={true}
+        bordered
         pagination={false}
         className={styles.dragTable}
         columns={addExtraColumns(columns)}

+ 3 - 3
src/components/AXItem/PictureItem.js

@@ -7,15 +7,15 @@ class PictureItem extends Component {
   handleItemChecked = (e) => {
     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);
-  }
+  };
   render() {
     const { item, selected } = this.props;
     const { path, code } = item;

+ 0 - 1
src/components/AXItem/PictureItem.less

@@ -29,7 +29,6 @@
   right: 5px;
   font-size: 16px;
   font-weight: 600;
-  color: @primary-9;
   &:hover {
     color: red;
   }

+ 16 - 16
src/components/AXList/StandardCardList.js

@@ -144,7 +144,7 @@ class StandardCardList extends PureComponent {
         />
       </div>
     );
-  }
+  };
   getListFooter = () => {
     const { footer: { batchActions, pagination } } = this.props;
     const paginationProps = {
@@ -194,7 +194,7 @@ class StandardCardList extends PureComponent {
         </div>)}
       </div>
     );
-  }
+  };
   // 过滤
   handleFilterOperation = (kv) => {
     const {
@@ -220,7 +220,7 @@ class StandardCardList extends PureComponent {
       delete queryParams.status;
     }
     onFilterClick(queryParams, this.state);
-  }
+  };
   // 单选/取消单选
   handleItemSelectChange = (itemId, checked) => {
     const { selectedKeys } = this.state;
@@ -230,7 +230,7 @@ class StandardCardList extends PureComponent {
     } else {
       this.setState({ selectedKeys: newSelectedKeys.filter(a => a !== itemId) });
     }
-  }
+  };
   // 全选/取消全选
   handleAllSelectChange = (e) => {
     const { dataSource } = this.props;
@@ -242,14 +242,14 @@ class StandardCardList extends PureComponent {
       allChecked: e.target.checked,
       selectedKeys: newSelectedKeys,
     });
-  }
+  };
   // 取消全选
   cleanSelectedKeys = () => {
     this.setState({
       selectedKeys: [],
       allChecked: false,
     });
-  }
+  };
   // 刷新页面,重置筛选参数
   cleanFilterParams = () => {
     const { header: { basicSearch } } = this.props;
@@ -262,7 +262,7 @@ class StandardCardList extends PureComponent {
       allChecked: false,
       selectedStatusKey: 'ALL',
     });
-  }
+  };
   // 过滤状态
   handleStatusChange = (value) => {
     this.setState({
@@ -270,15 +270,15 @@ class StandardCardList extends PureComponent {
     }, () =>
       this.handleFilterOperation({ status: value })
     );
-  }
+  };
   // 选择搜索字段
   handleSearchSelectChange = (value) => {
     this.setState({ searchSelectKey: value });
-  }
+  };
   // 响应input输入
   handleInputChange = (e) => {
     this.setState({ searchInputValue: e.target.value });
-  }
+  };
   // 筛选搜索操作
   handleSearchBtnClick = (value) => {
     const { searchSelectKey } = this.state;
@@ -287,11 +287,11 @@ class StandardCardList extends PureComponent {
     }, () =>
       this.handleFilterOperation({ [searchSelectKey]: value })
     );
-  }
+  };
   // 刷新操作
   handleRefreshBtnClick = () => {
     this.handleFilterOperation({});
-  }
+  };
   // list pageNo变化
   handleListPageChange = (page, pageSize) => {
     this.setState({
@@ -303,7 +303,7 @@ class StandardCardList extends PureComponent {
         pageNo: page,
       });
     });
-  }
+  };
   // list pageSize变化
   handleListPageSizeChange = (current, size) => {
     this.setState({
@@ -315,17 +315,17 @@ class StandardCardList extends PureComponent {
         pageNo: current,
       });
     });
-  }
+  };
   // 选择批量处理类型
   handleBatchActionSelectChange = (value) => {
     this.setState({ batchActionKey: value });
-  }
+  };
   // 批量处理操作
   handleBatchBtnClick = () => {
     const { footer: { onBatchClick } } = this.props;
     const { batchActionKey, selectedKeys } = this.state;
     onBatchClick(batchActionKey, selectedKeys);
-  }
+  };
   render() {
     const { selectedKeys } = this.state;
     const { component, dataSource, loading, header, footer, grid, onEdit, onDelete } = this.props;

+ 17 - 17
src/components/AXList/StandardTableList.js

@@ -19,7 +19,7 @@ export default class StandardTableList extends PureComponent {
     footer: false,
     showStatusSelect: true,
     rowSelectable: true,
-  }
+  };
   static propTypes = {
     loading: PropTypes.bool,
     dataSource: PropTypes.array,
@@ -35,7 +35,7 @@ export default class StandardTableList extends PureComponent {
     showStatusSelect: PropTypes.bool,
     rowSelectable: PropTypes.bool,
     keepUIState: PropTypes.object,
-  }
+  };
   constructor(props) {
     super(props);
     const {
@@ -146,7 +146,7 @@ export default class StandardTableList extends PureComponent {
         />
       </div>
     );
-  }
+  };
   getListFooter = () => {
     const { footer: { batchActions, pagination } } = this.props;
     const paginationProps = {
@@ -191,7 +191,7 @@ export default class StandardTableList extends PureComponent {
         </div>)}
       </div>
     );
-  }
+  };
   // 过滤
   handleFilterOperation = (kv) => {
     const {
@@ -217,7 +217,7 @@ export default class StandardTableList extends PureComponent {
       delete queryParams.status;
     }
     onFilterClick(queryParams, this.state);
-  }
+  };
   // 单选/取消单选
   handleItemSelectChange = (itemId, checked) => {
     const { selectedKeys } = this.state;
@@ -227,7 +227,7 @@ export default class StandardTableList extends PureComponent {
     } else {
       this.setState({ selectedKeys: newSelectedKeys.filter(a => a !== itemId) });
     }
-  }
+  };
   // 刷新页面,重置筛选参数
   cleanFilterParams = () => {
     const { header: { basicSearch } } = this.props;
@@ -239,7 +239,7 @@ export default class StandardTableList extends PureComponent {
       allChecked: false,
       selectedStatusKey: 'ALL',
     });
-  }
+  };
   // 过滤状态
   handleStatusChange = (value) => {
     this.setState({
@@ -247,15 +247,15 @@ export default class StandardTableList extends PureComponent {
     }, () =>
       this.handleFilterOperation({ status: value })
     );
-  }
+  };
   // 选择搜索字段
   handleSearchSelectChange = (value) => {
     this.setState({ searchSelectKey: value });
-  }
+  };
   // 响应input输入
   handleInputChange = (e) => {
     this.setState({ searchInputValue: e.target.value });
-  }
+  };
   // 筛选搜索操作
   handleSearchBtnClick = (value) => {
     const { searchSelectKey } = this.state;
@@ -264,11 +264,11 @@ export default class StandardTableList extends PureComponent {
     }, () =>
       this.handleFilterOperation({ [searchSelectKey]: value })
     );
-  }
+  };
   // 刷新操作
   handleRefreshBtnClick = () => {
     this.handleFilterOperation({});
-  }
+  };
   // list pageNo变化
   handleListPageChange = (page, pageSize) => {
     this.setState({
@@ -280,7 +280,7 @@ export default class StandardTableList extends PureComponent {
         pageNo: page,
       });
     });
-  }
+  };
   // list pageSize变化
   handleListPageSizeChange = (current, size) => {
     this.setState({
@@ -292,24 +292,24 @@ export default class StandardTableList extends PureComponent {
         pageNo: current,
       });
     });
-  }
+  };
   // 选择批量处理类型
   handleBatchActionSelectChange = (value) => {
     this.setState({ batchActionKey: value });
-  }
+  };
   // 批量处理操作
   handleBatchBtnClick = () => {
     const { footer: { onBatchClick } } = this.props;
     const { batchActionKey, selectedKeys } = this.state;
     onBatchClick(batchActionKey, selectedKeys);
-  }
+  };
   handleRowSelectChange = (selectedKeys) => {
     this.setState({ selectedKeys });
     // 把selectedKeys传递给父组件
     if (this.props.rowSelectChange) {
       this.props.rowSelectChange(selectedKeys);
     }
-  }
+  };
 
   render() {
     const {

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

@@ -14,7 +14,7 @@ export default class AXRemoteSelect extends PureComponent {
     if (this.props.onChange) {
       this.props.onChange(value);
     }
-  }
+  };
   lastTimeStamp = 0;
   handleOnSearch = (value) => {
     const eventTimeStamp = new Date().getTime();
@@ -27,7 +27,7 @@ export default class AXRemoteSelect extends PureComponent {
         this.lastTimeStamp = 0;
       }
     }, 800);
-  }
+  };
   render() {
     const { value, dataSource, placeholder, fetching } = this.props;
     return (

+ 8 - 8
src/components/AXSelectTable/RBSingleSelectTable.js

@@ -96,7 +96,7 @@ export default class AXSingleSelectTable extends PureComponent {
         </div>
       </div>
     );
-  }
+  };
   getListFooter = () => {
     if (!this.state.selectRowKey) {
       return (
@@ -116,20 +116,20 @@ export default class AXSingleSelectTable extends PureComponent {
         </span>
       </span>
     );
-  }
+  };
   handleSelectChange = (value) => {
     this.setState({ searchSelectKey: value });
-  }
+  };
   handleInputChange = (e) => {
     this.setState({ searchInputValue: e.target.value });
-  }
+  };
   handleFilterOperation = (kv) => {
     const { searchSelectKey, searchInputValue } = this.state;
     this.props.onFilterClick({
       [searchSelectKey]: searchInputValue,
       ...kv,
     });
-  }
+  };
   handleOnRowClick = (record) => {
     this.setState({
       selectRowKey: record.key,
@@ -138,16 +138,16 @@ export default class AXSingleSelectTable extends PureComponent {
     if (this.props.onChange) {
       this.props.onChange(record);
     }
-  }
+  };
   handleSearchBtnClick = () => {
     this.handleFilterOperation();
-  }
+  };
   handleListPageChange = (page, pageSize) => {
     this.handleFilterOperation({
       pageSize,
       pageNo: page,
     });
-  }
+  };
 
   render() {
     const { columns, dataSource, loading } = this.props;

src/components/AXSelectTable/RBSingleSelectTable.less → src/components/AXSelectTable/AXSingleSelectTable.less


+ 7 - 7
src/components/AXTableSelector/MultipleSelectTable.js

@@ -37,20 +37,20 @@ export default class MultipleSelectTable extends Component {
       selectedRows: allSelectableRows,
       selectedRowKeys: allSelectableRowKeys,
     });
-  }
+  };
   handleTransferOperation = () => {
     this.props.onTransfer(this.state.selectedRows);
     this.setState({
       selectedRows: [],
       selectedRowKeys: [],
     });
-  }
+  };
   /**
    * 移除操作回调
    */
   handleRemoveOperation = () => {
-    this.props.onRemove(this.state.selectedRows)
-  }
+    this.props.onRemove(this.state.selectedRows);
+  };
   /**
    * 选中项变化回调
    * @param selectedRowKeys
@@ -61,7 +61,7 @@ export default class MultipleSelectTable extends Component {
       selectedRows,
       selectedRowKeys,
     });
-  }
+  };
   /**
    * 待选table页码变化回调
    * @param page
@@ -69,7 +69,7 @@ export default class MultipleSelectTable extends Component {
    */
   handleTableChange = (page, pageSize) => {
     this.props.onChange(page, pageSize);
-  }
+  };
 
   render() {
     const { loading, columns, dataSource, pagination, tableType } = this.props;
@@ -94,7 +94,7 @@ export default class MultipleSelectTable extends Component {
       } else {
         return false;
       }
-    }
+    };
 
     return (
       <div className={styles.container}>

+ 21 - 16
src/components/AXTableSelector/Selector.js

@@ -7,15 +7,14 @@ import { addRowKey } from '../../utils/utils';
 import styles from './Selector.less';
 
 function getRowKeys(rows) {
-  const rowKeys = rows.map((item) => item.key);
-  return rowKeys;
+  return rows.map(item => item.key);
 }
 
 export default class Selector extends PureComponent {
   constructor(props) {
     super(props);
     const rows = addRowKey(props.selectedRows || []);
-    const rowKeys = getRowKeys(props.selectedRowKeys || []);
+    const rowKeys = getRowKeys(rows || []);
     this.state = {
       searchKey: 'name',
       searchValue: '',
@@ -23,6 +22,12 @@ export default class Selector extends PureComponent {
       selectedRowKeys: rowKeys,
     };
   }
+  componentWillReceiveProps(nextProps) {
+    this.setState({
+      selectedRows: addRowKey(nextProps.selectedRows),
+      selectedRowKeys: getRowKeys(addRowKey(nextProps.selectedRows) || []),
+    });
+  }
   /**
    * 选择搜索字段
    * @param value <code|name>
@@ -31,7 +36,7 @@ export default class Selector extends PureComponent {
     this.setState({
       searchKey: value,
     });
-  }
+  };
   /**
    * 搜索输入框内容改变回调
    * @param e
@@ -40,7 +45,7 @@ export default class Selector extends PureComponent {
     this.setState({
       searchValue: e.target.value,
     });
-  }
+  };
   /**
    * 过滤内容
    * @param page
@@ -53,7 +58,7 @@ export default class Selector extends PureComponent {
       pageNo: page,
       [searchKey]: searchValue,
     });
-  }
+  };
   /**
    * 点击`搜索`按钮回调
    */
@@ -62,7 +67,7 @@ export default class Selector extends PureComponent {
     this.props.onChange({
       [searchKey]: searchValue,
     });
-  }
+  };
   /**
    * 清除搜索框内容回调
    */
@@ -71,13 +76,13 @@ export default class Selector extends PureComponent {
       searchValue: '',
     });
     this.props.onChange({});
-  }
+  };
   /**
    * 待选列表中的选中项放到已选列表中
    * @params rows
    */
   handleMultipleTransfer = (rows) => {
-    const { selectedRowKeys } = this.state;
+    const { selectedRows, selectedRowKeys } = this.state;
     const newSelectedRowKeys = [];
     const newSelectedRows = rows.filter((item) => {
       if (selectedRowKeys.indexOf(item.key) === -1) {
@@ -87,10 +92,10 @@ export default class Selector extends PureComponent {
       return false;
     });
     this.setState({
-      selectedRows: [...newSelectedRows],
-      selectedRowKeys: [...newSelectedRowKeys],
+      selectedRows: [...selectedRows, ...newSelectedRows],
+      selectedRowKeys: [...selectedRowKeys, ...newSelectedRowKeys],
     });
-  }
+  };
   /**
    * 单选模式选中的项,更新到state
    * @param row
@@ -99,7 +104,7 @@ export default class Selector extends PureComponent {
     this.setState({
       selectedRows: [row],
     });
-  }
+  };
   /**
    * 点击`移除`按钮回调
    * @params removeRows
@@ -119,20 +124,20 @@ export default class Selector extends PureComponent {
       selectedRows: newSelectedRows,
       selectedRowKeys: newSelectedRowKeys,
     });
-  }
+  };
   /**
    * 点击`完成`按钮回调
    */
   handleFinishOperation = () => {
     const { selectedRows } = this.state;
     this.props.onFinish(selectedRows);
-  }
+  };
   /**
    * 点击`取消`按钮回调
    */
   handleCancelOperation = () => {
     this.props.onCancel();
-  }
+  };
 
   render() {
     const {

+ 2 - 2
src/components/AXTableSelector/SingleSelectTable.js

@@ -28,10 +28,10 @@ export default class SingleSelectTable extends Component {
       selectedRowKey: record.key,
     });
     this.props.onSingleTransfer(record);
-  }
+  };
   handleTableChange = (page, pageSize) => {
     this.props.onChange(page, pageSize);
-  }
+  };
 
   render() {
     const { loading, columns, dataSource, pagination } = this.props;

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

@@ -254,6 +254,18 @@ const clMap = {
       dataIndex: 'merchantName',
     }],
   },
+  TagType: {
+    columns: [{
+      title: '标签类型编号',
+      key: 1,
+      dataIndex: 'code',
+      width: '40%',
+    }, {
+      title: '标签类型名称',
+      key: 2,
+      dataIndex: 'name',
+    }],
+  },
   Tag: {
     columns: [{
       title: '标签名称',

+ 6 - 10
src/components/AXUpload/index.js

@@ -47,7 +47,6 @@ const getRandomFileName = (fileName, fileCode) => {
 
 /**
  * 将传入文件对象处理成upload组件格式
- * @param {Object/Array}
  * @return {Array} [{}]
  */
 const renderFileList = (fileList) => {
@@ -95,7 +94,7 @@ class Uploader extends Component {
           setSignature(res.data); // 保存签名到本地
         }
       });
-  }
+  };
   handleOnChange = ({ fileList }) => {
     const { ossSign, curFileName } = this.state;
     const { onUpload, totalLimit } = this.props;
@@ -118,10 +117,7 @@ class Uploader extends Component {
       fileList: renderFileList(newFileList),
     });
     const uploaded = newFileList.filter((file) => {
-      if (file.status === 'done' && file.processed) {
-        return true;
-      }
-      return false;
+      return file.status === 'done' && file.processed;
     });
     if (!uploaded.length) { return; }
     if (this.props.onChange) {
@@ -129,7 +125,7 @@ class Uploader extends Component {
     } else {
       onUpload(uploaded.slice(0, totalLimit));
     }
-  }
+  };
   handleOnRemove = (file) => {
     const newFileList = this.state.fileList.filter((item) => {
       return item.uid !== file.uid;
@@ -139,18 +135,18 @@ class Uploader extends Component {
     } else {
       this.props.onRemove(newFileList);
     }
-  }
+  };
   handleOnPreview = (file) => {
     this.setState({
       previewImg: file.url || file.thumbUrl,
       previewVisible: true,
     });
-  }
+  };
   handleCancelPreview = () => {
     this.setState({
       previewVisible: false,
     });
-  }
+  };
   render() {
     const { multiple, accept, totalLimit, forbidden } = this.props;
     const { ossSign, fileList, curFileName, previewImg, previewVisible } = this.state;

+ 7 - 0
src/index.less

@@ -20,6 +20,13 @@ body {
   -moz-osx-font-smoothing: grayscale;
 }
 
+:global(.a-link) {
+  color: #262626;
+  &:hover {
+    color: #f5222d !important;
+  }
+}
+
 .globalSpin {
   width: 100%;
   margin: 40px 0 !important;

+ 1 - 1
src/layouts/BasicLayout.js

@@ -128,7 +128,7 @@ class BasicLayout extends React.PureComponent {
       urlParams.searchParams.delete('redirect');
       window.history.replaceState(null, 'redirect', urlParams.href);
     } else {
-      return '/dashboard/analysis';
+      return '/dashboard/sold';
     }
     return redirect;
   };

+ 0 - 2
src/models/campus.js

@@ -23,7 +23,6 @@ export default {
     *fetchCampusList({ payload }, { call, put }) {
       const response = yield call(queryCampusList, payload);
       if (response.success) {
-        message.success('加载校区列表成功');
         yield put({
           type: 'querySuccess',
           payload: {
@@ -38,7 +37,6 @@ export default {
     *fetchCampusItem({ payload }, { call, put }) {
       const response = yield call(queryCampusItem, payload);
       if (response.success) {
-        message.success('加载校区详情成功');
         yield put({
           type: 'querySuccess',
           payload: {

+ 3 - 3
src/models/courseware.js

@@ -51,7 +51,7 @@ export default {
         message.success('创建课件成功');
         yield put(routerRedux.push({
           state,
-          pathname: '/product/courseware',
+          pathname: '/product/courseware/list',
         }));
       }
     },
@@ -70,7 +70,7 @@ export default {
       if (response.success) {
         message.success('修改课件成功');
         yield put(routerRedux.push({
-          pathname: '/product/courseware',
+          pathname: '/product/courseware/list',
           state: states,
         }));
       }
@@ -90,7 +90,7 @@ export default {
         currentItem: {
           ...state.currentItem,
           resourceList: action.payload,
-        }
+        },
       };
     },
     cleanItemState(state) {

+ 3 - 3
src/models/lesson.js

@@ -51,7 +51,7 @@ export default {
         message.success('创建课成功');
         yield put(routerRedux.push({
           state,
-          pathname: '/product/lesson',
+          pathname: '/product/lesson/list',
         }));
       }
     },
@@ -70,7 +70,7 @@ export default {
       if (response.success) {
         message.success('修改课成功');
         yield put(routerRedux.push({
-          pathname: '/product/lesson',
+          pathname: '/product/lesson/list',
           state: states,
         }));
       }
@@ -90,7 +90,7 @@ export default {
         currentItem: {
           ...state.currentItem,
           wareList: action.payload,
-        }
+        },
       };
     },
     cleanItemState(state) {

+ 8 - 8
src/models/product.js

@@ -134,7 +134,7 @@ export default {
         message.success('创建课程成功');
         yield put(routerRedux.push({
           state,
-          pathname: '/product/course',
+          pathname: '/product/course/list',
         }));
       }
     },
@@ -144,7 +144,7 @@ export default {
         message.success('创建配套成功');
         yield put(routerRedux.push({
           state,
-          pathname: '/product/support',
+          pathname: '/product/support/list',
         }));
       }
     },
@@ -154,7 +154,7 @@ export default {
         message.success('创建师训成功');
         yield put(routerRedux.push({
           state,
-          pathname: '/product/training',
+          pathname: '/product/training/list',
         }));
       }
     },
@@ -164,7 +164,7 @@ export default {
         message.success('创建套餐包成功');
         yield put(routerRedux.push({
           state,
-          pathname: '/product/package',
+          pathname: '/product/package/list',
         }));
       }
     },
@@ -173,7 +173,7 @@ export default {
       if (response.success) {
         message.success('修改课程成功');
         yield put(routerRedux.push({
-          pathname: '/product/course',
+          pathname: '/product/course/list',
           state: states,
         }));
       }
@@ -183,7 +183,7 @@ export default {
       if (response.success) {
         message.success('修改配套成功');
         yield put(routerRedux.push({
-          pathname: '/product/support',
+          pathname: '/product/support/list',
           state: states,
         }));
       }
@@ -193,7 +193,7 @@ export default {
       if (response.success) {
         message.success('修改师训成功');
         yield put(routerRedux.push({
-          pathname: '/product/training',
+          pathname: '/product/training/list',
           state: states,
         }));
       }
@@ -203,7 +203,7 @@ export default {
       if (response.success) {
         message.success('修改套餐包成功');
         yield put(routerRedux.push({
-          pathname: '/product/package',
+          pathname: '/product/package/list',
           state: states,
         }));
       }

+ 103 - 0
src/models/tagType.js

@@ -0,0 +1,103 @@
+import { message } from 'antd';
+import { routerRedux } from 'dva/router';
+import {
+  queryTagTypeList,
+  queryTagTypeItem,
+  createTagTypeItem,
+  updateTagTypeItem,
+  deleteTagTypeItem,
+} from '../services/tagType';
+
+export default {
+  namespace: 'tagType',
+
+  state: {
+    list: [],
+    pageNo: 1,
+    pageSize: 15,
+    totalSize: 0,
+    currentItem: {},
+  },
+
+  effects: {
+    *fetchTagTypeList({ payload }, { call, put }) {
+      const response = yield call(queryTagTypeList, 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,
+          },
+        });
+      }
+    },
+    *fetchTagTypeItem({ payload }, { call, put }) {
+      const response = yield call(queryTagTypeItem, payload);
+      if (response.success) {
+        yield put({
+          type: 'querySuccess',
+          payload: {
+            currentItem: response.data || {},
+          },
+        });
+      }
+    },
+    *createTagTypeItem({ payload, state }, { call, put }) {
+      const response = yield call(createTagTypeItem, payload);
+      if (response.success) {
+        message.success('创建标签类型成功');
+        yield put(routerRedux.push({
+          state,
+          pathname: '/frontend/tagType',
+        }));
+      }
+    },
+    *deleteTagTypeItem({ payload, states }, { call, put }) {
+      const response = yield call(deleteTagTypeItem, payload);
+      if (response.success) {
+        message.success('删除标签类型成功');
+        yield put({
+          type: 'fetchTagTypeList',
+          payload: states.Queryers,
+        });
+      }
+    },
+    *updateTagTypeItem({ payload, states }, { call, put }) {
+      const response = yield call(updateTagTypeItem, payload);
+      if (response.success) {
+        message.success('修改标签类型成功');
+        yield put(routerRedux.push({
+          pathname: '/frontend/tagType',
+          state: states,
+        }));
+      }
+    },
+  },
+
+  reducers: {
+    querySuccess(state, action) {
+      return {
+        ...state,
+        ...action.payload,
+      };
+    },
+    fixCurrentItem(state, action) {
+      return {
+        ...state,
+        currentItem: {
+          ...state.currentItem,
+          ...action.payload,
+        },
+      };
+    },
+    cleanItemState(state) {
+      return {
+        ...state,
+        currentItem: {},
+      };
+    },
+  },
+};

+ 2 - 2
src/routes/Dashboard/SnapshotList.js

@@ -24,10 +24,10 @@ export default class SnapshotListPage extends Component {
       type: 'trade/fetchSnapshotList',
       payload: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { trade, loading } = this.props;

+ 163 - 84
src/routes/Frontend/Tag/TagCreate.js

@@ -23,26 +23,32 @@ const formItemLayout = {
   },
 };
 
-@connect(({ loading, tag, tagGroup, shelves }) => ({
+@connect(({ loading, tag, tagGroup, shelves, tagType, merchant }) => ({
   tag,
   shelves,
   tagGroup,
+  tagType,
+  merchant,
   submitting: loading.models.tag,
   sLoading: loading.models.shelves,
+  mLoading: loading.models.merchant,
   tLoading: loading.models.tagGroup,
+  ttLoading: loading.models.tagType,
 }))
 @Form.create()
 export default class TagCreatePage extends Component {
   state = {
+    tagTypeSelectorDestroy: true,
     tagGroupSelectorDestroy: true,
+    merchantSelectorDestroy: true,
     shelvesSelectorDestroy: true,
     productType: 'Course',
   };
   componentWillMount() {
-    const match = pathToRegexp('/frontend/tag/create').exec(this.props.location.pathname);
-    if (match) {
-      this.cleanPageState();
-    }
+    this.props.dispatch({
+      type: 'tag/cleanItemState',
+      payload: {},
+    });
   }
   componentDidMount() {
     const matchId = this.isEdit();
@@ -60,17 +66,11 @@ export default class TagCreatePage extends Component {
       return match[1];
     }
     return false;
-  }
-  cleanPageState=() => {
-    this.props.dispatch({
-      type: 'tag/cleanItemState',
-      payload: {},
-    });
-  }
+  };
   handleRadioChange=(e) => {
     this.setState({ productType: e.target.value });
     this.selectorDataFetcher(e.target.value, {});
-  }
+  };
   selectorDataFetcher=(name, params) => {
     switch (name) {
       case 'Course':
@@ -85,28 +85,74 @@ export default class TagCreatePage extends Component {
           payload: params,
         });
         break;
-      case 'TagGroup':
+      case 'tagGroup':
         this.props.dispatch({
           type: 'tagGroup/fetchTagGroupList',
           payload: params,
         });
         break;
+      case 'tagType':
+        this.props.dispatch({
+          type: 'tagType/fetchTagTypeList',
+          payload: params,
+        });
+        break;
+      case 'merchant':
+        this.props.dispatch({
+          type: 'merchant/fetchMerchantList',
+          payload: params,
+        });
+        break;
       default:
         break;
     }
-  }
-  handleTagGroupSelectorModalShow = () => {
+  };
+  handleTagMetaSelectorModalShow = (flag) => {
     this.setState({
-      tagGroupSelectorDestroy: false,
+      [`${flag}SelectorDestroy`]: false,
     });
-    this.selectorDataFetcher('TagGroup');
-  }
+    this.selectorDataFetcher(flag);
+  };
+  handleTagMetaInfoSelectorChange = (flag, params) => {
+    this.selectorDataFetcher(flag, params);
+  };
+  handleTagMetaInfoSelectorCancel = (flag) => {
+    this.setState({
+      [`${flag}SelectorDestroy`]: true,
+    });
+  };
+  handleTagMetaInfoSelectorFinish = (flag, rows) => {
+    this.setState({
+      [`${flag}SelectorDestroy`]: true,
+    });
+    if (!rows || !rows.length) {
+      return;
+    }
+    let payload;
+    switch (flag) {
+      case 'tagGroup':
+        payload = { groupId: rows[0].id, groupName: rows[0].name };
+        break;
+      case 'tagType':
+        payload = { typeCode: rows[0].code };
+        break;
+      case 'merchant':
+        payload = { merchantId: rows[0].id, merchantName: rows[0].name };
+        break;
+      default:
+        break;
+    }
+    this.props.dispatch({
+      type: 'tag/fixCurrentItem',
+      payload,
+    });
+  };
   handleShelvesSelectorModalShow = () => {
     const { tag } = this.props;
     const { currentItem } = tag;
     const { merchantId } = currentItem;
     if (!merchantId) {
-      Message.error('请先选择标签所属的标签组!');
+      Message.error('请先选择标签所属的渠道!');
       return;
     }
     const params = { merchantId };
@@ -114,44 +160,18 @@ export default class TagCreatePage extends Component {
       shelvesSelectorDestroy: false,
     });
     this.selectorDataFetcher(this.state.productType, params);
-  }
-  handleTagGroupSelectorChange = (params) => {
-    this.selectorDataFetcher('TagGroup', params);
-  }
+  };
   handleShelvesSelectorChange = (params) => {
     const { tag } = this.props;
     const { currentItem } = tag;
     const { merchantId } = currentItem;
     this.selectorDataFetcher(this.state.productType, { ...params, merchantId });
-  }
-  handleTagGroupSelectorCancel = () => {
-    this.setState({
-      tagGroupSelectorDestroy: true,
-    });
-  }
+  };
   handleShelvesSelectorCancel = () => {
     this.setState({
       shelvesSelectorDestroy: true,
     });
-  }
-  handleTagGroupSelectorFinish = (rows) => {
-    this.setState({
-      tagGroupSelectorDestroy: true,
-    });
-    if (!rows || !rows.length) {
-      return;
-    }
-    const { id, name, merchantName, merchantId } = rows[0];
-    this.props.dispatch({
-      type: 'tag/fixCurrentItem',
-      payload: {
-        merchantId,
-        merchantName,
-        groupId: id,
-        groupName: name,
-      },
-    });
-  }
+  };
   handleShelvesSelectorFinish = (rows) => {
     this.setState({
       shelvesSelectorDestroy: true,
@@ -163,19 +183,19 @@ export default class TagCreatePage extends Component {
       type: 'tag/fixCurrentItem',
       payload: { productList: rows },
     });
-  }
+  };
   handleDragSortTableChange = (rows) => {
     this.props.dispatch({
       type: 'tag/fixCurrentItem',
       payload: { productList: rows },
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/frontend/tag',
       state: this.props.location.state,
     }));
-  }
+  };
   handlePageSubmit = (e) => {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
@@ -183,7 +203,7 @@ export default class TagCreatePage extends Component {
         const { name, status } = values;
         const { tag } = this.props;
         const { currentItem } = tag;
-        const { productList = [], groupId } = currentItem;
+        const { productList = [], groupId, typeCode } = currentItem;
         const id = this.isEdit();
         if (id) {
           this.props.dispatch({
@@ -192,6 +212,7 @@ export default class TagCreatePage extends Component {
               id,
               name,
               groupId,
+              typeCode,
               status: boolToStatus(status),
               productList: productList.map(item => item.pid),
             },
@@ -203,6 +224,7 @@ export default class TagCreatePage extends Component {
             payload: {
               name,
               groupId,
+              typeCode,
               status: boolToStatus(status),
               productList: productList.map(item => item.pid),
             },
@@ -211,32 +233,46 @@ export default class TagCreatePage extends Component {
         }
       }
     });
-  }
+  };
 
   render() {
-    const { form, submitting, tLoading, sLoading, shelves, tag, tagGroup } = this.props;
-    const { shelvesSelectorDestroy, tagGroupSelectorDestroy, productType } = this.state;
+    const {
+      form, submitting, mLoading, tLoading, ttLoading,
+      sLoading, shelves, tag, tagGroup, tagType, merchant,
+    } = this.props;
+    const {
+      shelvesSelectorDestroy, tagGroupSelectorDestroy,
+      merchantSelectorDestroy, tagTypeSelectorDestroy, productType,
+    } = this.state;
     const { currentItem } = tag;
-    const { status, name, groupName, merchantName, productList = [] } = currentItem;
+    const { status, typeCode, name, groupName, merchantName, productList = [] } = currentItem;
     const { getFieldDecorator } = form;
 
-    const tagGroupData = [{
-      fieldName: '标签组名称',
+    const tagMetaData = [{
+      fieldName: '所属类型:',
+      value: typeCode,
+      key: 'tagType',
+    }, {
+      fieldName: '所属标签组:',
       value: groupName,
-      key: 'groupName',
+      key: 'tagGroup',
     }, {
-      fieldName: '渠道名称',
+      fieldName: '所属渠道:',
       value: merchantName,
-      key: 'merchantName',
+      key: 'merchant',
     }];
-    const tagGroupColumns = [{
+    const tagMetaColumns = [{
       dataIndex: 'fieldName',
       key: 1,
-      width: '30%',
+      width: '10%',
+      align: 'left',
+      render: (text, record) => (
+        <a onClick={() => this.handleTagMetaSelectorModalShow(record.key)}>{text}</a>
+      ),
     }, {
       dataIndex: 'value',
       key: 2,
-      width: '70%',
+      width: '90%',
     }];
     const productColumns = [{
       title: '产品编号',
@@ -260,6 +296,31 @@ export default class TagCreatePage extends Component {
         </Radio.Group>
       );
     };
+    const getTagTypeModal = () => {
+      return (
+        <Modal
+          width={1100}
+          footer={null}
+          visible
+          title="标签类别"
+          maskClosable={false}
+          onCancel={() => this.handleTagMetaInfoSelectorCancel('tagType')}
+        >
+          <Selector
+            multiple={false}
+            loading={ttLoading}
+            selectorName="TagType"
+            list={tagType.list}
+            pageNo={tagType.pageNo}
+            pageSize={tagType.pageSize}
+            totalSize={tagType.totalSize}
+            onCancel={() => this.handleTagMetaInfoSelectorCancel('tagType')}
+            onChange={data => this.handleTagMetaInfoSelectorChange('tagType', data)}
+            onFinish={data => this.handleTagMetaInfoSelectorFinish('tagType', data)}
+          />
+        </Modal>
+      );
+    };
     const getTagGroupModal = () => {
       return (
         <Modal
@@ -268,7 +329,7 @@ export default class TagCreatePage extends Component {
           visible
           title="标签组"
           maskClosable={false}
-          onCancel={this.handleTagGroupSelectorCancel}
+          onCancel={() => this.handleTagMetaInfoSelectorCancel('tagGroup')}
         >
           <Selector
             multiple={false}
@@ -278,9 +339,34 @@ export default class TagCreatePage extends Component {
             pageNo={tagGroup.pageNo}
             pageSize={tagGroup.pageSize}
             totalSize={tagGroup.totalSize}
-            onCancel={this.handleTagGroupSelectorCancel}
-            onChange={this.handleTagGroupSelectorChange}
-            onFinish={this.handleTagGroupSelectorFinish}
+            onCancel={() => this.handleTagMetaInfoSelectorCancel('tagGroup')}
+            onChange={data => this.handleTagMetaInfoSelectorChange('tagGroup', data)}
+            onFinish={data => this.handleTagMetaInfoSelectorFinish('tagGroup', data)}
+          />
+        </Modal>
+      );
+    };
+    const getMerchantModal = () => {
+      return (
+        <Modal
+          width={1100}
+          footer={null}
+          visible
+          title="渠道列表"
+          maskClosable={false}
+          onCancel={() => this.handleTagMetaInfoSelectorCancel('merchant')}
+        >
+          <Selector
+            multiple={false}
+            loading={mLoading}
+            selectorName="Merchant"
+            list={merchant.list}
+            pageNo={merchant.pageNo}
+            pageSize={merchant.pageSize}
+            totalSize={merchant.totalSize}
+            onCancel={() => this.handleTagMetaInfoSelectorCancel('merchant')}
+            onChange={data => this.handleTagMetaInfoSelectorChange('merchant', data)}
+            onFinish={data => this.handleTagMetaInfoSelectorFinish('merchant', data)}
           />
         </Modal>
       );
@@ -310,21 +396,11 @@ export default class TagCreatePage extends Component {
         </Modal>
       );
     };
-
-    const renderTagGroupCardName = () => {
-      return (
-        <div className={styles.cardName}>
-          <span>
-            <a disabled={!!this.isEdit()} onClick={this.handleTagGroupSelectorModalShow}>所属标签组</a>
-          </span>
-        </div>
-      );
-    };
     const renderProductCardName = () => {
       return (
         <div className={styles.cardName}>
           <span>
-            <a onClick={this.handleShelvesSelectorModalShow}>上架产品</a>
+            <a onClick={this.handleShelvesSelectorModalShow}>关联产品</a>
           </span>
         </div>
       );
@@ -352,16 +428,19 @@ export default class TagCreatePage extends Component {
             </Form.Item>
           </Form>
         </Card>
-        {/* 标签选择Card */}
-        <Card title={renderTagGroupCardName()} style={{ marginBottom: 16 }}>
+        {/* 标签类别信息选择Card */}
+        <Card title="类别信息" style={{ marginBottom: 16 }}>
           <Table
             bordered
+            size="small"
             showHeader={false}
             pagination={false}
-            columns={tagGroupColumns}
-            dataSource={tagGroupData}
+            columns={tagMetaColumns}
+            dataSource={tagMetaData}
           />
           {!tagGroupSelectorDestroy && getTagGroupModal()}
+          {!tagTypeSelectorDestroy && getTagTypeModal()}
+          {!merchantSelectorDestroy && getMerchantModal()}
         </Card>
         {/* 产品选择Card */}
         <Card title={renderProductCardName()} style={{ marginBottom: 70 }}>

+ 19 - 14
src/routes/Frontend/Tag/TagList.js

@@ -32,7 +32,7 @@ export default class TagListPage extends Component {
       pathname: '/frontend/tag/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
@@ -46,13 +46,13 @@ export default class TagListPage extends Component {
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/frontend/tag/edit/${item.id}`,
       state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'tag/fetchTagList',
@@ -62,10 +62,10 @@ export default class TagListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, tag } = this.props;
@@ -112,32 +112,37 @@ export default class TagListPage extends Component {
       title: '标签名称',
       key: 1,
       dataIndex: 'name',
-      width: '20%',
+      width: '15%',
     }, {
-      title: '所属标签组',
+      title: '标签类型',
       key: 2,
+      dataIndex: 'typeCode',
+      width: '15%',
+    }, {
+      title: '所属标签组',
+      key: 3,
       dataIndex: 'groupName',
-      width: '20%',
+      width: '15%',
     }, {
       title: '所属渠道',
-      key: 3,
+      key: 4,
       dataIndex: 'merchantName',
-      width: '15%',
+      width: '12%',
     }, {
       title: '标签状态',
-      key: 4,
+      key: 5,
       dataIndex: 'status',
       render: text => renderStatus(text),
-      width: '12%',
+      width: '10%',
     }, {
       title: '更新时间',
-      key: 5,
+      key: 6,
       dataIndex: 'gmtModified',
       render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
       width: '15%',
     }, {
       title: '操作',
-      key: 6,
+      key: 7,
       render: (_, record) => renderOperation(record),
       width: '13%',
       align: 'right',

+ 311 - 0
src/routes/Frontend/TagType/TagTypeCreate.js

@@ -0,0 +1,311 @@
+/* eslint-disable prefer-destructuring */
+import React, { Component } from 'react';
+import pathToRegexp from 'path-to-regexp';
+import { connect } from 'dva';
+import { routerRedux } from 'dva/router';
+import { Form, Modal, Card, Button, Input, Switch, Divider } from 'antd';
+import { renderStatus, statusToBool, boolToStatus } from '../../../utils/utils';
+import AXDragSortTable from '../../../components/AXDragSortTable';
+import Selector from '../../../components/AXTableSelector/Selector';
+import FooterToolbar from '../../../components/FooterToolbar';
+
+const formItemLayout = {
+  labelCol: {
+    xs: { span: 24 },
+    sm: { span: 3 },
+  },
+  wrapperCol: {
+    xs: { span: 24 },
+    sm: { span: 14 },
+    md: { span: 12 },
+  },
+};
+
+/**
+ * 根据渠道id过滤标签
+ * @param merchantId
+ * @param tagList
+ */
+const filterTagListByMerchantId = (merchantId, tagList) => {
+  if (!merchantId) { return tagList; }
+  return tagList.filter(tag => tag.merchantId === merchantId);
+};
+/**
+ * 根据子数组顺序调整父数组
+ * @param subArray
+ * @param parentArray
+ */
+const arraySort = (subArray = [], parentArray = []) => {
+  let cursor = 0;
+  const newArray = [...parentArray];
+  while (cursor < subArray.length - 1) {
+    const prevId = subArray[cursor].id;
+    const nextId = subArray[cursor + 1].id;
+    const currentIndex = newArray.findIndex(data => data.id === prevId);
+    const targetIndex = newArray.findIndex(data => data.id === nextId);
+    if (currentIndex > targetIndex) {
+      newArray[currentIndex] = newArray.splice(targetIndex, 1, newArray[currentIndex])[0];
+    }
+    cursor += 1;
+  }
+  return newArray;
+};
+
+@connect(({ loading, tagType, merchant }) => ({
+  tagType,
+  merchant,
+  submitting: loading.models.tagType,
+  mLoading: loading.models.merchant,
+}))
+@Form.create()
+export default class TagTypeCreatePage extends Component {
+  state = {
+    merchantSelectorDestroy: true,
+    currentMerchantId: '',
+    currentMerchantName: '全部',
+  };
+  componentWillMount() {
+    this.props.dispatch({
+      type: 'tagType/cleanItemState',
+      payload: {},
+    });
+  }
+  componentDidMount() {
+    const matchId = this.isEdit();
+    if (matchId) {
+      this.props.dispatch({
+        type: 'tagType/fetchTagTypeItem',
+        payload: { tagTypeId: matchId },
+      });
+    }
+  }
+  isEdit = () => {
+    const { location } = this.props;
+    const match = pathToRegexp('/frontend/tagType/edit/:id').exec(location.pathname);
+    if (match) {
+      return match[1];
+    }
+    return false;
+  };
+  selectorDataFetcher = (name, params) => {
+    switch (name) {
+      case 'Merchant':
+        this.props.dispatch({
+          type: 'merchant/fetchMerchantList',
+          payload: params,
+        });
+        break;
+      case 'Tag':
+        this.props.dispatch({
+          type: 'tag/fetchTagList',
+          payload: params,
+        });
+        break;
+      default:
+        break;
+    }
+  };
+  handleMerchantSelectorModalShow = () => {
+    this.setState({
+      merchantSelectorDestroy: false,
+    });
+    this.selectorDataFetcher('Merchant');
+  };
+  handleMerchantSelectorChange = (params) => {
+    this.selectorDataFetcher('Merchant', params);
+  };
+  handleMerchantSelectorCancel = () => {
+    this.setState({
+      merchantSelectorDestroy: true,
+    });
+  };
+  handleMerchantSelectorFinish = (rows) => {
+    if (!rows || !rows.length) {
+      return;
+    }
+    const { id, name } = rows[0];
+    this.setState({
+      currentMerchantId: id,
+      currentMerchantName: name,
+      merchantSelectorDestroy: true,
+    });
+  };
+  handleDragSortTableChange = (rows) => {
+    const { currentItem } = this.props.tagType;
+    const { tagList } = currentItem;
+    this.props.dispatch({
+      type: 'tagType/fixCurrentItem',
+      payload: { tagList: arraySort(rows || [], tagList || []) },
+    });
+  };
+  handlePageBack = () => {
+    this.props.dispatch(routerRedux.push({
+      pathname: '/frontend/tagType',
+      state: this.props.location.state,
+    }));
+  };
+  handlePageSubmit = (e) => {
+    e.preventDefault();
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        const { code, name, status } = values;
+        const { tagType } = this.props;
+        const { currentItem } = tagType;
+        const { tagList = [], merchantId } = currentItem;
+        const id = this.isEdit();
+        if (id) {
+          this.props.dispatch({
+            type: 'tagType/updateTagTypeItem',
+            payload: {
+              id,
+              code,
+              name,
+              merchantId,
+              status: boolToStatus(status),
+              tagList: tagList.map(item => item.id),
+            },
+            states: this.props.location.state,
+          });
+        } else {
+          this.props.dispatch({
+            type: 'tagType/createTagTypeItem',
+            payload: {
+              code,
+              name,
+              merchantId,
+              status: boolToStatus(status),
+              tagList: tagList.map(item => item.id),
+            },
+            states: this.props.location.state,
+          });
+        }
+      }
+    });
+  };
+
+  render() {
+    const { form, submitting, mLoading, merchant, tagType } = this.props;
+    const { merchantSelectorDestroy, currentMerchantId, currentMerchantName } = this.state;
+    const { currentItem } = tagType;
+    const { status, code, name, tagList = [] } = currentItem;
+    const { getFieldDecorator } = form;
+
+    const tagColumns = [{
+      title: '标签名称',
+      dataIndex: 'name',
+      key: 1,
+      width: '35%',
+    }, {
+      title: '标签状态',
+      dataIndex: 'status',
+      render: text => renderStatus(text),
+      key: 2,
+    }];
+    const getMerchantModal = () => {
+      return (
+        <Modal
+          width={1100}
+          footer={null}
+          visible
+          title="渠道列表"
+          maskClosable={false}
+          onCancel={this.handleMerchantSelectorCancel}
+        >
+          <Selector
+            multiple={false}
+            loading={mLoading}
+            selectorName="Merchant"
+            list={merchant.list}
+            pageNo={merchant.pageNo}
+            pageSize={merchant.pageSize}
+            totalSize={merchant.totalSize}
+            onCancel={this.handleMerchantSelectorCancel}
+            onChange={this.handleMerchantSelectorChange}
+            onFinish={this.handleMerchantSelectorFinish}
+          />
+        </Modal>
+      );
+    };
+    return (
+      <div>
+        {/* 基础信息Card */}
+        <Card title="基础信息" style={{ marginBottom: 16 }}>
+          <Form>
+            <Form.Item hasFeedback label="标签类型编号" {...formItemLayout}>
+              {getFieldDecorator('code', {
+                rules: [
+                  {
+                    required: true, message: '请填写标签类型编号',
+                  }, {
+                    pattern: /^[a-zA-Z0-9_-]+$/g, message: '编号包含非法字符',
+                  },
+                ],
+                initialValue: code,
+              })(
+                <Input
+                  placeholder="请输入"
+                  disabled={!!this.isEdit()}
+                />
+              )}
+            </Form.Item>
+            <Form.Item hasFeedback label="标签类型名称" {...formItemLayout}>
+              {getFieldDecorator('name', {
+                rules: [{ required: true, message: '请填写标签类型名称' }],
+                initialValue: name,
+              })(
+                <Input placeholder="请输入" />
+              )}
+            </Form.Item>
+            <Form.Item label="标签类型状态" {...formItemLayout}>
+              {getFieldDecorator('status', {
+                valuePropName: 'checked',
+                initialValue: statusToBool(status),
+              })(
+                <Switch checkedChildren="正常" unCheckedChildren="删除" />
+              )}
+            </Form.Item>
+          </Form>
+        </Card>
+        {/* 标签排序Card */}
+        {this.isEdit() && (
+          <Card
+            title={
+              <div>
+                <span>标签列表</span>
+                <Divider type="vertical" />
+                <Button
+                  type="primary"
+                  size="small"
+                  style={{ width: 100 }}
+                  onClick={this.handleMerchantSelectorModalShow}
+                >{currentMerchantName}
+                </Button>
+              </div>
+            }
+            style={{ marginBottom: 70 }}
+          >
+            <AXDragSortTable
+              data={filterTagListByMerchantId(currentMerchantId, tagList)}
+              columns={tagColumns}
+              onChange={this.handleDragSortTableChange}
+            />
+            {!merchantSelectorDestroy && getMerchantModal()}
+          </Card>
+        )}
+        <FooterToolbar style={{ width: '100%' }}>
+          <Button
+            onClick={this.handlePageBack}
+            style={{ marginRight: 10 }}
+          >取消
+          </Button>
+          <Button
+            type="primary"
+            loading={submitting}
+            onClick={this.handlePageSubmit}
+          >提交
+          </Button>
+        </FooterToolbar>
+      </div>
+    );
+  }
+}

+ 32 - 46
src/routes/Shelves/Package/PackageList.js

@@ -3,17 +3,16 @@ import moment from 'moment';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Card, Modal, Button, message } from 'antd';
-import Ellipsis from '../../../components/Ellipsis/index';
 import { StandardTableList } from '../../../components/AXList';
 import { renderStatus, addRowKey } from '../../../utils/utils';
 
 const Message = message;
 
-@connect(({ loading, shelves }) => ({
-  shelves,
-  loading: loading.models.shelves,
+@connect(({ loading, tagType }) => ({
+  tagType,
+  loading: loading.models.tagType,
 }))
-export default class PackageListPage extends Component {
+export default class TagTypeListPage extends Component {
   constructor(props) {
     super(props);
     const { state } = props.location;
@@ -24,57 +23,53 @@ export default class PackageListPage extends Component {
   }
   componentDidMount() {
     this.props.dispatch({
-      type: 'shelves/fetchPackageItemList',
+      type: 'tagType/fetchTagTypeList',
       payload: { ...this.state.Queryers },
     });
   }
   handleCreateOperation = () => {
     this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/package/create',
+      pathname: '/frontend/tagType/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
       cancelText: '取消',
-      title: '你确定要下架该套餐包吗?',
+      title: '你确定要删除该标签类型吗?',
       onOk: () => {
         this.props.dispatch({
-          type: 'shelves/deleteItem',
-          payload: { id: item.id },
+          type: 'tagType/deleteTagTypeItem',
+          payload: { groupId: item.id },
           states: this.state,
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/package/edit',
-      state: {
-        pid: item.pid,
-        merchantId: item.merchantId,
-        ...this.state,
-      },
+      pathname: `/frontend/tagType/edit/${item.id}`,
+      state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
-      type: 'shelves/fetchPackageItemList',
+      type: 'tagType/fetchTagTypeList',
       payload: params,
     });
     this.setState({
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
-    const { loading, shelves } = this.props;
-    const { list, totalSize, pageSize, pageNo } = shelves;
+    const { loading, tagType } = this.props;
+    const { list, totalSize, pageSize, pageNo } = tagType;
 
     const renderOperation = (item) => {
       return (
@@ -89,7 +84,7 @@ export default class PackageListPage extends Component {
             size="small"
             className="delBtn"
             onClick={() => this.handleDeleteOperation(item)}
-          >下架
+          >删除
           </Button>
         </div>
       );
@@ -104,10 +99,10 @@ export default class PackageListPage extends Component {
     }];
     const basicSearch = {
       keys: [{
-        name: '套餐包编号',
+        name: '标签类型编号',
         field: 'code',
       }, {
-        name: '套餐包名称',
+        name: '标签类型名称',
         field: 'name',
       }],
     };
@@ -117,41 +112,32 @@ export default class PackageListPage extends Component {
       totalSize,
     };
     const columns = [{
-      title: '套餐包编号',
+      title: '标签类型编号',
       key: 1,
       dataIndex: 'code',
-      width: '20%',
+      width: '25%',
     }, {
-      title: '套餐包名称',
+      title: '标签类型名称',
       key: 2,
       dataIndex: 'name',
-      render: text => (
-        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
-      ),
       width: '25%',
     }, {
-      title: '上架渠道',
+      title: '标签类型状态',
       key: 3,
-      dataIndex: 'merchantName',
-      width: '14%',
-    }, {
-      title: '上架状态',
-      key: 4,
       dataIndex: 'status',
-      render: text => renderStatus(text, '已下架', '已上架'),
-      width: '10%',
+      render: text => renderStatus(text),
+      width: '15%',
     }, {
       title: '更新时间',
-      key: 5,
+      key: 4,
       dataIndex: 'gmtModified',
       render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
-      width: '17%',
+      width: '20%',
     }, {
       title: '操作',
-      key: 6,
-      dataIndex: 'operation',
+      key: 5,
       render: (_, record) => renderOperation(record),
-      width: '13%',
+      width: '15%',
       align: 'right',
     }];
     return (

+ 2 - 2
src/routes/Shelves/Course/index.js

@@ -5,7 +5,7 @@ import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
 import { getRoutes } from '../../../utils/utils';
 
 @connect()
-export default class Course extends Component {
+export default class TagType extends Component {
   render() {
     const { match, routerData } = this.props;
     const routes = getRoutes(match.path, routerData);
@@ -25,7 +25,7 @@ export default class Course extends Component {
               )
             )
           }
-          <Redirect exact from="/shelves/course" to="/shelves/course/list" />
+          <Redirect exact from="/frontend/tagType" to="/frontend/tagType/list" />
         </Switch>
       </PageHeaderLayout>
     );

+ 7 - 7
src/routes/Merchant/MerchantCreate.js

@@ -82,19 +82,19 @@ export default class MerchantCreatePage extends PureComponent {
       return match[1];
     }
     return false;
-  }
+  };
   cleanPageState = () => {
     this.props.dispatch({
       type: 'merchant/cleanItemState',
       payload: {},
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/merchant/list',
       state: this.props.location.state,
     }));
-  }
+  };
   handlePageSubmit = (e) => {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
@@ -118,7 +118,7 @@ export default class MerchantCreatePage extends PureComponent {
         }
       }
     });
-  }
+  };
 
   render() {
     const { submitting, merchant, form } = this.props;
@@ -126,7 +126,7 @@ export default class MerchantCreatePage extends PureComponent {
     const { currentItem } = merchant;
 
     // 是否可编辑
-    const isEditable = this.isEdit() ? true : false;
+    const isEditable = !!this.isEdit();
 
     return (
       <PageHeaderLayout>
@@ -135,7 +135,7 @@ export default class MerchantCreatePage extends PureComponent {
             <Form.Item label={fieldLabels.type} {...formItemLayout}>
               {getFieldDecorator('domain', {
                 rules: [{ required: true, message: '请选择商户类型!' }],
-                initialValue: currentItem.domain || DOMAIN_PJ,
+                initialValue: currentItem.domain || Hotax.DOMAIN_PJ,
               })(
                 <Radio.Group disabled={isEditable} className={styles.radio}>
                   {
@@ -196,7 +196,7 @@ export default class MerchantCreatePage extends PureComponent {
                   {
                     required: true, message: '请填写联系电话!',
                   }, {
-                    pattern: /^[1][3,4,5,7,8][0-9]{9}$/g, message: '请输入11位有效手机号!',
+                    pattern: /^[1][34578][0-9]{9}$/g, message: '请输入11位有效手机号!',
                   }],
                 initialValue: currentItem.mobile,
               })(

+ 56 - 15
src/routes/Product/Course/CourseCreate.js

@@ -173,7 +173,7 @@ export default class CourseItemCreatePage extends Component {
   };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
-      pathname: '/product/course',
+      pathname: '/product/course/list',
       state: this.props.location.state,
     }));
   };
@@ -254,11 +254,31 @@ export default class CourseItemCreatePage extends Component {
       dataIndex: 'code',
       key: 1,
       width: '20%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/lesson/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '课名称',
       dataIndex: 'title',
       key: 2,
       width: '30%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/lesson/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '状态',
       dataIndex: 'status',
@@ -270,11 +290,31 @@ export default class CourseItemCreatePage extends Component {
       dataIndex: 'code',
       key: 1,
       width: '20%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/support/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '配套名称',
       dataIndex: 'name',
       key: 2,
       width: '30%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/support/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '配套状态',
       dataIndex: 'status',
@@ -293,7 +333,7 @@ export default class CourseItemCreatePage extends Component {
     const getResourceModal = (isCover) => {
       return (
         <Modal
-          width={900}
+          width={1100}
           footer={null}
           visible
           title="图片资源"
@@ -329,6 +369,7 @@ export default class CourseItemCreatePage extends Component {
             multiple
             loading={lLoading}
             selectorName="Lesson"
+            selectedRows={subItemList}
             list={lesson.list}
             pageNo={lesson.pageNo}
             pageSize={lesson.pageSize}
@@ -354,6 +395,7 @@ export default class CourseItemCreatePage extends Component {
             multiple
             loading={pLoading}
             selectorName="Support"
+            selectedRows={supportList}
             list={product.list}
             pageNo={product.pageNo}
             pageSize={product.pageSize}
@@ -418,10 +460,7 @@ export default class CourseItemCreatePage extends Component {
                 ],
                 initialValue: code,
               })(
-                <Input
-                  placeholder="请输入"
-                  disabled={!!this.isEdit()}
-                />
+                <Input placeholder="请输入" />
               )}
             </Form.Item>
             {this.isEdit() && (
@@ -429,7 +468,7 @@ export default class CourseItemCreatePage extends Component {
                 {getFieldDecorator('name', {
                   initialValue: name,
                 })(
-                  <Input disabled />
+                  <Input placeholder="根据标题及副标题自动生成完整名称,不必填写" disabled />
                 )}
               </Form.Item>
             )}
@@ -468,7 +507,7 @@ export default class CourseItemCreatePage extends Component {
                       <Select.Option key={item.key} value={item.key}>
                         {item.text}
                       </Select.Option>
-))
+                    ))
                   }
                 </Select>
               )}
@@ -513,11 +552,13 @@ export default class CourseItemCreatePage extends Component {
                 hoverable
                 title={renderCoverCardName()}
               >
-                {coverUrl && (
-                <div className={styles.cover}>
-                  <img src={genAbsolutePicUrl(coverUrl)} alt="" />
-                </div>
-)}
+                {
+                  coverUrl && (
+                    <div className={styles.cover}>
+                      <img src={genAbsolutePicUrl(coverUrl)} alt="" />
+                    </div>
+                  )
+                }
                 {!coverSelectorDestroy && getResourceModal(true)}
               </Card>
             </Col>
@@ -530,14 +571,14 @@ export default class CourseItemCreatePage extends Component {
               <Card
                 hoverable
                 title={renderbgCardName()}
-                cover={
+              >
+                {
                   bgUrl ? (
                     <div className={styles.background}>
                       <img src={genAbsolutePicUrl(bgUrl)} alt="" />
                     </div>
                   ) : null
                 }
-              >
                 {!bgSelectorDestroy && getResourceModal(false)}
               </Card>
             </Col>

+ 52 - 37
src/routes/Product/Courseware/CoursewareCreate.js

@@ -3,17 +3,18 @@ import pathToRegexp from 'path-to-regexp';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Form, Modal, Card, Button, Input, Radio, Switch } from 'antd';
-import AXVideoPlayer from '../../../components/AXVideoPlayer/index';
-import AXDragSortTable from '../../../components/AXDragSortTable/index';
+import AXDragSortTable from '../../../components/AXDragSortTable';
 import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar/index';
-import { Hotax } from '../../../utils/config';
+import AXVideoPlayer from '../../../components/AXVideoPlayer';
+import FooterToolbar from '../../../components/FooterToolbar';
 import {
   genAbsolutePicUrl,
   renderStatus,
   statusToBool,
   boolToStatus,
+  getResourceTypeName,
 } from '../../../utils/utils';
+import { Hotax } from '../../../utils/config';
 import styles from './CoursewareCreate.less';
 
 const fieldLabels = {
@@ -52,7 +53,10 @@ export default class CoursewareCreatePage extends Component {
     // 进入页面前清空下model中state内容,防止上次内容造成干扰
     const match = pathToRegexp('/product/courseware/create').exec(this.props.location.pathname);
     if (match) {
-      this.cleanPageState();
+      this.props.dispatch({
+        type: 'courseware/cleanItemState',
+        payload: {},
+      });
     }
   }
   componentDidMount() {
@@ -73,12 +77,6 @@ export default class CoursewareCreatePage extends Component {
     }
     return false;
   };
-  cleanPageState = () => {
-    this.props.dispatch({
-      type: 'courseware/cleanItemState',
-      payload: {},
-    });
-  };
   selectorDataFetcher = (params) => {
     const { resourceType } = this.state;
     if (resourceType === 'Picture') {
@@ -121,6 +119,10 @@ export default class CoursewareCreatePage extends Component {
     this.setState({
       resourceType: e.target.value,
     }, () => this.selectorDataFetcher());
+    this.props.dispatch({
+      type: 'courseware/fixResourceList',
+      payload: [],
+    });
   };
   handleDragSortTableChange = (rows) => {
     this.props.dispatch({
@@ -130,7 +132,7 @@ export default class CoursewareCreatePage extends Component {
   };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
-      pathname: '/product/courseware',
+      pathname: '/product/courseware/list',
       state: this.props.location.state,
     }));
   };
@@ -145,7 +147,7 @@ export default class CoursewareCreatePage extends Component {
         const { resourceList } = currentItem;
 
         let resourceIdList;
-        if (resourceIdList) {
+        if (resourceList) {
           resourceIdList = resourceList.map(item => item.id);
         }
 
@@ -184,15 +186,32 @@ export default class CoursewareCreatePage extends Component {
     const { code, title, digest, category, status, resourceList = [] } = currentItem;
 
     const imageColumns = [{
-      title: '图',
+      title: '缩略图',
       dataIndex: 'path',
       key: 1,
-      render: text => (
-        <div className={styles.picture}>
-          <img src={genAbsolutePicUrl(text)} alt="" />
-        </div>
-      ),
+      render: (text, record) => {
+        const { type, url, format } = record;
+        if (type === Hotax.RESOURCE_IMAGE) {
+          return (
+            <div className={styles.picture}>
+              <img src={genAbsolutePicUrl(text)} alt="" />
+            </div>
+          );
+        } else {
+          return (
+            <div className={styles.video}>
+              <AXVideoPlayer
+                width="100%"
+                height="100%"
+                url={url}
+                isM3U8={format === 'm3u8'}
+              />
+            </div>
+          );
+        }
+      },
       width: '10%',
+      align: 'center',
     }, {
       title: '编号',
       dataIndex: 'code',
@@ -202,16 +221,25 @@ export default class CoursewareCreatePage extends Component {
       title: '名称',
       dataIndex: 'name',
       key: 3,
-      width: '30%',
+      width: '20%',
+    }, {
+      title: '类型',
+      dataIndex: 'type',
+      key: 4,
+      width: '10%',
+      render: text => getResourceTypeName(text),
+      align: 'center',
     }, {
       title: '格式',
       dataIndex: 'format',
-      key: 4,
+      key: 5,
+      align: 'center',
     }, {
       title: '状态',
       dataIndex: 'status',
-      key: 5,
+      key: 6,
       render: text => renderStatus(text),
+      align: 'center',
     }];
 
     const renderCardName = () => {
@@ -228,7 +256,6 @@ export default class CoursewareCreatePage extends Component {
         <Radio.Group
           value={resourceType}
           onChange={this.handleRadioChange}
-          className={styles.radio}
         >
           <Radio.Button value="Picture">图片</Radio.Button>
           <Radio.Button value="Video">视频</Radio.Button>
@@ -241,18 +268,6 @@ export default class CoursewareCreatePage extends Component {
         return (
           <h3 style={{ color: 'red' }}>你还未选择任何资源,请点击上方资源列表进行选择</h3>
         );
-      } else if (resourceList[0].type === Hotax.RESOURCE_VIDEO) {
-        const videoItem = resourceList[0];
-        return (
-          <div className={styles.video}>
-            <AXVideoPlayer
-              width="100%"
-              height="100%"
-              url={videoItem.url}
-              isM3U8={videoItem.format === 'm3u8'}
-            />
-          </div>
-        );
       } else {
         return (
           <AXDragSortTable
@@ -279,8 +294,7 @@ export default class CoursewareCreatePage extends Component {
                 initialValue: code,
               })(
                 <Input
-                  placeholder="请输入(课件一旦创建完成,编号不可修改)"
-                  disabled={!!this.isEdit()}
+                  placeholder="请输入"
                 />
               )}
             </Form.Item>
@@ -338,6 +352,7 @@ export default class CoursewareCreatePage extends Component {
                 pageNo={resource.pageNo}
                 pageSize={resource.pageSize}
                 totalSize={resource.totalSize}
+                selectedRows={resourceList}
                 onCancel={this.handleSelectorCancel}
                 onChange={this.handleSelectorChange}
                 onFinish={this.handleSelectorFinish}

+ 2 - 11
src/routes/Product/Courseware/CoursewareCreate.less

@@ -30,16 +30,7 @@
 }
 
 .video {
-  width: 600px;
-  height: 340px;
+  width: 100px;
+  height: 80px;
   text-align: center;
 }
-
-.radio {
-  :global {
-    .ant-radio-button-wrapper-checked {
-      background-color: @primary-color;
-      color: #fff;
-    }
-  }
-}

+ 16 - 9
src/routes/Product/Courseware/CoursewareList.js

@@ -3,7 +3,8 @@ import moment from 'moment';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Card, Modal, Button, message } from 'antd';
-import { StandardTableList } from '../../../components/AXList/index';
+import Ellipsis from '../../../components/Ellipsis';
+import { StandardTableList } from '../../../components/AXList';
 import { renderStatus, addRowKey } from '../../../utils/utils';
 
 const Message = message;
@@ -32,7 +33,7 @@ export default class CoursewareListPage extends Component {
       pathname: '/product/courseware/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
@@ -47,13 +48,13 @@ export default class CoursewareListPage extends Component {
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/product/courseware/edit/${item.id}`,
       state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'courseware/fetchCoursewareList',
@@ -63,10 +64,10 @@ export default class CoursewareListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, courseware } = this.props;
@@ -100,11 +101,11 @@ export default class CoursewareListPage extends Component {
     }];
     const basicSearch = {
       keys: [{
-        name: '课件编号',
-        field: 'code',
-      }, {
         name: '课件名称',
         field: 'name',
+      }, {
+        name: '课件编号',
+        field: 'code',
       }],
     };
     const pagination = {
@@ -117,11 +118,17 @@ export default class CoursewareListPage extends Component {
       key: 1,
       dataIndex: 'code',
       width: '25%',
+      render: text => (
+        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
+      ),
     }, {
       title: '课件名称',
       key: 2,
       dataIndex: 'title',
       width: '30%',
+      render: text => (
+        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
+      ),
     }, {
       title: '课件状态',
       key: 3,

+ 43 - 25
src/routes/Product/Lesson/LessonCreate.js

@@ -60,30 +60,30 @@ export default class LessonCreatePage extends Component {
       return match[1];
     }
     return false;
-  }
+  };
   cleanPageState = () => {
     this.props.dispatch({
       type: 'lesson/cleanItemState',
       payload: {},
     });
-  }
+  };
   selectorDataFetcher = (params) => {
     this.props.dispatch({
       type: 'courseware/fetchCoursewareList',
       payload: params,
     });
-  }
+  };
   handleSelectorModalShow = () => {
     this.setState({
       modalSelectorDestroy: false,
     });
     this.selectorDataFetcher();
-  }
+  };
   handleSelectorCancel = () => {
     this.setState({
       modalSelectorDestroy: true,
     });
-  }
+  };
   handleSelectorFinish = (rows) => {
     this.setState({
       modalSelectorDestroy: true,
@@ -92,29 +92,29 @@ export default class LessonCreatePage extends Component {
       type: 'lesson/fixCoursewareList',
       payload: rows,
     });
-  }
+  };
   handleSelectorChange = (params) => {
     this.selectorDataFetcher(params);
-  }
+  };
   handleDragSortTableChange = (rows) => {
     this.props.dispatch({
       type: 'lesson/fixCoursewareList',
       payload: rows,
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
-      pathname: '/product/lesson',
+      pathname: '/product/lesson/list',
       state: this.props.location.state,
     }));
-  }
+  };
   handlePageSubmit = (e) => {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
         // 从表单中提取相关字段
         const { status, ...rest } = values;
-        values = { status: boolToStatus(status), ...rest };
+        const newVals = { status: boolToStatus(status), ...rest };
         const { lesson } = this.props;
         const { currentItem } = lesson;
         const { wareList } = currentItem;
@@ -130,7 +130,7 @@ export default class LessonCreatePage extends Component {
           const params = {
             id: matchId,
             wareList: wareIdList,
-            ...values,
+            ...newVals,
           };
           this.props.dispatch({
             type: 'lesson/updateLessonItem',
@@ -140,7 +140,7 @@ export default class LessonCreatePage extends Component {
         } else {
           const params = {
             wareList: wareIdList,
-            ...values,
+            ...newVals,
           };
           this.props.dispatch({
             type: 'lesson/createLessonItem',
@@ -150,7 +150,7 @@ export default class LessonCreatePage extends Component {
         }
       }
     });
-  }
+  };
 
   render() {
     const { submitting, lesson, form, loading, courseware } = this.props;
@@ -165,16 +165,36 @@ export default class LessonCreatePage extends Component {
       dataIndex: 'code',
       key: 1,
       width: '20%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/courseware/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '名称',
       dataIndex: 'title',
       key: 2,
       width: '30%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/courseware/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '状态',
       dataIndex: 'status',
       key: 3,
-      render: (text) => renderStatus(text),
+      render: text => renderStatus(text),
     }];
 
     const renderCardName = () => {
@@ -185,10 +205,10 @@ export default class LessonCreatePage extends Component {
           </span>
         </div>
       );
-    }
+    };
     return (
       <div>
-        <Card title="基础信息" style={{marginBottom: 16}}>
+        <Card title="基础信息" style={{ marginBottom: 16 }}>
           <Form>
             <Form.Item hasFeedback label={fieldLabels.code} {...formItemLayout}>
               {getFieldDecorator('code', {
@@ -197,14 +217,11 @@ export default class LessonCreatePage extends Component {
                     required: true, message: '请填写课编号',
                   }, {
                     pattern: /^[a-zA-Z0-9|-]+$/g, message: '编号包含非法字符',
-                  }
+                  },
                 ],
                 initialValue: code,
               })(
-                <Input
-                  placeholder="请输入(课一旦创建完成,编号不可修改)"
-                  disabled={this.isEdit() ? true : false}
-                />
+                <Input placeholder="请输入" />
               )}
             </Form.Item>
             <Form.Item hasFeedback label={fieldLabels.title} {...formItemLayout}>
@@ -235,13 +252,13 @@ export default class LessonCreatePage extends Component {
             </Form.Item>
           </Form>
         </Card>
-        <Card title={renderCardName()} style={{marginBottom: 70}}>
+        <Card title={renderCardName()} style={{ marginBottom: 70 }}>
           <AXDragSortTable
             columns={coursewareColumns}
             data={wareList}
             onChange={this.handleDragSortTableChange}
           />
-          {!modalSelectorDestroy &&
+          {!modalSelectorDestroy && (
             <Modal
               visible
               width={1100}
@@ -258,12 +275,13 @@ export default class LessonCreatePage extends Component {
                 pageSize={pageSize}
                 totalSize={totalSize}
                 selectorName="Courseware"
+                selectedRows={wareList}
                 onChange={this.handleSelectorChange}
                 onCancel={this.handleSelectorCancel}
                 onFinish={this.handleSelectorFinish}
               />
             </Modal>
-          }
+          )}
         </Card>
         <FooterToolbar style={{ width: '100%' }}>
           <Button

+ 16 - 9
src/routes/Product/Lesson/LessonList.js

@@ -3,7 +3,8 @@ import moment from 'moment';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Card, Modal, Button, message } from 'antd';
-import { StandardTableList } from '../../../components/AXList/index';
+import Ellipsis from '../../../components/Ellipsis';
+import { StandardTableList } from '../../../components/AXList';
 import { renderStatus, addRowKey } from '../../../utils/utils';
 
 const Message = message;
@@ -32,7 +33,7 @@ export default class LessonListPage extends Component {
       pathname: '/product/lesson/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
@@ -47,13 +48,13 @@ export default class LessonListPage extends Component {
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/product/lesson/edit/${item.id}`,
       state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'lesson/fetchLessonList',
@@ -63,10 +64,10 @@ export default class LessonListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, lesson } = this.props;
@@ -100,11 +101,11 @@ export default class LessonListPage extends Component {
     }];
     const basicSearch = {
       keys: [{
-        name: '课编号',
-        field: 'code',
-      }, {
         name: '课名称',
         field: 'name',
+      }, {
+        name: '课编号',
+        field: 'code',
       }],
     };
     const pagination = {
@@ -117,11 +118,17 @@ export default class LessonListPage extends Component {
       key: 1,
       dataIndex: 'code',
       width: '25%',
+      render: text => (
+        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
+      ),
     }, {
       title: '课名称',
       key: 2,
       dataIndex: 'title',
       width: '30%',
+      render: text => (
+        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
+      ),
     }, {
       title: '课状态',
       key: 3,

+ 70 - 52
src/routes/Product/Package/PackageCreate.js

@@ -1,11 +1,12 @@
+/* eslint-disable guard-for-in */
 import React, { Component } from 'react';
 import pathToRegexp from 'path-to-regexp';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
-import { message, Form, Modal, Card, Button, Input, InputNumber, Table, Switch, Select, Radio } from 'antd';
+import { message, Form, Modal, Card, Button, Input, InputNumber, Table, Switch, Radio } from 'antd';
 import { renderProductType, statusToBool, boolToStatus, addRowKey } from '../../../utils/utils';
 import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar/index';
+import FooterToolbar from '../../../components/FooterToolbar';
 import styles from './PackageCreate.less';
 
 const Message = message;
@@ -27,7 +28,7 @@ const formItemLayout = {
   },
 };
 
-@connect(({loading, product}) => ({
+@connect(({ loading, product }) => ({
   product,
   pLoading: loading.models.product,
 }))
@@ -59,13 +60,13 @@ export default class PackageCreatePage extends Component {
       return match[1];
     }
     return false;
-  }
+  };
   cleanPageState = () => {
     this.props.dispatch({
       type: 'product/cleanItemState',
       payload: {},
     });
-  }
+  };
   selectorDataFetcher = (name, params) => {
     switch (name) {
       case 'Course':
@@ -73,33 +74,35 @@ export default class PackageCreatePage extends Component {
           type: 'product/fetchCourseList',
           payload: params,
         });
-        return;
+        break;
       case 'Support':
         this.props.dispatch({
           type: 'product/fetchSupportList',
           payload: params,
         });
-        return;
+        break;
+      default:
+        break;
     }
-  }
+  };
   handleRadioChange = (e) => {
     this.setState({
       productType: e.target.value,
     });
     this.selectorDataFetcher(e.target.value);
-  }
+  };
   handleSelectorModalShow = () => {
     this.setState({
       selectorModalDestroy: false,
     });
     this.selectorDataFetcher(this.state.productType);
-  }
+  };
   handleSelectorChange = (params) => {
     this.selectorDataFetcher(
       this.state.productType,
       params
     );
-  }
+  };
   handleSelectorFinish = (rows) => {
     this.setState({
       selectorModalDestroy: true,
@@ -110,75 +113,75 @@ export default class PackageCreatePage extends Component {
         products: rows,
       },
     });
-  }
+  };
   handleSelectorCancel = () => {
     this.setState({
       selectorModalDestroy: true,
     });
-  }
+  };
   handleDragSortTableChange = (rows) => {
     this.props.dispatch({
       type: 'product/fixCurrentItem',
       payload: {
-        products: rows
+        products: rows,
       },
     });
-  }
-  handlePriceInputChange  = (field, key, value) => {
+  };
+  handlePriceInputChange = (field, key, value) => {
     const { product } = this.props;
     const { currentItem } = product;
     const { products = [] } = currentItem;
-    let newData =[...products]
-    newData = newData.map(item => {
+    let newData = [...products];
+    newData = newData.map((item) => {
       if (item.id === key) {
         return {
           ...item,
           [`${field}Price`]: value,
         };
       } else {
-        return {...item};
+        return { ...item };
       }
     });
     this.props.dispatch({
       type: 'product/fixCurrentItem',
       payload: {
-        products: newData
-      }
+        products: newData,
+      },
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/product/package',
       state: this.props.location.state,
     }));
-  }
+  };
   handlePageSubmit = (e) => {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
         // 表单字段处理
         const { status, ...rest } = values;
-        values = { status: boolToStatus(status), ...rest };
+        const newVals = { status: boolToStatus(status), ...rest };
 
         // products字段处理
         const { product } = this.props;
         const { currentItem } = product;
         const { products } = currentItem;
-        let productList = [];
+        const productList = [];
         let submittable = true;
         if (products) {
-          for (let index in products) {
-            let product = products[index];
-            if (!product.cpPrice || !product.merchantPrice) {
+          for (const index in products) {
+            const productItem = products[index];
+            if (!productItem.cpPrice || !productItem.merchantPrice) {
               Message.error('还有价格未填写!');
               submittable = false;
               break;
             }
             productList.push({
-              pid: product.pid,
-              type: product.type,
-              cpPrice: product.cpPrice,
-              merchantPrice: product.merchantPrice,
+              pid: productItem.pid,
+              type: productItem.type,
+              cpPrice: productItem.cpPrice,
+              merchantPrice: productItem.merchantPrice,
             });
           }
         }
@@ -193,7 +196,7 @@ export default class PackageCreatePage extends Component {
           const params = {
             id: matchId,
             products: productList,
-            ...values,
+            ...newVals,
           };
           this.props.dispatch({
             type: 'product/updatePackageItem',
@@ -203,7 +206,7 @@ export default class PackageCreatePage extends Component {
         } else {
           const params = {
             products: productList,
-            ...values,
+            ...newVals,
           };
           this.props.dispatch({
             type: 'product/createPackageItem',
@@ -213,7 +216,7 @@ export default class PackageCreatePage extends Component {
         }
       }
     });
-  }
+  };
 
   render() {
     const { form, pLoading, product } = this.props;
@@ -234,28 +237,47 @@ export default class PackageCreatePage extends Component {
       dataIndex: 'code',
       key: 1,
       width: '22%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/${record.type.toLowerCase()}/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '产品名称',
       dataIndex: 'name',
       key: 2,
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/${record.type.toLowerCase()}/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '产品类型',
       dataIndex: 'type',
       key: 3,
       align: 'center',
-      render: (text) => renderProductType(text),
+      render: text => renderProductType(text),
       width: '10%',
     }, {
       title: '供应商价格(¥)',
       dataIndex: 'cpPrice',
       key: 4,
-      align: 'center',
       render: (text, record) => (
         <InputNumber
           min={0}
           value={text}
-          style={{width: '100%'}}
-          onChange={(value) => this.handlePriceInputChange('cp', record.key, value)}
+          style={{ width: '100%' }}
+          onChange={value => this.handlePriceInputChange('cp', record.key, value)}
         />
       ),
       width: '15%',
@@ -263,13 +285,12 @@ export default class PackageCreatePage extends Component {
       title: '平台方价格(¥)',
       dataIndex: 'merchantPrice',
       key: 5,
-      align: 'center',
       render: (text, record) => (
         <InputNumber
           min={0}
           value={text}
-          style={{width: '100%'}}
-          onChange={(value) => this.handlePriceInputChange('merchant', record.key, value)}
+          style={{ width: '100%' }}
+          onChange={value => this.handlePriceInputChange('merchant', record.key, value)}
         />
       ),
       width: '15%',
@@ -283,7 +304,7 @@ export default class PackageCreatePage extends Component {
           </span>
         </div>
       );
-    }
+    };
     const renderModalTitle = () => {
       return (
         <Radio.Group
@@ -295,7 +316,7 @@ export default class PackageCreatePage extends Component {
           <Radio.Button value="Support">配套</Radio.Button>
         </Radio.Group>
       );
-    }
+    };
 
     const getProductModal = () => {
       return (
@@ -322,11 +343,11 @@ export default class PackageCreatePage extends Component {
           />
         </Modal>
       );
-    }
+    };
     return (
       <div>
         {/* 基础信息Card */}
-        <Card title="基础信息" style={{marginBottom: 16}}>
+        <Card title="基础信息" style={{ marginBottom: 16 }}>
           <Form>
             <Form.Item hasFeedback label={fieldLabels.code} {...formItemLayout}>
               {getFieldDecorator('code', {
@@ -335,14 +356,11 @@ export default class PackageCreatePage extends Component {
                     required: true, message: '请填写套餐包编号',
                   }, {
                     pattern: /^[a-zA-Z0-9|-]+$/g, message: '编号包含非法字符',
-                  }
+                  },
                 ],
                 initialValue: code,
               })(
-                <Input
-                  placeholder="请输入"
-                  disabled={this.isEdit() ? true : false}
-                />
+                <Input placeholder="请输入" />
               )}
             </Form.Item>
             <Form.Item hasFeedback label={fieldLabels.name} {...formItemLayout}>
@@ -366,7 +384,7 @@ export default class PackageCreatePage extends Component {
             </Form.Item>
           </Form>
         </Card>
-        <Card title={renderCardName()} style={{marginBottom: 70}}>
+        <Card title={renderCardName()} style={{ marginBottom: 70 }}>
           <Table
             bordered
             pagination={false}

+ 5 - 5
src/routes/Product/Package/PackageList.js

@@ -32,7 +32,7 @@ export default class PackageListPage extends Component {
       pathname: '/product/package/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
@@ -46,13 +46,13 @@ export default class PackageListPage extends Component {
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/product/package/edit/${item.pid}`,
       state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'product/fetchPackageList',
@@ -62,10 +62,10 @@ export default class PackageListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, product } = this.props;

+ 92 - 88
src/routes/Product/Support/SupportCreate.js

@@ -4,9 +4,9 @@ import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Form, Modal, Card, Button, Input, Switch, Row, Col, Carousel, Select } from 'antd';
 import { renderStatus, statusToBool, boolToStatus, genAbsolutePicUrl } from '../../../utils/utils';
-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 styles from './SupportCreate.less';
 
 const fieldLabels = {
@@ -33,7 +33,7 @@ const formItemLayout = {
   },
 };
 
-@connect(({loading, product, resource, merchant}) => ({
+@connect(({ loading, product, resource, merchant }) => ({
   product,
   resource,
   merchant,
@@ -64,7 +64,7 @@ export default class SupportCreatePage extends Component {
     }
     this.props.dispatch({
       type: 'merchant/fetchMerchantList',
-      payload: {pageSize: 1000}, // TODO 以后商户多了需要改写交互样式
+      payload: { pageSize: 1000 }, // TODO 以后商户多了需要改写交互样式
     });
   }
   isEdit = () => {
@@ -74,13 +74,13 @@ export default class SupportCreatePage extends Component {
       return match[1];
     }
     return false;
-  }
+  };
   cleanPageState = () => {
     this.props.dispatch({
       type: 'product/cleanItemState',
       payload: {},
     });
-  }
+  };
   selectorDataFetcher = (name, params) => {
     switch (name) {
       case 'cover':
@@ -88,45 +88,49 @@ export default class SupportCreatePage extends Component {
           type: 'resource/fetchImageList',
           payload: params,
         });
-        return;
+        break;
       case 'carousel':
         this.props.dispatch({
           type: 'resource/fetchImageList',
           payload: params,
         });
-        return;
+        break;
       case 'support':
         this.props.dispatch({
           type: 'product/fetchSupportList',
           payload: params,
         });
-        return;
+        break;
+      default:
+        break;
     }
-  }
+  };
   currentItemFormatter = (name, rows) => {
     let payload;
     switch (name) {
       case 'cover':
-        payload = {coverUrl: rows[0].path};
+        payload = { coverUrl: rows[0].path };
         break;
       case 'carousel':
-        payload = {imgList: rows.map(row => row.path)};
+        payload = { imgList: rows.map(row => row.path) };
         break;
       case 'support':
-        payload = {supportList: rows};
+        payload = { supportList: rows };
+        break;
+      default:
         break;
     }
     return payload;
-  }
+  };
   handleSelectorModalShow = (name) => {
     this.setState({
       [`${name}SelectorDestroy`]: false,
     });
     this.selectorDataFetcher(name);
-  }
+  };
   handleSelectorChange = (name, params) => {
     this.selectorDataFetcher(name, params);
-  }
+  };
   handleSelectorFinish = (name, rows) => {
     this.setState({
       [`${name}SelectorDestroy`]: true,
@@ -136,33 +140,33 @@ export default class SupportCreatePage extends Component {
       payload,
       type: 'product/fixCurrentItem',
     });
-  }
+  };
   handleDragSortTableChange = (name, rows) => {
     const payload = this.currentItemFormatter(name, rows);
     this.props.dispatch({
       payload,
       type: 'product/fixCurrentItem',
     });
-  }
+  };
   handleSelectorCancel = (name) => {
     this.setState({
       [`${name}SelectorDestroy`]: true,
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
-      pathname: '/product/support',
+      pathname: '/product/support/list',
       state: this.props.location.state,
     }));
-  }
+  };
   handlePageSubmit = (e) => {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
         // 从表单提取基础信息字段
-        let { status, title, subTitle, name, ...rest } = values;
-        name = `${title}_${subTitle}`;
-        values = { name, title, subTitle, status: boolToStatus(status), ...rest };
+        const { status, title, subTitle, name, ...rest } = values;
+        const newName = `${title}_${subTitle}`;
+        const newVals = { newName, title, subTitle, status: boolToStatus(status), ...rest };
 
         // 从props中提取coverUrl、imgList、supportList字段
         const { product } = this.props;
@@ -183,7 +187,7 @@ export default class SupportCreatePage extends Component {
             coverUrl,
             supportList: supportIdList,
             id: matchId,
-            ...values,
+            ...newVals,
           };
           this.props.dispatch({
             type: 'product/updateSupportItem',
@@ -195,7 +199,7 @@ export default class SupportCreatePage extends Component {
             imgList,
             coverUrl,
             supportList: supportIdList,
-            ...values,
+            ...newVals,
           };
           this.props.dispatch({
             type: 'product/createSupportItem',
@@ -205,74 +209,77 @@ export default class SupportCreatePage extends Component {
         }
       }
     });
-  }
+  };
 
   render() {
     const {
-      form, submitting, rLoading, pLoading, product, resource, merchant
+      form, submitting, rLoading, pLoading, product, resource, merchant,
     } = this.props;
     const {
       supportSelectorDestroy, coverSelectorDestroy, carouselSelectorDestroy,
     } = this.state;
     const {
-      currentItem
+      currentItem,
     } = product;
     const {
       code, title, subTitle, name, digest, detail, status, coverUrl, cpId,
       imgList = [], supportList = [],
     } = currentItem;
     const {
-      getFieldDecorator
+      getFieldDecorator,
     } = form;
 
-    const lessonColumns = [{
-      title: '课编号',
-      dataIndex: 'code',
-      key: 1,
-      width: '20%',
-    }, {
-      title: '课名称',
-      dataIndex: 'title',
-      key: 2,
-      width: '30%',
-    }, {
-      title: '状态',
-      dataIndex: 'status',
-      key: 3,
-      render: (text) => renderStatus(text),
-    }];
     const supportColumns = [{
       title: '配套编号',
       dataIndex: 'code',
       key: 1,
       width: '20%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/support/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '配套名称',
       dataIndex: 'name',
       key: 2,
       width: '30%',
+      render: (text, record) => (
+        <a
+          className="a-link"
+          target="_blank"
+          rel="noopener noreferrer"
+          href={`/product/support/edit/${record.id}`}
+        >
+          {text}
+        </a>
+      ),
     }, {
       title: '配套状态',
       dataIndex: 'status',
       key: 3,
-      render: (text) => renderStatus(text),
+      render: text => renderStatus(text),
     }];
 
     const getMerchants = () => {
-      let { list } = merchant;
-      let options = list.map(item => ({
+      const { list } = merchant;
+      return list.map(item => ({
         text: item.name,
         key: item.id,
       }));
-      return options;
-    }
+    };
 
     const getResourceModal = (isCover) => {
       return (
         <Modal
           width={isCover ? 900 : 1100}
           footer={null}
-          visible={true}
+          visible
           title="图片资源"
           maskClosable={false}
           onCancel={() => this.handleSelectorCancel(isCover ? 'cover' : 'carousel')}
@@ -283,27 +290,27 @@ export default class SupportCreatePage extends Component {
             pageNo={resource.pageNo}
             pageSize={resource.pageSize}
             totalSize={resource.totalSize}
-            multiple={isCover ? false : true}
+            multiple={!isCover}
             selectorName={isCover ? 'PictureSingle' : 'Index'}
             onCancel={() => this.handleSelectorCancel(isCover ? 'cover' : 'carousel')}
-            onChange={(data) => this.handleSelectorChange(isCover ? 'cover' : 'carousel', data)}
-            onFinish={(rows) => this.handleSelectorFinish(isCover ? 'cover' : 'carousel', rows)}
+            onChange={data => this.handleSelectorChange(isCover ? 'cover' : 'carousel', data)}
+            onFinish={rows => this.handleSelectorFinish(isCover ? 'cover' : 'carousel', rows)}
           />
         </Modal>
       );
-    }
+    };
     const getSupportModal = () => {
       return (
         <Modal
           width={1100}
           footer={null}
-          visible={true}
+          visible
           title="配套资源"
           maskClosable={false}
           onCancel={() => this.handleSelectorCancel('support')}
         >
           <Selector
-            multiple={true}
+            multiple
             loading={pLoading}
             selectorName="Support"
             list={product.list}
@@ -311,12 +318,12 @@ export default class SupportCreatePage extends Component {
             pageSize={product.pageSize}
             totalSize={product.totalSize}
             onCancel={() => this.handleSelectorCancel('support')}
-            onChange={(data) => this.handleSelectorChange('support', data)}
-            onFinish={(rows) => this.handleSelectorFinish('support', rows)}
+            onChange={data => this.handleSelectorChange('support', data)}
+            onFinish={rows => this.handleSelectorFinish('support', rows)}
           />
         </Modal>
       );
-    }
+    };
 
     const renderSupportCardName = () => {
       return (
@@ -326,7 +333,7 @@ export default class SupportCreatePage extends Component {
           </span>
         </div>
       );
-    }
+    };
     const renderCoverCardName = () => {
       return (
         <div className={styles.cardName}>
@@ -335,7 +342,7 @@ export default class SupportCreatePage extends Component {
           </span>
         </div>
       );
-    }
+    };
     const renderCarouselCardName = () => {
       return (
         <div className={styles.cardName}>
@@ -344,11 +351,11 @@ export default class SupportCreatePage extends Component {
           </span>
         </div>
       );
-    }
+    };
     return (
       <div>
         {/* 基础信息Card */}
-        <Card title="基础信息" style={{marginBottom: 16}}>
+        <Card title="基础信息" style={{ marginBottom: 16 }}>
           <Form>
             <Form.Item hasFeedback label={fieldLabels.code} {...formItemLayout}>
               {getFieldDecorator('code', {
@@ -357,25 +364,22 @@ export default class SupportCreatePage extends Component {
                     required: true, message: '请填写配套编号',
                   }, {
                     pattern: /^[a-zA-Z0-9|-]+$/g, message: '编号包含非法字符',
-                  }
+                  },
                 ],
                 initialValue: code,
               })(
-                <Input
-                  placeholder="请输入"
-                  disabled={this.isEdit() ? true : false}
-                />
+                <Input placeholder="请输入" />
               )}
             </Form.Item>
-            {this.isEdit() &&
+            {this.isEdit() && (
               <Form.Item label={fieldLabels.name} {...formItemLayout}>
                 {getFieldDecorator('name', {
                   initialValue: name,
                 })(
-                  <Input disabled={true} />
+                  <Input disabled />
                 )}
               </Form.Item>
-            }
+            )}
             <Form.Item hasFeedback label={fieldLabels.title} {...formItemLayout}>
               {getFieldDecorator('title', {
                 rules: [{ required: true, message: '请填写配套标题' }],
@@ -399,11 +403,11 @@ export default class SupportCreatePage extends Component {
               })(
                 <Select placeholder="请选择">
                   {
-                    getMerchants().map(item =>
+                    getMerchants().map(item => (
                       <Select.Option key={item.key} value={item.key}>
                         {item.text}
                       </Select.Option>
-                    )
+                    ))
                   }
                 </Select>
               )}
@@ -436,13 +440,13 @@ 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}}
-              lg={{span: 8, offset: 2}}
-              xl={{span: 6, offset: 4}}
-              xxl={{span: 4, offset: 5}}
+              md={{ span: 10, offset: 1 }}
+              lg={{ span: 8, offset: 2 }}
+              xl={{ span: 6, offset: 4 }}
+              xxl={{ span: 4, offset: 5 }}
             >
               <Card
                 hoverable
@@ -455,10 +459,10 @@ export default class SupportCreatePage extends Component {
               </Card>
             </Col>
             <Col
-              md={{span: 10, offset: 2}}
-              lg={{span: 8, offset: 4}}
-              xl={{span: 6, offset: 4}}
-              xxl={{span: 4, offset: 5}}
+              md={{ span: 10, offset: 2 }}
+              lg={{ span: 8, offset: 4 }}
+              xl={{ span: 6, offset: 4 }}
+              xxl={{ span: 4, offset: 5 }}
             >
               <Card
                 hoverable
@@ -468,8 +472,8 @@ export default class SupportCreatePage extends Component {
                   <Carousel autoplay>
                     {
                       imgList.map(
-                        (path,index) => (
-                          <img key={index} src={genAbsolutePicUrl(path)} alt="" />
+                        path => (
+                          <img key={path} src={genAbsolutePicUrl(path)} alt="" />
                         )
                       )
                     }
@@ -481,11 +485,11 @@ export default class SupportCreatePage extends Component {
           </Row>
         </Card>
         {/* 相关周边配套选择Card */}
-        <Card title={renderSupportCardName()} style={{marginBottom: 70}}>
+        <Card title={renderSupportCardName()} style={{ marginBottom: 70 }}>
           <AXDragSortTable
             columns={supportColumns}
             data={supportList}
-            onChange={(rows) => this.handleDragSortTableChange('support', rows)}
+            onChange={rows => this.handleDragSortTableChange('support', rows)}
           />
           {!supportSelectorDestroy && getSupportModal()}
         </Card>

+ 5 - 5
src/routes/Product/Support/SupportList.js

@@ -32,7 +32,7 @@ export default class SupportListPage extends Component {
       pathname: '/product/support/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
@@ -47,13 +47,13 @@ export default class SupportListPage extends Component {
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/product/support/edit/${item.pid}`,
       state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'product/fetchSupportList',
@@ -63,10 +63,10 @@ export default class SupportListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, product } = this.props;

+ 21 - 25
src/routes/Product/Training/TrainingCreate.js

@@ -7,7 +7,7 @@ import {
   Form, Modal, Card, Button, Input, Switch, Row, Col, Carousel, Select, DatePicker } from 'antd';
 import { statusToBool, boolToStatus, genAbsolutePicUrl } from '../../../utils/utils';
 import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar/index';
+import FooterToolbar from '../../../components/FooterToolbar';
 import styles from './TrainingCreate.less';
 
 const fieldLabels = {
@@ -63,7 +63,7 @@ export default class TrainingCreatePage extends Component {
     }
     this.props.dispatch({
       type: 'merchant/fetchMerchantList',
-      payload: {pageSize: 1000}, // TODO 以后商户多了需要改写交互样式
+      payload: { pageSize: 1000 }, // TODO 以后商户多了需要改写交互样式
     });
   }
   isEdit = () => {
@@ -73,13 +73,13 @@ export default class TrainingCreatePage extends Component {
       return match[1];
     }
     return false;
-  }
+  };
   cleanPageState = () => {
     this.props.dispatch({
       type: 'product/cleanItemState',
       payload: {},
     });
-  }
+  };
   selectorDataFetcher = (name, params) => {
     switch (name) {
       case 'cover':
@@ -97,7 +97,7 @@ export default class TrainingCreatePage extends Component {
       default:
         break;
     }
-  }
+  };
   currentItemFormatter = (name, rows) => {
     let payload;
     switch (name) {
@@ -111,16 +111,16 @@ export default class TrainingCreatePage extends Component {
         break;
     }
     return payload;
-  }
+  };
   handleSelectorModalShow = (name) => {
     this.setState({
       [`${name}SelectorDestroy`]: false,
     });
     this.selectorDataFetcher(name);
-  }
+  };
   handleSelectorChange = (name, params) => {
     this.selectorDataFetcher(name, params);
-  }
+  };
   handleSelectorFinish = (name, rows) => {
     this.setState({
       [`${name}SelectorDestroy`]: true,
@@ -130,18 +130,18 @@ export default class TrainingCreatePage extends Component {
       payload,
       type: 'product/fixCurrentItem',
     });
-  }
+  };
   handleSelectorCancel = (name) => {
     this.setState({
       [`${name}SelectorDestroy`]: true,
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/product/training',
       state: this.props.location.state,
     }));
-  }
+  };
   handlePageSubmit = (e) => {
     e.preventDefault();
     this.props.form.validateFieldsAndScroll((err, values) => {
@@ -189,7 +189,7 @@ export default class TrainingCreatePage extends Component {
         }
       }
     });
-  }
+  };
 
   render() {
     const { form, submitting, rLoading, product, resource, merchant } = this.props;
@@ -203,12 +203,11 @@ export default class TrainingCreatePage extends Component {
 
     const getMerchants = () => {
       const { list } = merchant;
-      const options = list.map(item => ({
+      return list.map(item => ({
         text: item.name,
         key: item.id,
       }));
-      return options;
-    }
+    };
 
     const getResourceModal = (isCover) => {
       return (
@@ -226,15 +225,15 @@ export default class TrainingCreatePage extends Component {
             pageNo={resource.pageNo}
             pageSize={resource.pageSize}
             totalSize={resource.totalSize}
-            multiple={isCover ? false : true}
+            multiple={!isCover}
             selectorName={isCover ? 'PictureSingle' : 'Picture'}
             onCancel={() => this.handleSelectorCancel(isCover ? 'cover' : 'carousel')}
-            onChange={(data) => this.handleSelectorChange(isCover ? 'cover' : 'carousel', data)}
-            onFinish={(rows) => this.handleSelectorFinish(isCover ? 'cover' : 'carousel', rows)}
+            onChange={data => this.handleSelectorChange(isCover ? 'cover' : 'carousel', data)}
+            onFinish={rows => this.handleSelectorFinish(isCover ? 'cover' : 'carousel', rows)}
           />
         </Modal>
       );
-    }
+    };
     const renderCoverCardName = () => {
       return (
         <div className={styles.cardName}>
@@ -243,7 +242,7 @@ export default class TrainingCreatePage extends Component {
           </span>
         </div>
       );
-    }
+    };
     const renderCarouselCardName = () => {
       return (
         <div className={styles.cardName}>
@@ -252,7 +251,7 @@ export default class TrainingCreatePage extends Component {
           </span>
         </div>
       );
-    }
+    };
     return (
       <div>
         {/* 基础信息Card */}
@@ -269,10 +268,7 @@ export default class TrainingCreatePage extends Component {
                 ],
                 initialValue: code,
               })(
-                <Input
-                  placeholder="请输入"
-                  disabled={this.isEdit() ? true : false}
-                />
+                <Input placeholder="请输入" />
               )}
             </Form.Item>
             <Form.Item hasFeedback label={fieldLabels.title} {...formItemLayout}>

+ 5 - 5
src/routes/Product/Training/TrainingList.js

@@ -32,7 +32,7 @@ export default class TrainingListPage extends Component {
       pathname: '/product/training/create',
       state: this.state,
     }));
-  }
+  };
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
@@ -46,13 +46,13 @@ export default class TrainingListPage extends Component {
         });
       },
     });
-  }
+  };
   handleEditOperation = (item) => {
     this.props.dispatch(routerRedux.push({
       pathname: `/product/training/edit/${item.pid}`,
       state: this.state,
     }));
-  }
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'product/fetchTrainingList',
@@ -62,10 +62,10 @@ export default class TrainingListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, product } = this.props;

+ 7 - 7
src/routes/Resource/Picture/PictureMultipleUpload.js

@@ -13,33 +13,33 @@ const Message = message;
 export default class PictureMultipleUpload extends PureComponent {
   state = {
     fileList: [],
-  }
+  };
 
   handleUploadSuccess = (fileList) => {
     this.setState({ fileList });
-  }
+  };
   handleOnRemove = (fileList) => {
     this.setState({ fileList });
-  }
+  };
   handleCodeInputChange = (index, e) => {
     const newFileList = [...this.state.fileList];
     newFileList[index].code = e.target.value;
     this.setState({
       fileList: newFileList,
     });
-  }
+  };
   handleNameInputChange = (index, e) => {
     const newFileList = [...this.state.fileList];
     newFileList[index].name = e.target.value;
     this.setState({
       fileList: newFileList,
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/resource/image',
     }));
-  }
+  };
   handlePageSubmit = () => {
     const { fileList } = this.state;
     let correct = true;
@@ -65,7 +65,7 @@ export default class PictureMultipleUpload extends PureComponent {
     } else {
       Message.error('还有图片编号或名称未指定!');
     }
-  }
+  };
 
   render() {
     const { fileList } = this.state;

+ 3 - 3
src/routes/Resource/Picture/PictureUploadResult.js

@@ -12,7 +12,7 @@ class PictureUploadSuccessResult extends Component {
         pathname: '/resource/picture',
       })
     );
-  }
+  };
   jumpToPictureDetailPage = (params) => {
     this.props.dispatch(
       routerRedux.push({
@@ -20,14 +20,14 @@ class PictureUploadSuccessResult extends Component {
         state: params,
       })
     );
-  }
+  };
   jumpToPictureSingleUpload = () => {
     this.props.dispatch(
       routerRedux.push({
         pathname: '/resource/picture-upload/single',
       })
     );
-  }
+  };
   render() {
     const { location } = this.props;
     const { state = {} } = location;

+ 1 - 1
src/routes/Resource/Video/VideoCreate.js

@@ -39,7 +39,7 @@ export default class VideoCreatePage extends PureComponent {
       return match[1];
     }
     return false;
-  }
+  };
   handlePageBack = () => {
     const { UIParams, Queryers } = this.props.location.state || {};
     this.props.dispatch(

+ 7 - 7
src/routes/Resource/Video/VideoPlayList.js

@@ -21,13 +21,13 @@ export default class VideoPlayList extends PureComponent {
   }
   handleOnRowClick = (index) => {
     this.setState({ currentPlayingIndex: index });
-  }
+  };
   handleSearchSelectChange = (value) => {
     this.setState({ searchSelectKey: value });
-  }
+  };
   handleInputChange = (e) => {
     this.setState({ searchInputValue: e.target.value });
-  }
+  };
   handleFilterOperation = (params) => {
     const { pageSize, pageNo, onFilterClick } = this.props;
     const { searchSelectKey, searchInputValue } = this.state;
@@ -37,22 +37,22 @@ export default class VideoPlayList extends PureComponent {
       [searchSelectKey]: searchInputValue,
       ...params,
     });
-  }
+  };
   handleSearchBtnClick = () => {
     this.handleFilterOperation();
-  }
+  };
   handleTablePageChange = (page, pageSize) => {
     this.handleFilterOperation({
       pageSize,
       pageNo: page,
     });
-  }
+  };
   handleTablePageSizeChange = (current, size) => {
     this.handleFilterOperation({
       pageSize: size,
       pageNo: current,
     });
-  }
+  };
 
   render() {
     const { dataSource, loading, totalSize, pageSize, pageNo } = this.props;

+ 19 - 19
src/routes/Resource/Video/VideoTableList.js

@@ -25,11 +25,11 @@ function VideoTableList({
   }];
   const basicSearch = {
     keys: [{
-      name: '视频编号',
-      field: 'code',
-    }, {
       name: '视频名称',
       field: 'name',
+    }, {
+      name: '视频编号',
+      field: 'code',
     }],
   };
   const columns = [{
@@ -116,22 +116,22 @@ function VideoTableList({
         footer={{ pagination, batchActions, onBatchClick }}
       />
       {!modalDestroy && (
-      <Modal
-        title={currentItem.name}
-        visible
-        footer={null}
-        onCancel={onModalDestroy}
-        maskClosable={false}
-        width={800}
-      >
-        <AXVideoPlayer
-          width="100%"
-          height="100%"
-          url={currentItem.url}
-          isM3U8={currentItem.format === 'm3u8'}
-        />
-      </Modal>
-)}
+        <Modal
+          title={currentItem.name}
+          visible
+          footer={null}
+          onCancel={onModalDestroy}
+          maskClosable={false}
+          width={800}
+        >
+          <AXVideoPlayer
+            width="100%"
+            height="100%"
+            url={currentItem.url}
+            isM3U8={currentItem.format === 'm3u8'}
+          />
+        </Modal>
+      )}
     </div>
   );
 }

+ 0 - 37
src/routes/Result/Error.js

@@ -1,37 +0,0 @@
-import React, { Fragment } from 'react';
-import { Button, Icon, Card } from 'antd';
-import Result from '../../components/Result';
-import PageHeaderLayout from '../../layouts/PageHeaderLayout';
-
-const extra = (
-  <Fragment>
-    <div style={{ fontSize: 16, color: 'rgba(0, 0, 0, 0.85)', fontWeight: '500', marginBottom: 16 }}>
-      您提交的内容有如下错误:
-    </div>
-    <div style={{ marginBottom: 16 }}>
-      <Icon style={{ color: '#f5222d', marginRight: 8 }} type="close-circle-o" />您的账户已被冻结
-      <a style={{ marginLeft: 16 }}>立即解冻 <Icon type="right" /></a>
-    </div>
-    <div>
-      <Icon style={{ color: '#f5222d', marginRight: 8 }} type="close-circle-o" />您的账户还不具备申请资格
-      <a style={{ marginLeft: 16 }}>立即升级 <Icon type="right" /></a>
-    </div>
-  </Fragment>
-);
-
-const actions = <Button type="primary">返回修改</Button>;
-
-export default () => (
-  <PageHeaderLayout>
-    <Card bordered={false}>
-      <Result
-        type="error"
-        title="提交失败"
-        description="请核对并修改以下信息后,再重新提交。"
-        extra={extra}
-        actions={actions}
-        style={{ marginTop: 48, marginBottom: 16 }}
-      />
-    </Card>
-  </PageHeaderLayout>
-);

+ 0 - 78
src/routes/Result/Success.js

@@ -1,78 +0,0 @@
-import React, { Fragment } from 'react';
-import { Button, Row, Col, Icon, Steps, Card } from 'antd';
-import Result from '../../components/Result';
-import PageHeaderLayout from '../../layouts/PageHeaderLayout';
-
-const { Step } = Steps;
-
-const desc1 = (
-  <div style={{ fontSize: 12, color: 'rgba(0, 0, 0, 0.45)', position: 'relative', left: 42 }}>
-    <div style={{ margin: '8px 0 4px' }}>
-      曲丽丽<Icon style={{ marginLeft: 8 }} type="dingding-o" />
-    </div>
-    <div>2016-12-12 12:32</div>
-  </div>
-);
-
-const desc2 = (
-  <div style={{ fontSize: 12, position: 'relative', left: 42 }}>
-    <div style={{ margin: '8px 0 4px' }}>
-      周毛毛<Icon type="dingding-o" style={{ color: '#00A0E9', marginLeft: 8 }} />
-    </div>
-    <div><a href="">催一下</a></div>
-  </div>
-);
-
-const extra = (
-  <Fragment>
-    <div style={{ fontSize: 16, color: 'rgba(0, 0, 0, 0.85)', fontWeight: '500', marginBottom: 20 }}>
-      项目名称
-    </div>
-    <Row style={{ marginBottom: 16 }}>
-      <Col xs={24} sm={12} md={12} lg={12} xl={6}>
-        <span style={{ color: 'rgba(0, 0, 0, 0.85)' }}>项目 ID:</span>
-        23421
-      </Col>
-      <Col xs={24} sm={12} md={12} lg={12} xl={6}>
-        <span style={{ color: 'rgba(0, 0, 0, 0.85)' }}>负责人:</span>
-        曲丽丽
-      </Col>
-      <Col xs={24} sm={24} md={24} lg={24} xl={12}>
-        <span style={{ color: 'rgba(0, 0, 0, 0.85)' }}>生效时间:</span>
-        2016-12-12 ~ 2017-12-12
-      </Col>
-    </Row>
-    <Steps style={{ marginLeft: -42, width: 'calc(100% + 84px)' }} progressDot current={1}>
-      <Step title={<span style={{ fontSize: 14 }}>创建项目</span>} description={desc1} />
-      <Step title={<span style={{ fontSize: 14 }}>部门初审</span>} description={desc2} />
-      <Step title={<span style={{ fontSize: 14 }}>财务复核</span>} />
-      <Step title={<span style={{ fontSize: 14 }}>完成</span>} />
-    </Steps>
-  </Fragment>
-);
-
-const actions = (
-  <Fragment>
-    <Button type="primary">返回列表</Button>
-    <Button>查看项目</Button>
-    <Button>打 印</Button>
-  </Fragment>
-);
-
-export default () => (
-  <PageHeaderLayout>
-    <Card bordered={false}>
-      <Result
-        type="success"
-        title="提交成功"
-        description="提交结果页用于反馈一系列操作任务的处理结果,
-        如果仅是简单操作,使用 Message 全局提示反馈即可。
-        本文字区域可以展示简单的补充说明,如果有类似展示
-        “单据”的需求,下面这个灰色区域可以呈现比较复杂的内容。"
-        extra={extra}
-        actions={actions}
-        style={{ marginTop: 48, marginBottom: 16 }}
-      />
-    </Card>
-  </PageHeaderLayout>
-);

+ 0 - 9
src/routes/Result/Success.test.js

@@ -1,9 +0,0 @@
-import React from 'react';
-import { shallow } from 'enzyme';
-import Success from './Success';
-
-it('renders with Result', () => {
-  const wrapper = shallow(<Success />);
-  expect(wrapper.find('Result').length).toBe(1);
-  expect(wrapper.find('Result').prop('type')).toBe('success');
-});

+ 0 - 294
src/routes/Shelves/Course/CourseCreate.js

@@ -1,294 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { message, Modal, Table, Card, Button } from 'antd';
-import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar';
-import { Hotax } from '../../../utils/config';
-import { renderCategory, statusCodeToName } from '../../../utils/utils';
-import styles from './CourseCreate.less';
-
-const Message = message;
-
-@connect(({ loading, shelves, product, merchant }) => ({
-  product,
-  shelves,
-  merchant,
-  mLoading: loading.models.merchant,
-  pLoading: loading.models.product,
-  submitting: loading.models.shelves,
-}))
-export default class CourseCreatePage extends Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      productItem: {},
-      merchantItem: {},
-      productSelectorDestroy: true,
-      merchantSelectorDestroy: true,
-    };
-  }
-  handleProductSelectorModalShow = () => {
-    this.setState({
-      productSelectorDestroy: false,
-    });
-    this.props.dispatch({
-      type: 'product/fetchCourseList',
-      payload: {},
-    });
-  };
-  handleMerchantSelectorModalShow = () => {
-    this.setState({
-      merchantSelectorDestroy: false,
-    });
-    this.props.dispatch({
-      type: 'merchant/fetchMerchantList',
-      payload: {},
-    });
-  };
-  handleProductSelectorChange = (params) => {
-    this.props.dispatch({
-      type: 'product/fetchCourseList',
-      payload: params,
-    });
-  };
-  handleMerchantSelectorChange = (params) => {
-    this.props.dispatch({
-      type: 'merchant/fetchMerchantList',
-      payload: params,
-    });
-  };
-  handleProductSelectorFinish = (rows) => {
-    this.setState({
-      productSelectorDestroy: true,
-      productItem: rows[0],
-    });
-  };
-  handleMerchantSelectorFinish = (rows) => {
-    this.setState({
-      merchantSelectorDestroy: true,
-      merchantItem: rows[0],
-    });
-  };
-  handleProductSelectorCancel = () => {
-    this.setState({
-      productSelectorDestroy: true,
-    });
-  };
-  handleMerchantSelectorCancel = () => {
-    this.setState({
-      merchantSelectorDestroy: true,
-    });
-  };
-  handlePageBack = () => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/course/list',
-      state: this.props.location.state,
-    }));
-  };
-  handlePageSubmit = (e) => {
-    e.preventDefault();
-    const { productItem, merchantItem } = this.state;
-    const { pid } = productItem;
-    const { id } = merchantItem;
-    if (!pid) {
-      Message.error('请选择要上架的课程!');
-      return;
-    }
-    if (!id) {
-      Message.error('请选择要上架的渠道!');
-      return;
-    }
-    this.props.dispatch({
-      type: 'shelves/createItem',
-      payload: {
-        pid,
-        merchantId: id,
-        status: Hotax.STATUS_NORMAL,
-      },
-      states: {
-        itemType: 'course',
-        ...this.props.location.state,
-      },
-    });
-  };
-
-  render() {
-    const { submitting, pLoading, mLoading, merchant, product } = this.props;
-    const {
-      productSelectorDestroy, merchantSelectorDestroy, productItem, merchantItem,
-    } = this.state;
-
-    // format selected data
-    const productItemFormatter = () => {
-      const { code, name, status } = productItem;
-      return [{
-        key: '课程编号:',
-        value: code,
-      }, {
-        key: '课程名称:',
-        value: name,
-      }, {
-        key: '课程状态:',
-        value: statusCodeToName(status),
-      }];
-    };
-    const merchantItemFormatter = () => {
-      const { code, name, status, simple, contactName, mobile, domain } = merchantItem;
-      return [{
-        key: '商户编号:',
-        value: code,
-      }, {
-        key: '商户名称:',
-        value: name,
-      }, {
-        key: '商户简称:',
-        value: simple,
-      }, {
-        key: '商户类型:',
-        value: renderCategory(domain),
-      }, {
-        key: '商户联系人:',
-        value: contactName,
-      }, {
-        key: '联系人电话:',
-        value: mobile,
-      }, {
-        key: '商户状态:',
-        value: statusCodeToName(status),
-      }];
-    };
-
-    // table columns
-    const columns = [{
-      title: '字段名',
-      key: 1,
-      dataIndex: 'key',
-      width: '15%',
-    }, {
-      title: '字段值',
-      key: 2,
-      dataIndex: 'value',
-      width: '65%',
-    }];
-
-    // render modal selector
-    const getProductModal = () => {
-      return (
-        <Modal
-          visible
-          width={900}
-          footer={null}
-          title="课程列表"
-          maskClosable={false}
-          onCancel={this.handleProductSelectorCancel}
-        >
-          <Selector
-            multiple={false}
-            loading={pLoading}
-            selectorName="Course"
-            list={product.list}
-            pageNo={product.pageNo}
-            pageSize={product.pageSize}
-            totalSize={product.totalSize}
-            onCancel={this.handleProductSelectorCancel}
-            onChange={this.handleProductSelectorChange}
-            onFinish={this.handleProductSelectorFinish}
-          />
-        </Modal>
-      );
-    };
-    const getMerchantModal = () => {
-      return (
-        <Modal
-          visible
-          width={1100}
-          footer={null}
-          title="商户列表"
-          maskClosable={false}
-          onCancel={this.handleMerchantSelectorCancel}
-        >
-          <Selector
-            multiple={false}
-            loading={mLoading}
-            selectorName="Merchant"
-            list={merchant.list}
-            pageNo={merchant.pageNo}
-            pageSize={merchant.pageSize}
-            totalSize={merchant.totalSize}
-            onCancel={this.handleMerchantSelectorCancel}
-            onChange={this.handleMerchantSelectorChange}
-            onFinish={this.handleMerchantSelectorFinish}
-          />
-        </Modal>
-      );
-    };
-
-    // render card title
-    const renderProductCardName = () => {
-      return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleProductSelectorModalShow}>
-              选择课程
-            </a>
-          </span>
-        </div>
-      );
-    };
-    const renderMerchantCardName = () => {
-      return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleMerchantSelectorModalShow}>
-              选择商户
-            </a>
-          </span>
-        </div>
-      );
-    };
-
-    return (
-      <div>
-        {/* 课程选择Card */}
-        <Card title={renderProductCardName()} style={{ marginBottom: 16 }}>
-          <Table
-            bordered
-            showHeader={false}
-            pagination={false}
-            columns={columns}
-            className={styles.table}
-            dataSource={productItemFormatter()}
-          />
-          {!productSelectorDestroy && getProductModal()}
-        </Card>
-        {/* 商户选择Card */}
-        <Card title={renderMerchantCardName()} style={{ marginBottom: 70 }}>
-          <Table
-            bordered
-            showHeader={false}
-            pagination={false}
-            columns={columns}
-            className={styles.table}
-            dataSource={merchantItemFormatter()}
-          />
-          {!merchantSelectorDestroy && getMerchantModal()}
-        </Card>
-        <FooterToolbar style={{ width: '100%' }}>
-          <Button
-            onClick={this.handlePageBack}
-            style={{ marginRight: 10 }}
-          >取消
-          </Button>
-          <Button
-            type="primary"
-            loading={submitting}
-            onClick={this.handlePageSubmit}
-          >提交
-          </Button>
-        </FooterToolbar>
-      </div>
-    );
-  }
-}
-

+ 0 - 29
src/routes/Shelves/Course/CourseCreate.less

@@ -1,29 +0,0 @@
-@import "~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;
-    }
-  }
-}
-
-.table {
-  :global {
-    .ant-table-body > table {
-      padding: 0 !important;
-    }
-    .ant-table-tbody > tr > td {
-      &:first-child {
-        background: #69c0ff;
-        font-weight: 500;
-      }
-    }
-  }
-}

+ 0 - 179
src/routes/Shelves/Course/CourseList.js

@@ -1,179 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { Card, Modal, Button, message } from 'antd';
-import { StandardTableList } from '../../../components/AXList';
-import Ellipsis from '../../../components/Ellipsis';
-import { renderStatus, addRowKey } from '../../../utils/utils';
-
-const Message = message;
-
-@connect(({ loading, shelves }) => ({
-  shelves,
-  loading: loading.models.shelves,
-}))
-export default class CourseListPage extends Component {
-  constructor(props) {
-    super(props);
-    const { state } = props.location;
-    this.state = {
-      UIParams: (state || {}).UIParams, // 组件的状态参数
-      Queryers: (state || {}).Queryers, // 查询的条件参数
-    };
-  }
-  componentDidMount() {
-    this.props.dispatch({
-      type: 'shelves/fetchCourseItemList',
-      payload: { ...this.state.Queryers },
-    });
-  }
-  handleCreateOperation = () => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/course/create',
-      state: this.state,
-    }));
-  }
-  handleDeleteOperation = (item) => {
-    Modal.confirm({
-      okText: '确定',
-      cancelText: '取消',
-      title: '你确定要下架该课程吗?',
-      content: '下架后该课程将不在对应平台上展现',
-      onOk: () => {
-        this.props.dispatch({
-          type: 'shelves/deleteItem',
-          payload: { id: item.id },
-          states: this.state,
-        });
-      },
-    });
-  }
-  handleEditOperation = (item) => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/course/edit',
-      state: {
-        pid: item.pid,
-        merchantId: item.merchantId,
-        ...this.state,
-      },
-    }));
-  }
-  handleFilterOperation = (params, states) => {
-    this.props.dispatch({
-      type: 'shelves/fetchCourseItemList',
-      payload: params,
-    });
-    this.setState({
-      UIParams: states,
-      Queryers: params,
-    });
-  }
-  handleBatchOperation = () => {
-    Message.info('暂不支持批量操作!');
-  }
-
-  render() {
-    const { loading, shelves } = this.props;
-    const { list, totalSize, pageSize, pageNo } = shelves;
-
-    const renderOperation = (item) => {
-      return (
-        <div>
-          <Button
-            size="small"
-            className="editBtn"
-            onClick={() => this.handleEditOperation(item)}
-          >编辑
-          </Button>
-          <Button
-            size="small"
-            className="delBtn"
-            onClick={() => this.handleDeleteOperation(item)}
-          >下架
-          </Button>
-        </div>
-      );
-    };
-
-    const batchActions = [{
-      key: 'delete',
-      name: '批量删除',
-    }, {
-      key: 'recovery',
-      name: '批量恢复',
-    }];
-    const basicSearch = {
-      keys: [{
-        name: '课程编号',
-        field: 'code',
-      }, {
-        name: '课程名称',
-        field: 'name',
-      }],
-    };
-    const pagination = {
-      pageNo,
-      pageSize,
-      totalSize,
-    };
-    const columns = [{
-      title: '课程编号',
-      key: 1,
-      dataIndex: 'code',
-      width: '15%',
-    }, {
-      title: '课程名称',
-      key: 2,
-      dataIndex: 'name',
-      render: text => (
-        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
-      ),
-      width: '30%',
-    }, {
-      title: '上架渠道',
-      key: 3,
-      dataIndex: 'merchantName',
-      width: '14%',
-    }, {
-      title: '上架状态',
-      key: 4,
-      dataIndex: 'status',
-      render: text => renderStatus(text, '已下架', '已上架'),
-      width: '10%',
-    }, {
-      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) => renderOperation(record),
-      width: '13%',
-      align: 'right',
-    }];
-    return (
-      <Card>
-        <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 }}
-        />
-      </Card>
-    );
-  }
-}

+ 0 - 323
src/routes/Shelves/Course/TableForm.js

@@ -1,323 +0,0 @@
-import React, { PureComponent, Fragment } from 'react';
-import {
-  Table,
-  Button,
-  Select,
-  InputNumber,
-  Popconfirm,
-  Divider,
-  message,
-} from 'antd';
-import { Hotax } from '../../../utils/config';
-import styles from './TableForm.less';
-
-const chargeUnitMap = [{
-  text: Hotax.CHARGE_UNIT_YEAR,
-  value: Hotax.CHARGE_UNIT_YEAR,
-}, {
-  text: Hotax.CHARGE_UNIT_HALF_YEAR,
-  value: Hotax.CHARGE_UNIT_HALF_YEAR,
-}, {
-  text: Hotax.CHARGE_UNIT_SEASON,
-  value: Hotax.CHARGE_UNIT_SEASON,
-}];
-const durationMap = {
-  [Hotax.CHARGE_UNIT_SEASON]: Hotax.DURATION_SEASON,
-  [Hotax.CHARGE_UNIT_HALF_YEAR]: Hotax.DURATION_HALF_YEAR,
-  [Hotax.CHARGE_UNIT_YEAR]: Hotax.DURATION_YEAR,
-};
-const sortMap = {
-  [Hotax.CHARGE_UNIT_SEASON]: 0,
-  [Hotax.CHARGE_UNIT_HALF_YEAR]: 1,
-  [Hotax.CHARGE_UNIT_YEAR]: 2,
-};
-
-export default class TableForm extends PureComponent {
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      data: props.value,
-      loading: props.loading,
-    };
-  }
-  componentWillReceiveProps(nextProps) {
-    if ('value' in nextProps) {
-      this.setState({
-        data: nextProps.value,
-      });
-    }
-  }
-  getRowByKey(key, newData) {
-    return (newData || this.state.data).filter(item => item.key === key)[0];
-  }
-  index = 0;
-  cacheOriginData = {};
-  toggleEditable=(e, key) => {
-    e.preventDefault();
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      // 进入编辑状态时保存原始数据
-      if (!target.editable) {
-        this.cacheOriginData[key] = { ...target };
-      }
-      target.editable = !target.editable;
-      this.setState({ data: newData });
-    }
-  };
-  chargeUnitSelectable=(value) => {
-    const tmp = this.state.data.find(item => item.chargeUnit === value);
-    return tmp !== undefined;
-  };
-  remove(record) {
-    const { key, isNew } = record;
-    const newData = this.state.data.filter(item => item.key !== key);
-    this.setState({ data: newData });
-    if (!isNew) {
-      this.props.onDelete({ goodsId: key });
-    }
-  }
-  newPrice = () => {
-    const newData = this.state.data.map(item => ({ ...item }));
-    newData.push({
-      key: `NEW_TEMP_ID_${this.index}`,
-      cpPrice: '',
-      merchantPrice: '',
-      terminalPrice: '',
-      editable: true,
-      isNew: true,
-    });
-    this.index += 1;
-    this.setState({ data: newData });
-  };
-  handleFieldChange(value, fieldName, key) {
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      target[fieldName] = value;
-      this.setState({ data: newData });
-    }
-  }
-  handleSelectChange(value, key) {
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      target.chargeUnit = value;
-      target.duration = durationMap[value];
-      this.setState({ data: newData });
-    }
-  }
-  saveRow(e, key) {
-    e.persist();
-    if (this.clickedCancel) {
-      this.clickedCancel = false;
-      return;
-    }
-    const target = this.getRowByKey(key) || {};
-    if (!target.chargeUnit || !target.cpPrice || !target.merchantPrice || !target.terminalPrice) {
-      message.error('请填写完整价格信息');
-      e.target.focus();
-      return;
-    }
-    const { id, chargeUnit, cpPrice, merchantPrice, terminalPrice, duration } = target;
-    const sort = sortMap[chargeUnit];
-    if (target.isNew) {
-      this.props.onCreate({
-        sort,
-        cpPrice,
-        duration,
-        chargeUnit,
-        merchantPrice,
-        terminalPrice,
-      });
-    } else {
-      this.props.onUpdate({
-        id,
-        sort,
-        cpPrice,
-        duration,
-        chargeUnit,
-        merchantPrice,
-        terminalPrice,
-      });
-    }
-    delete target.isNew;
-    this.toggleEditable(e, key);
-  }
-  cancel(e, key) {
-    this.clickedCancel = true;
-    e.preventDefault();
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (this.cacheOriginData[key]) {
-      Object.assign(target, this.cacheOriginData[key]);
-      target.editable = false;
-      delete this.cacheOriginData[key];
-    }
-    this.setState({ data: newData });
-    this.clickedCancel = false;
-  }
-  render() {
-    const columns = [{
-      title: '计价单位',
-      dataIndex: 'chargeUnit',
-      key: 'chargeUnit',
-      width: '15%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <Select
-              placeholder="请选择"
-              style={{ width: '100%' }}
-              value={text}
-              onChange={value => this.handleSelectChange(value, record.key)}
-              className={styles.select}
-            >
-              {
-                chargeUnitMap.map(item => (
-                  <Select.Option
-                    key={item.value}
-                    value={item.value}
-                    disabled={this.chargeUnitSelectable(item.value)}
-                  >
-                    {item.text}
-                  </Select.Option>
-                ))
-              }
-            </Select>
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '时长(天)',
-      dataIndex: 'duration',
-      key: 'duration',
-      width: '15%',
-      align: 'center',
-    }, {
-      title: '供应商售价(¥)',
-      dataIndex: 'cpPrice',
-      key: 'cpPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={e => this.handleFieldChange(e, 'cpPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '平台方售价(¥)',
-      dataIndex: 'merchantPrice',
-      key: 'merchantPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={value => this.handleFieldChange(value, 'merchantPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '终端显示价格(¥)',
-      dataIndex: 'terminalPrice',
-      key: 'terminalPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={value => this.handleFieldChange(value, 'terminalPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '操作',
-      key: 'action',
-      align: 'center',
-      render: (text, record) => {
-        if (!!record.editable && this.state.loading) {
-          return null;
-        }
-        if (record.editable) {
-          if (record.isNew) {
-            return (
-              <span>
-                <a onClick={e => this.saveRow(e, record.key)}>添加</a>
-                <Divider type="vertical" />
-                <Popconfirm title="是否要删除此价格?" onConfirm={() => this.remove(record)}>
-                  <a>删除</a>
-                </Popconfirm>
-              </span>
-            );
-          }
-          return (
-            <span>
-              <a onClick={e => this.saveRow(e, record.key)}>保存</a>
-              <Divider type="vertical" />
-              <a onClick={e => this.cancel(e, record.key)}>取消</a>
-            </span>
-          );
-        }
-        return (
-          <span>
-            <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
-            <Divider type="vertical" />
-            <Popconfirm title="是否要删除此价格?" onConfirm={() => this.remove(record)}>
-              <a>删除</a>
-            </Popconfirm>
-          </span>
-        );
-      },
-    }];
-
-    return (
-      <Fragment>
-        <Table
-          bordered
-          pagination={false}
-          columns={columns}
-          loading={this.state.loading}
-          dataSource={this.state.data}
-          rowClassName={() => {
-            return styles.editable;
-          }}
-        />
-        <Button
-          style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
-          type="dashed"
-          onClick={this.newPrice}
-          icon="plus"
-        >
-          新增价格
-        </Button>
-      </Fragment>
-    );
-  }
-}

+ 0 - 291
src/routes/Shelves/Package/PackageCreate.js

@@ -1,291 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { message, Modal, Table, Card, Button } from 'antd';
-import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar';
-import { Hotax } from '../../../utils/config';
-import { renderCategory, statusCodeToName } from '../../../utils/utils';
-import styles from './PackageCreate.less';
-
-const Message = message;
-
-@connect(({ loading, shelves, product, merchant }) => ({
-  product,
-  shelves,
-  merchant,
-  mLoading: loading.models.merchant,
-  pLoading: loading.models.product,
-  submitting: loading.models.shelves,
-}))
-export default class PackageCreatePage extends Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      productItem: {},
-      merchantItem: {},
-      productSelectorDestroy: true,
-      merchantSelectorDestroy: true,
-    };
-  }
-  handleProductSelectorModalShow = () => {
-    this.setState({
-      productSelectorDestroy: false,
-    });
-    this.props.dispatch({
-      type: 'product/fetchPackageList',
-      payload: {},
-    });
-  };
-  handleMerchantSelectorModalShow = () => {
-    this.setState({
-      merchantSelectorDestroy: false,
-    });
-    this.props.dispatch({
-      type: 'merchant/fetchMerchantList',
-      payload: {},
-    });
-  };
-  handleProductSelectorChange = (params) => {
-    this.props.dispatch({
-      type: 'product/fetchPackageList',
-      payload: params,
-    });
-  };
-  handleMerchantSelectorChange = (params) => {
-    this.props.dispatch({
-      type: 'merchant/fetchMerchantList',
-      payload: params,
-    });
-  };
-  handleProductSelectorFinish = (rows) => {
-    this.setState({
-      productSelectorDestroy: true,
-      productItem: rows[0],
-    });
-  };
-  handleMerchantSelectorFinish = (rows) => {
-    this.setState({
-      merchantSelectorDestroy: true,
-      merchantItem: rows[0],
-    });
-  };
-  handleProductSelectorCancel = () => {
-    this.setState({
-      productSelectorDestroy: true,
-    });
-  };
-  handleMerchantSelectorCancel = () => {
-    this.setState({
-      merchantSelectorDestroy: true,
-    });
-  };
-  handlePageBack = () => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/package/list',
-      state: this.props.location.state,
-    }));
-  };
-  handlePageSubmit = (e) => {
-    e.preventDefault();
-    const { productItem, merchantItem } = this.state;
-    const { pid } = productItem;
-    const { id } = merchantItem;
-    if (!pid) {
-      Message.error('请选择要上架的套餐包!');
-      return;
-    }
-    if (!id) {
-      Message.error('请选择要上架的渠道!');
-      return;
-    }
-    this.props.dispatch({
-      type: 'shelves/createItem',
-      payload: {
-        pid,
-        merchantId: id,
-        status: Hotax.STATUS_NORMAL,
-      },
-      states: this.props.location.state,
-    });
-  };
-
-  render() {
-    const { submitting, pLoading, mLoading, merchant, product } = this.props;
-    const {
-      productSelectorDestroy, merchantSelectorDestroy, productItem, merchantItem,
-    } = this.state;
-
-    // format selected data
-    const productItemFormatter = () => {
-      const { code, name, status } = productItem;
-      return [{
-        key: '套餐包编号:',
-        value: code,
-      }, {
-        key: '套餐包名称:',
-        value: name,
-      }, {
-        key: '套餐包状态:',
-        value: statusCodeToName(status),
-      }];
-    };
-    const merchantItemFormatter = () => {
-      const { code, name, status, simple, contactName, mobile, domain } = merchantItem;
-      return [{
-        key: '商户编号:',
-        value: code,
-      }, {
-        key: '商户名称:',
-        value: name,
-      }, {
-        key: '商户简称:',
-        value: simple,
-      }, {
-        key: '商户类型:',
-        value: renderCategory(domain),
-      }, {
-        key: '商户联系人:',
-        value: contactName,
-      }, {
-        key: '联系人电话:',
-        value: mobile,
-      }, {
-        key: '商户状态:',
-        value: statusCodeToName(status),
-      }];
-    };
-
-    // table columns
-    const columns = [{
-      title: '字段名',
-      key: 1,
-      dataIndex: 'key',
-      width: '15%',
-    }, {
-      title: '字段值',
-      key: 2,
-      dataIndex: 'value',
-      width: '65%',
-    }];
-
-    // render modal selector
-    const getProductModal = () => {
-      return (
-        <Modal
-          visible
-          width={900}
-          footer={null}
-          title="套餐包列表"
-          maskClosable={false}
-          onCancel={this.handleProductSelectorCancel}
-        >
-          <Selector
-            multiple={false}
-            loading={pLoading}
-            selectorName="Course"
-            list={product.list}
-            pageNo={product.pageNo}
-            pageSize={product.pageSize}
-            totalSize={product.totalSize}
-            onCancel={this.handleProductSelectorCancel}
-            onChange={this.handleProductSelectorChange}
-            onFinish={this.handleProductSelectorFinish}
-          />
-        </Modal>
-      );
-    };
-    const getMerchantModal = () => {
-      return (
-        <Modal
-          visible
-          width={1100}
-          footer={null}
-          title="商户列表"
-          maskClosable={false}
-          onCancel={this.handleMerchantSelectorCancel}
-        >
-          <Selector
-            multiple={false}
-            loading={mLoading}
-            selectorName="Merchant"
-            list={merchant.list}
-            pageNo={merchant.pageNo}
-            pageSize={merchant.pageSize}
-            totalSize={merchant.totalSize}
-            onCancel={this.handleMerchantSelectorCancel}
-            onChange={this.handleMerchantSelectorChange}
-            onFinish={this.handleMerchantSelectorFinish}
-          />
-        </Modal>
-      );
-    };
-
-    // render card title
-    const renderProductCardName = () => {
-      return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleProductSelectorModalShow}>
-              选择套餐包
-            </a>
-          </span>
-        </div>
-      );
-    };
-    const renderMerchantCardName = () => {
-      return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleMerchantSelectorModalShow}>
-              选择商户
-            </a>
-          </span>
-        </div>
-      );
-    };
-
-    return (
-      <div>
-        {/* 产品选择Card */}
-        <Card title={renderProductCardName()} style={{ marginBottom: 16 }}>
-          <Table
-            bordered
-            showHeader={false}
-            pagination={false}
-            columns={columns}
-            className={styles.table}
-            dataSource={productItemFormatter()}
-          />
-          {!productSelectorDestroy && getProductModal()}
-        </Card>
-        {/* 渠道选择Card */}
-        <Card title={renderMerchantCardName()} style={{ marginBottom: 70 }}>
-          <Table
-            bordered
-            showHeader={false}
-            pagination={false}
-            columns={columns}
-            className={styles.table}
-            dataSource={merchantItemFormatter()}
-          />
-          {!merchantSelectorDestroy && getMerchantModal()}
-        </Card>
-        <FooterToolbar style={{ width: '100%' }}>
-          <Button
-            onClick={this.handlePageBack}
-            style={{ marginRight: 10 }}
-          >取消
-          </Button>
-          <Button
-            type="primary"
-            loading={submitting}
-            onClick={this.handlePageSubmit}
-          >提交
-          </Button>
-        </FooterToolbar>
-      </div>
-    );
-  }
-}
-

+ 0 - 29
src/routes/Shelves/Package/PackageCreate.less

@@ -1,29 +0,0 @@
-@import "~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;
-    }
-  }
-}
-
-.table {
-  :global {
-    .ant-table-body > table {
-      padding: 0 !important;
-    }
-    .ant-table-tbody > tr > td {
-      &:first-child {
-        background: #69c0ff;
-        font-weight: 500;
-      }
-    }
-  }
-}

+ 0 - 224
src/routes/Shelves/Package/PackageEdit.js

@@ -1,224 +0,0 @@
-import React, { Component } from 'react';
-import { Card, Modal, Form, Button, Tag, Icon } from 'antd';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import TableForm from './TableForm';
-import FooterToolbar from '../../../components/FooterToolbar';
-import Selector from '../../../components/AXTableSelector/Selector';
-import { addRowKey } from '../../../utils/utils';
-import { Hotax } from '../../../utils/config';
-
-@connect(({ loading, shelves, tag }) => ({
-  tag,
-  shelves,
-  tLoading: loading.models.tag,
-  submitting: loading.models.shelves,
-}))
-@Form.create()
-export default class PackageEdit extends Component {
-  constructor(props) {
-    super(props);
-    const { location } = props;
-    const { state } = location;
-    const { merchantId, pid, productType } = state;
-    this.state = {
-      pid,
-      merchantId,
-      productType,
-      tagSelectorDestroy: true,
-    };
-  }
-  componentDidMount() {
-    const { merchantId, pid } = this.state;
-    this.props.dispatch({
-      type: 'shelves/fetchItemDetail',
-      payload: {
-        pid,
-        merchantId,
-      },
-    });
-  }
-  handleGoodsCreate=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/createItemPrice',
-      payload: {
-        ...data,
-        ...this.state,
-        productType: Hotax.PRODUCT_PACKAGE,
-        status: Hotax.STATUS_NORMAL,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleGoodsUpdate=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/updateItemPrice',
-      payload: {
-        ...data,
-        ...this.state,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleGoodsDelete=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/deleteItemPrice',
-      payload: data,
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleTagClose=(index) => {
-    const { pid, merchantId } = this.state;
-    const { shelves } = this.props;
-    const { currentItem } = shelves;
-    const { tags } = currentItem;
-    const newTags = tags.filter((item, location) => location !== index);
-    const newTagIds = newTags.map(item => item.id);
-    this.props.dispatch({
-      type: 'shelves/updateItemTags',
-      payload: {
-        pid,
-        merchantId,
-        tags: newTagIds,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleTagSelectorModalShow = () => {
-    this.setState({
-      tagSelectorDestroy: false,
-    });
-    const { merchantId } = this.state;
-    this.props.dispatch({
-      type: 'tag/fetchTagList',
-      payload: { merchantId },
-    });
-  };
-  handleTagSelectorCancel = () => {
-    this.setState({
-      tagSelectorDestroy: true,
-    });
-  };
-  handleTagSelectorChange = (params) => {
-    const { merchantId } = this.state;
-    this.props.dispatch({
-      type: 'tag/fetchTagList',
-      payload: { merchantId, ...params },
-    });
-  };
-  handleTagSelectorFinish = (rows) => {
-    const { pid, merchantId } = this.state;
-    const newTagIds = (rows || []).map(row => row.id);
-    this.props.dispatch({
-      type: 'shelves/updateItemTags',
-      payload: {
-        pid,
-        merchantId,
-        tags: newTagIds,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-    this.setState({
-      tagSelectorDestroy: true,
-    });
-  };
-  handlePageBack=() => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/package',
-      state: this.props.location.state,
-    }));
-  };
-  render() {
-    const { tagSelectorDestroy } = this.state;
-    const { submitting, tLoading, shelves, tag, form } = this.props;
-    const { getFieldDecorator } = form;
-    const { currentItem } = shelves;
-    const { goods, tags } = currentItem;
-
-    return (
-      <div>
-        <Card title="价格管理" style={{ marginBottom: 16 }}>
-          {getFieldDecorator('goods', {
-            initialValue: addRowKey(goods),
-          })(
-            <TableForm
-              loading={submitting}
-              onCreate={this.handleGoodsCreate}
-              onUpdate={this.handleGoodsUpdate}
-              onDelete={this.handleGoodsDelete}
-            />
-          )}
-        </Card>
-        <Card title="栏目管理" style={{ marginBottom: 70 }}>
-          {tags && tags.map((item, index) => (
-            <Tag
-              closable
-              afterClose={() => this.handleTagClose(index)}
-              color="#87d068"
-              key={item.id}
-            >
-              {item.name}
-            </Tag>
-          ))}
-          <Tag
-            style={{ borderStyle: 'dashed' }}
-            onClick={this.handleTagSelectorModalShow}
-          >
-            <Icon type="plus" />添加栏目
-          </Tag>
-          {!tagSelectorDestroy && (
-            <Modal
-              width={1100}
-              footer={null}
-              visible
-              title="标签列表"
-              maskClosable={false}
-              onCancel={this.handleMerchantSelectorCancel}
-            >
-              <Selector
-                multiple
-                loading={tLoading}
-                selectorName="Tag"
-                list={tag.list}
-                pageNo={tag.pageNo}
-                pageSize={tag.pageSize}
-                totalSize={tag.totalSize}
-                selectedRows={tags}
-                onCancel={this.handleTagSelectorCancel}
-                onChange={this.handleTagSelectorChange}
-                onFinish={this.handleTagSelectorFinish}
-              />
-            </Modal>
-          )}
-        </Card>
-        <FooterToolbar style={{ width: '100%' }}>
-          <Button
-            type="primary"
-            onClick={this.handlePageBack}
-            style={{ marginRight: 10 }}
-          >返回上一页
-          </Button>
-        </FooterToolbar>
-      </div>
-    );
-  }
-}
-

+ 0 - 326
src/routes/Shelves/Package/TableForm.js

@@ -1,326 +0,0 @@
-import React, { PureComponent, Fragment } from 'react';
-import {
-  Table,
-  Button,
-  Select,
-  InputNumber,
-  Popconfirm,
-  Divider,
-  message,
-} from 'antd';
-import { Hotax } from '../../../utils/config';
-import styles from './TableForm.less';
-
-const chargeUnitMap = [{
-  text: Hotax.CHARGE_UNIT_YEAR,
-  value: Hotax.CHARGE_UNIT_YEAR,
-}, {
-  text: Hotax.CHARGE_UNIT_HALF_YEAR,
-  value: Hotax.CHARGE_UNIT_HALF_YEAR,
-}, {
-  text: Hotax.CHARGE_UNIT_SEASON,
-  value: Hotax.CHARGE_UNIT_SEASON,
-}];
-const durationMap = {
-  [Hotax.CHARGE_UNIT_SEASON]: Hotax.DURATION_SEASON,
-  [Hotax.CHARGE_UNIT_HALF_YEAR]: Hotax.DURATION_HALF_YEAR,
-  [Hotax.CHARGE_UNIT_YEAR]: Hotax.DURATION_YEAR,
-};
-
-export default class TableForm extends PureComponent {
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      data: props.value,
-      loading: props.loading,
-    };
-  }
-  componentWillReceiveProps(nextProps) {
-    if ('value' in nextProps) {
-      this.setState({
-        data: nextProps.value,
-      });
-    }
-  }
-  getRowByKey(key, newData) {
-    return (newData || this.state.data).filter(item => item.key === key)[0];
-  }
-  index = 0;
-  cacheOriginData = {};
-  toggleEditable=(e, key) => {
-    e.preventDefault();
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      // 进入编辑状态时保存原始数据
-      if (!target.editable) {
-        this.cacheOriginData[key] = { ...target };
-      }
-      target.editable = !target.editable;
-      this.setState({ data: newData });
-    }
-  };
-  chargeUnitSelectable=(value) => {
-    const tmp = this.state.data.find(item => item.chargeUnit === value);
-    return tmp !== undefined;
-  };
-  remove(record) {
-    const { key, isNew } = record;
-    const newData = this.state.data.filter(item => item.key !== key);
-    this.setState({ data: newData });
-    if (!isNew) {
-      this.props.onDelete({ goodsId: key });
-    }
-  }
-  newPrice = () => {
-    const newData = this.state.data.map(item => ({ ...item }));
-    newData.push({
-      key: `NEW_TEMP_ID_${this.index}`,
-      cpPrice: '',
-      merchantPrice: '',
-      terminalPrice: '',
-      editable: true,
-      isNew: true,
-    });
-    this.index += 1;
-    this.setState({ data: newData });
-  };
-  handleFieldChange(value, fieldName, key) {
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      target[fieldName] = value;
-      this.setState({ data: newData });
-    }
-  }
-  handleSelectChange(value, key) {
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      target.chargeUnit = value;
-      this.setState({ data: newData });
-    }
-  }
-  saveRow(e, key) {
-    e.persist();
-    if (this.clickedCancel) {
-      this.clickedCancel = false;
-      return;
-    }
-    const target = this.getRowByKey(key) || {};
-    if (!target.chargeUnit || !target.cpPrice || !target.merchantPrice || !target.terminalPrice) {
-      message.error('请填写完整价格信息');
-      e.target.focus();
-      return;
-    }
-    let sort = 0;
-    const { chargeUnit, cpPrice, merchantPrice, terminalPrice, duration } = target;
-    if (chargeUnit === Hotax.CHARGE_UNIT_HALF_YEAR) {
-      sort = 1;
-    } else if (chargeUnit === Hotax.CHARGE_UNIT_YEAR) {
-      sort = 2;
-    }
-    if (target.isNew) {
-      this.props.onCreate({
-        sort,
-        cpPrice,
-        duration,
-        chargeUnit,
-        merchantPrice,
-        terminalPrice,
-      });
-    } else {
-      this.props.onUpdate({
-        sort,
-        cpPrice,
-        duration,
-        chargeUnit,
-        merchantPrice,
-        terminalPrice,
-      });
-    }
-    delete target.isNew;
-    this.toggleEditable(e, key);
-  }
-  cancel(e, key) {
-    this.clickedCancel = true;
-    e.preventDefault();
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (this.cacheOriginData[key]) {
-      Object.assign(target, this.cacheOriginData[key]);
-      target.editable = false;
-      delete this.cacheOriginData[key];
-    }
-    this.setState({ data: newData });
-    this.clickedCancel = false;
-  }
-  render() {
-    const columns = [{
-      title: '计价单位',
-      dataIndex: 'chargeUnit',
-      key: 'chargeUnit',
-      width: '15%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <Select
-              placeholder="请选择"
-              style={{ width: '100%' }}
-              value={text}
-              onChange={value => this.handleSelectChange(value, record.key)}
-            >
-              {
-                chargeUnitMap.map(item => (
-                  <Select.Option
-                    key={item.value}
-                    value={item.value}
-                    disabled={this.chargeUnitSelectable(item.value)}
-                  >
-                    {item.text}
-                  </Select.Option>
-                ))
-              }
-            </Select>
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '时长(天)',
-      dataIndex: 'duration',
-      key: 'duration',
-      width: '15%',
-      align: 'center',
-      render: (_, record) => {
-        if (record.chargeUnit) {
-          return durationMap[record.chargeUnit];
-        }
-        return '';
-      },
-    }, {
-      title: '供应商售价(¥)',
-      dataIndex: 'cpPrice',
-      key: 'cpPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={e => this.handleFieldChange(e, 'cpPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '平台方售价(¥)',
-      dataIndex: 'merchantPrice',
-      key: 'merchantPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={value => this.handleFieldChange(value, 'merchantPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '终端显示价格(¥)',
-      dataIndex: 'terminalPrice',
-      key: 'terminalPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={value => this.handleFieldChange(value, 'terminalPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '操作',
-      key: 'action',
-      align: 'center',
-      render: (text, record) => {
-        if (!!record.editable && this.state.loading) {
-          return null;
-        }
-        if (record.editable) {
-          if (record.isNew) {
-            return (
-              <span>
-                <a onClick={e => this.saveRow(e, record.key)}>添加</a>
-                <Divider type="vertical" />
-                <Popconfirm title="是否要删除此种价格?" onConfirm={() => this.remove(record.key)}>
-                  <a>删除</a>
-                </Popconfirm>
-              </span>
-            );
-          }
-          return (
-            <span>
-              <a onClick={e => this.saveRow(e, record.key)}>保存</a>
-              <Divider type="vertical" />
-              <a onClick={e => this.cancel(e, record.key)}>取消</a>
-            </span>
-          );
-        }
-        return (
-          <span>
-            <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
-            <Divider type="vertical" />
-            <Popconfirm title="是否要删除此种价格?" onConfirm={() => this.remove(record)}>
-              <a>删除</a>
-            </Popconfirm>
-          </span>
-        );
-      },
-    }];
-
-    return (
-      <Fragment>
-        <Table
-          bordered
-          pagination={false}
-          columns={columns}
-          loading={this.state.loading}
-          dataSource={this.state.data}
-          rowClassName={() => {
-            return styles.editable;
-          }}
-        />
-        <Button
-          style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
-          type="dashed"
-          onClick={this.newPrice}
-          icon="plus"
-        >
-          新增价格
-        </Button>
-      </Fragment>
-    );
-  }
-}

+ 0 - 8
src/routes/Shelves/Package/TableForm.less

@@ -1,8 +0,0 @@
-@import "~antd/lib/style/themes/default.less";
-
-.editable {
-  td {
-    height: 32px;
-    padding: 0 !important;
-  }
-}

+ 49 - 33
src/routes/Shelves/Support/SupportCreate.js

@@ -1,15 +1,23 @@
 import React, { Component } from 'react';
+import pathToRegexp from 'path-to-regexp';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { message, Modal, Table, Card, Button } from 'antd';
-import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar';
-import { Hotax } from '../../../utils/config';
-import { renderCategory, statusCodeToName } from '../../../utils/utils';
-import styles from './SupportCreate.less';
+import Selector from '../../components/AXTableSelector/Selector';
+import FooterToolbar from '../../components/FooterToolbar';
+import { Hotax } from '../../utils/config';
+import { renderCategory, statusCodeToName } from '../../utils/utils';
+import styles from './ShelvesCreate.less';
 
 const Message = message;
 
+const productNameMap = {
+  Course: '课程',
+  Support: '配套',
+  Training: '师训',
+  Package: '套餐包',
+};
+
 @connect(({ loading, shelves, product, merchant }) => ({
   product,
   shelves,
@@ -18,10 +26,13 @@ const Message = message;
   pLoading: loading.models.product,
   submitting: loading.models.shelves,
 }))
-export default class SupportCreatePage extends Component {
+export default class ShelvesCreatePage extends Component {
   constructor(props) {
     super(props);
+    const match = pathToRegexp('/shelves/:type/create').exec(location.pathname);
+    const type = match[1];
     this.state = {
+      scene: type && (type.substring(0, 1).toUpperCase() + type.substring(1)),
       productItem: {},
       merchantItem: {},
       productSelectorDestroy: true,
@@ -29,11 +40,12 @@ export default class SupportCreatePage extends Component {
     };
   }
   handleProductSelectorModalShow = () => {
+    const { scene } = this.state;
     this.setState({
       productSelectorDestroy: false,
     });
     this.props.dispatch({
-      type: 'product/fetchSupportList',
+      type: `product/fetch${scene}List`,
       payload: {},
     });
   };
@@ -47,8 +59,9 @@ export default class SupportCreatePage extends Component {
     });
   };
   handleProductSelectorChange = (params) => {
+    const { scene } = this.state;
     this.props.dispatch({
-      type: 'product/fetchSupportList',
+      type: `product/fetch${scene}List`,
       payload: params,
     });
   };
@@ -81,18 +94,19 @@ export default class SupportCreatePage extends Component {
     });
   };
   handlePageBack = () => {
+    const { scene } = this.state;
     this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/support/list',
+      pathname: `/shelves/${scene}/list`,
       state: this.props.location.state,
     }));
   };
   handlePageSubmit = (e) => {
     e.preventDefault();
-    const { productItem, merchantItem } = this.state;
+    const { productItem, merchantItem, scene } = this.state;
     const { pid } = productItem;
     const { id } = merchantItem;
     if (!pid) {
-      Message.error('请选择要上架的配套!');
+      Message.error(`请选择要上架的${productNameMap[scene]}!`);
       return;
     }
     if (!id) {
@@ -106,52 +120,55 @@ export default class SupportCreatePage extends Component {
         merchantId: id,
         status: Hotax.STATUS_NORMAL,
       },
-      states: this.props.location.state,
+      states: {
+        itemType: scene.toLowerCase(),
+        ...this.props.location.state,
+      },
     });
   };
 
   render() {
     const { submitting, pLoading, mLoading, merchant, product } = this.props;
     const {
-      productSelectorDestroy, merchantSelectorDestroy, productItem, merchantItem,
+      productSelectorDestroy, merchantSelectorDestroy, productItem, merchantItem, scene,
     } = this.state;
 
     // format selected data
     const productItemFormatter = () => {
       const { code, name, status } = productItem;
       return [{
-        key: '配套编号:',
+        key: `${productNameMap[scene]}编号:`,
         value: code,
       }, {
-        key: '配套名称:',
+        key: `${productNameMap[scene]}名称:`,
         value: name,
       }, {
-        key: '配套状态:',
+        key: `${productNameMap[scene]}状态:`,
         value: statusCodeToName(status),
       }];
     };
     const merchantItemFormatter = () => {
       const { code, name, status, simple, contactName, mobile, domain } = merchantItem;
       return [{
-        key: '商户编号:',
+        key: '渠道编号:',
         value: code,
       }, {
-        key: '商户名称:',
+        key: '渠道名称:',
         value: name,
       }, {
-        key: '商户简称:',
+        key: '渠道简称:',
         value: simple,
       }, {
-        key: '商户类型:',
+        key: '渠道类型:',
         value: renderCategory(domain),
       }, {
-        key: '商户联系人:',
+        key: '渠道联系人:',
         value: contactName,
       }, {
         key: '联系人电话:',
         value: mobile,
       }, {
-        key: '商户状态:',
+        key: '渠道状态:',
         value: statusCodeToName(status),
       }];
     };
@@ -161,7 +178,8 @@ export default class SupportCreatePage extends Component {
       title: '字段名',
       key: 1,
       dataIndex: 'key',
-      width: '15%',
+      width: '10%',
+      align: 'right',
     }, {
       title: '字段值',
       key: 2,
@@ -174,16 +192,16 @@ export default class SupportCreatePage extends Component {
       return (
         <Modal
           visible
-          width={900}
+          width={1100}
           footer={null}
-          title="配套列表"
+          title={`${productNameMap[scene]}列表`}
           maskClosable={false}
           onCancel={this.handleProductSelectorCancel}
         >
           <Selector
             multiple={false}
             loading={pLoading}
-            selectorName="Support"
+            selectorName={scene}
             list={product.list}
             pageNo={product.pageNo}
             pageSize={product.pageSize}
@@ -201,7 +219,7 @@ export default class SupportCreatePage extends Component {
           visible
           width={1100}
           footer={null}
-          title="商户列表"
+          title="渠道列表"
           maskClosable={false}
           onCancel={this.handleMerchantSelectorCancel}
         >
@@ -226,9 +244,7 @@ export default class SupportCreatePage extends Component {
       return (
         <div className={styles.cardName}>
           <span>
-            <a onClick={this.handleProductSelectorModalShow}>
-              选择配套
-            </a>
+            <a onClick={this.handleProductSelectorModalShow}>{`选择${productNameMap[scene]}`}</a>
           </span>
         </div>
       );
@@ -237,9 +253,7 @@ export default class SupportCreatePage extends Component {
       return (
         <div className={styles.cardName}>
           <span>
-            <a onClick={this.handleMerchantSelectorModalShow}>
-              选择商户
-            </a>
+            <a onClick={this.handleMerchantSelectorModalShow}>选择渠道</a>
           </span>
         </div>
       );
@@ -251,6 +265,7 @@ export default class SupportCreatePage extends Component {
         <Card title={renderProductCardName()} style={{ marginBottom: 16 }}>
           <Table
             bordered
+            size="small"
             showHeader={false}
             pagination={false}
             columns={columns}
@@ -263,6 +278,7 @@ export default class SupportCreatePage extends Component {
         <Card title={renderMerchantCardName()} style={{ marginBottom: 70 }}>
           <Table
             bordered
+            size="small"
             showHeader={false}
             pagination={false}
             columns={columns}

+ 0 - 6
src/routes/Shelves/Training/TrainingCreate.less

@@ -19,11 +19,5 @@
     .ant-table-body > table {
       padding: 0 !important;
     }
-    .ant-table-tbody > tr > td {
-      &:first-child {
-        background: #69c0ff;
-        font-weight: 500;
-      }
-    }
   }
 }

+ 18 - 13
src/routes/Shelves/Course/CourseEdit.js

@@ -1,12 +1,13 @@
 import React, { Component } from 'react';
+import pathToRegexp from 'path-to-regexp';
 import { Card, Modal, Form, Button, Tag, Icon } from 'antd';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import TableForm from './TableForm';
-import FooterToolbar from '../../../components/FooterToolbar';
-import Selector from '../../../components/AXTableSelector/Selector';
-import { addRowKey } from '../../../utils/utils';
-import { Hotax } from '../../../utils/config';
+import FooterToolbar from '../../components/FooterToolbar';
+import Selector from '../../components/AXTableSelector/Selector';
+import { addRowKey } from '../../utils/utils';
+import { Hotax } from '../../utils/config';
 
 @connect(({ loading, shelves, tag }) => ({
   tag,
@@ -15,16 +16,19 @@ import { Hotax } from '../../../utils/config';
   submitting: loading.models.shelves,
 }))
 @Form.create()
-export default class CourseEdit extends Component {
+export default class ShelvesEdit extends Component {
   constructor(props) {
     super(props);
     const { location } = props;
     const { state } = location;
     const { merchantId, pid, productType } = state;
+    const match = pathToRegexp('/shelves/:type/edit').exec(location.pathname);
+    const type = match[1];
     this.state = {
       pid,
       merchantId,
       productType,
+      scene: type,
       tagSelectorDestroy: true,
     };
   }
@@ -38,14 +42,14 @@ export default class CourseEdit extends Component {
       },
     });
   }
-  handleGoodsCreate=(data) => {
-    const { pid, merchantId } = this.state;
+  handleGoodsCreate = (data) => {
+    const { pid, merchantId, scene } = this.state;
     this.props.dispatch({
       type: 'shelves/createItemPrice',
       payload: {
         ...data,
         ...this.state,
-        productType: Hotax.PRODUCT_COURSE,
+        productType: scene.toUpperCase(),
         status: Hotax.STATUS_NORMAL,
       },
       states: {
@@ -54,7 +58,7 @@ export default class CourseEdit extends Component {
       },
     });
   };
-  handleGoodsUpdate=(data) => {
+  handleGoodsUpdate = (data) => {
     const { pid, merchantId } = this.state;
     this.props.dispatch({
       type: 'shelves/updateItemPrice',
@@ -68,7 +72,7 @@ export default class CourseEdit extends Component {
       },
     });
   };
-  handleGoodsDelete=(data) => {
+  handleGoodsDelete = (data) => {
     const { pid, merchantId } = this.state;
     this.props.dispatch({
       type: 'shelves/deleteItemPrice',
@@ -79,7 +83,7 @@ export default class CourseEdit extends Component {
       },
     });
   };
-  handleTagClose=(index) => {
+  handleTagClose = (index) => {
     const { pid, merchantId } = this.state;
     const { shelves } = this.props;
     const { currentItem } = shelves;
@@ -140,9 +144,10 @@ export default class CourseEdit extends Component {
       tagSelectorDestroy: true,
     });
   };
-  handlePageBack=() => {
+  handlePageBack = () => {
+    const { scene } = this.state;
     this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/course',
+      pathname: `/shelves/${scene.toLowerCase()}`,
       state: this.props.location.state,
     }));
   };

+ 56 - 21
src/routes/Shelves/Support/SupportList.js

@@ -1,45 +1,65 @@
 import React, { Component } from 'react';
+import pathToRegexp from 'path-to-regexp';
 import moment from 'moment';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Card, Modal, Button, message } from 'antd';
-import Ellipsis from '../../../components/Ellipsis';
-import { StandardTableList } from '../../../components/AXList';
-import { renderStatus, addRowKey } from '../../../utils/utils';
+import { StandardTableList } from '../../components/AXList';
+import Ellipsis from '../../components/Ellipsis';
+import { renderStatus, addRowKey } from '../../utils/utils';
 
 const Message = message;
 
+const productNameMap = {
+  Course: '课程',
+  Support: '配套',
+  Training: '师训',
+  Package: '套餐包',
+};
+
 @connect(({ loading, shelves }) => ({
   shelves,
   loading: loading.models.shelves,
 }))
-export default class SupportListPage extends Component {
+export default class ShelvesListPage extends Component {
   constructor(props) {
     super(props);
     const { state } = props.location;
+    const match = pathToRegexp('/shelves/:type/list').exec(location.pathname);
+    const type = match[1];
     this.state = {
+      scene: type && (type.substring(0, 1).toUpperCase() + type.substring(1)),
       UIParams: (state || {}).UIParams, // 组件的状态参数
       Queryers: (state || {}).Queryers, // 查询的条件参数
     };
   }
   componentDidMount() {
+    const { scene } = this.state;
     this.props.dispatch({
-      type: 'shelves/fetchSupportItemList',
+      type: `shelves/fetch${scene}ItemList`,
       payload: { ...this.state.Queryers },
     });
   }
+  /**
+   * 跳转到创建页面
+   */
   handleCreateOperation = () => {
+    const { scene } = this.state;
     this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/support/create',
+      pathname: `/shelves/${scene.toLowerCase()}/create`,
       state: this.state,
     }));
-  }
+  };
+  /**
+   * 下架某渠道下的一个产品
+   * @param {Object} item
+   */
   handleDeleteOperation = (item) => {
     Modal.confirm({
       okText: '确定',
       cancelText: '取消',
-      title: '你确定要下架该配套吗?',
-      content: '下架后该配套将不在对应平台上展现',
+      title: '你确定要下架该产品吗?',
+      content: '下架后该产品将不再任何栏目下展现',
       onOk: () => {
         this.props.dispatch({
           type: 'shelves/deleteItem',
@@ -48,32 +68,47 @@ export default class SupportListPage extends Component {
         });
       },
     });
-  }
+  };
+  /**
+   * 跳转到编辑界面
+   * @param {Object} item
+   */
   handleEditOperation = (item) => {
+    const { scene } = this.state;
     this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/support/edit',
+      pathname: `/shelves/${scene.toLowerCase()}/edit`,
       state: {
         pid: item.pid,
         merchantId: item.merchantId,
         ...this.state,
       },
     }));
-  }
+  };
+  /**
+   * 执行过滤操作
+   * @param {Object} params
+   * @param {Object} states
+   */
   handleFilterOperation = (params, states) => {
+    const { scene } = this.state;
     this.props.dispatch({
-      type: 'shelves/fetchSupportItemList',
+      type: `shelves/fetch${scene}ItemList`,
       payload: params,
     });
     this.setState({
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
+  /**
+   * TODO: 批量操作
+   */
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
+    const { scene } = this.state;
     const { loading, shelves } = this.props;
     const { list, totalSize, pageSize, pageNo } = shelves;
 
@@ -105,11 +140,11 @@ export default class SupportListPage extends Component {
     }];
     const basicSearch = {
       keys: [{
-        name: '配套编号',
-        field: 'code',
-      }, {
-        name: '配套名称',
+        name: `${productNameMap[scene]}名称`,
         field: 'name',
+      }, {
+        name: `${productNameMap[scene]}编号`,
+        field: 'code',
       }],
     };
     const pagination = {
@@ -118,12 +153,12 @@ export default class SupportListPage extends Component {
       totalSize,
     };
     const columns = [{
-      title: '配套编号',
+      title: `${productNameMap[scene]}编号`,
       key: 1,
       dataIndex: 'code',
       width: '15%',
     }, {
-      title: '配套名称',
+      title: `${productNameMap[scene]}名称`,
       key: 2,
       dataIndex: 'name',
       render: text => (

+ 0 - 29
src/routes/Shelves/Support/SupportCreate.less

@@ -1,29 +0,0 @@
-@import "~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;
-    }
-  }
-}
-
-.table {
-  :global {
-    .ant-table-body > table {
-      padding: 0 !important;
-    }
-    .ant-table-tbody > tr > td {
-      &:first-child {
-        background: #69c0ff;
-        font-weight: 500;
-      }
-    }
-  }
-}

+ 0 - 225
src/routes/Shelves/Support/SupportEdit.js

@@ -1,225 +0,0 @@
-import React, { Component } from 'react';
-import { Card, Modal, Form, Button, Tag, Icon } from 'antd';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import TableForm from './TableForm';
-import FooterToolbar from '../../../components/FooterToolbar';
-import Selector from '../../../components/AXTableSelector/Selector';
-import { addRowKey } from '../../../utils/utils';
-import { Hotax } from '../../../utils/config';
-
-@connect(({ loading, shelves, tag }) => ({
-  tag,
-  shelves,
-  tLoading: loading.models.tag,
-  submitting: loading.models.shelves,
-}))
-@Form.create()
-export default class SupportEdit extends Component {
-  constructor(props) {
-    super(props);
-    const { location } = props;
-    const { state } = location;
-    const { merchantId, pid, productType } = state;
-    this.state = {
-      pid,
-      merchantId,
-      productType,
-      tagSelectorDestroy: true,
-    };
-  }
-  componentDidMount() {
-    const { merchantId, pid } = this.state;
-    this.props.dispatch({
-      type: 'shelves/fetchItemDetail',
-      payload: {
-        pid,
-        merchantId,
-      },
-    });
-  }
-  handleGoodsCreate=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/createItemPrice',
-      payload: {
-        pid,
-        merchantId,
-        productType: Hotax.PRODUCT_SUPPORT,
-        status: Hotax.STATUS_NORMAL,
-        ...data,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleGoodsUpdate=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/updateItemPrice',
-      payload: {
-        ...data,
-        ...this.state,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleGoodsDelete=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/deleteItemPrice',
-      payload: data,
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleTagClose=(index) => {
-    const { pid, merchantId } = this.state;
-    const { shelves } = this.props;
-    const { currentItem } = shelves;
-    const { tags } = currentItem;
-    const newTags = tags.filter((item, location) => location !== index);
-    const newTagIds = newTags.map(item => item.id);
-    this.props.dispatch({
-      type: 'shelves/updateItemTags',
-      payload: {
-        pid,
-        merchantId,
-        tags: newTagIds,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleTagSelectorModalShow = () => {
-    this.setState({
-      tagSelectorDestroy: false,
-    });
-    const { merchantId } = this.state;
-    this.props.dispatch({
-      type: 'tag/fetchTagList',
-      payload: { merchantId },
-    });
-  };
-  handleTagSelectorCancel = () => {
-    this.setState({
-      tagSelectorDestroy: true,
-    });
-  };
-  handleTagSelectorChange = (params) => {
-    const { merchantId } = this.state;
-    this.props.dispatch({
-      type: 'tag/fetchTagList',
-      payload: { merchantId, ...params },
-    });
-  };
-  handleTagSelectorFinish = (rows) => {
-    const { pid, merchantId } = this.state;
-    const newTagIds = (rows || []).map(row => row.id);
-    this.props.dispatch({
-      type: 'shelves/updateItemTags',
-      payload: {
-        pid,
-        merchantId,
-        tags: newTagIds,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-    this.setState({
-      tagSelectorDestroy: true,
-    });
-  };
-  handlePageBack=() => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/support',
-      state: this.props.location.state,
-    }));
-  };
-  render() {
-    const { tagSelectorDestroy } = this.state;
-    const { submitting, tLoading, shelves, tag, form } = this.props;
-    const { getFieldDecorator } = form;
-    const { currentItem } = shelves;
-    const { goods, tags } = currentItem;
-
-    return (
-      <div>
-        <Card title="价格管理" style={{ marginBottom: 16 }}>
-          {getFieldDecorator('goods', {
-            initialValue: addRowKey(goods),
-          })(
-            <TableForm
-              loading={submitting}
-              onCreate={this.handleGoodsCreate}
-              onUpdate={this.handleGoodsUpdate}
-              onDelete={this.handleGoodsDelete}
-            />
-          )}
-        </Card>
-        <Card title="栏目管理" style={{ marginBottom: 70 }}>
-          {tags && tags.map((item, index) => (
-            <Tag
-              closable
-              key={item.id}
-              color="#87d068"
-              afterClose={() => this.handleTagClose(index)}
-            >
-              {item.name}
-            </Tag>
-          ))}
-          <Tag
-            style={{ borderStyle: 'dashed' }}
-            onClick={this.handleTagSelectorModalShow}
-          >
-            <Icon type="plus" />添加栏目
-          </Tag>
-          {!tagSelectorDestroy && (
-            <Modal
-              width={1100}
-              footer={null}
-              visible
-              title="标签列表"
-              maskClosable={false}
-              onCancel={this.handleMerchantSelectorCancel}
-            >
-              <Selector
-                multiple
-                loading={tLoading}
-                selectorName="Tag"
-                list={tag.list}
-                pageNo={tag.pageNo}
-                pageSize={tag.pageSize}
-                totalSize={tag.totalSize}
-                selectedRows={tags}
-                onCancel={this.handleTagSelectorCancel}
-                onChange={this.handleTagSelectorChange}
-                onFinish={this.handleTagSelectorFinish}
-              />
-            </Modal>
-          )}
-        </Card>
-        <FooterToolbar style={{ width: '100%' }}>
-          <Button
-            type="primary"
-            onClick={this.handlePageBack}
-            style={{ marginRight: 10 }}
-          >返回上一页
-          </Button>
-        </FooterToolbar>
-      </div>
-    );
-  }
-}
-

+ 0 - 297
src/routes/Shelves/Support/TableForm.js

@@ -1,297 +0,0 @@
-import React, { PureComponent, Fragment } from 'react';
-import {
-  Table,
-  Button,
-  Select,
-  InputNumber,
-  Popconfirm,
-  Divider,
-  message,
-} from 'antd';
-import { Hotax } from '../../../utils/config';
-import styles from './TableForm.less';
-
-const chargeUnitMap = [{
-  text: Hotax.CHARGE_UNIT_ITEM,
-  value: Hotax.CHARGE_UNIT_ITEM,
-}];
-
-export default class TableForm extends PureComponent {
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      data: props.value,
-      loading: props.loading,
-    };
-  }
-  componentWillReceiveProps(nextProps) {
-    if ('value' in nextProps) {
-      this.setState({
-        data: nextProps.value,
-      });
-    }
-  }
-  getRowByKey(key, newData) {
-    return (newData || this.state.data).filter(item => item.key === key)[0];
-  }
-  index = 0;
-  cacheOriginData = {};
-  toggleEditable=(e, key) => {
-    e.preventDefault();
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      // 进入编辑状态时保存原始数据
-      if (!target.editable) {
-        this.cacheOriginData[key] = { ...target };
-      }
-      target.editable = !target.editable;
-      this.setState({ data: newData });
-    }
-  };
-  chargeUnitSelectable=(value) => {
-    const tmp = this.state.data.find(item => item.chargeUnit === value);
-    return tmp !== undefined;
-  };
-  remove(record) {
-    const { key, isNew } = record;
-    const newData = this.state.data.filter(item => item.key !== key);
-    this.setState({ data: newData });
-    if (!isNew) {
-      this.props.onDelete({ goodsId: key });
-    }
-  }
-  newPrice = () => {
-    const newData = this.state.data.map(item => ({ ...item }));
-    newData.push({
-      key: `NEW_TEMP_ID_${this.index}`,
-      cpPrice: '',
-      merchantPrice: '',
-      terminalPrice: '',
-      editable: true,
-      isNew: true,
-    });
-    this.index += 1;
-    this.setState({ data: newData });
-  };
-  handleFieldChange(value, fieldName, key) {
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      target[fieldName] = value;
-      this.setState({ data: newData });
-    }
-  }
-  handleSelectChange(value, key) {
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (target) {
-      target.chargeUnit = value;
-      this.setState({ data: newData });
-    }
-  }
-  saveRow(e, key) {
-    e.persist();
-    if (this.clickedCancel) {
-      this.clickedCancel = false;
-      return;
-    }
-    const target = this.getRowByKey(key) || {};
-    if (!target.chargeUnit || !target.cpPrice || !target.merchantPrice || !target.terminalPrice) {
-      message.error('请填写完整价格信息');
-      e.target.focus();
-      return;
-    }
-    const { id, chargeUnit, cpPrice, merchantPrice, terminalPrice } = target;
-    if (target.isNew) {
-      this.props.onCreate({
-        cpPrice,
-        chargeUnit,
-        merchantPrice,
-        terminalPrice,
-        duration: 0,
-      });
-    } else {
-      this.props.onUpdate({
-        id,
-        cpPrice,
-        chargeUnit,
-        merchantPrice,
-        terminalPrice,
-        duration: 0,
-      });
-    }
-    delete target.isNew;
-    this.toggleEditable(e, key);
-  }
-  cancel(e, key) {
-    this.clickedCancel = true;
-    e.preventDefault();
-    const newData = this.state.data.map(item => ({ ...item }));
-    const target = this.getRowByKey(key, newData);
-    if (this.cacheOriginData[key]) {
-      Object.assign(target, this.cacheOriginData[key]);
-      target.editable = false;
-      delete this.cacheOriginData[key];
-    }
-    this.setState({ data: newData });
-    this.clickedCancel = false;
-  }
-  render() {
-    const columns = [{
-      title: '计价单位',
-      dataIndex: 'chargeUnit',
-      key: 'chargeUnit',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <Select
-              placeholder="请选择"
-              style={{ width: '100%' }}
-              value={text}
-              onChange={value => this.handleSelectChange(value, record.key)}
-              className={styles.select}
-            >
-              {
-                chargeUnitMap.map(item => (
-                  <Select.Option
-                    key={item.value}
-                    value={item.value}
-                    disabled={this.chargeUnitSelectable(item.value)}
-                  >
-                    {item.text}
-                  </Select.Option>
-                ))
-              }
-            </Select>
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '供应商售价(¥)',
-      dataIndex: 'cpPrice',
-      key: 'cpPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={e => this.handleFieldChange(e, 'cpPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '平台方售价(¥)',
-      dataIndex: 'merchantPrice',
-      key: 'merchantPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={value => this.handleFieldChange(value, 'merchantPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '终端显示价格(¥)',
-      dataIndex: 'terminalPrice',
-      key: 'terminalPrice',
-      width: '20%',
-      align: 'center',
-      render: (text, record) => {
-        if (record.editable) {
-          return (
-            <InputNumber
-              min={1}
-              value={text}
-              onChange={value => this.handleFieldChange(value, 'terminalPrice', record.key)}
-              style={{ width: '100%', border: 'unset' }}
-              placeholder="请输入"
-            />
-          );
-        }
-        return text;
-      },
-    }, {
-      title: '操作',
-      key: 'action',
-      align: 'center',
-      render: (text, record) => {
-        if (!!record.editable && this.state.loading) {
-          return null;
-        }
-        if (record.editable) {
-          if (record.isNew) {
-            return (
-              <span>
-                <a onClick={e => this.saveRow(e, record.key)}>添加</a>
-                <Divider type="vertical" />
-                <Popconfirm title="是否要删除此价格?" onConfirm={() => this.remove(record)}>
-                  <a>删除</a>
-                </Popconfirm>
-              </span>
-            );
-          }
-          return (
-            <span>
-              <a onClick={e => this.saveRow(e, record.key)}>保存</a>
-              <Divider type="vertical" />
-              <a onClick={e => this.cancel(e, record.key)}>取消</a>
-            </span>
-          );
-        }
-        return (
-          <span>
-            <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
-            <Divider type="vertical" />
-            <Popconfirm title="是否要删除此价格?" onConfirm={() => this.remove(record)}>
-              <a>删除</a>
-            </Popconfirm>
-          </span>
-        );
-      },
-    }];
-
-    return (
-      <Fragment>
-        <Table
-          bordered
-          pagination={false}
-          columns={columns}
-          loading={this.state.loading}
-          dataSource={this.state.data}
-          rowClassName={() => {
-            return styles.editable;
-          }}
-        />
-        <Button
-          style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
-          type="dashed"
-          onClick={this.newPrice}
-          icon="plus"
-        >
-          新增价格
-        </Button>
-      </Fragment>
-    );
-  }
-}

+ 0 - 13
src/routes/Shelves/Support/TableForm.less

@@ -1,13 +0,0 @@
-@import "~antd/lib/style/themes/default.less";
-
-.editable {
-  td {
-    height: 32px;
-    padding: 0 !important;
-  }
-}
-.select {
-  :global(.ant-select-selection) {
-    border: unset;
-  }
-}

+ 0 - 33
src/routes/Shelves/Support/index.js

@@ -1,33 +0,0 @@
-import React, { Component } from 'react';
-import { Redirect, Route, Switch } from 'dva/router';
-import { connect } from 'dva';
-import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
-import { getRoutes } from '../../../utils/utils';
-
-@connect()
-export default class Course extends Component {
-  render() {
-    const { match, routerData } = this.props;
-    const routes = getRoutes(match.path, routerData);
-
-    return (
-      <PageHeaderLayout>
-        <Switch>
-          {
-            routes.map(item =>
-              (
-                <Route
-                  key={item.key}
-                  path={item.path}
-                  component={item.component}
-                  exact={item.exact}
-                />
-              )
-            )
-          }
-          <Redirect exact from="/shelves/support" to="/shelves/support/list" />
-        </Switch>
-      </PageHeaderLayout>
-    );
-  }
-}

+ 20 - 15
src/routes/Shelves/Training/TableForm.js

@@ -8,14 +8,9 @@ import {
   Divider,
   message,
 } from 'antd';
-import { Hotax } from '../../../utils/config';
+import { chargeUnitMap, durationMap, sortMap } from '../../utils/utils';
 import styles from './TableForm.less';
 
-const chargeUnitMap = [{
-  text: Hotax.CHARGE_UNIT_ITEM,
-  value: Hotax.CHARGE_UNIT_ITEM,
-}];
-
 export default class TableForm extends PureComponent {
   constructor(props) {
     super(props);
@@ -88,6 +83,7 @@ export default class TableForm extends PureComponent {
     const target = this.getRowByKey(key, newData);
     if (target) {
       target.chargeUnit = value;
+      target.duration = durationMap[value];
       this.setState({ data: newData });
     }
   }
@@ -103,23 +99,26 @@ export default class TableForm extends PureComponent {
       e.target.focus();
       return;
     }
-    const { id, chargeUnit, cpPrice, merchantPrice, terminalPrice } = target;
+    const { id, chargeUnit, cpPrice, merchantPrice, terminalPrice, duration } = target;
+    const sort = sortMap[chargeUnit];
     if (target.isNew) {
       this.props.onCreate({
+        sort,
         cpPrice,
+        duration,
         chargeUnit,
         merchantPrice,
         terminalPrice,
-        duration: 0,
       });
     } else {
       this.props.onUpdate({
         id,
+        sort,
         cpPrice,
+        duration,
         chargeUnit,
         merchantPrice,
         terminalPrice,
-        duration: 0,
       });
     }
     delete target.isNew;
@@ -143,7 +142,7 @@ export default class TableForm extends PureComponent {
       title: '计价单位',
       dataIndex: 'chargeUnit',
       key: 'chargeUnit',
-      width: '20%',
+      width: '15%',
       align: 'center',
       render: (text, record) => {
         if (record.editable) {
@@ -156,13 +155,13 @@ export default class TableForm extends PureComponent {
               className={styles.select}
             >
               {
-                chargeUnitMap.map(item => (
+                Object.keys(chargeUnitMap).map(key => (
                   <Select.Option
-                    key={item.value}
-                    value={item.value}
-                    disabled={this.chargeUnitSelectable(item.value)}
+                    key={key}
+                    value={key}
+                    disabled={this.chargeUnitSelectable(key)}
                   >
-                    {item.text}
+                    {chargeUnitMap[key]}
                   </Select.Option>
                 ))
               }
@@ -172,6 +171,12 @@ export default class TableForm extends PureComponent {
         return text;
       },
     }, {
+      title: '时长(天)',
+      dataIndex: 'duration',
+      key: 'duration',
+      width: '15%',
+      align: 'center',
+    }, {
       title: '供应商售价(¥)',
       dataIndex: 'cpPrice',
       key: 'cpPrice',

src/routes/Shelves/Course/TableForm.less → src/routes/Shelves/TableForm.less


+ 0 - 13
src/routes/Shelves/Training/TableForm.less

@@ -1,13 +0,0 @@
-@import "~antd/lib/style/themes/default.less";
-
-.editable {
-  td {
-    height: 32px;
-    padding: 0 !important;
-  }
-}
-.select {
-  :global(.ant-select-selection) {
-    border: unset;
-  }
-}

+ 0 - 291
src/routes/Shelves/Training/TrainingCreate.js

@@ -1,291 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { message, Modal, Table, Card, Button } from 'antd';
-import Selector from '../../../components/AXTableSelector/Selector';
-import FooterToolbar from '../../../components/FooterToolbar';
-import { Hotax } from '../../../utils/config';
-import { renderCategory, statusCodeToName } from '../../../utils/utils';
-import styles from './TrainingCreate.less';
-
-const Message = message;
-
-@connect(({ loading, shelves, product, merchant }) => ({
-  product,
-  shelves,
-  merchant,
-  mLoading: loading.models.merchant,
-  pLoading: loading.models.product,
-  submitting: loading.models.shelves,
-}))
-export default class TrainingCreatePage extends Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      productItem: {},
-      merchantItem: {},
-      productSelectorDestroy: true,
-      merchantSelectorDestroy: true,
-    };
-  }
-  handleProductSelectorModalShow = () => {
-    this.setState({
-      productSelectorDestroy: false,
-    });
-    this.props.dispatch({
-      type: 'product/fetchTrainingList',
-      payload: {},
-    });
-  };
-  handleMerchantSelectorModalShow = () => {
-    this.setState({
-      merchantSelectorDestroy: false,
-    });
-    this.props.dispatch({
-      type: 'merchant/fetchMerchantList',
-      payload: {},
-    });
-  };
-  handleProductSelectorChange = (params) => {
-    this.props.dispatch({
-      type: 'product/fetchTrainingList',
-      payload: params,
-    });
-  };
-  handleMerchantSelectorChange = (params) => {
-    this.props.dispatch({
-      type: 'merchant/fetchMerchantList',
-      payload: params,
-    });
-  };
-  handleProductSelectorFinish = (rows) => {
-    this.setState({
-      productSelectorDestroy: true,
-      productItem: rows[0],
-    });
-  };
-  handleMerchantSelectorFinish = (rows) => {
-    this.setState({
-      merchantSelectorDestroy: true,
-      merchantItem: rows[0],
-    });
-  };
-  handleProductSelectorCancel = () => {
-    this.setState({
-      productSelectorDestroy: true,
-    });
-  };
-  handleMerchantSelectorCancel = () => {
-    this.setState({
-      merchantSelectorDestroy: true,
-    });
-  };
-  handlePageBack = () => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/training/list',
-      state: this.props.location.state,
-    }));
-  };
-  handlePageSubmit = (e) => {
-    e.preventDefault();
-    const { productItem, merchantItem } = this.state;
-    const { pid } = productItem;
-    const { id } = merchantItem;
-    if (!pid) {
-      Message.error('请选择要上架的师训内容!');
-      return;
-    }
-    if (!id) {
-      Message.error('请选择要上架的渠道!');
-      return;
-    }
-    this.props.dispatch({
-      type: 'shelves/createItem',
-      payload: {
-        pid,
-        merchantId: id,
-        status: Hotax.STATUS_NORMAL,
-      },
-      states: this.props.location.state,
-    });
-  };
-
-  render() {
-    const { submitting, pLoading, mLoading, merchant, product } = this.props;
-    const {
-      productSelectorDestroy, merchantSelectorDestroy, productItem, merchantItem,
-    } = this.state;
-
-    // format selected data
-    const productItemFormatter = () => {
-      const { code, name, status } = productItem;
-      return [{
-        key: '师训编号:',
-        value: code,
-      }, {
-        key: '师训名称:',
-        value: name,
-      }, {
-        key: '状态:',
-        value: statusCodeToName(status),
-      }];
-    };
-    const merchantItemFormatter = () => {
-      const { code, name, status, simple, contactName, mobile, domain } = merchantItem;
-      return [{
-        key: '商户编号:',
-        value: code,
-      }, {
-        key: '商户名称:',
-        value: name,
-      }, {
-        key: '商户简称:',
-        value: simple,
-      }, {
-        key: '商户类型:',
-        value: renderCategory(domain),
-      }, {
-        key: '商户联系人:',
-        value: contactName,
-      }, {
-        key: '联系人电话:',
-        value: mobile,
-      }, {
-        key: '商户状态:',
-        value: statusCodeToName(status),
-      }];
-    };
-
-    // table columns
-    const columns = [{
-      title: '字段名',
-      key: 1,
-      dataIndex: 'key',
-      width: '15%',
-    }, {
-      title: '字段值',
-      key: 2,
-      dataIndex: 'value',
-      width: '65%',
-    }];
-
-    // render modal selector
-    const getProductModal = () => {
-      return (
-        <Modal
-          visible
-          width={900}
-          footer={null}
-          title="师训列表"
-          maskClosable={false}
-          onCancel={this.handleProductSelectorCancel}
-        >
-          <Selector
-            multiple={false}
-            loading={pLoading}
-            selectorName="Training"
-            list={product.list}
-            pageNo={product.pageNo}
-            pageSize={product.pageSize}
-            totalSize={product.totalSize}
-            onCancel={this.handleProductSelectorCancel}
-            onChange={this.handleProductSelectorChange}
-            onFinish={this.handleProductSelectorFinish}
-          />
-        </Modal>
-      );
-    };
-    const getMerchantModal = () => {
-      return (
-        <Modal
-          visible
-          width={1100}
-          footer={null}
-          title="商户列表"
-          maskClosable={false}
-          onCancel={this.handleMerchantSelectorCancel}
-        >
-          <Selector
-            multiple={false}
-            loading={mLoading}
-            selectorName="Merchant"
-            list={merchant.list}
-            pageNo={merchant.pageNo}
-            pageSize={merchant.pageSize}
-            totalSize={merchant.totalSize}
-            onCancel={this.handleMerchantSelectorCancel}
-            onChange={this.handleMerchantSelectorChange}
-            onFinish={this.handleMerchantSelectorFinish}
-          />
-        </Modal>
-      );
-    };
-
-    // render card title
-    const renderProductCardName = () => {
-      return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleProductSelectorModalShow}>
-              选择配套
-            </a>
-          </span>
-        </div>
-      );
-    };
-    const renderMerchantCardName = () => {
-      return (
-        <div className={styles.cardName}>
-          <span>
-            <a onClick={this.handleMerchantSelectorModalShow}>
-              选择商户
-            </a>
-          </span>
-        </div>
-      );
-    };
-
-    return (
-      <div>
-        {/* 产品选择Card */}
-        <Card title={renderProductCardName()} style={{ marginBottom: 16 }}>
-          <Table
-            bordered
-            showHeader={false}
-            pagination={false}
-            columns={columns}
-            className={styles.table}
-            dataSource={productItemFormatter()}
-          />
-          {!productSelectorDestroy && getProductModal()}
-        </Card>
-        {/* 渠道选择Card */}
-        <Card title={renderMerchantCardName()} style={{ marginBottom: 70 }}>
-          <Table
-            bordered
-            showHeader={false}
-            pagination={false}
-            columns={columns}
-            className={styles.table}
-            dataSource={merchantItemFormatter()}
-          />
-          {!merchantSelectorDestroy && getMerchantModal()}
-        </Card>
-        <FooterToolbar style={{ width: '100%' }}>
-          <Button
-            onClick={this.handlePageBack}
-            style={{ marginRight: 10 }}
-          >取消
-          </Button>
-          <Button
-            type="primary"
-            loading={submitting}
-            onClick={this.handlePageSubmit}
-          >提交
-          </Button>
-        </FooterToolbar>
-      </div>
-    );
-  }
-}
-

+ 0 - 225
src/routes/Shelves/Training/TrainingEdit.js

@@ -1,225 +0,0 @@
-import React, { Component } from 'react';
-import { Card, Modal, Form, Button, Tag, Icon } from 'antd';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import TableForm from './TableForm';
-import FooterToolbar from '../../../components/FooterToolbar';
-import Selector from '../../../components/AXTableSelector/Selector';
-import { addRowKey } from '../../../utils/utils';
-import { Hotax } from '../../../utils/config';
-
-@connect(({ loading, shelves, tag }) => ({
-  tag,
-  shelves,
-  tLoading: loading.models.tag,
-  submitting: loading.models.shelves,
-}))
-@Form.create()
-export default class TrainingEdit extends Component {
-  constructor(props) {
-    super(props);
-    const { location } = props;
-    const { state } = location;
-    const { merchantId, pid, productType } = state;
-    this.state = {
-      pid,
-      merchantId,
-      productType,
-      tagSelectorDestroy: true,
-    };
-  }
-  componentDidMount() {
-    const { merchantId, pid } = this.state;
-    this.props.dispatch({
-      type: 'shelves/fetchItemDetail',
-      payload: {
-        pid,
-        merchantId,
-      },
-    });
-  }
-  handleGoodsCreate=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/createItemPrice',
-      payload: {
-        pid,
-        merchantId,
-        productType: Hotax.PRODUCT_SUPPORT,
-        status: Hotax.STATUS_NORMAL,
-        ...data,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleGoodsUpdate=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/updateItemPrice',
-      payload: {
-        ...data,
-        ...this.state,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleGoodsDelete=(data) => {
-    const { pid, merchantId } = this.state;
-    this.props.dispatch({
-      type: 'shelves/deleteItemPrice',
-      payload: data,
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleTagClose=(index) => {
-    const { pid, merchantId } = this.state;
-    const { shelves } = this.props;
-    const { currentItem } = shelves;
-    const { tags } = currentItem;
-    const newTags = tags.filter((item, location) => location !== index);
-    const newTagIds = newTags.map(item => item.id);
-    this.props.dispatch({
-      type: 'shelves/updateItemTags',
-      payload: {
-        pid,
-        merchantId,
-        tags: newTagIds,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-  };
-  handleTagSelectorModalShow = () => {
-    this.setState({
-      tagSelectorDestroy: false,
-    });
-    const { merchantId } = this.state;
-    this.props.dispatch({
-      type: 'tag/fetchTagList',
-      payload: { merchantId },
-    });
-  };
-  handleTagSelectorCancel = () => {
-    this.setState({
-      tagSelectorDestroy: true,
-    });
-  };
-  handleTagSelectorChange = (params) => {
-    const { merchantId } = this.state;
-    this.props.dispatch({
-      type: 'tag/fetchTagList',
-      payload: { merchantId, ...params },
-    });
-  };
-  handleTagSelectorFinish = (rows) => {
-    const { pid, merchantId } = this.state;
-    const newTagIds = (rows || []).map(row => row.id);
-    this.props.dispatch({
-      type: 'shelves/updateItemTags',
-      payload: {
-        pid,
-        merchantId,
-        tags: newTagIds,
-      },
-      states: {
-        pid,
-        merchantId,
-      },
-    });
-    this.setState({
-      tagSelectorDestroy: true,
-    });
-  };
-  handlePageBack=() => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/support',
-      state: this.props.location.state,
-    }));
-  };
-  render() {
-    const { tagSelectorDestroy } = this.state;
-    const { submitting, tLoading, shelves, tag, form } = this.props;
-    const { getFieldDecorator } = form;
-    const { currentItem } = shelves;
-    const { goods, tags } = currentItem;
-
-    return (
-      <div>
-        <Card title="价格管理" style={{ marginBottom: 16 }}>
-          {getFieldDecorator('goods', {
-            initialValue: addRowKey(goods),
-          })(
-            <TableForm
-              loading={submitting}
-              onCreate={this.handleGoodsCreate}
-              onUpdate={this.handleGoodsUpdate}
-              onDelete={this.handleGoodsDelete}
-            />
-          )}
-        </Card>
-        <Card title="栏目管理" style={{ marginBottom: 70 }}>
-          {tags && tags.map((item, index) => (
-            <Tag
-              closable
-              key={item.id}
-              color="#87d068"
-              afterClose={() => this.handleTagClose(index)}
-            >
-              {item.name}
-            </Tag>
-          ))}
-          <Tag
-            style={{ borderStyle: 'dashed' }}
-            onClick={this.handleTagSelectorModalShow}
-          >
-            <Icon type="plus" />添加栏目
-          </Tag>
-          {!tagSelectorDestroy && (
-            <Modal
-              width={1100}
-              footer={null}
-              visible
-              title="标签列表"
-              maskClosable={false}
-              onCancel={this.handleMerchantSelectorCancel}
-            >
-              <Selector
-                multiple
-                loading={tLoading}
-                selectorName="Tag"
-                list={tag.list}
-                pageNo={tag.pageNo}
-                pageSize={tag.pageSize}
-                totalSize={tag.totalSize}
-                selectedRows={tags}
-                onCancel={this.handleTagSelectorCancel}
-                onChange={this.handleTagSelectorChange}
-                onFinish={this.handleTagSelectorFinish}
-              />
-            </Modal>
-          )}
-        </Card>
-        <FooterToolbar style={{ width: '100%' }}>
-          <Button
-            type="primary"
-            onClick={this.handlePageBack}
-            style={{ marginRight: 10 }}
-          >返回上一页
-          </Button>
-        </FooterToolbar>
-      </div>
-    );
-  }
-}
-

+ 0 - 179
src/routes/Shelves/Training/TrainingList.js

@@ -1,179 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { Card, Modal, Button, message } from 'antd';
-import Ellipsis from '../../../components/Ellipsis';
-import { StandardTableList } from '../../../components/AXList';
-import { renderStatus, addRowKey } from '../../../utils/utils';
-
-const Message = message;
-
-@connect(({ loading, shelves }) => ({
-  shelves,
-  loading: loading.models.shelves,
-}))
-export default class TrainingListPage extends Component {
-  constructor(props) {
-    super(props);
-    const { state } = props.location;
-    this.state = {
-      UIParams: (state || {}).UIParams, // 组件的状态参数
-      Queryers: (state || {}).Queryers, // 查询的条件参数
-    };
-  }
-  componentDidMount() {
-    this.props.dispatch({
-      type: 'shelves/fetchTrainingItemList',
-      payload: { ...this.state.Queryers },
-    });
-  }
-  handleCreateOperation = () => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/training/create',
-      state: this.state,
-    }));
-  }
-  handleDeleteOperation = (item) => {
-    Modal.confirm({
-      okText: '确定',
-      cancelText: '取消',
-      title: '你确定要下架该师训课程吗?',
-      content: '下架后该师训课程后将不在对应平台上展现',
-      onOk: () => {
-        this.props.dispatch({
-          type: 'shelves/deleteItem',
-          payload: { id: item.id },
-          states: this.state,
-        });
-      },
-    });
-  }
-  handleEditOperation = (item) => {
-    this.props.dispatch(routerRedux.push({
-      pathname: '/shelves/training/edit',
-      state: {
-        pid: item.pid,
-        merchantId: item.merchantId,
-        ...this.state,
-      },
-    }));
-  }
-  handleFilterOperation = (params, states) => {
-    this.props.dispatch({
-      type: 'shelves/fetchTrainingItemList',
-      payload: params,
-    });
-    this.setState({
-      UIParams: states,
-      Queryers: params,
-    });
-  }
-  handleBatchOperation = () => {
-    Message.info('暂不支持批量操作!');
-  }
-
-  render() {
-    const { loading, shelves } = this.props;
-    const { list, totalSize, pageSize, pageNo } = shelves;
-
-    const renderOperation = (item) => {
-      return (
-        <div>
-          <Button
-            size="small"
-            className="editBtn"
-            onClick={() => this.handleEditOperation(item)}
-          >编辑
-          </Button>
-          <Button
-            size="small"
-            className="delBtn"
-            onClick={() => this.handleDeleteOperation(item)}
-          >下架
-          </Button>
-        </div>
-      );
-    };
-
-    const batchActions = [{
-      key: 'delete',
-      name: '批量删除',
-    }, {
-      key: 'recovery',
-      name: '批量恢复',
-    }];
-    const basicSearch = {
-      keys: [{
-        name: '师训编号',
-        field: 'code',
-      }, {
-        name: '师训主题',
-        field: 'name',
-      }],
-    };
-    const pagination = {
-      pageNo,
-      pageSize,
-      totalSize,
-    };
-    const columns = [{
-      title: '师训编号',
-      key: 1,
-      dataIndex: 'code',
-      width: '15%',
-    }, {
-      title: '师训主题',
-      key: 2,
-      dataIndex: 'name',
-      render: text => (
-        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
-      ),
-      width: '30%',
-    }, {
-      title: '上架渠道',
-      key: 3,
-      dataIndex: 'merchantName',
-      width: '14%',
-    }, {
-      title: '上架状态',
-      key: 4,
-      dataIndex: 'status',
-      render: text => renderStatus(text, '已下架', '已上架'),
-      width: '10%',
-    }, {
-      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) => renderOperation(record),
-      width: '13%',
-      align: 'right',
-    }];
-    return (
-      <Card>
-        <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 }}
-        />
-      </Card>
-    );
-  }
-}

+ 0 - 33
src/routes/Shelves/Training/index.js

@@ -1,33 +0,0 @@
-import React, { Component } from 'react';
-import { Redirect, Route, Switch } from 'dva/router';
-import { connect } from 'dva';
-import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
-import { getRoutes } from '../../../utils/utils';
-
-@connect()
-export default class Training extends Component {
-  render() {
-    const { match, routerData } = this.props;
-    const routes = getRoutes(match.path, routerData);
-
-    return (
-      <PageHeaderLayout>
-        <Switch>
-          {
-            routes.map(item =>
-              (
-                <Route
-                  key={item.key}
-                  path={item.path}
-                  component={item.component}
-                  exact={item.exact}
-                />
-              )
-            )
-          }
-          <Redirect exact from="/shelves/training" to="/shelves/training/list" />
-        </Switch>
-      </PageHeaderLayout>
-    );
-  }
-}

+ 10 - 4
src/routes/Shelves/Package/index.js

@@ -1,12 +1,18 @@
 import React, { Component } from 'react';
+import pathToRegexp from 'path-to-regexp';
 import { Redirect, Route, Switch } from 'dva/router';
 import { connect } from 'dva';
-import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
-import { getRoutes } from '../../../utils/utils';
+import PageHeaderLayout from '../../layouts/PageHeaderLayout';
+import { getRoutes } from '../../utils/utils';
 
 @connect()
-export default class Course extends Component {
+export default class Shelves extends Component {
   render() {
+    let targetPath = pathToRegexp('/shelves/:target').exec(this.props.location.pathname);
+    if (!targetPath) {
+      targetPath = pathToRegexp('/shelves/:target/:operation').exec(this.props.location.pathname);
+    }
+    const target = targetPath[1];
     const { match, routerData } = this.props;
     const routes = getRoutes(match.path, routerData);
 
@@ -25,7 +31,7 @@ export default class Course extends Component {
               )
             )
           }
-          <Redirect exact from="/shelves/package" to="/shelves/package/list" />
+          <Redirect exact from={`/shelves/${target}`} to={`/shelves/${target}/list`} />
         </Switch>
       </PageHeaderLayout>
     );

+ 0 - 1
src/routes/System/CmsUser/CmsUserCreate.less

@@ -14,7 +14,6 @@
     }
     .ant-table-tbody > tr > td {
       &:first-child {
-        background: #69c0ff;
         font-weight: 500;
       }
     }

+ 5 - 5
src/routes/System/CmsUser/CmsUserEdit.js

@@ -121,12 +121,12 @@ export default class CmsUserEditPage extends PureComponent {
     } else {
       callback();
     }
-  }
+  };
   handlePasswordEdit = () => {
     this.setState({
       passwordEdit: true,
     });
-  }
+  };
   handlePasswordSave = () => {
     this.props.form.validateFieldsAndScroll((error) => {
       if (!error) {
@@ -135,7 +135,7 @@ export default class CmsUserEditPage extends PureComponent {
         });
       }
     });
-  }
+  };
   handlePageSubmit = () => {
     this.props.form.validateFieldsAndScroll((error, values) => {
       const { currentItem, passwordEdit } = this.state;
@@ -151,13 +151,13 @@ export default class CmsUserEditPage extends PureComponent {
         });
       }
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/system/cms-user/list',
       state: this.props.location.state,
     }));
-  }
+  };
 
   render() {
     const { form, submitting } = this.props;

+ 5 - 1
src/routes/System/CmsUser/CmsUserList.js

@@ -3,7 +3,8 @@ import moment from 'moment';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Card, Modal, Button, message } from 'antd';
-import { StandardTableList } from '../../../components/AXList/index';
+import Ellipsis from '../../../components/Ellipsis';
+import { StandardTableList } from '../../../components/AXList';
 import {
   addRowKey,
   renderStatus,
@@ -163,6 +164,9 @@ export default class CmsUserListPage extends Component {
       key: 2,
       dataIndex: 'name',
       width: '10%',
+      render: text => (
+        <Ellipsis tooltip lines={1}>{text}</Ellipsis>
+      ),
     }, {
       title: '用户昵称',
       key: 3,

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

@@ -49,7 +49,7 @@ export default class TerminalCreatePage extends PureComponent {
     } else {
       callback();
     }
-  }
+  };
   handleCampusSelectorModalShow = () => {
     this.setState({
       campusSelectorDestroy: false,
@@ -58,7 +58,7 @@ export default class TerminalCreatePage extends PureComponent {
       type: 'campus/fetchCampusList',
       payload: {},
     });
-  }
+  };
   handleCampusSelectorFinish = (rows) => {
     this.setState({
       campusSelectorDestroy: true,
@@ -87,7 +87,7 @@ export default class TerminalCreatePage extends PureComponent {
       type: 'campus/fetchCampusList',
       payload: params,
     });
-  }
+  };
   handlePageSubmit = () => {
     this.props.form.validateFieldsAndScroll((error, values) => {
       const { currentItem } = this.props.terminal;
@@ -107,13 +107,13 @@ export default class TerminalCreatePage extends PureComponent {
         });
       }
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/terminal/user/list',
       state: this.props.location.state,
     }));
-  }
+  };
 
   render() {
     const { campusSelectorDestroy } = this.state;

+ 0 - 1
src/routes/Terminal/User/TerminalCreate.less

@@ -15,7 +15,6 @@
     }
     .ant-table-tbody > tr > td {
       &:first-child {
-        background: #69c0ff;
         font-weight: 500;
       }
     }

+ 5 - 5
src/routes/Terminal/User/TerminalEdit.js

@@ -99,12 +99,12 @@ export default class TerminalEditPage extends PureComponent {
     } else {
       callback();
     }
-  }
+  };
   handlePasswordEdit = () => {
     this.setState({
       passwordEdit: true,
     });
-  }
+  };
   handlePasswordSave = () => {
     this.props.form.validateFieldsAndScroll((error) => {
       if (!error) {
@@ -113,7 +113,7 @@ export default class TerminalEditPage extends PureComponent {
         });
       }
     });
-  }
+  };
   handlePageSubmit = () => {
     this.props.form.validateFieldsAndScroll((error, values) => {
       const { currentItem, passwordEdit } = this.state;
@@ -129,13 +129,13 @@ export default class TerminalEditPage extends PureComponent {
         });
       }
     });
-  }
+  };
   handlePageBack = () => {
     this.props.dispatch(routerRedux.push({
       pathname: '/terminal/user/list',
       state: this.props.location.state,
     }));
-  }
+  };
 
   render() {
     const { form, submitting } = this.props;

+ 12 - 5
src/routes/Terminal/User/TerminalList.js

@@ -6,7 +6,7 @@ import { Card, Modal, Form, Button, message } from 'antd';
 import { StandardTableList } from '../../../components/AXList/index';
 import AXRemoteSelect from '../../../components/AXRemoteSelect/index';
 import Ellipsis from '../../../components/Ellipsis/index';
-import { addRowKey, renderStatus } from '../../../utils/utils';
+import { addRowKey, renderStatus, renderBindStatus } from '../../../utils/utils';
 import { Hotax } from '../../../utils/config';
 
 const Message = message;
@@ -192,6 +192,7 @@ export default class TerminalListPage extends Component {
             size="small"
             className="depositBtn"
             onClick={() => this.handleDeviceUnboundOperation(item)}
+            disabled={!item.deviceStatus}
           >解绑
           </Button>
           {
@@ -253,7 +254,7 @@ export default class TerminalListPage extends Component {
       key: 3,
       dataIndex: 'campusName',
       render: text => renderCampusName(text),
-      width: '20%',
+      width: '13%',
     }, {
       title: '所属渠道',
       key: 4,
@@ -264,16 +265,22 @@ export default class TerminalListPage extends Component {
       key: 5,
       dataIndex: 'status',
       render: text => renderStatus(text, '已禁用'),
-      width: '10%',
+      width: '8%',
     }, {
-      title: '更新时间',
+      title: '绑定状态',
       key: 6,
+      dataIndex: 'deviceStatus',
+      render: text => renderBindStatus(text),
+      width: '9%',
+    }, {
+      title: '更新时间',
+      key: 7,
       dataIndex: 'gmtModified',
       render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
       width: '15%',
     }, {
       title: '操作',
-      key: 7,
+      key: 8,
       dataIndex: 'operation',
       render: (_, record) => renderOperation(record),
       width: '18%',

+ 5 - 5
src/routes/User/Login.js

@@ -14,11 +14,11 @@ export default class LoginPage extends Component {
   state = {
     type: 'account',
     autoLogin: true,
-  }
+  };
 
   onTabChange = (type) => {
     this.setState({ type });
-  }
+  };
 
   handleSubmit = (err, values) => {
     if (!err) {
@@ -29,19 +29,19 @@ export default class LoginPage extends Component {
         },
       });
     }
-  }
+  };
 
   changeAutoLogin = (e) => {
     this.setState({
       autoLogin: e.target.checked,
     });
-  }
+  };
 
   renderMessage = (content) => {
     return (
       <Alert style={{ marginBottom: 24 }} message={content} type="error" showIcon />
     );
-  }
+  };
 
   render() {
     const { login, submitting } = this.props;

+ 38 - 0
src/services/tagType.js

@@ -0,0 +1,38 @@
+import { stringify } from 'qs';
+import request from '../utils/request';
+import { api, Hotax } from '../utils/config';
+
+export async function queryTagTypeList(params) {
+  const newParams = {
+    pageSize: Hotax.PAGE_SIZE,
+    ...params,
+  };
+  return request(`${api.tagType}?${stringify(newParams)}`);
+}
+
+export async function queryTagTypeItem({ tagTypeId }) {
+  return request(`${api.tagTypeItem}/${tagTypeId}`);
+}
+
+export async function createTagTypeItem(params) {
+  const options = {
+    method: 'POST',
+    body: params,
+  };
+  return request(`${api.tagTypeItem}`, options);
+}
+
+export async function updateTagTypeItem(params) {
+  const options = {
+    method: 'PUT',
+    body: params,
+  };
+  return request(`${api.tagTypeItem}`, options);
+}
+
+export async function deleteTagTypeItem({ tagTypeId }) {
+  const options = {
+    method: 'DELETE',
+  };
+  return request(`${api.tagTypeItem}/${tagTypeId}`, options);
+}

+ 9 - 0
src/utils/config.js

@@ -54,9 +54,16 @@ Hotax.CHARGE_UNIT_SEASON = '季';
 Hotax.CHARGE_UNIT_HALF_YEAR = '半年';
 Hotax.CHARGE_UNIT_YEAR = '年';
 Hotax.CHARGE_UNIT_ITEM = '件';
+Hotax.CHARGE_UNIT_DAY = '天';
 Hotax.DURATION_SEASON = 90;
 Hotax.DURATION_HALF_YEAR = 180;
 Hotax.DURATION_YEAR = 365;
+Hotax.DURATION_DAY = 1;
+Hotax.DURATION_ITEM = 0;
+
+// 账号的绑定状态
+Hotax.ACCOUNT_BINDING = 1;
+Hotax.ACCOUNT_UNBOUND = 0;
 
 // 分页大小
 Hotax.PAGE_SIZE = 20;
@@ -104,6 +111,8 @@ const apiObj = {
   lessonItem: '/lesson',
   tagGroup: '/group/list',
   tagGroupItem: '/group',
+  tagType: '/tagType/list',
+  tagTypeItem: '/tagType',
   tag: '/tag/list',
   tagItem: '/tag',
   product: '/product',

+ 47 - 1
src/utils/utils.js

@@ -241,6 +241,17 @@ export function statusCodeToName(status) {
     return '';
   }
 }
+export function renderBindStatus(status, delText, normalText) {
+  if (status === Hotax.ACCOUNT_BINDING) {
+    return (
+      <Badge status="warning" text={normalText || '已绑定'} />
+    );
+  } else {
+    return (
+      <Badge status="success" text={delText || '未绑定'} />
+    );
+  }
+}
 export function renderVideoQuality(quality) {
   if (quality === 'high') {
     return '高清';
@@ -428,6 +439,19 @@ export function renderGoodsType(status) {
   }
 }
 
+export function getResourceTypeName(type) {
+  switch (type) {
+    case Hotax.RESOURCE_VIDEO:
+      return '视频';
+    case Hotax.RESOURCE_AUDIO:
+      return '音频';
+    case Hotax.RESOURCE_IMAGE:
+      return '图片';
+    default:
+      return '';
+  }
+}
+
 // 视频相关常量
 const resourceTypes = {
   [Hotax.RESOURCE_AUDIO]: '音频',
@@ -439,4 +463,26 @@ const resourceQuality = {
   [Hotax.QUALITY_HIGH]: '高清',
   [Hotax.QUALITY_SUPERCLEAR]: '超清',
 };
-export { resourceTypes, resourceQuality };
+// 价格相关常量
+const chargeUnitMap = {
+  [Hotax.CHARGE_UNIT_DAY]: '天',
+  [Hotax.CHARGE_UNIT_SEASON]: '季',
+  [Hotax.CHARGE_UNIT_HALF_YEAR]: '半年',
+  [Hotax.CHARGE_UNIT_YEAR]: '年',
+  [Hotax.CHARGE_UNIT_ITEM]: '件',
+};
+const durationMap = {
+  [Hotax.CHARGE_UNIT_SEASON]: Hotax.DURATION_SEASON,
+  [Hotax.CHARGE_UNIT_HALF_YEAR]: Hotax.DURATION_HALF_YEAR,
+  [Hotax.CHARGE_UNIT_YEAR]: Hotax.DURATION_YEAR,
+  [Hotax.CHARGE_UNIT_DAY]: Hotax.DURATION_DAY,
+  [Hotax.CHARGE_UNIT_ITEM]: Hotax.DURATION_ITEM,
+};
+const sortMap = {
+  [Hotax.CHARGE_UNIT_ITEM]: -1,
+  [Hotax.CHARGE_UNIT_DAY]: 0,
+  [Hotax.CHARGE_UNIT_SEASON]: 1,
+  [Hotax.CHARGE_UNIT_HALF_YEAR]: 2,
+  [Hotax.CHARGE_UNIT_YEAR]: 3,
+};
+export { resourceTypes, resourceQuality, chargeUnitMap, durationMap, sortMap };