界面浮动布局

66 阅读5分钟
import { connect, Dispatch } from 'dva';
import {
  Switch,
  Button,
  Pagination,
  Space,
  Table,
  Popconfirm,
  Input,
  Select,
  Modal,
  Form,
  Input,
  Loading
} from 'antd';
import React, { useEffect, useState } from 'react';
import empty from '@/Images/others/empty.png';
import AddTemp from './compoments/AddTemp';
import { getGuid } from '@/utils';
import GoPreview from './compoments/GoPreview';
import SelectProduct from '@/components/SelectProduct';
import styles from './index.less';

interface Props {
  dispatch: Dispatch;
  searchParams: { [key: string]: any };
  initialValues: { [key: string]: any };
  pageNum: number;
  pageSize: number;
  total: number;
  tempList: Array<any>;
  searchLoading: boolean;
  currentRow: any;
  getDetailLoading: boolean;
}

const ProductParamTemp = (props: Props) => {
  const {
    dispatch,
    searchParams,
    initialValues,
    pageNum,
    pageSize,
    total,
    tempList,
    searchLoading,
    getDetailLoading
  } = props;

  // 添加模板参数弹框显隐
  const [showAdd, setShowAdd] = useState<boolean>(false);

  // 当前编辑的模板信息
  const [currentEdit, setCurrentEdit] = useState<any>({});

  // 勾选的列表
  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);

  // 更多搜索条件显隐
  const [showMore, setShowMore] = useState<boolean>(false);

  // 产品目录分类(只有一级、二级)
  const [catalogs, setCatalogs] = useState<Array<any>>([]);

  // 产品目录分类,平铺数组
  const [catalogList, setCatalogList] = useState<Array<any>>([]);

  // 预览数据
  const [previewData, setPreviewData] = useState<any>([]);

  // 是否展示预览弹框
  const [showLook, setShowLook] = useState<boolean>(false);

  // 产品弹框显隐
  const [showProduct, setShowProduct] = useState<boolean>(false);

  // 当前产品数据(已绑定的)
  const [currentProducts, setCurrentProducts] = useState<Array<any>>([]);

  // 表单实例
  const [forms] = Form.useForm();

  // 表头
  const columns: any = [
    {
      title: intl.formatMessage({ id: 'Template Name' }),
      dataIndex: 'templateName',
      align: 'center',
      ellipsis: true
    },
    {
      title: intl.formatMessage({ id: 'Category1' }),
      dataIndex: 'catalogName',
      align: 'center',
      ellipsis: true
    },
    {
      title: intl.formatMessage({ id: 'Remark' }),
      dataIndex: 'remark',
      align: 'center',
      ellipsis: true
    },
    {
      title: intl.formatMessage({ id: 'Enable Status' }),
      dataIndex: 'enableStatus',
      align: 'center',
      ellipsis: true,
      render: (_: any, record: any) => {
        return (
          <Switch
            onChange={(e: any) => _changeAble(record, e)}
            checked={record.enableStatus}
          />
        );
      }
    },
    {
      title: intl.formatMessage({ id: 'Operation' }),
      dataIndex: 'operation',
      align: 'center',
      className: styles.drag_hidden,
      render: (_: any, record: any) => {
        return (
          <Space size={32}>
            <Icon
              title={intl.formatMessage({ id: 'Bulk binding products' })}
              icon="bindIcon"
              onClick={() => {
                setCurrentEdit(record);
                setTimeout(() => {
                  setShowProduct(true);
                }, 300);
              }}
            />
            <Icon
              title={intl.formatMessage({ id: 'Preview' })}
              icon="previewIcon"
              onClick={() => _goLook(record)}
            />
            <Icon icon="modifyIcon" onClick={() => _getDetail(record)} />
            <Popconfirm
              title={intl.formatMessage({
                id: 'Are you sure you want to delete it?'
              })}
              onConfirm={() => _delTemp(record.id)}
            >
              <Icon
                title={intl.formatMessage({ id: 'Delete' })}
                icon="deleteIcon"
              />
            </Popconfirm>
          </Space>
        );
      }
    }
  ];

  /**
   * 预览
   * @param record 模板数据
   */
  const _goLook = (record: any) => {
    setShowLook(true);
    const { id } = record;
    dispatch({
      type: 'paramTemp/getDetail',
      payload: {
        id
      },
      callback: (data: any) => {
        const { items } = data;
        const newList: Array<any> =
          (Array.isArray(items) &&
            items.length > 0 &&
            items.map((item: any) => {
              return {
                ...item,
                identifyId: getGuid()
              };
            })) ||
          [];
        setPreviewData(newList);
      }
    });
  };

  /**
   * 获取详情
   * @param record 模板部分信息
   */
  const _getDetail = (record: any) => {
    setCurrentEdit({});
    dispatch({
      type: 'paramTemp/getDetail',
      payload: {
        id: record.id
      },
      callback: (data: any) => {
        setCurrentEdit(data);
      }
    });
    setShowAdd(true);
  };

  useEffect(() => {
    dispatch({
      type: 'paramTemp/getCatalog',
      callback: (data: Array<any>) => {
        setCatalogs(_treeToTree(data));
        setCatalogList(_treeToArray(data));
      }
    });
  }, []);

  useEffect(() => {
    const { productIdList } = currentEdit;
    if (Array.isArray(productIdList) && productIdList.length > 0) {
      dispatch({
        type: 'paramTemp/queryProductList',
        payload: {
          idList: [...productIdList],
          pageNum: 1,
          pageSize: 400,
          isAggBomCode: false
        },
        callback: (res: any) => {
          setCurrentProducts(res);
        }
      });
    } else {
      setCurrentProducts([]);
    }
  }, [currentEdit]);

  /**
   * 获取一二级产品目录列表
   * @param data 待改造数据
   * @returns 返回新的树
   */
  const _treeToTree = (data: Array<any>) => {
    const newTree: Array<any> =
      data.map((item: any) => {
        return {
          ...item,
          title: item.productCatalogName,
          key: item.id,
          value: item.id,
          disabled: [1].includes(item.catalogLevel) ? true : false,
          children:
            Array.isArray(item.childList) && item.childList.length > 0 ?
              _treeToTree(item.childList) :
              null
        };
      }) || [];
    return newTree;
  };

  /**
   *
   * @param tree
   * @returns
   */
  const _treeToArray = (tree: Array<any>) => {
    const newList: Array<any> = [];
    const _getChild = (tree: Array<any>) => {
      tree.forEach((item: any) => {
        const { childList } = item;
        newList.push(item);
        if (Array.isArray(childList) && childList.length > 0) {
          _getChild(childList);
        }
      });
    };
    _getChild(tree);
    return newList;
  };

  useEffect(() => {
    _getTemps();
  }, [searchParams]);

  /**
   * 获取模板
   */
  const _getTemps = () => {
    dispatch({
      type: 'paramTemp/getTemp',
      payload: {
        ...searchParams
      }
    });
    setSelectedRowKeys([]);
  };

  /**
   * 删除模板
   * @param id 模板id
   */
  const _delTemp = (id: any) => {
    dispatch({
      type: 'paramTemp/delTemp',
      payload: [id],
      callback: () => {
        _getTemps();
      }
    });
  };

  /**
   * 切换启用状态
   * @param record 当前模板信息
   * @param e 组件自带属性
   */
  const _changeAble = (record: any, e: any) => {
    dispatch({
      type: 'paramTemp/editTemp',
      payload: {
        id: record.id,
        enableStatus: e ? 0 : 1
      },
      callback: () => {
        _getTemps();
      }
    });
  };

  /**
   * 关键字查询
   * @param key 搜索关键字
   */
  const _onSearch = (key: string) => {
    dispatch({
      type: 'paramTemp/updateState',
      payload: {
        searchParams: {
          ...searchParams,
          searchKey: key
        }
      }
    });
  };

  /**
   * 切换分页
   * @param page 页码
   * @param pageSize 条数
   */
  const _changePage = (page: number, size: number) => {
    dispatch({
      type: 'paramTemp/updateState',
      payload: {
        searchParams: {
          ...searchParams,
          pageNum: page,
          pageSize: size
        }
      }
    });
  };

  /**
   * 多条件查询
   */
  const _moreSearch = () => {
    const tempObj = forms.getFieldsValue();
    const { enableStatus, ...left } = tempObj;
    dispatch({
      type: 'paramTemp/updateState',
      payload: {
        searchParams: {
          pageNum: 1,
          pageSize: searchParams.pageSize,
          ...left,
          enableStatus: enableStatus === 'all' ? undefined : enableStatus
        }
      }
    });
  };

  /**
   * 重置方法
   */
  const _onReset = () => {
    forms.setFieldsValue({
      ...initialValues
    });
    dispatch({
      type: 'paramTemp/updateState',
      payload: {
        searchParams: {
          pageNum: 1,
          pageSize: 10
        }
      }
    });
  };

  /**
   * 提交模板数据
   */
  const submitTemp = (data: any) => {
    dispatch({
      type: 'paramTemp/addTemp',
      payload: {
        ...data
      },
      callback: () => {
        _getTemps();
        setShowAdd(false);
        // 重新给当前模板下的产品再换绑一次
        const { id, templateId, productIdList } = currentEdit;
        if (Array.isArray(productIdList) && productIdList.length > 0) {
          dispatch({
            type: 'paramTemp/bindTemp',
            payload: {
              productIdList: productIdList,
              templateId,
              baseId: id
            },
            callback: () => {
              _getTemps();
            }
          });
        }
      }
    });
  };

  /**
   * 批量删除模板
   */
  const _delTempMore = () => {
    Modal.confirm({
      title: intl.formatMessage({
        id: 'Are you sure you want to delete it?'
      }),
      cancelText: intl.formatMessage({ id: 'Cancel' }),
      okText: intl.formatMessage({ id: 'OK' }),
      onOk: () => {
        dispatch({
          type: 'paramTemp/delTemp',
          payload: [...selectedRowKeys],
          callback: () => {
            _getTemps();
          }
        });
      }
    });
  };

  /**
   * 批量绑定
   * @param data 产品列表
   */
  const addProducts = (data: any) => {
    console.log('data6969', data);
    const { id, templateId } = currentEdit;
    const ids = data.map((item: any) => item.id);
    dispatch({
      type: 'paramTemp/bindTemp',
      payload: {
        productIdList: [...ids],
        templateId,
        baseId: id,
        clearTemplateAllBindRelation: true
      },
      callback: () => {
        setShowProduct(false);
        _getTemps();
      }
    });
  };

  return (
    <div className={styles.pParamTemp}>
      <div className={styles.pParamTemp_header}>
        {intl.formatMessage({ id: 'Product Parameter Template' })}
      </div>
      <div className={styles.pParamTemp_content}>
        <div className={styles.pParamTemp_btns}>
          <Space size={4} className={styles.pParamTemp_btns_left}>
            <Button
              type="primary"
              onClick={() => {
                setCurrentEdit({});
                setShowAdd(true);
              }}
            >
              {intl.formatMessage({ id: 'Add2' })}
            </Button>
            <Button
              onClick={() => _delTempMore()}
              disabled={selectedRowKeys.length < 1}
            >
              {intl.formatMessage({ id: 'Delete' })}
            </Button>
            <Button onClick={_getTemps}>
              {intl.formatMessage({ id: 'Refresh1' })}
            </Button>
          </Space>
          <Space>
            <Input
              onSearch={_onSearch}
              onEnterPress={_onSearch}
              placeholder={intl.formatMessage({
                id: 'Please enter search criteria'
              })}
            />
            <Icon
              icon="selectionIcon"
              onClick={() => setShowMore(!showMore)}
            />
          </Space>
        </div>
        {showMore && (
          <Form
            form={forms}
            layout="inline"
            className={styles.pParamTemp_forms}
            labelAlign="left"
          >
            <Form.Item
              label={intl.formatMessage({ id: 'Template Name' })}
              name="templateName"
            >
              <Input />
            </Form.Item>
            <Form.Item
              label={intl.formatMessage({ id: 'Category1' })}
              name="catalogName"
            >
              <Input />
            </Form.Item>
            <Form.Item
              label={intl.formatMessage({ id: 'Remark' })}
              name="remark"
            >
              <Input />
            </Form.Item>
            <Form.Item
              label={intl.formatMessage({ id: 'Enable Status' })}
              name="enableStatus"
              initialValue={'all'}
            >
              <Select>
                <Select.Option key="all" value="all">
                  {intl.formatMessage({ id: 'All' })}
                </Select.Option>
                <Select.Option key={1} value={1}>
                  {intl.formatMessage({ id: 'Enable' })}
                </Select.Option>
                <Select.Option key={0} value={0}>
                  {intl.formatMessage({ id: 'Disable' })}
                </Select.Option>
              </Select>
            </Form.Item>
            <div className={styles.pParamTemp_forms_emptyOne} />
            <Space className={styles.pParamTemp_forms_btns}>
              <Button type="primary" onClick={_moreSearch}>
                {intl.formatMessage({ id: 'Search1' })}
              </Button>
              <Button onClick={_onReset}>
                {intl.formatMessage({ id: 'Reset' })}
              </Button>
            </Space>
          </Form>
        )}
        <div className={styles.pParamTemp_tables}>
          <Loading loading={searchLoading}>
            <Table
              className={styles.pParamTemp_table}
              dataSource={tempList}
              columns={columns}
              size="small"
              bordered
              rowKey="id"
              scroll={{ y: 'calc(100% - 40px)' }}
              rowSelection={{
                selectedRowKeys,
                onChange: (selectedRowKeys: React.Key[]) => {
                  setSelectedRowKeys(selectedRowKeys);
                }
              }}
              onRow={(record: any) => {
                return {
                  onDoubleClick: () => {
                    _getDetail(record);
                  }
                };
              }}
              pagination={false}
              locale={{
                emptyText: (
                  <div
                    className="empty"
                    style={{
                      height: '100%',
                      paddingTop: '10%'
                    }}
                  >
                    <img src={empty} />
                    <div>{intl.formatMessage({ id: 'No data' })}</div>
                  </div>
                )
              }}
            />
            <Pagination
              className={styles.pParamTemp_page}
              showTotal={(total: number) =>
                intl.formatMessage({ id: 'Total xx items' }, { total: total })
              }
              current={pageNum}
              pageSize={pageSize}
              total={total}
              showSizeChanger
              showQuickJumper
              onChange={_changePage}
            />
          </Loading>
        </div>
      </div>
      {showAdd && (
        <AddTemp
          // <ForProduct
          currentEdit={currentEdit}
          // setCurrentEdit={setCurrentEdit}
          onCancel={() => setShowAdd(false)}
          submitTemp={submitTemp}
          catalogs={catalogs}
          catalogList={catalogList}
          setPreviewData={setPreviewData}
          previewData={previewData}
          setShowLook={setShowLook}
          showLook={showLook}
          getDetailLoading={getDetailLoading}
        />
      )}
      {showLook && (
        <GoPreview
          onCancel={() => setShowLook(false)}
          data={previewData}
          getDetailLoading={getDetailLoading}
        />
      )}
      {showProduct && (
        <SelectProduct
          onCancel={() => setShowProduct(false)}
          onConfirm={addProducts}
          selectType="multi"
          initList={currentProducts || undefined}
          bottomText="binded"
          isAggBomCode={false}
        />
      )}
    </div>
  );
};

export default connect(({ paramTemp, loading }: any) => {
  const { searchParams, tempList, pageNum, pageSize, total, initialValues } =
    paramTemp;
  return {
    searchParams,
    initialValues,
    tempList,
    pageNum,
    pageSize,
    total,
    searchLoading: loading.effects['paramTemp/getTemp'] || false,
    getDetailLoading: loading.effects['paramTemp/getDetail'] || false
  };
})(ProductParamTemp);

.pParamTemp {
  height: 100%;
  width: 100%;
  padding: 10px;
  border-radius: 8px;
  background-color: white;


  :global {
    .ant4-form-item-label {
      width: 108px !important;
    }

    .ant-select {
      width: 180px;
    }

    .ant4-form-item {
      margin-bottom: 12px !important;
    }

    .ant-switch-checked {
      background: #70b603;
    }
  }

  .pParamTemp_header {
    height: 30px;
    width: 100%;
    border-bottom: 1px solid rgb(234, 234, 234);
    font-size: 14px;
    color: rgba(0, 0, 0, 0.5);
    padding-left: 10px;
  }

  .pParamTemp_content {
    width: 100%;
    height: calc(100% - 40px);
    flex-direction: column;
    display: flex;

    .pParamTemp_btns {
      display: flex;
      justify-content: space-between;
      margin-top: 10px;
      padding-right: 10px;

      .pParamTemp_btns_left {
        button {
          width: 80px;
          height: 30px;
          padding: 0;
        }
      }
    }

    .pParamTemp_forms {
      margin-top: 10px;
      position: relative;
      padding: 20px 20px 8px;
      background-color: #f7f8fa;

      .pParamTemp_forms_emptyOne {
        width: 190px;
        height: 32px;
        visibility: hidden;
        margin-bottom: 12px;
      }

      .pParamTemp_forms_btns {
        position: absolute;
        right: 10px;
        bottom: 20px;
        height: 32px;

        button {
          width: 80px;
          height: 30px;
        }
      }
    }

    .pParamTemp_tables {
      flex: 1 1 auto;
      overflow-y: hidden;
      margin-top: 10px;

      :global {
        .ant-table-thead {
          .ant-table-cell {
            text-align: center !important;
          }
        }

        .ant-spin-nested-loading,
        .ant-spin-container,
        .ant-table,
        .ant-table-container,
        .ant-table-content {
          width: 100%;
          height: 100%;
        }

        .ant-table-container {
          background-color: #f7f8fa;
        }

        .ant-table-row {
          background-color: #fff;
        }
      }

      .pParamTemp_table {
        height: calc(100% - 42px);
      }

      .pParamTemp_page {
        margin-top: 10px;
        text-align: center;
      }
    }
  }
}

Tabs组件样式

 :global {
    .ant-tabs-tab {
      width: 170px;
      text-align: center;
      height: 40px;
      margin-left: 0;
    }

    .ant-tabs-tab-btn {
      margin: auto;

      &:hover {
        color: #0183cc;
      }
    }

    .ant-tabs-tab-active .ant-tabs-tab-btn {
      margin: auto;
      color: #0183cc;
    }

    .ant-tabs-nav {
      margin: 0;
    }

    .ant-tabs-ink-bar {
      background: #0183cc;
    }

    .ant-tabs>.ant-tabs-nav {
      position: relative;
      display: flex;
      flex: none;
      align-items: center;
      margin: 0;
    }
  }