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>
>([]);
const [currentId, setCurrentId] = useState<number[]>([]);
const [actionProduct, setActionProduct] = useState<ProductType | undefined>(
undefined
);
const [addPartsVisible, setAddPartsVisible] = useState<boolean>(false);
const [keyword, setKeyWord] = useState('');
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
);
const [selectedBu, setSelectedBu] = useState<string[] | undefined>(undefined);
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) {
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);
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);
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);
});
};
const _skipToDetailPage = (value: any) => {
window.open(
`/common/ProductAndService/ProductDetails?productId=${value.id}&productModel=${value.productModel}`
);
};
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);
};
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);
}
}
});
};
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' })}
/>
);
default:
break;
}
};
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([]);
}
};
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}
{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);