Merge branch 'dev' of ssh://git.online.zzfzyc.com:10022/mp/spider_cloud_warehouse into 订单页
This commit is contained in:
commit
c5b74e3dd9
@ -1,6 +1,7 @@
|
|||||||
|
import { usePropsValue } from '@/use/useCommon'
|
||||||
import { View } from '@tarojs/components'
|
import { View } from '@tarojs/components'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
|
import React, { forwardRef, SetStateAction, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'
|
||||||
import IconFont from '../iconfont/iconfont'
|
import IconFont from '../iconfont/iconfont'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
|
|
||||||
@ -37,7 +38,25 @@ export default forwardRef((props: params, ref) => {
|
|||||||
customTextClass = '',
|
customTextClass = '',
|
||||||
hiddenCheckboxIcon = false,
|
hiddenCheckboxIcon = false,
|
||||||
} = props
|
} = props
|
||||||
const [selected, SetSelected] = useState(false)
|
console.log('Rerender component: checkbox', status)
|
||||||
|
const [selected, setSelected] = usePropsValue({
|
||||||
|
value: status,
|
||||||
|
defaultValue: false
|
||||||
|
})
|
||||||
|
// const selectedRef = useRef(status)
|
||||||
|
// if (status !== undefined){
|
||||||
|
// selectedRef.current = status
|
||||||
|
// }
|
||||||
|
// const [, setForceUpdate] = useState({})
|
||||||
|
// const setSelected = useCallback((v: SetStateAction<boolean>) => {
|
||||||
|
// const nextValue = typeof v === 'function' ? (v as (prevValue: boolean) => boolean)(selectedRef.current) : v
|
||||||
|
// console.log('对比',nextValue, selectedRef.current)
|
||||||
|
// if (nextValue === selectedRef.current) return
|
||||||
|
// selectedRef.current = nextValue
|
||||||
|
// console.log('强制刷新', nextValue, selectedRef.current)
|
||||||
|
// setForceUpdate({})
|
||||||
|
// }, [])
|
||||||
|
|
||||||
const onSelectEven = () => {
|
const onSelectEven = () => {
|
||||||
if (disabled) return false
|
if (disabled) return false
|
||||||
let res = !selected
|
let res = !selected
|
||||||
@ -46,11 +65,12 @@ export default forwardRef((props: params, ref) => {
|
|||||||
} else {
|
} else {
|
||||||
onClose?.()
|
onClose?.()
|
||||||
}
|
}
|
||||||
SetSelected(res)
|
console.log('res', res)
|
||||||
|
setSelected(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClickChildren = (event) => {
|
const handleClickChildren = event => {
|
||||||
if (!triggerLabel){
|
if (!triggerLabel) {
|
||||||
return event.stopPropagation()
|
return event.stopPropagation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,9 +96,9 @@ export default forwardRef((props: params, ref) => {
|
|||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
onSelectEven,
|
onSelectEven,
|
||||||
}))
|
}))
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
SetSelected(status)
|
// setSelected(status)
|
||||||
}, [status])
|
// }, [status])
|
||||||
return (
|
return (
|
||||||
<View className={classnames(customClassName, styles.checkbox)} style={customStyles} onClick={onSelectEven}>
|
<View className={classnames(customClassName, styles.checkbox)} style={customStyles} onClick={onSelectEven}>
|
||||||
{!hiddenCheckboxIcon && (
|
{!hiddenCheckboxIcon && (
|
||||||
|
@ -15,6 +15,7 @@ type params = {
|
|||||||
disable?: boolean, //是否禁用
|
disable?: boolean, //是否禁用
|
||||||
}
|
}
|
||||||
export default ({minNum = 0, maxNum = 10000, step=1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = '', disable = false}: params) => {
|
export default ({minNum = 0, maxNum = 10000, step=1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = '', disable = false}: params) => {
|
||||||
|
console.log('Rerender component: Counter');
|
||||||
const [value, setValue] = useState<any>({count:defaultNum})
|
const [value, setValue] = useState<any>({count:defaultNum})
|
||||||
|
|
||||||
const onPlus = (event) => {
|
const onPlus = (event) => {
|
||||||
@ -65,22 +66,26 @@ export default ({minNum = 0, maxNum = 10000, step=1, digits = 0, defaultNum = 0,
|
|||||||
if(res === '') {
|
if(res === '') {
|
||||||
setValue({...value, count:minNum})
|
setValue({...value, count:minNum})
|
||||||
onChange?.(minNum)
|
onChange?.(minNum)
|
||||||
|
return minNum
|
||||||
}
|
}
|
||||||
else if(!isNaN(Number(res))) {
|
else if(!isNaN(Number(res))) {
|
||||||
let count = formatDigits(res)
|
let count = formatDigits(res)
|
||||||
count = checkData(count)
|
count = checkData(count)
|
||||||
setValue({...value, count})
|
setValue({...value, count})
|
||||||
onChange?.(parseFloat(count as string))
|
onChange?.(parseFloat(count as string))
|
||||||
|
return count
|
||||||
} else {
|
} else {
|
||||||
let num = parseFloat(res)
|
let num = parseFloat(res)
|
||||||
if(!isNaN(num)) {
|
if (!isNaN(num)) {
|
||||||
let count = formatDigits(num)
|
let count = formatDigits(num)
|
||||||
count = checkData(count)
|
count = checkData(count)
|
||||||
setValue({...value, count})
|
setValue({ ...value, count })
|
||||||
onChange?.(count as number)
|
onChange?.(count as number)
|
||||||
|
return count
|
||||||
} else {
|
} else {
|
||||||
setValue({...value, count:defaultNum})
|
setValue({ ...value, count: defaultNum })
|
||||||
onChange?.(defaultNum)
|
onChange?.(defaultNum)
|
||||||
|
return defaultNum
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -88,14 +93,16 @@ export default ({minNum = 0, maxNum = 10000, step=1, digits = 0, defaultNum = 0,
|
|||||||
|
|
||||||
const onBluerEven = () => {
|
const onBluerEven = () => {
|
||||||
let num = parseFloat(value.count)
|
let num = parseFloat(value.count)
|
||||||
if(!isNaN(num)) {
|
if (!isNaN(num)) {
|
||||||
let count = formatDigits(num)
|
let count = formatDigits(num)
|
||||||
count = checkData(count)
|
count = checkData(count)
|
||||||
setValue({...value, count})
|
setValue({ ...value, count })
|
||||||
onBlue?.(count as number)
|
onBlue?.(count as number)
|
||||||
|
return count
|
||||||
} else {
|
} else {
|
||||||
setValue({...value, count:defaultNum})
|
setValue({ ...value, count: defaultNum })
|
||||||
onBlue?.(defaultNum)
|
onBlue?.(defaultNum)
|
||||||
|
return defaultNum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const noop = (e) => {
|
const noop = (e) => {
|
||||||
|
@ -62,7 +62,6 @@ const Login: FC = () => {
|
|||||||
account,
|
account,
|
||||||
password,
|
password,
|
||||||
})
|
})
|
||||||
console.log('state===>', res)
|
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
alert.success('登陆成功')
|
alert.success('登陆成功')
|
||||||
setToken(res.data.token)
|
setToken(res.data.token)
|
||||||
|
@ -1,33 +1,40 @@
|
|||||||
import { formatPriceDiv } from '@/common/format'
|
import { formatPriceDiv } from '@/common/format'
|
||||||
import NormalButton from '@/components/normalButton'
|
import NormalButton from '@/components/normalButton'
|
||||||
import { View, Text } from '@tarojs/components'
|
import { View, Text } from '@tarojs/components'
|
||||||
import { memo, useState } from 'react'
|
import { memo, SetStateAction, useMemo, useRef, useState } from 'react'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import MCheckbox from '@/components/checkbox'
|
import MCheckbox from '@/components/checkbox'
|
||||||
|
import { usePropsValue } from '@/use/useCommon'
|
||||||
|
import { ShoppingDispatchType, useShoppingDispatch } from '../../context'
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
onDelete?: Function
|
onDelete?: Function
|
||||||
onSelectCheckbox?: (bool: boolean) => void
|
onSelectCheckbox?: (bool: boolean) => void
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
|
isSelectAll?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default memo<PropsType>(props => {
|
export default (props: PropsType) => {
|
||||||
const { onDelete, onSelectCheckbox, disabled = false } = props
|
const { onDelete, onSelectCheckbox, disabled = false, isSelectAll: selectAll = false } = props
|
||||||
|
const dispatch = useShoppingDispatch()
|
||||||
|
console.log('isSelectAll==>', selectAll)
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
onDelete && onDelete()
|
onDelete && onDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectCallBack = () => {
|
const selectCallBack = () => {
|
||||||
onSelectCheckbox && onSelectCheckbox(true)
|
onSelectCheckbox && onSelectCheckbox(true)
|
||||||
setSelectAll(true)
|
dispatch({ type: ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION, data: true })
|
||||||
}
|
}
|
||||||
const closeCallBack = () => {
|
const closeCallBack = () => {
|
||||||
setSelectAll(false)
|
dispatch({ type: ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION, data: false })
|
||||||
onSelectCheckbox && onSelectCheckbox(false)
|
onSelectCheckbox && onSelectCheckbox(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [isSelectAll, setSelectAll] = useState(false)
|
const [isSelectAll, setSelectAll] = usePropsValue({
|
||||||
|
value: selectAll,
|
||||||
|
defaultValue: false,
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className={styles.bottomBar}>
|
<View className={styles.bottomBar}>
|
||||||
@ -50,4 +57,4 @@ export default memo<PropsType>(props => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
@ -1,136 +1,130 @@
|
|||||||
import { View, Text, Image } from '@tarojs/components'
|
import { View, Text, Image } from '@tarojs/components'
|
||||||
import MCheckbox from '@/components/checkbox'
|
import MCheckbox from '@/components/checkbox'
|
||||||
import Counter from '@/components/counter'
|
import Counter from '@/components/counter'
|
||||||
import { FC, memo, ReactNode, useCallback, useEffect, useState } from 'react'
|
import { FC, forwardRef, memo } from 'react'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import { debounce } from '@/common/util'
|
import { debounce } from '@/common/util'
|
||||||
import { formatImgUrl, formatPriceDiv } from '@/common/format'
|
import { formatImgUrl, formatPriceDiv } from '@/common/format'
|
||||||
import { EnumSaleMode } from '@/common/Enumerate'
|
import { EnumSaleMode } from '@/common/Enumerate'
|
||||||
import { useNeedMemoCallback } from '@/use/useCommon'
|
|
||||||
import { selectList } from '../../config'
|
import { selectList } from '../../config'
|
||||||
import { ShoppingDispatchType, useShoppingDispatch, useShoppingState } from '../../context'
|
import { Goods, ShoppingDispatchType, ShoppingStateContextValue, useShoppingDispatch, useShoppingState } from '../../context'
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
|
state?: Goods
|
||||||
purchaserId: number
|
purchaserId: number
|
||||||
itemData: Record<string, any> & object
|
itemData: Record<string, any> & object
|
||||||
orderType: EnumSaleMode
|
orderType: EnumSaleMode
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注意:如果在表单控件内部使用 useWatch,由于是直接从Context中取值,memo也会直接失去作用。
|
let ColorKindItem: FC<PropsType> = props => {
|
||||||
|
console.log('Rerender component: ColorKindItem')
|
||||||
|
const { state: multipleSelection, purchaserId, itemData, orderType = EnumSaleMode.Bulk } = props
|
||||||
|
const dispatch = useShoppingDispatch()
|
||||||
|
// console.log('checked==>', checked)
|
||||||
|
|
||||||
const ColorKindItem: FC<PropsType> = memo(
|
//格式化金额
|
||||||
props => {
|
const formatPrice = (price: number) => {
|
||||||
console.log('Rerender component: ColorKindItem')
|
return Number(formatPriceDiv(price))
|
||||||
const { purchaserId, itemData, orderType = EnumSaleMode.Bulk } = props
|
}
|
||||||
const { colorStore } = useShoppingState()
|
|
||||||
const dispatch = useShoppingDispatch()
|
|
||||||
// @ts-ignore
|
|
||||||
const { checked } = colorStore[purchaserId]['goodsKind']![itemData.id] || { checked: false }
|
|
||||||
|
|
||||||
//格式化金额
|
//格式化数量
|
||||||
const formatPrice = (price: number) => {
|
const formatCount = itemData => {
|
||||||
return Number(formatPriceDiv(price))
|
return itemData.sale_mode == EnumSaleMode.Bulk ? itemData.roll : itemData.length / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式化单位
|
||||||
|
const formatUnit = itemData => {
|
||||||
|
return itemData.sale_mode == EnumSaleMode.Bulk ? '条' : '米'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = () => {
|
||||||
|
dispatch({
|
||||||
|
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||||
|
data: {
|
||||||
|
purchaserId: purchaserId,
|
||||||
|
multipleSelection: { ...multipleSelection, [itemData.id]: itemData },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleClose = () => {
|
||||||
|
const temp = multipleSelection
|
||||||
|
delete temp?.[itemData.id]
|
||||||
|
dispatch({
|
||||||
|
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||||
|
data: {
|
||||||
|
purchaserId: purchaserId,
|
||||||
|
multipleSelection: temp,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO:需要新增调整条数/米数的接口 并在调整完成后重新请求整个购物车页面
|
||||||
|
const getInputValue = debounce(async (num, itemData) => {
|
||||||
|
if (itemData.sale_mode === EnumSaleMode.Bulk) {
|
||||||
|
itemData.roll = num
|
||||||
|
} else {
|
||||||
|
itemData.length = num
|
||||||
}
|
}
|
||||||
|
|
||||||
//格式化数量
|
}, 260)
|
||||||
const formatCount = itemData => {
|
|
||||||
return itemData.sale_mode == EnumSaleMode.Bulk ? itemData.roll : itemData.length / 100
|
|
||||||
}
|
|
||||||
|
|
||||||
//格式化单位
|
|
||||||
const formatUnit = itemData => {
|
|
||||||
return itemData.sale_mode == EnumSaleMode.Bulk ? '条' : '米'
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSelect = () => {
|
|
||||||
// console.log('handleSelect')
|
|
||||||
dispatch({
|
|
||||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
|
||||||
data: {
|
|
||||||
purchaserId: purchaserId,
|
|
||||||
goodsKind: { [itemData.id]: { ...colorStore[purchaserId].goodsKind?.[itemData.id]!, checked: true } },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
// setChangedCheckbox({
|
|
||||||
// purchaserId: purchaserId,
|
|
||||||
// goodsKind: { [itemData.id]: { ...colorStore[purchaserId].goodsKind?.[itemData.id]!, checked: true } },
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
const handleClose = () => {
|
|
||||||
dispatch({
|
|
||||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
|
||||||
data: {
|
|
||||||
purchaserId: purchaserId,
|
|
||||||
goodsKind: { [itemData.id]: { ...colorStore[purchaserId].goodsKind?.[itemData.id]!, checked: false } },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
// setChangedCheckbox({
|
|
||||||
// purchaserId: purchaserId,
|
|
||||||
// goodsKind: { [itemData.id]: { ...colorStore[purchaserId].goodsKind?.[itemData.id]!, checked: false } },
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
|
|
||||||
const getInputValue = debounce(async (num, itemData) => {
|
return (
|
||||||
if (itemData.sale_mode === EnumSaleMode.Bulk) {
|
<MCheckbox
|
||||||
itemData.roll = num
|
status={multipleSelection?.hasOwnProperty(itemData.id) || false}
|
||||||
} else {
|
onSelect={handleSelect}
|
||||||
itemData.length = num
|
onClose={handleClose}
|
||||||
}
|
customClassName={classnames(styles.checkbox, multipleSelection?.hasOwnProperty(itemData.id) ? styles.selected : '')}
|
||||||
}, 300)
|
customTextClass={styles.colorKindItem}>
|
||||||
|
<View className={styles['colorKindItem__left']}>
|
||||||
return (
|
<Image className={styles['colorKindItem__left--image']} mode='aspectFill' src={formatImgUrl(itemData.product_color_texture_url)}></Image>
|
||||||
<MCheckbox
|
</View>
|
||||||
status={checked}
|
<View className={styles['colorKindItem__center']}>
|
||||||
onSelect={handleSelect}
|
<Text className={styles['colorKindItem__center--title']}>
|
||||||
onClose={handleClose}
|
{itemData.product_code}# {itemData.product_name}
|
||||||
customClassName={classnames(styles.checkbox, checked ? styles.selected : '')}
|
</Text>
|
||||||
customTextClass={styles.colorKindItem}>
|
<View className={styles['colorKindItem__center--detail']}>
|
||||||
<View className={styles['colorKindItem__left']}>
|
<Text className={styles['colorKindItem__center--ID']}>{itemData.product_color_code}</Text>
|
||||||
<Image className={styles['colorKindItem__left--image']} mode='aspectFill' src={formatImgUrl(itemData.product_color_texture_url)}></Image>
|
<Text className={styles['colorKindItem__center--description']}>{itemData.product_color_name}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className={styles['colorKindItem__center']}>
|
</View>
|
||||||
<Text className={styles['colorKindItem__center--title']}>
|
<View className={styles['colorKindItem__right']}>
|
||||||
{itemData.product_code}# {itemData.product_name}
|
<View className={styles['colorKindItem__right--price']}>¥ {formatPrice(itemData.sale_price)}/kg</View>
|
||||||
</Text>
|
<View className={styles['colorKindItem__right--counter']}>
|
||||||
<View className={styles['colorKindItem__center--detail']}>
|
<Counter
|
||||||
<Text className={styles['colorKindItem__center--ID']}>{itemData.product_color_code}</Text>
|
onBlue={e => getInputValue(e, itemData)}
|
||||||
<Text className={styles['colorKindItem__center--description']}>{itemData.product_color_name}</Text>
|
defaultNum={formatCount(itemData)}
|
||||||
</View>
|
step={selectList[orderType].step}
|
||||||
|
digits={selectList[orderType].digits}
|
||||||
|
onClickBtn={e => getInputValue(e, itemData)}
|
||||||
|
unit={formatUnit(itemData)}
|
||||||
|
minNum={selectList[orderType].minNum}
|
||||||
|
maxNum={selectList[orderType].maxNum}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View className={styles['colorKindItem__right']}>
|
</View>
|
||||||
<View className={styles['colorKindItem__right--price']}>¥ {formatPrice(itemData.sale_price)}/kg</View>
|
</MCheckbox>
|
||||||
<View className={styles['colorKindItem__right--counter']}>
|
)
|
||||||
<Counter
|
}
|
||||||
onBlue={e => getInputValue(e, itemData)}
|
// State 分割组件 思路就是把 context 直接通过 props 的形式传给组件,这样的话就解决了 context 强制刷新 memo 的问题了
|
||||||
defaultNum={formatCount(itemData)}
|
// 那么当 context 内的 value 被更新的时候,react 只会强制渲染 Wrapper
|
||||||
step={selectList[orderType].step}
|
const withStateSlice = (comp, slice) => {
|
||||||
digits={selectList[orderType].digits}
|
const MemoComp = memo(comp)
|
||||||
onClickBtn={e => getInputValue(e, itemData)}
|
const Wrapper = (props, ref) => {
|
||||||
unit={formatUnit(itemData)}
|
const state = useShoppingState()
|
||||||
minNum={selectList[orderType].minNum}
|
return <MemoComp ref={ref} state={slice(state, props)} {...props} />
|
||||||
maxNum={selectList[orderType].maxNum}
|
}
|
||||||
/>
|
return memo(forwardRef(Wrapper))
|
||||||
</View>
|
}
|
||||||
</View>
|
|
||||||
</MCheckbox>
|
ColorKindItem = withStateSlice(
|
||||||
// <View>1111</View>
|
ColorKindItem,
|
||||||
)
|
(state: ShoppingStateContextValue, props: PropsType) => {
|
||||||
},
|
return state.colorStore[props.purchaserId]['multipleSelection']
|
||||||
(preProp, nextProp) => {
|
|
||||||
const stringifyPreProp = JSON.stringify(preProp.itemData)
|
|
||||||
const stringifyNextProp = JSON.stringify(nextProp.itemData)
|
|
||||||
// console.log('memo==>', preProp, nextProp)
|
|
||||||
let needMemoized = true
|
|
||||||
if (preProp.purchaserId !== nextProp.purchaserId) {
|
|
||||||
needMemoized = false
|
|
||||||
}
|
|
||||||
if (preProp.orderType !== nextProp.orderType) {
|
|
||||||
needMemoized = false
|
|
||||||
}
|
|
||||||
if (stringifyPreProp !== stringifyNextProp) {
|
|
||||||
needMemoized = false
|
|
||||||
}
|
|
||||||
return needMemoized
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
export default ColorKindItem
|
export default ColorKindItem
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
import { Dispatch, FC, ReactNode, useEffect, useMemo, useReducer, useRef, useState } from 'react'
|
import { FC, ReactNode, useEffect, useReducer, useRef } from 'react'
|
||||||
import { ShoppingAction, ShoppingCartAction, ShoppingDispatchContext, ShoppingDispatchContextValue, ShoppingDispatchType, shoppingReducer, ShoppingStateContext } from '../../context'
|
import {
|
||||||
import { GoodsMeta, ColorStore, ShoppingStateContextValue } from '../../context'
|
ShoppingAction,
|
||||||
|
ShoppingDispatchContext,
|
||||||
|
ShoppingDispatchContextValue,
|
||||||
|
ShoppingDispatchType,
|
||||||
|
shoppingReducer,
|
||||||
|
ShoppingStateContext,
|
||||||
|
} from '../../context'
|
||||||
|
import { ColorStore, ShoppingStateContextValue } from '../../context'
|
||||||
|
|
||||||
export type TriggerCheckboxOptions = {
|
export type TriggerCheckboxOptions = {
|
||||||
colorStore: ColorStore
|
colorStore: ColorStore
|
||||||
@ -13,6 +20,7 @@ type InitialState = {
|
|||||||
currentCheckedPurchaserId: number
|
currentCheckedPurchaserId: number
|
||||||
currentCheckedSaleMode: number
|
currentCheckedSaleMode: number
|
||||||
isManageStatus: boolean
|
isManageStatus: boolean
|
||||||
|
isMultipleSelection: boolean
|
||||||
selectedAmount: number
|
selectedAmount: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,17 +41,16 @@ export const ShoppingProvider: FC<ShoppingCartPropsType> = props => {
|
|||||||
currentCheckedPurchaserId: -1,
|
currentCheckedPurchaserId: -1,
|
||||||
currentCheckedSaleMode: 0,
|
currentCheckedSaleMode: 0,
|
||||||
isManageStatus: false,
|
isManageStatus: false,
|
||||||
|
isMultipleSelection: false,
|
||||||
selectedAmount: 0,
|
selectedAmount: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 这里要在 useEffect 也就是刷新 state 后再调用,否则如果在 onFieldsChangeRef 修改值会覆盖掉上次修改
|
// 这里要在 useEffect 也就是刷新 state 后再调用,否则如果在 onFieldsChangeRef 修改值会覆盖掉上次修改
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onTriggerCheckboxRef.current?.({
|
onTriggerCheckboxRef.current?.({
|
||||||
colorStore: state.colorStore,
|
colorStore: state.colorStore,
|
||||||
currentCheckedPurchaserId: state.currentCheckedPurchaserId,
|
currentCheckedPurchaserId: state.currentCheckedPurchaserId,
|
||||||
setSelectedAmount: (amount) => dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT,data: amount }),
|
setSelectedAmount: amount => dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: amount }),
|
||||||
})
|
})
|
||||||
}, [state.colorStore, state.currentCheckedPurchaserId])
|
}, [state.colorStore, state.currentCheckedPurchaserId])
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Text, View } from '@tarojs/components'
|
import { Text, View } from '@tarojs/components'
|
||||||
import { FC, memo, useEffect, useMemo, useState, useTransition } from 'react'
|
import { FC, forwardRef, memo, useEffect, useMemo, useState, useTransition } from 'react'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { formatMeterDiv } from '@/common/format'
|
import { formatMeterDiv } from '@/common/format'
|
||||||
@ -9,14 +9,29 @@ import Divider from '@/components/divider'
|
|||||||
import ColorKindItem from '../colorKindItem'
|
import ColorKindItem from '../colorKindItem'
|
||||||
import { EnumSaleMode } from '@/common/Enumerate'
|
import { EnumSaleMode } from '@/common/Enumerate'
|
||||||
import { selectList } from '../../config'
|
import { selectList } from '../../config'
|
||||||
import { Goods, ShoppingDispatchType, useShoppingDispatch, useShoppingState } from '../../context'
|
import { Goods, GoodsMeta, ShoppingDispatchType, ShoppingStateContextValue, useShoppingDispatch, useShoppingState } from '../../context'
|
||||||
import IconFont from '@/components/iconfont/iconfont'
|
import IconFont from '@/components/iconfont/iconfont'
|
||||||
import { isEmptyObject } from '@/common/common'
|
import { isEmptyObject } from '@/common/common'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import LoadingCard from '@/components/loadingCard'
|
import LoadingCard from '@/components/loadingCard'
|
||||||
|
|
||||||
type PropsType = {
|
interface ButtonPropsType {
|
||||||
itemData?: ShoppingCartData
|
isActive: boolean
|
||||||
|
onClick?: Function
|
||||||
|
children?: React.ReactNode
|
||||||
|
customStyle?: React.CSSProperties
|
||||||
|
}
|
||||||
|
// 订单类型
|
||||||
|
const SaleModeButton: FC<ButtonPropsType> = props => {
|
||||||
|
const { onClick, children, isActive = false, customStyle } = props
|
||||||
|
const handleClick = () => {
|
||||||
|
onClick?.()
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View className={classnames(styles.saleModeButton, isActive && styles['saleModeButton--active'])} style={customStyle} onClick={handleClick}>
|
||||||
|
<View className={classnames(styles['saleModeButton--text'])}>{children}</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const DrawerButton = memo<{ isOpen: boolean }>(({ isOpen }) => {
|
const DrawerButton = memo<{ isOpen: boolean }>(({ isOpen }) => {
|
||||||
@ -33,9 +48,17 @@ enum BackEndSaleModeListFieldMap {
|
|||||||
weight_cut_color_list = 2,
|
weight_cut_color_list = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default memo<PropsType>(props => {
|
type PropsType = {
|
||||||
const { itemData } = props
|
itemData?: ShoppingCartData
|
||||||
|
state?: {
|
||||||
|
multipleSelection?: GoodsMeta['multipleSelection']
|
||||||
|
currentCheckedPurchaserId?: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ShoppingCartItem: FC<PropsType> = props => {
|
||||||
|
const { itemData, state } = props
|
||||||
|
const { multipleSelection, currentCheckedPurchaserId } = state!
|
||||||
const dispatch = useShoppingDispatch()
|
const dispatch = useShoppingDispatch()
|
||||||
|
|
||||||
const [openDetail, setOpenDetail] = useState(false)
|
const [openDetail, setOpenDetail] = useState(false)
|
||||||
@ -53,93 +76,59 @@ export default memo<PropsType>(props => {
|
|||||||
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: type })
|
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: type })
|
||||||
// 重置预估金额
|
// 重置预估金额
|
||||||
dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
|
dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
|
||||||
|
dispatch({ type: ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION, data: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { currentCheckedPurchaserId, colorStore } = useShoppingState()
|
|
||||||
|
|
||||||
console.log('Rerender component: shoppingCartItem')
|
console.log('Rerender component: shoppingCartItem')
|
||||||
|
|
||||||
// const memoList = useMemo(() => {
|
|
||||||
// console.log('ext useMemo')
|
|
||||||
// const component = itemData?.[BackEndSaleModeListFieldMap[selected]].map(item => {
|
|
||||||
// dispatch({
|
|
||||||
// type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
|
||||||
// data: {
|
|
||||||
// purchaserId: itemData?.purchaser_id!,
|
|
||||||
// goodsKind: {
|
|
||||||
// [item?.id]: {
|
|
||||||
// id: item?.id,
|
|
||||||
// estimate_amount: item.estimate_amount,
|
|
||||||
// checked: false,
|
|
||||||
// product_code: item.product_code,
|
|
||||||
// product_color_code: item.product_color_code,
|
|
||||||
// sale_mode: item.sale_mode,
|
|
||||||
// count: selected === EnumSaleMode.Bulk ? item.roll : Number(formatMeterDiv(item.length)),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
// return <ColorKindItem purchaserId={itemData.purchaser_id} key={item.id} itemData={item} orderType={selected}></ColorKindItem>
|
|
||||||
// })
|
|
||||||
// // 向 context 中初始化数据
|
|
||||||
// const result = itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0 ? component : <View className={styles.noList}>暂无数据</View>
|
|
||||||
|
|
||||||
// return result
|
|
||||||
// }, [itemData, selected])
|
|
||||||
|
|
||||||
const handleClickLayout = () => {
|
const handleClickLayout = () => {
|
||||||
if (currentCheckedPurchaserId === itemData?.purchaser_id) {
|
if (currentCheckedPurchaserId === itemData?.purchaser_id) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
|
dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
|
||||||
// setSelectedAmount(0)
|
|
||||||
// setCurrentCheckedSaleMode(selected)
|
|
||||||
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: selected })
|
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: selected })
|
||||||
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID, data: itemData?.purchaser_id as number })
|
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID, data: itemData?.purchaser_id as number })
|
||||||
// setCurrentCheckedPurchaserId(itemData?.purchaser_id as number)
|
dispatch({ type: ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION, data: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统计已选面料
|
// 统计已选面料
|
||||||
const materialChecked = useMemo(() => {
|
const materialChecked = useMemo(() => {
|
||||||
const targetGoodsKind = colorStore?.[itemData?.purchaser_id!]?.['goodsKind']
|
if (!multipleSelection || isEmptyObject(multipleSelection)) return 0
|
||||||
if (!targetGoodsKind || isEmptyObject(targetGoodsKind)) return 0
|
|
||||||
return new Set(
|
return new Set(
|
||||||
Object.values(targetGoodsKind)?.reduce((prev, item: Goods) => {
|
Object.values(multipleSelection)?.reduce((prev, item: Goods) => {
|
||||||
if (item.checked && item.sale_mode === selected) {
|
if (item.sale_mode === selected) {
|
||||||
return [...prev, item.product_code]
|
return [...prev, item.product_code]
|
||||||
}
|
}
|
||||||
return prev
|
return prev
|
||||||
}, []),
|
}, []),
|
||||||
).size
|
).size
|
||||||
}, [colorStore, currentCheckedPurchaserId, selected, itemData])
|
}, [multipleSelection, currentCheckedPurchaserId, selected, itemData])
|
||||||
|
|
||||||
// 统计已选颜色
|
// 统计已选颜色
|
||||||
const colorChecked = useMemo(() => {
|
const colorChecked = useMemo(() => {
|
||||||
const targetGoodsKind = colorStore?.[itemData?.purchaser_id!]?.['goodsKind']
|
if (!multipleSelection || isEmptyObject(multipleSelection)) return 0
|
||||||
if (!targetGoodsKind || isEmptyObject(targetGoodsKind)) return 0
|
|
||||||
return new Set(
|
return new Set(
|
||||||
Object.values(targetGoodsKind).reduce((prev, item: Goods) => {
|
Object.values(multipleSelection).reduce((prev, item: Goods) => {
|
||||||
if (item.checked && item.sale_mode === selected) {
|
if (item.sale_mode === selected) {
|
||||||
return [...prev, item.product_color_code]
|
return [...prev, item.product_color_code]
|
||||||
}
|
}
|
||||||
return prev
|
return prev
|
||||||
}, []),
|
}, []),
|
||||||
).size
|
).size
|
||||||
}, [colorStore, currentCheckedPurchaserId, selected, itemData])
|
}, [multipleSelection, currentCheckedPurchaserId, selected, itemData])
|
||||||
|
|
||||||
// 统计已选条数 / 米数
|
// 统计已选条数 / 米数
|
||||||
const lengthOrRollChecked = useMemo(() => {
|
const lengthOrRollChecked = useMemo(() => {
|
||||||
const targetGoodsKind = colorStore?.[itemData?.purchaser_id!]?.['goodsKind']
|
if (!multipleSelection || isEmptyObject(multipleSelection)) return 0
|
||||||
if (!targetGoodsKind || isEmptyObject(targetGoodsKind)) return 0
|
|
||||||
return (
|
return (
|
||||||
Object.values(targetGoodsKind).reduce((prev, item: Goods) => {
|
Object.values(multipleSelection).reduce((prev, item: Goods) => {
|
||||||
if (item.checked && item.sale_mode === selected) {
|
if (item.sale_mode === selected) {
|
||||||
return prev + item.count
|
return prev + item.count
|
||||||
}
|
}
|
||||||
return prev
|
return prev
|
||||||
}, 0) || 0
|
}, 0) || 0
|
||||||
)
|
)
|
||||||
}, [colorStore, currentCheckedPurchaserId, selected, itemData])
|
}, [multipleSelection, currentCheckedPurchaserId, selected, itemData])
|
||||||
|
|
||||||
const [isPending, startTransition] = useTransition()
|
const [isPending, startTransition] = useTransition()
|
||||||
|
|
||||||
@ -205,7 +194,6 @@ export default memo<PropsType>(props => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className={styles.orderContainer}>
|
<View className={styles.orderContainer}>
|
||||||
{/* <GoodsList itemData={itemData} selected={selected} /> */}
|
|
||||||
<GoodsList itemData={itemData} selected={selected} isPending={isPending} startTransition={startTransition} />
|
<GoodsList itemData={itemData} selected={selected} isPending={isPending} startTransition={startTransition} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@ -213,7 +201,7 @@ export default memo<PropsType>(props => {
|
|||||||
)}
|
)}
|
||||||
</LayoutBlock>
|
</LayoutBlock>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
|
||||||
interface GoodsListPropType {
|
interface GoodsListPropType {
|
||||||
itemData?: ShoppingCartData
|
itemData?: ShoppingCartData
|
||||||
@ -241,13 +229,13 @@ const GoodsList = memo<GoodsListPropType>(props => {
|
|||||||
[item?.id]: {
|
[item?.id]: {
|
||||||
id: item?.id,
|
id: item?.id,
|
||||||
estimate_amount: item.estimate_amount,
|
estimate_amount: item.estimate_amount,
|
||||||
checked: false,
|
|
||||||
product_code: item.product_code,
|
product_code: item.product_code,
|
||||||
product_color_code: item.product_color_code,
|
product_color_code: item.product_color_code,
|
||||||
sale_mode: item.sale_mode,
|
sale_mode: item.sale_mode,
|
||||||
count: selected === EnumSaleMode.Bulk ? item.roll : Number(formatMeterDiv(item.length)),
|
count: selected === EnumSaleMode.Bulk ? item.roll : Number(formatMeterDiv(item.length)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
multipleSelection: {},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return <ColorKindItem purchaserId={itemData.purchaser_id} key={item.id} itemData={item} orderType={selected}></ColorKindItem>
|
return <ColorKindItem purchaserId={itemData.purchaser_id} key={item.id} itemData={item} orderType={selected}></ColorKindItem>
|
||||||
@ -271,22 +259,30 @@ const GoodsList = memo<GoodsListPropType>(props => {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
// State 分割组件 思路就是把 context 直接通过 props 的形式传给组件,这样的话就解决了 context 强制刷新 memo 的问题了
|
||||||
interface ButtonPropsType {
|
// 那么当 context 内的 value 被更新的时候,react 只会强制渲染 Wrapper
|
||||||
isActive: boolean
|
const withStateSlice = (comp, slice) => {
|
||||||
onClick?: Function
|
const MemoComp = memo(comp, (prevProps, nextProps)=>{
|
||||||
children?: React.ReactNode
|
let needMemo = true
|
||||||
customStyle?: React.CSSProperties
|
if (JSON.stringify(prevProps.itemData) !== JSON.stringify(nextProps.itemData)) {
|
||||||
}
|
needMemo = false
|
||||||
// 订单类型
|
}
|
||||||
const SaleModeButton: FC<ButtonPropsType> = props => {
|
if(JSON.stringify(prevProps.state) !== JSON.stringify(nextProps.state)){
|
||||||
const { onClick, children, isActive = false, customStyle } = props
|
needMemo = false
|
||||||
const handleClick = () => {
|
}
|
||||||
onClick?.()
|
return needMemo
|
||||||
|
})
|
||||||
|
const Wrapper = (props, ref) => {
|
||||||
|
const state = useShoppingState()
|
||||||
|
console.log('state===>', state)
|
||||||
|
return <MemoComp ref={ref} state={slice(state, props)} {...props} />
|
||||||
}
|
}
|
||||||
return (
|
return memo(forwardRef(Wrapper))
|
||||||
<View className={classnames(styles.saleModeButton, isActive && styles['saleModeButton--active'])} style={customStyle} onClick={handleClick}>
|
|
||||||
<View className={classnames(styles['saleModeButton--text'])}>{children}</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShoppingCartItem = withStateSlice(ShoppingCartItem, (state: ShoppingStateContextValue, props) => ({
|
||||||
|
multipleSelection: state.colorStore?.[props.itemData?.purchaser_id]?.['multipleSelection'],
|
||||||
|
currentCheckedPurchaserId: state.currentCheckedPurchaserId,
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default ShoppingCartItem
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { Dispatch, useRef } from 'react'
|
import { EnumSaleMode } from '@/common/Enumerate'
|
||||||
|
import React, { Dispatch } from 'react'
|
||||||
import { useContext } from 'react'
|
import { useContext } from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,41 +32,46 @@ export type Goods = {
|
|||||||
product_color_code: number // 颜色编号
|
product_color_code: number // 颜色编号
|
||||||
estimate_amount: number // 预估金额
|
estimate_amount: number // 预估金额
|
||||||
count: number // 已选的条数或米数
|
count: number // 已选的条数或米数
|
||||||
sale_mode: number
|
sale_mode: EnumSaleMode
|
||||||
checked: boolean
|
|
||||||
}
|
}
|
||||||
// 分组
|
// 分组
|
||||||
export interface GoodsMeta {
|
export interface GoodsMeta {
|
||||||
purchaserId: number
|
purchaserId: number
|
||||||
goodsKind?: {
|
goodsKind?: {
|
||||||
[id: number]: Goods
|
[id: Goods['id']]: Goods
|
||||||
|
}
|
||||||
|
multipleSelection: {
|
||||||
|
[id: Goods['id']]: Goods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ShoppingStateContextValue {
|
export interface ShoppingStateContextValue {
|
||||||
isManageStatus: boolean
|
isManageStatus: boolean // 管理按钮的状态
|
||||||
|
isMultipleSelection: boolean // 全选按钮的状态
|
||||||
currentCheckedPurchaserId: number // 当前高亮的客户ID
|
currentCheckedPurchaserId: number // 当前高亮的客户ID
|
||||||
currentCheckedSaleMode: number
|
currentCheckedSaleMode: EnumSaleMode
|
||||||
colorStore: ColorStore
|
colorStore: ColorStore
|
||||||
selectedAmount: number
|
selectedAmount: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ShoppingDispatchType {
|
export enum ShoppingDispatchType {
|
||||||
UPDATE_MANAGE_STATUS = 'UPDATE_MANAGE_STATUS',
|
UPDATE_MANAGE_STATUS = 'UPDATE_MANAGE_STATUS',
|
||||||
|
UPDATE_MULTIPLE_SELECTION = 'UPDATE_MULTIPLE_SELECTION',
|
||||||
UPDATE_CURRENT_CHECKED_PURCHASERID = 'UPDATE_CURRENT_CHECKED_PURCHASERID',
|
UPDATE_CURRENT_CHECKED_PURCHASERID = 'UPDATE_CURRENT_CHECKED_PURCHASERID',
|
||||||
UPDATE_CURRENT_CHECKED_SALEMODE = 'UPDATE_CURRENT_CHECKED_SALEMODE',
|
UPDATE_CURRENT_CHECKED_SALEMODE = 'UPDATE_CURRENT_CHECKED_SALEMODE',
|
||||||
UPDATE_COLOR_STORE = 'UPDATE_COLOR_STORE',
|
UPDATE_COLOR_STORE = 'UPDATE_COLOR_STORE',
|
||||||
UPDATE_SELECTED_AMOUNT = 'UPDATE_SELECTED_AMOUNT',
|
UPDATE_SELECTED_AMOUNT = 'UPDATE_SELECTED_AMOUNT',
|
||||||
UPDATE_CHANGED_CHECKBOX = 'UPDATE_CHANGED_CHECKBOX',
|
UPDATE_CHANGED_CHECKBOX = 'UPDATE_CHANGED_CHECKBOX',
|
||||||
}
|
}
|
||||||
|
// UPDATE_MultipleSelection
|
||||||
export interface ShoppingDispatchContextValue {
|
export interface ShoppingDispatchContextValue {
|
||||||
[ShoppingDispatchType.UPDATE_MANAGE_STATUS]: (isManageStatus: boolean) => void
|
[ShoppingDispatchType.UPDATE_MANAGE_STATUS]: (isManageStatus: ShoppingStateContextValue['isManageStatus']) => void
|
||||||
[ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID]: (purchaserId: number) => void
|
[ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION]: (isMultipleSelection: ShoppingStateContextValue['isMultipleSelection']) => void
|
||||||
[ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE]: (saleMode: number) => void
|
[ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID]: (purchaserId: ShoppingStateContextValue['currentCheckedPurchaserId']) => void
|
||||||
|
[ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE]: (saleMode: ShoppingStateContextValue['currentCheckedSaleMode']) => void
|
||||||
[ShoppingDispatchType.UPDATE_COLOR_STORE]: (colorStore: React.SetStateAction<ColorStore>) => void
|
[ShoppingDispatchType.UPDATE_COLOR_STORE]: (colorStore: React.SetStateAction<ColorStore>) => void
|
||||||
[ShoppingDispatchType.UPDATE_SELECTED_AMOUNT]: (amount: React.SetStateAction<number>) => void
|
[ShoppingDispatchType.UPDATE_SELECTED_AMOUNT]: (amount: React.SetStateAction<ShoppingStateContextValue['selectedAmount']>) => void
|
||||||
[ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX]: (amount: React.SetStateAction<number>) => void
|
[ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX]: (amount: React.SetStateAction<ShoppingStateContextValue['selectedAmount']>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -80,6 +86,9 @@ export function shoppingReducer(state: ShoppingStateContextValue, action: Shoppi
|
|||||||
case ShoppingDispatchType.UPDATE_MANAGE_STATUS: {
|
case ShoppingDispatchType.UPDATE_MANAGE_STATUS: {
|
||||||
return { ...state, isManageStatus: data }
|
return { ...state, isManageStatus: data }
|
||||||
}
|
}
|
||||||
|
case ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION: {
|
||||||
|
return { ...state, isMultipleSelection: data }
|
||||||
|
}
|
||||||
case ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID: {
|
case ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID: {
|
||||||
return { ...state, currentCheckedPurchaserId: data }
|
return { ...state, currentCheckedPurchaserId: data }
|
||||||
}
|
}
|
||||||
@ -100,6 +109,7 @@ export function shoppingReducer(state: ShoppingStateContextValue, action: Shoppi
|
|||||||
[data.purchaserId as number]: {
|
[data.purchaserId as number]: {
|
||||||
purchaserId: data.purchaserId,
|
purchaserId: data.purchaserId,
|
||||||
goodsKind: { ...state.colorStore[data.purchaserId]?.goodsKind, ...data.goodsKind },
|
goodsKind: { ...state.colorStore[data.purchaserId]?.goodsKind, ...data.goodsKind },
|
||||||
|
multipleSelection: { ...data.multipleSelection },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -20,15 +20,12 @@ import LoadingCard from '@/components/loadingCard'
|
|||||||
export const Shopping: FC = memo(() => {
|
export const Shopping: FC = memo(() => {
|
||||||
// 计算总的预估金额
|
// 计算总的预估金额
|
||||||
const handleTriggerCheckbox = ({ colorStore, currentCheckedPurchaserId, setSelectedAmount }) => {
|
const handleTriggerCheckbox = ({ colorStore, currentCheckedPurchaserId, setSelectedAmount }) => {
|
||||||
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind']
|
const multipleSelection = colorStore?.[currentCheckedPurchaserId]?.multipleSelection
|
||||||
console.log('handleTriggerCheckbox==>', colorStore)
|
console.log('handleTriggerCheckbox==>', colorStore)
|
||||||
|
|
||||||
if (targetGoodsKind) {
|
if (multipleSelection) {
|
||||||
const result = Object.values(targetGoodsKind).reduce((prev: number, value: Goods) => {
|
const result = Object.values(multipleSelection).reduce((prev: number, value: Goods) => {
|
||||||
if (value.checked) {
|
return prev + Number(formatPriceDiv(value.estimate_amount))
|
||||||
return prev + Number(formatPriceDiv(value.estimate_amount))
|
|
||||||
}
|
|
||||||
return prev
|
|
||||||
}, 0) as number
|
}, 0) as number
|
||||||
console.log('result==>', result)
|
console.log('result==>', result)
|
||||||
// 同步修改上下文的 预估金额
|
// 同步修改上下文的 预估金额
|
||||||
@ -49,12 +46,15 @@ interface InternalContainer {}
|
|||||||
const ShoppingCartContainer: FC<InternalContainer> = () => {
|
const ShoppingCartContainer: FC<InternalContainer> = () => {
|
||||||
let isFirst = useRef(true)
|
let isFirst = useRef(true)
|
||||||
|
|
||||||
const { isManageStatus, selectedAmount, currentCheckedPurchaserId, currentCheckedSaleMode, colorStore } = useShoppingState()
|
const { isMultipleSelection, isManageStatus, selectedAmount, currentCheckedPurchaserId, currentCheckedSaleMode, colorStore } = useShoppingState()
|
||||||
|
|
||||||
const dispatch = useShoppingDispatch()
|
const dispatch = useShoppingDispatch()
|
||||||
|
|
||||||
// 管理
|
// 管理
|
||||||
const onStartToManage = () => {
|
const onStartToManage = () => {
|
||||||
|
if(isManageStatus){
|
||||||
|
handleSelectAllCheckbox(false) // 取消全选
|
||||||
|
}
|
||||||
dispatch({ type: ShoppingDispatchType.UPDATE_MANAGE_STATUS, data: !isManageStatus })
|
dispatch({ type: ShoppingDispatchType.UPDATE_MANAGE_STATUS, data: !isManageStatus })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,13 +125,10 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
|
|||||||
|
|
||||||
// 结算
|
// 结算
|
||||||
const handleSettleAccount = debounce(() => {
|
const handleSettleAccount = debounce(() => {
|
||||||
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind']
|
const multipleSelection = colorStore?.[currentCheckedPurchaserId]?.['multipleSelection']
|
||||||
if (!targetGoodsKind) return Taro.showToast({ title: '请先选择客户', icon: 'error' })
|
if (!multipleSelection) return Taro.showToast({ title: '请先选择客户', icon: 'error' })
|
||||||
const checkedGoodsKind = Object.values(targetGoodsKind).reduce((prev, item: Goods) => {
|
const checkedGoodsKind = Object.values(multipleSelection).reduce((prev, item: Goods) => {
|
||||||
if (item.checked) {
|
return [...prev, item.id]
|
||||||
return [...prev, item.id]
|
|
||||||
}
|
|
||||||
return prev
|
|
||||||
}, [])
|
}, [])
|
||||||
if (checkedGoodsKind.length === 0) return Taro.showToast({ title: '请先选择商品', icon: 'error' })
|
if (checkedGoodsKind.length === 0) return Taro.showToast({ title: '请先选择商品', icon: 'error' })
|
||||||
goLink('/pages/submitOrder/index', {
|
goLink('/pages/submitOrder/index', {
|
||||||
@ -146,13 +143,10 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
|
|||||||
|
|
||||||
// 批量某个客户的删除商品
|
// 批量某个客户的删除商品
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind']
|
const multipleSelection = colorStore?.[currentCheckedPurchaserId]?.['multipleSelection']
|
||||||
let checked: Goods[] = []
|
let checked: Goods[] = Object.values(multipleSelection)
|
||||||
if (targetGoodsKind) {
|
if (checked.length === 0) {
|
||||||
checked = Object.values(targetGoodsKind).filter((item: Goods) => item.checked)
|
return Taro.showToast({ title: '请选择商品', icon: 'error' })
|
||||||
if (checked.length === 0) {
|
|
||||||
return Taro.showToast({ title: '请选择商品', icon: 'error' })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
console.log('checked==>', checked)
|
console.log('checked==>', checked)
|
||||||
Taro.showModal({
|
Taro.showModal({
|
||||||
@ -179,26 +173,15 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
|
|||||||
if (!targetGoodsKind) return Taro.showToast({ title: '请先选择客户', icon: 'error' })
|
if (!targetGoodsKind) return Taro.showToast({ title: '请先选择客户', icon: 'error' })
|
||||||
console.log('targetGoodsKind==>', targetGoodsKind)
|
console.log('targetGoodsKind==>', targetGoodsKind)
|
||||||
|
|
||||||
const tempObject = {}
|
const tempObject = { ...targetGoodsKind }
|
||||||
Object.entries(targetGoodsKind).forEach(([key, value]) => {
|
|
||||||
tempObject[key] = {
|
|
||||||
...value,
|
|
||||||
checked: isSelectAll,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.log('tempObject==>', tempObject)
|
console.log('tempObject==>', tempObject)
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||||
data: {
|
data: {
|
||||||
purchaserId: currentCheckedPurchaserId,
|
purchaserId: currentCheckedPurchaserId,
|
||||||
goodsKind: tempObject,
|
multipleSelection: isSelectAll ? tempObject : {},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// setChangedCheckbox({
|
|
||||||
// purchaserId: currentCheckedPurchaserId,
|
|
||||||
// goodsKind: tempObject,
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载刷新数据
|
// 加载刷新数据
|
||||||
@ -250,6 +233,7 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
|
|||||||
{isManageStatus ? (
|
{isManageStatus ? (
|
||||||
<BottomEditBar
|
<BottomEditBar
|
||||||
disabled={currentCheckedPurchaserId < 0}
|
disabled={currentCheckedPurchaserId < 0}
|
||||||
|
isSelectAll={isMultipleSelection}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onSelectCheckbox={isAll => handleSelectAllCheckbox(isAll)}></BottomEditBar>
|
onSelectCheckbox={isAll => handleSelectAllCheckbox(isAll)}></BottomEditBar>
|
||||||
) : (
|
) : (
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState, SetStateAction, useMemo, useCallback } from 'react'
|
||||||
|
|
||||||
//倒计时hook
|
//倒计时hook
|
||||||
export const useTimeCountDown = () => {
|
export const useTimeCountDown = () => {
|
||||||
@ -33,7 +33,7 @@ export const useTimeCountDown = () => {
|
|||||||
setTimeStatus(() => 1)
|
setTimeStatus(() => 1)
|
||||||
if (startData >= endDate) {
|
if (startData >= endDate) {
|
||||||
clearInterval(timeObj.current)
|
clearInterval(timeObj.current)
|
||||||
setShowTime((e) => ({ ...e, DD: '00', HH: '00', MM: '00', SS: '00' }))
|
setShowTime(e => ({ ...e, DD: '00', HH: '00', MM: '00', SS: '00' }))
|
||||||
setTimeStatus(() => 2)
|
setTimeStatus(() => 2)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ export const useTimeCountDown = () => {
|
|||||||
var MM = ('00' + mm).slice(-2)
|
var MM = ('00' + mm).slice(-2)
|
||||||
var SS = ('00' + ss).slice(-2)
|
var SS = ('00' + ss).slice(-2)
|
||||||
// console.log('endTime::', `${DD}-${HH}-${MM}-${SS}`)
|
// console.log('endTime::', `${DD}-${HH}-${MM}-${SS}`)
|
||||||
setShowTime((e) => ({ ...e, DD, HH, MM, SS }))
|
setShowTime(e => ({ ...e, DD, HH, MM, SS }))
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
showTime,
|
showTime,
|
||||||
@ -93,7 +93,7 @@ type Options = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
deep: false
|
deep: false,
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 适用于 memo 第二个入参 手动触发渲染
|
* 适用于 memo 第二个入参 手动触发渲染
|
||||||
@ -113,7 +113,7 @@ export const useNeedMemoCallback = (options: Options = defaultOptions) => {
|
|||||||
|
|
||||||
// 循环props对象
|
// 循环props对象
|
||||||
const handleDiff = () => {
|
const handleDiff = () => {
|
||||||
for (let [key, value] of Object.entries(prevProps)){
|
for (let [key, value] of Object.entries(prevProps)) {
|
||||||
if (!Object.is(value, nextProps[key])) {
|
if (!Object.is(value, nextProps[key])) {
|
||||||
// console.log('函数不相等',value === nextProps[key])
|
// console.log('函数不相等',value === nextProps[key])
|
||||||
// console.log('asdfasdf',value)
|
// console.log('asdfasdf',value)
|
||||||
@ -121,48 +121,56 @@ export const useNeedMemoCallback = (options: Options = defaultOptions) => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Object.entries(prevProps).forEach(([key, value]) => {
|
// Object.entries(prevProps).forEach(([key, value]) => {
|
||||||
// if (!nextProps.hasOwnProperty(key)) {
|
// if (!nextProps.hasOwnProperty(key)) {
|
||||||
// needMemoized = false
|
// needMemoized = false
|
||||||
// // 新增的属性
|
// // 新增的属性
|
||||||
// if (Object.prototype.toString.call(value) === '[object Object]') {
|
// if (Object.prototype.toString.call(value) === '[object Object]') {
|
||||||
// parent[key] = {}
|
// parent[key] = {}
|
||||||
// } else if (Object.prototype.toString.call(value) === '[object Array]') {
|
// } else if (Object.prototype.toString.call(value) === '[object Array]') {
|
||||||
// parent[key] = []
|
// parent[key] = []
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// if (typeof data[key] === 'object') {
|
// if (typeof data[key] === 'object') {
|
||||||
// o[key] = internalSetData(parent[key], data[key])
|
// o[key] = internalSetData(parent[key], data[key])
|
||||||
// } else {
|
// } else {
|
||||||
// // 核心处理逻辑
|
// // 核心处理逻辑
|
||||||
// // key == data第一层 如果要做到data第二层呢?所以需要递归
|
// // key == data第一层 如果要做到data第二层呢?所以需要递归
|
||||||
// if (parent[key] != data[key]) {
|
// if (parent[key] != data[key]) {
|
||||||
// o[key] = data[key]
|
// o[key] = data[key]
|
||||||
// changed = true
|
// changed = true
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
handleDiff()
|
handleDiff()
|
||||||
return needMemoized
|
return needMemoized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const needMemo = useNeedMemoCallback()
|
type UsePropsValueOptions<T> = {
|
||||||
const hobby = {
|
value?: T
|
||||||
play1: 1,
|
defaultValue: T
|
||||||
play2: 2
|
onChange?: (v: T) => void
|
||||||
}
|
}
|
||||||
const bool = needMemo(
|
|
||||||
{
|
export function usePropsValue<T>(options: UsePropsValueOptions<T>) {
|
||||||
name: '小明',
|
const { value, defaultValue, onChange } = options
|
||||||
age: 18,
|
|
||||||
hobby: hobby,
|
const [, setForceUpdate] = useState({})
|
||||||
},
|
|
||||||
{
|
const stateRef = useRef<T>(value !== undefined ? value : defaultValue)
|
||||||
name: '小明',
|
if (value !== undefined) {
|
||||||
age: 18,
|
stateRef.current = value
|
||||||
hobby: hobby,
|
}
|
||||||
},
|
|
||||||
)
|
const setState = useCallback((v: SetStateAction<T>, forceTrigger: boolean = false) => {
|
||||||
// console.log('bool==>', bool)
|
// `forceTrigger` means trigger `onChange` even if `v` is the same as `stateRef.current`
|
||||||
|
const nextValue = typeof v === 'function' ? (v as (prevState: T) => T)(stateRef.current) : v
|
||||||
|
if (!forceTrigger && nextValue === stateRef.current) return
|
||||||
|
stateRef.current = nextValue
|
||||||
|
setForceUpdate({})
|
||||||
|
return onChange?.(nextValue)
|
||||||
|
}, [])
|
||||||
|
return [stateRef.current, setState] as const
|
||||||
|
}
|
||||||
|
13993
yarn-error.log
Normal file
13993
yarn-error.log
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user