Przeglądaj źródła

:sparkles: add feature `create poster`;
:sparkles: add feature `update poster`;
:sparkles: add feature `delete poster`;

zhanghe 6 lat temu
rodzic
commit
f0230be547

BIN
src/assets/bitmap.png


+ 1 - 1
src/common/menu.js

@@ -85,7 +85,7 @@ const menuData = () => {
         name: '侧边栏目',
         path: 'tag',
       }, {
-        name: '推荐位配置',
+        name: '推荐内容',
         path: 'recommend',
       }],
       authority: ['admin', 'platform'],

+ 6 - 3
src/common/router.js

@@ -315,11 +315,14 @@ export const getRouterData = (app) => {
     '/frontend/recommend': {
       component: dynamicWrapper(app, ['merchant'], () => import('../routes/Frontend/Recommend')),
     },
-    '/frontend/recommend/list': {
+    '/frontend/recommend/merchant-list': {
       component: dynamicWrapper(app, ['merchant'], () => import('../routes/Frontend/Recommend/RecommendList')),
     },
-    '/frontend/recommend/edit/:id': {
-      component: dynamicWrapper(app, ['merchant', 'shelves'], () => import('../routes/Frontend/Recommend/RecommendEdit')),
+    '/frontend/recommend/course-edit/:id': {
+      component: dynamicWrapper(app, ['merchant', 'shelves'], () => import('../routes/Frontend/Recommend/RecommendCourse')),
+    },
+    '/frontend/recommend/poster-edit/:id': {
+      component: dynamicWrapper(app, ['merchant', 'shelves'], () => import('../routes/Frontend/Recommend/RecommendPoster')),
     },
     // 交易管理相关路由注册
     '/trade/shopcart': {

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

@@ -138,6 +138,30 @@ const clMap = {
       dataIndex: 'name',
     }],
   },
+  Training: {
+    columns: [{
+      title: '师训编号',
+      key: 1,
+      dataIndex: 'code',
+      width: '40%',
+    }, {
+      title: '师训主题',
+      key: 2,
+      dataIndex: 'name',
+    }],
+  },
+  Package: {
+    columns: [{
+      title: '套餐包编号',
+      key: 1,
+      dataIndex: 'code',
+      width: '40%',
+    }, {
+      title: '套餐包名称',
+      key: 2,
+      dataIndex: 'name',
+    }],
+  },
   Product: {
     columns: [{
       title: '产品编号',

+ 92 - 2
src/models/merchant.js

@@ -9,7 +9,12 @@ import {
   depositMerchantItem,
   queryMerchantRecommend,
   updateMerchantRecommend,
+  queryMerchantPoster,
+  createMerchantPosterItem,
+  updateMerchantPosterItem,
+  deleteMerchantPosterItem, queryMerchantPosterItem,
 } from '../services/merchant';
+import { Hotax } from '../utils/config';
 
 export default {
   namespace: 'merchant',
@@ -103,13 +108,92 @@ export default {
     *updateMerchantRecommend({ payload, states }, { call, put }) {
       const response = yield call(updateMerchantRecommend, payload);
       if (response.success) {
-        message.success('推荐列表更新成功');
+        message.success('推荐课程列表更新成功');
         yield put(routerRedux.push({
-          pathname: '/frontend/recommend/list',
+          pathname: '/frontend/recommend',
           state: states,
         }));
       }
     },
+    *fetchMerchantPoster({ payload }, { call, put }) {
+      const response = yield call(queryMerchantPoster, payload);
+      if (response.success) {
+        yield put({
+          type: 'querySuccess',
+          payload: {
+            posterList: response.data || [],
+          },
+        });
+      }
+    },
+    *fetchMerchantPosterItem({ payload }, { call, put }) {
+      const response = yield call(queryMerchantPosterItem, payload);
+      if (response.success) {
+        yield put({
+          type: 'querySuccess',
+          payload: {
+            posterItem: response.data || {},
+          },
+        });
+      }
+    },
+    *createMerchantPosterItem({ payload, posterId }, { call, put, select }) {
+      const response = yield call(createMerchantPosterItem, payload);
+      if (response.success) {
+        message.success('创建海报成功');
+        // 创建成功,更新该条数据id
+        const originalData = yield select(state => state.merchant.posterList);
+        const newData = originalData.map((data) => {
+          const { id, isNew, isEdit, ...rest } = data;
+          if (id === posterId) {
+            return { ...rest, id: response.data.id };
+          }
+          return { ...data };
+        });
+        yield put({
+          type: 'fixPosterList',
+          payload: newData,
+        });
+      }
+    },
+    *updateMerchantPosterItem({ payload, posterId }, { call, put, select }) {
+      const response = yield call(updateMerchantPosterItem, payload);
+      if (response.success) {
+        message.success('修改海报成功');
+        // 修改成功,去掉isEdit字段
+        const originalData = yield select(state => state.merchant.posterList);
+        const newData = originalData.map((data) => {
+          const { isEdit, ...rest } = data;
+          if (data.id === posterId) {
+            return { ...rest };
+          }
+          return { ...data };
+        });
+        yield put({
+          type: 'fixPosterList',
+          payload: newData,
+        });
+      }
+    },
+    *deleteMerchantPosterItem({ payload }, { call, put, select }) {
+      const response = yield call(deleteMerchantPosterItem, payload);
+      if (response.success) {
+        message.success('删除海报成功');
+        // 删除成功后修改该条的status字段为删除状态
+        const { posterId } = payload;
+        const originalData = yield select(state => state.merchant.posterList);
+        const newData = originalData.map((data) => {
+          if (data.id === posterId) {
+            return { ...data, status: Hotax.STATUS_DELETE };
+          }
+          return { ...data };
+        });
+        yield put({
+          type: 'fixPosterList',
+          payload: newData,
+        });
+      }
+    },
   },
 
   reducers: {
@@ -125,6 +209,12 @@ export default {
         recommendList: action.payload,
       };
     },
+    fixPosterList(state, action) {
+      return {
+        ...state,
+        posterList: action.payload,
+      };
+    },
     cleanItemState(state) {
       return {
         ...state,

+ 2 - 2
src/routes/Frontend/Recommend/RecommendEdit.js

@@ -13,7 +13,7 @@ import FooterToolbar from '../../../components/FooterToolbar/index';
   sLoading: loading.models.product,
   submitting: loading.models.merchant,
 }))
-export default class RecommendEditPage extends Component {
+export default class RecommendCourseEditPage extends Component {
   state = {
     productSelectorDestroy: true,
   };
@@ -24,7 +24,7 @@ export default class RecommendEditPage extends Component {
     });
   }
   getMerchantId = () => {
-    const match = pathToRegexp('/frontend/recommend/edit/:id')
+    const match = pathToRegexp('/frontend/recommend/course-edit/:id')
       .exec(this.props.location.pathname);
     return match[1];
   }

+ 15 - 11
src/routes/Frontend/Recommend/RecommendList.js

@@ -2,7 +2,7 @@ import React, { Component } from 'react';
 import moment from 'moment';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
-import { Card, Button, message } from 'antd';
+import { Card, Divider, message } from 'antd';
 import { StandardTableList } from '../../../components/AXList';
 import { renderStatus, renderCategory, addRowKey } from '../../../utils/utils';
 
@@ -29,10 +29,16 @@ export default class MerchantListPage extends Component {
   }
   handleEditRecommend = ({ id }) => {
     this.props.dispatch(routerRedux.push({
-      pathname: `/frontend/recommend/edit/${id}`,
+      pathname: `/frontend/recommend/course-edit/${id}`,
       state: this.state,
     }));
-  }
+  };
+  handleEditPoster = ({ id }) => {
+    this.props.dispatch(routerRedux.push({
+      pathname: `/frontend/recommend/poster-edit/${id}`,
+      state: this.state,
+    }));
+  };
   handleFilterOperation = (params, states) => {
     this.props.dispatch({
       type: 'merchant/fetchMerchantList',
@@ -42,24 +48,22 @@ export default class MerchantListPage extends Component {
       UIParams: states,
       Queryers: params,
     });
-  }
+  };
   handleBatchOperation = () => {
     Message.info('暂不支持批量操作!');
-  }
+  };
 
   render() {
     const { loading, merchant } = this.props;
     const { list, totalSize, pageSize, pageNo } = merchant;
 
     const renderOperation = (item) => {
+      const tagAStyle = { fontWeight: 'bold' };
       return (
         <div>
-          <Button
-            type="primary"
-            size="small"
-            onClick={() => this.handleEditRecommend(item)}
-          >修改推荐位
-          </Button>
+          <a style={tagAStyle} onClick={() => this.handleEditRecommend(item)}>课程</a>
+          <Divider type="vertical" />
+          <a style={tagAStyle} onClick={() => this.handleEditPoster(item)}>海报</a>
         </div>
       );
     };

+ 514 - 0
src/routes/Frontend/Recommend/RecommendPoster.js

@@ -0,0 +1,514 @@
+import React, { Component } from 'react';
+import pathToRegexp from 'path-to-regexp';
+import { connect } from 'dva';
+import { routerRedux } from 'dva/router';
+import { Card, Table, Modal, Popconfirm, Radio, Switch, Button, Input } from 'antd';
+import Selector from '../../../components/AXTableSelector/Selector';
+import FooterToolbar from '../../../components/FooterToolbar';
+import {
+  boolToStatus, genAbsolutePicUrl, renderProductType, renderStatus, statusToBool,
+} from '../../../utils/utils';
+import bitmap from '../../../assets/bitmap.png';
+import styles from './RecommendPoster.less';
+
+function dataSort(array) {
+  if (!array || !Array.isArray(array)) {
+    return array;
+  }
+  const sorted = array.sort((a, b) => {
+    return a.sort - b.sort;
+  });
+  return sorted;
+}
+
+@connect(({ loading, merchant, shelves, resource }) => ({
+  shelves,
+  merchant,
+  resource,
+  rLoading: loading.models.resource,
+  sLoading: loading.models.shelves,
+  mLoading: loading.models.merchant,
+}))
+export default class RecommendPosterEditPage extends Component {
+  state = {
+    productSelectorDestroy: true,
+    resourceSelectorDestroy: true,
+    productType: 'Course',
+    currentEditPosterId: '',
+  };
+  componentDidMount() {
+    this.props.dispatch({
+      type: 'merchant/fetchMerchantPoster',
+      payload: { merchantId: this.getMerchantId() },
+    });
+  }
+  /**
+   * 1.从URL中提取merchantId
+   * @returns {String}
+   */
+  getMerchantId = () => {
+    const match = pathToRegexp('/frontend/recommend/poster-edit/:id')
+      .exec(this.props.location.pathname);
+    return match[1];
+  };
+  /**
+   * 2.响应产品类型变化
+   * @param e
+   */
+  handleRadioChange = (e) => {
+    this.setState({ productType: e.target.value });
+    this.props.dispatch({
+      type: `shelves/fetch${e.target.value}ItemList`,
+      payload: { merchantId: this.getMerchantId() },
+    });
+  };
+  /**
+   * 3.新建一条海报
+   */
+  handlePosterItemCreate = () => {
+    const newData = [...this.props.merchant.posterList];
+    newData.push({
+      id: `new-poster-${newData.length + 1}`,
+      isNew: true,
+      isEdit: true,
+    });
+    this.props.dispatch({
+      type: 'merchant/fixPosterList',
+      payload: newData,
+    });
+  };
+  /**
+   * 4.删除一条海报
+   * @param postId
+   * @param isNew
+   */
+  handlePosterItemDelete = (posterId, isNew) => {
+    if (isNew) {
+      const originalData = [...this.props.merchant.posterList];
+      const newData = originalData.filter(data => data.id !== posterId);
+      this.props.dispatch({
+        type: 'merchant/fixPosterList',
+        payload: newData,
+      });
+      return;
+    }
+    this.props.dispatch({
+      type: 'merchant/deleteMerchantPosterItem',
+      payload: { posterId },
+    });
+  }
+  /**
+   * 5.编辑一条海报
+   * @param postId
+   */
+  handlePosterItemEdit = (posterId) => {
+    const newData = [...this.props.merchant.posterList];
+    for (const index in newData) {
+      if (newData[index].id === posterId) {
+        newData[index].isEdit = true;
+      }
+    }
+    this.props.dispatch({
+      type: 'merchant/fixPosterList',
+      payload: newData,
+    });
+  };
+  /**
+   * 6.控制模态框的展现
+   * @param {String} flag
+   */
+  handleSelectorModalShow = (flag, posterId) => {
+    this.setState({
+      [`${flag}SelectorDestroy`]: false,
+      currentEditPosterId: posterId,
+    });
+    if (flag !== 'resource') {
+      const { productType } = this.state;
+      this.props.dispatch({
+        type: `shelves/fetch${productType}ItemList`,
+        payload: { merchantId: this.getMerchantId() },
+      });
+      return;
+    }
+    this.props.dispatch({
+      type: 'resource/fetchImageList',
+      payload: {},
+    });
+  };
+  /**
+   * 7.控制模态框的销毁
+   */
+  handleSelectorCancel = (flag) => {
+    this.setState({ [`${flag}SelectorDestroy`]: true });
+  };
+  /**
+   * 8.响应模态框内查询操作
+   * @param {String} flag
+   * @param {Object} params
+   */
+  handleSelectorChange = (flag, params) => {
+    if (flag !== 'resource') {
+      const { productType } = this.state;
+      this.props.dispatch({
+        type: `shelves/fetch${productType}ItemList`,
+        payload: { ...params, merchantId: this.getMerchantId() },
+      });
+      return;
+    }
+    this.props.dispatch({
+      type: 'resource/fetchImageList',
+      payload: params,
+    });
+  };
+  /**
+   * 9.响应选择完成操作
+   * @param {String} flag
+   * @param {Array} rows
+   */
+  handleSelectorFinish = (flag, rows) => {
+    this.setState({ [`${flag}SelectorDestroy`]: true });
+    const { currentEditPosterId } = this.state;
+    const originalData = [...this.props.merchant.posterList];
+    const newData = originalData.map((data) => {
+      if (flag === 'product' && data.id === currentEditPosterId) {
+        const { id, name, code, type } = rows[0];
+        return { ...data, type, name, code, pid: id };
+      }
+      if (flag === 'resource' && data.id === currentEditPosterId) {
+        const { path } = rows[0];
+        return { ...data, img: path };
+      }
+      return { ...data };
+    });
+    this.props.dispatch({
+      type: 'merchant/fixPosterList',
+      payload: newData,
+    });
+  };
+  /**
+   * 10.修改排序值
+   * @param e
+   * @param posterId
+   */
+  handleSortInputChange = (e, posterId) => {
+    const originalData = [...this.props.merchant.posterList];
+    const newData = originalData.map((data) => {
+      if (data.id === posterId) {
+        return { ...data, sort: parseInt(e.target.value, 10) || 0 };
+      }
+      return { ...data };
+    });
+    this.props.dispatch({
+      type: 'merchant/fixPosterList',
+      payload: newData,
+    });
+  };
+  /**
+   * 11.修改状态
+   * @param checked
+   * @param posterId
+   */
+  handleStatusSwitchChange = (checked, posterId) => {
+    const originalData = [...this.props.merchant.posterList];
+    const newData = originalData.map((data) => {
+      if (data.id === posterId) {
+        return { ...data, status: boolToStatus(checked) };
+      }
+      return { ...data };
+    });
+    this.props.dispatch({
+      type: 'merchant/fixPosterList',
+      payload: newData,
+    });
+  };
+  /**
+   * 12.提交海报内容
+   * @param posterId
+   */
+  handleSaveOperation = (posterId) => {
+    const originalData = [...this.props.merchant.posterList];
+    const targetData = originalData.filter(data => data.id === posterId)[0];
+    const { id, pid, img, sort, type, status, isNew } = targetData;
+    if (isNew) {
+      this.props.dispatch({
+        type: 'merchant/createMerchantPosterItem',
+        payload: {
+          img, pid, type, sort, status: boolToStatus(status), merchantId: this.getMerchantId(),
+        },
+        posterId: id,
+      });
+      return;
+    }
+    this.props.dispatch({
+      type: 'merchant/updateMerchantPosterItem',
+      payload: {
+        id, img, pid, type, sort, status: boolToStatus(status), merchantId: this.getMerchantId(),
+      },
+      posterId: id,
+    });
+  };
+  /**
+   * 13.返回上一页
+   */
+  handlePageBack = () => {
+    this.props.dispatch(routerRedux.push({
+      pathname: '/frontend/recommend',
+      state: this.props.location.state,
+    }));
+  };
+  render() {
+    const { productType, productSelectorDestroy, resourceSelectorDestroy } = this.state;
+    const { merchant, shelves, resource, rLoading, sLoading, mLoading } = this.props;
+    const { posterList } = merchant;
+    /* 海报列表格式设定 */
+    const posterColumns = [{
+      title: '位置',
+      key: 1,
+      dataIndex: 'sort',
+      width: '15%',
+      render: (text, record) => {
+        // 编辑状态下排序可自由填写
+        const { id, isEdit } = record;
+        if (isEdit) {
+          return (
+            <Input
+              value={text}
+              onChange={e => this.handleSortInputChange(e, id)}
+              placeholder="请填写"
+              style={{ width: 100 }}
+            />
+          );
+        }
+        return text;
+      },
+      align: 'center',
+    }, {
+      title: '海报封面',
+      key: 2,
+      dataIndex: 'img',
+      width: '27%',
+      render: (text, record) => {
+        // 将海报封面渲染为一张图片,编辑状态下可更换
+        const { id, isNew, isEdit } = record;
+        return (
+          <div className={styles.cover}>
+            {isEdit && (
+              <div className={styles.mongolian}>
+                <a onClick={() => this.handleSelectorModalShow('resource', id)}>{isNew ? '选择' : '更换'}</a>
+              </div>
+            )}
+            {(isNew && !text) ? <img src={bitmap} alt="" /> : <img src={genAbsolutePicUrl(text)} alt="海报封面" />}
+          </div>
+        );
+      },
+      align: 'center',
+    }, {
+      title: '关联产品信息',
+      key: 3,
+      render: (_, record) => {
+        // 将产品信息渲染成一个小表格
+        const { id, type, name, code, isEdit, isNew } = record;
+        const columns = [{
+          dataIndex: 'label',
+          width: '40%',
+        }, {
+          dataIndex: 'value',
+          width: '60%',
+        }];
+        const data = [{
+          key: 'name',
+          label: '产品名称',
+          value: name,
+        }, {
+          key: 'code',
+          label: '产品编号',
+          value: code,
+        }, {
+          key: 'type',
+          label: '产品类型',
+          value: renderProductType(type),
+        }];
+        return (
+          <div className={styles.product}>
+            {isEdit && (
+              <div className={styles.mongolian}>
+                <a onClick={() => this.handleSelectorModalShow('product', id)}>{isNew ? '选择' : '更换'}</a>
+              </div>
+            )}
+            <Table
+              bordered
+              size="small"
+              showHeader={false}
+              pagination={false}
+              columns={columns}
+              dataSource={data}
+            />
+          </div>
+        );
+      },
+      width: '30%',
+      align: 'center',
+    }, {
+      title: '删除状态',
+      key: 4,
+      dataIndex: 'status',
+      width: '13%',
+      render: (text, record) => {
+        const { id, isEdit } = record;
+        if (isEdit) {
+          return (
+            <Switch
+              checked={statusToBool(text)}
+              checkedChildren="正常"
+              unCheckedChildren="删除"
+              onChange={checked => this.handleStatusSwitchChange(checked, id)}
+            />
+          );
+        }
+        return renderStatus(text);
+      },
+      align: 'center',
+    }, {
+      title: '相关操作',
+      key: 5,
+      width: '15%',
+      render: (_, record) => {
+        const { id, isNew, isEdit } = record;
+        const getPopconfirmBtn = () => {
+          return (
+            <Popconfirm
+              placement="top"
+              title="确定要删除该海报?"
+              okText="确定"
+              cancelText="取消"
+              onConfirm={() => this.handlePosterItemDelete(id, isNew)}
+            >
+              <Button
+                size="small"
+                className="delBtn"
+              >删除
+              </Button>
+            </Popconfirm>
+          );
+        };
+        if (isEdit) {
+          return (
+            <div>
+              <Button
+                size="small"
+                className="editBtn"
+                onClick={() => this.handleSaveOperation(id)}
+              >保存
+              </Button>
+              {getPopconfirmBtn()}
+            </div>
+          );
+        }
+        return (
+          <div>
+            <Button
+              size="small"
+              className="editBtn"
+              onClick={() => this.handlePosterItemEdit(id)}
+            >编辑
+            </Button>
+            {getPopconfirmBtn()}
+          </div>
+        );
+      },
+      align: 'right',
+    }];
+    /* 产品模态框选择器 */
+    const renderModalTitle = () => {
+      return (
+        <Radio.Group
+          value={productType}
+          onChange={this.handleRadioChange}
+        >
+          <Radio.Button value="Course">课程</Radio.Button>
+          <Radio.Button value="Support">配套</Radio.Button>
+          <Radio.Button value="Training">师训</Radio.Button>
+          <Radio.Button value="Package">套餐包</Radio.Button>
+        </Radio.Group>
+      );
+    };
+    const getProductModal = () => {
+      return (
+        <Modal
+          visible
+          width={1100}
+          footer={null}
+          title={renderModalTitle()}
+          maskClosable={false}
+          onCancel={() => this.handleSelectorCancel('product')}
+        >
+          <Selector
+            multiple={false}
+            loading={sLoading}
+            selectorName={productType}
+            fixedName="Product"
+            list={shelves.list}
+            pageNo={shelves.pageNo}
+            pageSize={shelves.pageSize}
+            totalSize={shelves.totalSize}
+            onCancel={() => this.handleSelectorCancel('product')}
+            onChange={data => this.handleSelectorChange('product', data)}
+            onFinish={data => this.handleSelectorFinish('product', data)}
+          />
+        </Modal>
+      );
+    };
+    /* 封面模态框选择器 */
+    const getResourceModal = () => {
+      return (
+        <Modal
+          width={1100}
+          footer={null}
+          visible
+          title="图片资源"
+          maskClosable={false}
+          onCancel={() => this.handleSelectorCancel('resource')}
+        >
+          <Selector
+            multiple={false}
+            loading={rLoading}
+            selectorName="PictureSingle"
+            list={resource.list}
+            pageNo={resource.pageNo}
+            pageSize={resource.pageSize}
+            totalSize={resource.totalSize}
+            onCancel={() => this.handleSelectorCancel('resource')}
+            onChange={data => this.handleSelectorChange('resource', data)}
+            onFinish={rows => this.handleSelectorFinish('resource', rows)}
+          />
+        </Modal>
+      );
+    };
+    return (
+      <div>
+        <Card style={{ marginBottom: 70 }}>
+          <Table
+            pagination={false}
+            loading={mLoading}
+            dataSource={dataSort(posterList)}
+            columns={posterColumns}
+            rowKey={record => record.id}
+            className={styles.posterTable}
+          />
+          <Button
+            type="dashed"
+            icon="plus"
+            style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
+            onClick={this.handlePosterItemCreate}
+          >新建
+          </Button>
+          {!resourceSelectorDestroy && getResourceModal()}
+          {!productSelectorDestroy && getProductModal()}
+        </Card>
+        <FooterToolbar style={{ width: '100%' }}>
+          <Button type="primary" onClick={this.handlePageBack}>返回上一页</Button>
+        </FooterToolbar>
+      </div>
+    );
+  }
+}

+ 63 - 0
src/routes/Frontend/Recommend/RecommendPoster.less

@@ -0,0 +1,63 @@
+@import "../../../../node_modules/antd/lib/style/themes/default.less";
+
+.posterTable {
+  :global {
+    .ant-table-title {
+      padding: 0 0 16px 0;
+    }
+    .ant-table-footer {
+      padding: 10px;
+    }
+    .ant-table-tbody > tr > td {
+      padding: 5px 10px;
+    }
+    .ant-table-thead > tr > th {
+      padding: 10px 5px;
+    }
+  }
+}
+
+.mongolian {
+  z-index: 10;
+  display: none;
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  a {
+    position: relative;
+    top: 45%;
+    transform: translateY(-45%);
+    padding: 5px 15px;
+    background: #fff;
+    color: #73777a;
+  }
+}
+
+.cover {
+  position: relative;
+  margin: 0;
+  width: 100%;
+  height: 100%;
+  img {
+    width: 100%;
+    height: 100%;
+  }
+  &:hover {
+    .mongolian {
+      display: block;
+      background: rgba(0,193,222,.8);
+    }
+  }
+}
+
+.product {
+  position: relative;
+  &:hover {
+    .mongolian {
+      display: block;
+      background: rgba(0,193,222,.8);
+    }
+  }
+}

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

@@ -25,7 +25,7 @@ export default class Recommend extends Component {
               )
             )
           }
-          <Redirect exact from="/frontend/recommend" to="/frontend/recommend/list" />
+          <Redirect exact from="/frontend/recommend" to="/frontend/recommend/merchant-list" />
         </Switch>
       </PageHeaderLayout>
     );

+ 31 - 0
src/services/merchant.js

@@ -56,3 +56,34 @@ export async function updateMerchantRecommend({ merchantId, idList }) {
   };
   return request(`${api.recommend}/${merchantId}`, options);
 }
+
+export async function queryMerchantPoster({ merchantId }) {
+  return request(`${api.poster}/${merchantId}`);
+}
+
+export async function queryMerchantPosterItem({ posterId }) {
+  return request(`${api.posterItem}/${posterId}`);
+}
+
+export async function createMerchantPosterItem(params) {
+  const options = {
+    method: 'POST',
+    body: params,
+  };
+  return request(`${api.posterItem}`, options);
+}
+
+export async function updateMerchantPosterItem(params) {
+  const options = {
+    method: 'PUT',
+    body: params,
+  };
+  return request(`${api.posterItem}`, options);
+}
+
+export async function deleteMerchantPosterItem({ posterId }) {
+  const options = {
+    method: 'DELETE',
+  };
+  return request(`${api.posterItem}/${posterId}`, options);
+}

+ 2 - 0
src/utils/config.js

@@ -86,6 +86,8 @@ const apiObj = {
   merchant: '/merchant/list',
   merchantItem: '/merchant',
   recommend: '/merchant/recommend',
+  poster: '/merchant/poster',
+  posterItem: '/poster',
   deposit: '/money/charge',
   campus: '/campus/list',
   campusItem: '/campus',