268 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Search from '@/components/search'
import { View } from '@tarojs/components'
import Taro, { useDidShow } from '@tarojs/taro'
import { FC, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useTransition } from 'react'
import styles from './index.module.scss'
import classnames from 'classnames'
import IconText from '@/components/iconText'
import InfiniteScroll from '@/components/infiniteScroll'
import ItemList from './components/shoppingCartItem/index'
import { formatPriceDiv } from '@/common/format'
import BottomSettleBar from './components/bottomSettleBar'
import BottomEditBar from './components/bottomEditBar'
import { ShoppingCartDeleteApi, ShoppingCartListApi } from '@/api/index'
import { dataLoadingStatus, debounce, getFilterData } from '@/common/util'
import { ShoppingProvider } from './components/shoppingCart/index'
import { Goods, ShoppingDispatchType, useShoppingDispatch, useShoppingState } from './context'
import { alert, goLink, isEmptyObject } from '@/common/common'
export const Shopping: FC = memo(() => {
// 计算总的预估金额
const handleTriggerCheckbox = ({ multipleSelection, setSelectedAmount }) => {
console.log('handleTriggerCheckbox==>', multipleSelection)
if (multipleSelection) {
const result = Object.values(multipleSelection).reduce((prev: number , value: Goods) => {
return prev + Number(formatPriceDiv(value.estimate_amount))
}, 0) as number
// 同步修改上下文的 预估金额
setSelectedAmount(result)
} else {
setSelectedAmount(0)
}
}
return (
<ShoppingProvider onTriggerCheckbox={handleTriggerCheckbox}>
<ShoppingCartContainer />
</ShoppingProvider>
)
})
interface SearchOptions {
short_name_or_phone?: string
}
const ShoppingCartContainer: FC = () => {
let isFirst = useRef(true)
const { isMultipleSelection, isManageStatus, selectedAmount, currentCheckedPurchaserId, currentCheckedSaleMode, colorStore } = useShoppingState()
const dispatch = useShoppingDispatch()
// 管理
const onStartToManage = () => {
// if (isManageStatus) {
// handleSelectAllCheckbox(false) // 取消全选
// }
dispatch({ type: ShoppingDispatchType.UPDATE_MANAGE_STATUS, data: !isManageStatus })
}
const listHeightRef = useRef('auto')
// 强制刷新
const [, setForceUpdate] = useState({})
const { fetchData, state } = ShoppingCartListApi()
const [searchOptions, setSearchOptions] = useState<SearchOptions>({})
useDidShow(() => {
// 第二次进入该页面时触发
if (!isFirst.current) {
// 重新刷新
// setShoppingCartData({ list: [], total: 0 })
fetchData(getFilterData(searchOptions))
}
})
useEffect(() => {
console.log('useEffect fetchData', getFilterData(searchOptions))
if (!isFirst.current) {
fetchData(getFilterData(searchOptions))
}
}, [searchOptions])
// 输入了搜索关键字
const getSearchData = useCallback(e => {
console.log('getSearchData===>',e);
setSearchOptions({ short_name_or_phone: e })
}, [])
const [shoppingCartData, setShoppingCartData] = useState<{
list: ShoppingCartData[]
total: number
}>({ list: [], total: 0 })
//数据加载状态
const statusMore = useMemo(() => {
console.log('shoppingCartData==>', shoppingCartData, state)
const status = dataLoadingStatus({
list: shoppingCartData.list,
total: shoppingCartData.total,
status: state.loading!,
})
console.log('status==>', status)
return status
}, [shoppingCartData, state])
// useLayoutEffect 执行在DOM更新之后浏览器绘制之前 如果放在 useEffect 里面会产生多一次不必要的回流和重绘,可能会引起视图闪现
useLayoutEffect(() => {
;(async () => {
console.log('useLayoutEffect')
await fetchData(getFilterData(searchOptions))
isFirst.current = false
let query = Taro.createSelectorQuery()
console.log('query', query)
query.select('#shoppingContainer').boundingClientRect()
query.select('#topBar').boundingClientRect()
query.select('#bottomBar').boundingClientRect()
query.exec(res => {
console.log('res==>', res)
const containerHeight = res[0].height
const topBarHeight = res[1].height
const bottomBarHeight = res[2].height
const listHeight = containerHeight - topBarHeight - bottomBarHeight
listHeightRef.current = listHeight + 'px'
// 强制刷新
setForceUpdate({})
})
})()
}, [])
useEffect(() => {
if (state.success) {
console.log('fetch success', state);
setShoppingCartData({ list: state.data.list, total: state.data.total })
}
}, [state])
// 结算
const handleSettleAccount = debounce(() => {
const multipleSelection = colorStore?.[currentCheckedPurchaserId]?.['multipleSelection']
if (!multipleSelection) return alert.error('请先选择客户')
const checkedGoodsKind = Object.values(multipleSelection).reduce((prev, item: Goods) => {
return [...prev, item.id]
}, [])
if (checkedGoodsKind.length === 0) return alert.error('请先选择商品')
goLink('/pages/submitOrder/index', {
purchaser_id: currentCheckedPurchaserId,
sale_mode: currentCheckedSaleMode,
shopping_cart_product_color_list: JSON.stringify(checkedGoodsKind),
purchaser_name: shoppingCartData?.list.find(item => item.purchaser_id === currentCheckedPurchaserId)?.purchaser_name,
})
}, 400)
const { fetchData: deleteApi } = ShoppingCartDeleteApi()
// 批量某个客户的删除商品
const handleDelete = async () => {
const multipleSelection = colorStore?.[currentCheckedPurchaserId].multipleSelection
let checked: Goods[] = Object.values(multipleSelection!)
if (checked.length === 0) {
return alert.error('请选择商品')
}
console.log('checked==>', checked)
Taro.showModal({
title: '要删除这些商品吗?',
success: async function(res) {
if (res.confirm) {
alert.showLoading('删除中')
const res = await deleteApi({
ids: checked.map(item => item.id).join(','),
})
if (res.success) {
alert.hideLoading()
alert.success('删除成功')
// 清空多选
dispatch({
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
data: {
purchaserId: currentCheckedPurchaserId,
goodsKind: colorStore?.[currentCheckedPurchaserId].goodsKind,
multipleSelection: {},
},
})
fetchData(searchOptions)
// Observer.notify(currentCheckedPurchaserId)
} else {
alert.hideLoading()
alert.none(res.msg)
}
}
},
})
}
// 全选
const handleSelectAllCheckbox = (isSelectAll: boolean) => {
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId].goodsKind
if (!targetGoodsKind) return alert.error('请先选择客户')
const tempObject = { ...targetGoodsKind }
dispatch({
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
data: {
purchaserId: currentCheckedPurchaserId,
multipleSelection: isSelectAll ? tempObject : {},
},
})
}
// 加载刷新数据
const [refreshStatus, setRefreshStatus] = useState(false)
// 下拉刷新
const handleRefresh = async () => {
setRefreshStatus(true)
const res = await fetchData(getFilterData(searchOptions))
if (res.success) {
setRefreshStatus(false)
alert.success('刷新成功')
} else {
alert.error('刷新失败')
setRefreshStatus(false)
}
}
// const [isPending, startTransition] = useTransition()
return (
<View className={classnames('flex-col', styles.shopping)} id='shoppingContainer'>
<View className={styles['shopping--topBar']} id='topBar'>
<Search placeholder='请输入客户名称' showBtn={false} changeOnSearch={getSearchData} debounceTime={300}>
<View className={styles.flexBox} onClick={onStartToManage}>
{isManageStatus ? (
<IconText svg iconName='icon-guanlidingdan' text='取消' color='#4581ff' customClass={styles['icon--manage--cancel']} />
) : (
<IconText svg iconName='icon-guanlidingdan' text='管理' />
)}
</View>
</Search>
</View>
<View className={classnames('flex-item', 'flex-col', styles['shopping--context'])}>
<View id='shoppingListContainer' className={classnames(styles.shopping__list__container, 'flex-item')} style={{ height: listHeightRef.current }}>
<InfiniteScroll statusMore={statusMore} refresherEnabled={true} selfOnRefresherRefresh={handleRefresh} refresherTriggered={refreshStatus}>
{
!!shoppingCartData?.list?.length &&
shoppingCartData?.list?.map((item, index) => {
return <ItemList itemData={item} key={index}></ItemList>
})
}
</InfiniteScroll>
</View>
</View>
<View id='bottomBar'>
{isManageStatus ? (
<BottomEditBar
disabled={currentCheckedPurchaserId < 0}
isSelectAll={isMultipleSelection}
onDelete={handleDelete}
onSelectCheckbox={isAll => handleSelectAllCheckbox(isAll)}></BottomEditBar>
) : (
<BottomSettleBar onSettleAccount={handleSettleAccount} amount={selectedAmount}></BottomSettleBar>
)}
</View>
</View>
)
}
export default Shopping