懒加载

34 阅读4分钟
import controlled from '@/Images/controlled.png';
import productSmall from '@/Images/productSmall.png';
import strictControlled from '@/Images/strictControlled.png';
import { ascOrder, descOrder } from '@/Images/svgIcon';
import {
  CheckResultType,
  PartType,
  ProductType
} from '@/modelType/myQuotation';
import { BuListType } from '@/modelType/productDataModelType';
import {
  queryProductList,
  getQuotationSelectSpecFilterCondition
} from '@/services/productAndService';
import {
  UNVButton,
  UNVIcon,
  UNVInput,
  UNVLoading,
  UNVMessageBox,
  UNVModal,
  UNVTags
} from 'UNV-DESIGN';
import { Button, Checkbox, InputNumber, Select, Tree } from 'antd';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useUpdateEffect } from 'ahooks';
import { connect } from 'umi';
import AddParts from '../AddParts';
import GetImg from '@/components/GetImg';
import './index.less';
import { getLocalStorage } from '@/utils/auth';

const lodash = require('lodash');
const { cloneDeep, uniqBy } = lodash;

const SelectProduct = (props: { [key: string]: any }) => {
  const {
    dispatch,
    allBuList,
    productCatalogTree,
    checkProduct,
    onCancel,
    onConfirm,
    initList,
    selectType = 'multi',
    isAggBomCode = true,
    needPriceInfo = false
  } = props;

  // 是否是外部用户
  const isExternalAccount = !!JSON.parse(getLocalStorage('__userInfo'))
    ?.externalAccount;

  // 当前选择的产品列表
  const [currentProduct, setCurrentProduct] = useState<Array<ProductType>>([]);

  // 本次弹窗已查询过的所有的产品列表
  const [allSearchedProductList, setAllSearchedProductList] = useState<
    Array<ProductType>
  >([]);

  // 当前选择的目录id
  const [currentId, setCurrentId] = useState<number[]>([]);

  // 当前操作的产品
  const [actionProduct, setActionProduct] = useState<ProductType | undefined>(
    undefined
  );

  // 配置配件弹窗
  const [addPartsVisible, setAddPartsVisible] = useState<boolean>(false);

  // 搜索的关键字
  const [keyword, setKeyWord] = useState('');

  // 当前选择的产品id集合
  const [currentSelectedList, setCurrentSelectedList] = useState<
    Array<ProductType>
  >([]);

  // 加载产品数据
  const [productLoading, setProductLoading] = useState(false);

  // 分页查询产品数据
  const [pageInfo, setPageInfo] = useState({
    pageNum: 1,
    pageSize: 100
  });

  // 价格排序
  const [priceOrder, setPriceOrder] = useState<'desc' | 'asc' | undefined>(
    undefined
  );

  // 所选BU
  const [selectedBu, setSelectedBu] = useState<string[] | undefined>(undefined);

  // 数据列表的div Ref
  const productRef = useRef<any>(null);

  //弹框高级筛选条件 最多三个
  const [filterConditions, setFilterConditions] = useState<Array<any>>([]);

  // 已选择的简选条件
  const [specValueList, setSpecValueList] = useState<Array<any>>([]);

  useEffect(() => {
    if (allBuList && !isExternalAccount) {
      const defaultSelect = allBuList.filter(
        (bu: BuListType) => bu.productBuName === '项目'
      );
      defaultSelect.length > 0 &&
        setSelectedBu([defaultSelect[0].productBuName]);
    }
  }, [allBuList]);

  useEffect(() => {
    dispatch({
      type: 'productData/getAllBuList'
    });
    dispatch({
      type: 'productData/queryProductCatalogTree'
    });
  }, []);

  const getDataList = useCallback(
    async (
      productCatalogId: number[],
      keyword: string,
      pageNum: number,
      pageSize: number,
      usePriceOrder?: boolean,
      specValueList?: Array<any>
    ) => {
      setProductLoading(true);
      const res = await queryProductList({
        productCatalogId: productCatalogId?.[0],
        searchKey: keyword || '',
        pageNum,
        pageSize,
        isAggBomCode,
        needPriceInfo,
        releaseStatus: 1,
        orderByPrice: usePriceOrder,
        orderType: usePriceOrder ? priceOrder : undefined,
        productBuList: BUILD_ENV === 'zh-CN' ? selectedBu : undefined,
        needProductBuInfo: true,
        returnMainProductId: true,
        needPolicyInfo: true,
        specValueList:
          Array.isArray(specValueList) && specValueList.length > 0 ?
            uniqBy(specValueList, 'specId') :
            undefined
      });
      const { code, msg, data } = res || {};
      if (code === 0) {
        if (data.records && Array.isArray(data.records)) {
          if (pageNum === 1) {
            // 切换目录的旧数据,在allSearchedProductList也需要保留
            const oldAllList = cloneDeep(allSearchedProductList);
            data.records.forEach((item: ProductType) => {
              const exit = oldAllList.find(
                (oldItem: ProductType) => oldItem.id === item.id
              );
              if (!exit) {
                oldAllList.push(item);
              }
            });
            setCurrentProduct(data.records || []);
            setAllSearchedProductList(oldAllList);
          } else {
            const oldProductList = cloneDeep(currentProduct);
            // 切换目录的旧数据,在allSearchedProductList也需要保留
            const oldAllList = cloneDeep(allSearchedProductList);
            // 用新数据去做遍历,从老数据中进行比对
            data.records.forEach((item: ProductType) => {
              const exit = oldProductList.find(
                (oldItem: ProductType) => oldItem.id === item.id
              );
              if (!exit) {
                oldProductList.push(item);
              }
              const exitAll = oldAllList.find(
                (oldItem: ProductType) => oldItem.id === item.id
              );
              if (!exitAll) {
                oldAllList.push(item);
              }
            });
            setCurrentProduct(oldProductList || []);
            setAllSearchedProductList(oldAllList);
          }
          setPageInfo({
            pageNum: data.current,
            pageSize: data.size
          });
        }
      } else {
        UNVMessageBox.msgBox({
          msg,
          iconType: 'error'
        });
      }
      setProductLoading(false);
    },
    [currentProduct, pageInfo, priceOrder, selectedBu]
  );

  useUpdateEffect(() => {
    priceOrder &&
      getDataList(
        currentId,
        keyword,
        1,
        pageInfo.pageSize,
        true,
        specValueList
      );
  }, [priceOrder]);

  useUpdateEffect(() => {
    setPriceOrder(undefined);
    if (selectType !== 'multi') {
      setCurrentSelectedList([]);
    }
    getDataList(currentId, keyword, 1, pageInfo.pageSize, false, specValueList);
    const tableElement = document.getElementById('scrollBox');
    tableElement && tableElement.scrollTo(0, 0);
  }, [currentId, selectedBu, keyword, specValueList]);

  useEffect(() => {
    if (Array.isArray(initList) && initList.length > 0) {
      setCurrentSelectedList(initList);
    }
  }, [initList]);

  const _onScroll = () => {
    if (productRef.current) {
      // 当前位置距离滚动框最高点的距离
      const scrollTop = productRef.current.scrollTop;
      // 当前滚动框的高度(固定)
      const clientHeight = productRef.current.clientHeight;
      // 当前列表所有元素的高度
      const scrollHeight = productRef.current.scrollHeight;
     
      console.log('clientHeight666', clientHeight);
      console.log('scrollHeight888', scrollHeight);
      console.log('scrollTop999', scrollTop);
      
      if (scrollHeight - clientHeight - scrollTop === 0 && !productLoading) {
        getDataList(
          currentId,
          keyword,
          pageInfo.pageNum + 1,
          pageInfo.pageSize,
          undefined,
          specValueList
        );
      }
    }
  };

  const _onInputSearch = (key: string) => {
    setKeyWord(key);
    setCurrentId([]);
  };

  const _checkboxChange = (id: number) => {
    if (currentSelectedList.map((item: ProductType) => item.id).includes(id)) {
      setCurrentSelectedList(() => {
        return currentSelectedList.filter(
          (item: ProductType) => item.id !== id
        );
      });
    } else {
      const productData: ProductType | undefined = currentProduct.find(
        (product: ProductType) => product.id === id
      );
      if (productData) {
        setCurrentSelectedList(
          selectType === 'multi' ?
            [...currentSelectedList, { ...productData, quantity: 1 }] :
            [{ ...productData, quantity: 1 }]
        );
      }
    }
  };

  const _onClose = (id: number) => {
    setCurrentSelectedList(() => {
      return currentSelectedList.filter((item: ProductType) => item.id !== id);
    });
  };

  console.log('currentSelectedList666', currentSelectedList);
  

  /**
   * @method 确认事件
   */
  const buttonClick = () => {
    if (!currentSelectedList.length) {
      return;
    }
    const checkData = currentSelectedList.map((item: ProductType) => ({
      product: {
        count: item.quantity,
        productId: item.id
      },
      partProducts: item.partsList?.map((i: PartType) => ({
        count: i.quantity,
        productId: i.partsId
      }))
    }));
    checkProduct(checkData, true)
      .then(() => {
        console.log('success');
        onConfirm && onConfirm(currentSelectedList);
      })
      .catch((err: CheckResultType[]) => {
        console.log(err);
        // setCurrentSelectedList(currentSelectedList.map((item) => ({
        //   ...item,
        //   message: err.filter((i: CheckResultType) => i.productId === item.id).map((j: CheckResultType) => j.warnMsg).join('、')
        // })));
      });
  };

  /**
   * 跳转到产品详情界面方法
   * @param {any} value 当前选择的跳转产品
   */
  const _skipToDetailPage = (value: any) => {
    window.open(
      `/common/ProductAndService/ProductDetails?productId=${value.id}&productModel=${value.productModel}`
    );
  };

  /**
   * @method 配置产品配件
   * @param productData
   */
  const _addParts = (productData: ProductType) => {
    setCurrentSelectedList((currentSelectedList) => {
      const bakList = JSON.parse(JSON.stringify(currentSelectedList));
      const index = bakList.findIndex(
        (item: PartType) => item.id === productData.id
      );
      if (index !== -1) {
        bakList[index] = productData;
        return bakList;
      } else {
        return selectType === 'multi' ?
          [...bakList, productData] :
          [productData];
      }
    });
    setAddPartsVisible(false);
  };

  /**
   * @method 前往配置配件页
   * @param productData 操作的产品对象
   */
  const goToAddParts = (productData: ProductType) => {
    dispatch({
      type: 'myQuotation/queryProductPartsDetailsMapByProductId',
      payload: productData.mainProductId || productData.id,
      callback: (partsList: any) => {
        if (
          !Object.values(partsList).reduce((prev: any[], cur) => {
            return prev.concat(cur);
          }, []).length
        ) {
          UNVMessageBox.info(
            intl.formatMessage({
              id: 'The product has no accessory'
            })
          );
        } else {
          const currentProduct = currentSelectedList.find(
            (i) => i.id === productData.id
          );
          setActionProduct(currentProduct || productData);
          setAddPartsVisible(true);
        }
      }
    });
  };

  /**
   * @method  根据产品状态设置产品图标
   */
  const _getTagPicUrl = (productStatus: number) => {
    switch (productStatus) {
      case 2:
        return (
          <img
            src={controlled}
            title={intl.formatMessage({ id: 'Controlled' })}
          />
        );
      case 3:
        return (
          <img
            src={strictControlled}
            title={intl.formatMessage({ id: 'Strictly Controlled' })}
          />
        );
      // case 4:
      //   return <img src={newStrictControlled} />; //暂时注释
      default:
        break;
    }
  };

  /**
   * @method  查询弹框筛选检索条件
   * @param
   */
  const getOptions = async (productCatalogId: string | number | undefined) => {
    setProductLoading(true);
    const res = await getQuotationSelectSpecFilterCondition(productCatalogId);
    const { code, msg, data } = res || {};
    if (code !== 0) {
      UNVMessageBox.msgBox({
        msg,
        iconType: 'error'
      });
    } else {
      Array.isArray(data) && data.length > 0 ?
        setFilterConditions(data) :
        setFilterConditions([]);
    }
  };

  /**
   * @method  选择弹框简选条件
   * @param
   */
  const _selectOptions = (e: string, item: any) => {
    const specValue = [...specValueList];
    const { id, filterConditionId, conditionId } = item;
    if (e !== 'clear') {
      const values = specValue.filter((it) => it.filterConditionId !== id);
      values.push({
        specId: filterConditionId || conditionId || undefined,
        specValue: e,
        filterConditionId: id,
        id
      });
      setSpecValueList(values);
    } else {
      const list = specValue.filter((it) => it.filterConditionId !== id);
      setSpecValueList(list);
    }
  };

  return (
    <>
      <UNVModal
        visible
        centered
        canDragm
        title={intl.formatMessage({ id: 'Select Product' })}
        width={900}
        footer={[
          <UNVButton
            key="1"
            btnType="primary"
            style={{ marginRight: '10px' }}
            onClick={buttonClick}
          >
            {intl.formatMessage({ id: 'OK' })}
          </UNVButton>,
          <UNVButton key="2" onClick={onCancel}>
            {intl.formatMessage({ id: 'Cancel' })}
          </UNVButton>
        ]}
        onCancel={onCancel}
        destroyOnClose
        className="component_selectProduct_modal"
      >
        <UNVLoading loading={productLoading}>
          <div className="component_selectProduct_body">
            <div className="component_selectProduct_bodyTop">
              <div className="component_selectProduct_tree">
                <Tree
                  blockNode
                  selectedKeys={currentId}
                  treeData={productCatalogTree}
                  showLine={{ showLeafIcon: true }}
                  onSelect={(selectedKeys: any[], e) => {
                    if (e.selected) {
                      setCurrentId(selectedKeys);
                      setKeyWord('');
                      selectedKeys && getOptions(selectedKeys);
                      setSpecValueList([]);
                    }
                  }}
                  fieldNames={{
                    title: 'productCatalogName',
                    key: 'id',
                    children: 'childList'
                  }}
                />
              </div>
              <div className="component_selectProduct_product">
                <div className="component_selectProduct_search">
                  <Select
                    value={selectedBu ? selectedBu[0] : 'all'}
                    onSelect={(value: string) => {
                      if (value && value !== 'all') {
                        setSelectedBu([value]);
                      } else {
                        setSelectedBu(undefined);
                      }
                    }}
                    style={{
                      display: BUILD_ENV === 'zh-CN' ? 'inline-block' : 'none'
                    }}
                    className="component_selectProduct_select"
                    defaultValue={
                      allBuList.filter(
                        (bu: BuListType) => bu.productBuName === '项目'
                      )[0]?.productBuName
                    }
                  >
                    <Select.Option value="all">
                      {intl.formatMessage({ id: 'All BU' })}
                    </Select.Option>
                    {allBuList.map((item: BuListType) => {
                      return (
                        <Select.Option value={item.productBuName} key={item.id}>
                          {item.productBuName}
                        </Select.Option>
                      );
                    })}
                  </Select>
                  {filterConditions.map((condition: any) => {
                    return (
                      <Select
                        placeholder={
                          condition.realDisplayName ||
                          condition.filterTypeName ||
                          ''
                        }
                        title={
                          condition.realDisplayName ||
                          condition.filterTypeName ||
                          ''
                        }
                        onSelect={(e) => _selectOptions(e, condition)}
                        allowClear
                        onClear={() => _selectOptions('clear', condition)}
                        className="component_selectProduct_search"
                        value={
                          specValueList.find(
                            (value: any) =>
                              value.filterConditionId === condition.id
                          )?.specValue
                        }
                      >
                        {Array.isArray(condition.disPlayFilterCondition) &&
                        condition.disPlayFilterCondition.length > 0 ?
                          condition.disPlayFilterCondition.map(
                            (item: any) => (
                              <Option value={item} key={item} title={item}>
                                {item}
                              </Option>
                            )
                          ) :
                          Array.isArray(condition.filterCondition) &&
                            condition.filterCondition.length > 0 &&
                            condition.filterCondition.map((item: any) => (
                              <Option value={item} key={item} title={item}>
                                {item}
                              </Option>
                            ))}
                      </Select>
                    );
                  })}

                  <UNVInput
                    placeholder={intl.formatMessage({
                      id: 'Please enter product keywords'
                    })}
                    onSearch={_onInputSearch}
                    onEnterPress={_onInputSearch}
                    value={keyword}
                    allowClear
                  />
                  <Button
                    data-use-order={Boolean(priceOrder)}
                    className="component_selectProduct_priceOrder"
                    onClick={() =>
                      setPriceOrder(priceOrder === 'asc' ? 'desc' : 'asc')
                    }
                  >
                    {priceOrder === 'desc' ? descOrder : ascOrder}
                    &nbsp;{intl.formatMessage({ id: 'Price' })}
                  </Button>
                </div>
                <div
                  id="scrollBox"
                  className="component_selectProduct_productList"
                  ref={productRef}
                  onScrollCapture={_onScroll}
                >
                  {currentProduct.map((item: ProductType) => {
                    return (
                      <div
                        key={item.id}
                        className="component_selectProduct_productListItem"
                      >
                        <Checkbox
                          onChange={() => {
                            _checkboxChange(item.id);
                          }}
                          checked={currentSelectedList
                            .map((item: ProductType) => item.id)
                            .includes(item.id)}
                        />
                        <div className="component_selectProduct_pic">
                          <GetImg
                            src={item.productPicUrl || productSmall}
                            alt={intl.formatMessage({ id: 'Product Icon' })}
                            onError={(e: any) => {
                              e.target.src = productSmall;
                            }}
                          />
                          {item.expandPolicyInfo && (
                            <GetImg
                              className="component_selectProduct_policyPic"
                              src={item.expandPolicyInfo.cornerMarkPicUrl}
                              alt=""
                            />
                          )}
                        </div>
                        <div
                          className="component_selectProduct_productItemInfo"
                          onClick={() => {
                            _skipToDetailPage(item);
                          }}
                        >
                          <div>
                            {item.productModel}
                            {_getTagPicUrl(item.productStatus)}
                          </div>
                          <div
                            title={
                              BUILD_ENV === 'zh-CN' ?
                                item.productName :
                                item.productEnName
                            }
                            className="component_selectProduct_productItemName"
                          >
                            {BUILD_ENV === 'zh-CN' ?
                              item.productName :
                              item.productEnName}
                          </div>
                          <div>
                            BOM:{item.bomCode}
                            {BUILD_ENV === 'zh-CN' &&
                              Array.isArray(item.productBuList) &&
                              item.productBuList.length > 0 &&
                              ` | ${item.productBuList.join('、')}`}
                          </div>
                        </div>
                        <div className="component_selectProduct_controlNum">
                          {currentSelectedList.find(
                            (i: ProductType) => i.id === item.id
                          ) && (
                            <InputNumber
                              addonBefore={
                                <div
                                  className="component_selectProduct_numButton"
                                  onClick={() => {
                                    const productData = currentSelectedList.find(
                                      (i: ProductType) => i.id === item.id
                                    );
                                    if (
                                      !productData ||
                                      productData.quantity < 2
                                    ) {
                                      return;
                                    } else {
                                      setCurrentSelectedList(
                                        (currentSelectedList) => {
                                          const bakList = JSON.parse(
                                            JSON.stringify(currentSelectedList)
                                          );
                                          const index = bakList.findIndex(
                                            (i: ProductType) => i.id === item.id
                                          );
                                          bakList[index].quantity--;
                                          return bakList;
                                        }
                                      );
                                    }
                                  }}
                                >
                                  <UNVIcon icon="minusIcon" />
                                </div>
                              }
                              addonAfter={
                                <div
                                  className="component_selectProduct_numButton"
                                  onClick={() => {
                                    const productData = currentSelectedList.find(
                                      (i: ProductType) => i.id === item.id
                                    );
                                    if (
                                      !productData ||
                                      productData.quantity > 9999998
                                    ) {
                                      return;
                                    } else {
                                      setCurrentSelectedList(
                                        (currentSelectedList) => {
                                          const bakList = JSON.parse(
                                            JSON.stringify(currentSelectedList)
                                          );
                                          const index = bakList.findIndex(
                                            (i: ProductType) => i.id === item.id
                                          );
                                          bakList[index].quantity++;
                                          return bakList;
                                        }
                                      );
                                    }
                                  }}
                                >
                                  <UNVIcon icon="addIcon" />
                                </div>
                              }
                              controls={false}
                              value={
                                currentSelectedList.find(
                                  (i: ProductType) => i.id === item.id
                                )?.quantity
                              }
                              maxLength={7}
                              precision={0}
                              onChange={(value) => {
                                if (!!value && (value < 1 || value > 9999999)) {
                                  return;
                                } else {
                                  setCurrentSelectedList(
                                    (currentSelectedList) => {
                                      const bakList = JSON.parse(
                                        JSON.stringify(currentSelectedList)
                                      );
                                      const index = bakList.findIndex(
                                        (i: ProductType) => i.id === item.id
                                      );
                                      bakList[index].quantity = value || 1;
                                      return bakList;
                                    }
                                  );
                                }
                              }}
                            />
                          )}
                        </div>
                        {needPriceInfo && (
                          <div className="component_selectProduct_price">
                            {item.productPriceInfo &&
                            item.productPriceInfo.originalPrice ?
                              `¥${item.productPriceInfo.originalPrice}` :
                              `${intl.formatMessage({
                                id: 'Pending upload'
                              })}`}
                          </div>
                        )}
                        <div
                          className="component_selectProduct_productItemAction"
                          data-selected={currentSelectedList
                            .map((item: ProductType) => item.id)
                            .includes(item.id)}
                          onClick={() => {
                            goToAddParts(item);
                          }}
                        >
                          {intl.formatMessage({ id: 'Select Accessory1' })}
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
            </div>
            {selectType === 'multi' && (
              <div className="component_selectProduct_bodyBottom">
                <div>{intl.formatMessage({ id: 'Selected' })}:</div>
                {currentSelectedList.map((item: ProductType) => {
                  return (
                    <UNVTags
                      key={item.id}
                      closable
                      bgColor="rgba(247, 248, 250)"
                      color="rgba(0, 0, 0, 0.85)"
                      onClose={() => {
                        _onClose(item.id);
                      }}
                    >
                      {item.productModel}
                    </UNVTags>
                  );
                })}
              </div>
            )}
          </div>
        </UNVLoading>
      </UNVModal>
    </>
  );
};

export default connect(({ productData }: { [key: string]: any }) => {
  const { allBuList, productCatalogTree } = productData;
  return {
    allBuList,
    productCatalogTree
  };
})(SelectProduct);