|
@@ -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>
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|