🦄 refactor(购物页面): 优化购物页面切换订单类型的渲染

This commit is contained in:
xuan 2022-10-18 19:02:13 +08:00
parent 4b75ef1493
commit 9a759f67f1
10 changed files with 323 additions and 204 deletions

View File

@ -169,6 +169,13 @@
"query": "orderId=28503", "query": "orderId=28503",
"launchMode": "default", "launchMode": "default",
"scene": null "scene": null
},
{
"name": "",
"pathName": "pages/saleStatistic/index",
"query": "",
"launchMode": "default",
"scene": null
} }
] ]
} }

View File

@ -8,8 +8,9 @@ type PropsType = {
onSettleAccount?: Function onSettleAccount?: Function
} }
export default memo<PropsType>(props => { export default props => {
const { onSettleAccount, amount = 0 } = props const { onSettleAccount, amount = 0 } = props
console.log('amount==>', amount)
const handleSettle = () => { const handleSettle = () => {
onSettleAccount && onSettleAccount() onSettleAccount && onSettleAccount()
@ -31,4 +32,4 @@ export default memo<PropsType>(props => {
</View> </View>
</View> </View>
) )
}) }

View File

@ -9,7 +9,7 @@ import { formatImgUrl, formatPriceDiv } from '@/common/format'
import { EnumSaleMode } from '@/common/Enumerate' import { EnumSaleMode } from '@/common/Enumerate'
import { useNeedMemoCallback } from '@/use/useCommon' import { useNeedMemoCallback } from '@/use/useCommon'
import { selectList } from '../../config' import { selectList } from '../../config'
import { useShoppingContext, useWatch } from '../../context' import { ShoppingDispatchType, useShoppingDispatch, useShoppingState } from '../../context'
type PropsType = { type PropsType = {
purchaserId: number purchaserId: number
itemData: Record<string, any> & object itemData: Record<string, any> & object
@ -19,39 +19,55 @@ type PropsType = {
// 注意:如果在表单控件内部使用 useWatch由于是直接从Context中取值memo也会直接失去作用。 // 注意:如果在表单控件内部使用 useWatch由于是直接从Context中取值memo也会直接失去作用。
const ColorKindItem: FC<PropsType> = memo( const ColorKindItem: FC<PropsType> = memo(
(props) => { props => {
console.log('Rerender component: ColorKindItem')
const { purchaserId, itemData, orderType = EnumSaleMode.Bulk } = props const { purchaserId, itemData, orderType = EnumSaleMode.Bulk } = props
const { setChangedCheckbox, colorStore } = useShoppingContext() const { colorStore } = useShoppingState()
const dispatch = useShoppingDispatch()
// @ts-ignore // @ts-ignore
const { checked } = useWatch(purchaserId, itemData?.id) const { checked } = colorStore[purchaserId]['goodsKind']![itemData.id] || { checked: false }
//格式化金额 //格式化金额
const formatPrice = useCallback((price) => { const formatPrice = (price: number) => {
return Number(formatPriceDiv(price)) return Number(formatPriceDiv(price))
}, []) }
//格式化数量 //格式化数量
const formatCount = useCallback((itemData) => { const formatCount = itemData => {
return itemData.sale_mode == EnumSaleMode.Bulk ? itemData.roll : itemData.length / 100 return itemData.sale_mode == EnumSaleMode.Bulk ? itemData.roll : itemData.length / 100
}, []) }
//格式化单位 //格式化单位
const formatUnit = useCallback((itemData) => { const formatUnit = itemData => {
return itemData.sale_mode == EnumSaleMode.Bulk ? '条' : '米' return itemData.sale_mode == EnumSaleMode.Bulk ? '条' : '米'
}, []) }
const handleSelect = () => { const handleSelect = () => {
// console.log('handleSelect') // console.log('handleSelect')
setChangedCheckbox({ dispatch({
purchaserId: purchaserId, type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
goodsKind: { [itemData.id]: { ...colorStore[purchaserId].goodsKind?.[itemData.id]!, checked: true } }, 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 = () => { const handleClose = () => {
setChangedCheckbox({ dispatch({
purchaserId: purchaserId, type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
goodsKind: { [itemData.id]: { ...colorStore[purchaserId].goodsKind?.[itemData.id]!, checked: false } }, 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) => { const getInputValue = debounce(async (num, itemData) => {
@ -85,11 +101,11 @@ const ColorKindItem: FC<PropsType> = memo(
<View className={styles['colorKindItem__right--price']}> {formatPrice(itemData.sale_price)}/kg</View> <View className={styles['colorKindItem__right--price']}> {formatPrice(itemData.sale_price)}/kg</View>
<View className={styles['colorKindItem__right--counter']}> <View className={styles['colorKindItem__right--counter']}>
<Counter <Counter
onBlue={(e) => getInputValue(e, itemData)} onBlue={e => getInputValue(e, itemData)}
defaultNum={formatCount(itemData)} defaultNum={formatCount(itemData)}
step={selectList[orderType].step} step={selectList[orderType].step}
digits={selectList[orderType].digits} digits={selectList[orderType].digits}
onClickBtn={(e) => getInputValue(e, itemData)} onClickBtn={e => getInputValue(e, itemData)}
unit={formatUnit(itemData)} unit={formatUnit(itemData)}
minNum={selectList[orderType].minNum} minNum={selectList[orderType].minNum}
maxNum={selectList[orderType].maxNum} maxNum={selectList[orderType].maxNum}
@ -97,6 +113,7 @@ const ColorKindItem: FC<PropsType> = memo(
</View> </View>
</View> </View>
</MCheckbox> </MCheckbox>
// <View>1111</View>
) )
}, },
(preProp, nextProp) => { (preProp, nextProp) => {

View File

@ -1,92 +1,55 @@
import { FC, ReactNode, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react' import { Dispatch, FC, ReactNode, useEffect, useMemo, useReducer, useRef, useState } from 'react'
import { InternalShoppingCartAction, ShoppingCartAction, ShoppingContext, useShoppingCart } from '../../context' import { ShoppingAction, ShoppingCartAction, ShoppingDispatchContext, ShoppingDispatchContextValue, ShoppingDispatchType, shoppingReducer, ShoppingStateContext } from '../../context'
import { GoodsMeta, ColorStore, ShoppingContextValue } from '../../context' import { GoodsMeta, ColorStore, ShoppingStateContextValue } from '../../context'
export type TriggerCheckboxOptions = { export type TriggerCheckboxOptions = {
colorStore: ColorStore colorStore: ColorStore
changedCheckbox: GoodsMeta currentCheckedPurchaserId: ShoppingStateContextValue['currentCheckedPurchaserId']
currentCheckedPurchaserId: ShoppingContextValue['currentCheckedPurchaserId'] setSelectedAmount: ShoppingDispatchContextValue['UPDATE_SELECTED_AMOUNT']
setSelectedAmount: ShoppingContextValue['setSelectedAmount'] }
type InitialState = {
colorStore: ColorStore
currentCheckedPurchaserId: number
currentCheckedSaleMode: number
isManageStatus: boolean
selectedAmount: number
} }
export interface ShoppingCartPropsType { export interface ShoppingCartPropsType {
initialValues?: ColorStore initialValues?: ColorStore
onTriggerCheckbox?: (options: TriggerCheckboxOptions) => void onTriggerCheckbox?: (options: TriggerCheckboxOptions) => void
children?: ReactNode children?: ReactNode
ref?: ShoppingCartAction
} }
// 购物车上下文组件 // 购物车上下文组件
export const ShoppingCart: FC<ShoppingCartPropsType> = (props) => { export const ShoppingProvider: FC<ShoppingCartPropsType> = props => {
const { children, onTriggerCheckbox, initialValues, ref: refProps } = props const { children, onTriggerCheckbox, initialValues } = props
const defaultShoppingCart = useShoppingCart()
const ref = (refProps || defaultShoppingCart) as InternalShoppingCartAction
const onTriggerCheckboxRef = useRef(onTriggerCheckbox) const onTriggerCheckboxRef = useRef(onTriggerCheckbox)
onTriggerCheckboxRef.current = onTriggerCheckbox onTriggerCheckboxRef.current = onTriggerCheckbox
const [colorStore, setColorStore] = useState<ColorStore>(() => initialValues || {}) const [state, dispatch] = useReducer<(state: ShoppingStateContextValue, action: ShoppingAction) => InitialState>(shoppingReducer, {
// 客户的选中状态 colorStore: initialValues || {},
const [changedCheckbox, setChangedCheckbox] = useState<GoodsMeta>({} as GoodsMeta) currentCheckedPurchaserId: -1,
// 当前高亮的客户 currentCheckedSaleMode: 0,
const [currentCheckedPurchaserId, setCurrentCheckedPurchaserId] = useState<number>(-1) isManageStatus: false,
const [currentCheckedSaleMode, setCurrentCheckedSaleMode] = useState<number>(0) selectedAmount: 0,
// 是否管理状态 })
const [isManageStatus, setManageStatus] = useState(false)
const [selectedAmount, setSelectedAmount] = useState(0)
const ctx: ShoppingContextValue = useMemo(() => {
// console.log('useMemo ShoppingContextValue')
return {
isManageStatus,
setManageStatus,
currentCheckedPurchaserId, // 当前高亮的客户
setCurrentCheckedPurchaserId, // 设置高亮当前客户
currentCheckedSaleMode,
setCurrentCheckedSaleMode,
colorStore,
setChangedCheckbox(changedGoods) {
// console.log('changedGoods==>', colorStore, changedGoods)
setColorStore((prev) => {
const currentGoodsKind = { ...prev[changedGoods.purchaserId]?.goodsKind, ...changedGoods.goodsKind }
return {
...prev,
[changedGoods.purchaserId as number]: {
purchaserId: changedGoods.purchaserId,
goodsKind: currentGoodsKind,
},
}
})
setChangedCheckbox(changedGoods)
},
setColorStore,
selectedAmount,
setSelectedAmount,
}
}, [colorStore, currentCheckedPurchaserId, isManageStatus, selectedAmount])
// 暴露给外界
useImperativeHandle(
ref.__INTERNAL__,
() => ({
getManageStatus() {
return ctx.isManageStatus
},
setManageStatus: ctx.setManageStatus,
}),
[ctx.isManageStatus, ctx.setManageStatus],
)
// 这里要在 useEffect 也就是刷新 state 后再调用,否则如果在 onFieldsChangeRef 修改值会覆盖掉上次修改 // 这里要在 useEffect 也就是刷新 state 后再调用,否则如果在 onFieldsChangeRef 修改值会覆盖掉上次修改
useEffect(() => { useEffect(() => {
onTriggerCheckboxRef.current?.({ onTriggerCheckboxRef.current?.({
colorStore, colorStore: state.colorStore,
changedCheckbox, currentCheckedPurchaserId: state.currentCheckedPurchaserId,
currentCheckedPurchaserId, setSelectedAmount: (amount) => dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT,data: amount }),
setSelectedAmount,
}) })
}, [colorStore, changedCheckbox, currentCheckedPurchaserId]) }, [state.colorStore, state.currentCheckedPurchaserId])
return <ShoppingContext.Provider value={ctx}>{children}</ShoppingContext.Provider> return (
<ShoppingStateContext.Provider value={state}>
<ShoppingDispatchContext.Provider value={dispatch}>{children}</ShoppingDispatchContext.Provider>
</ShoppingStateContext.Provider>
)
} }

View File

@ -1,10 +1,11 @@
.layout { .layout {
margin: 24px; margin: 24px;
// padding-left: 0; padding-left: 0;
// padding-right: 0; padding-right: 0;
border: 1px solid transparent; border: 1px solid transparent;
.checkbox { .checkbox {
padding: 0 24px; padding: 0 24px;
box-sizing: border-box;
&--text { &--text {
width: 100%; width: 100%;
margin-left: 20px; margin-left: 20px;

View File

@ -1,20 +1,19 @@
import { Text, View } from '@tarojs/components' import { Text, View } from '@tarojs/components'
import { FC, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' import { FC, 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, formatPriceDiv } from '@/common/format' import { formatMeterDiv } from '@/common/format'
import Taro, { useDidShow } from '@tarojs/taro'
import LayoutBlock from '@/components/layoutBlock' import LayoutBlock from '@/components/layoutBlock'
import MCheckbox from '@/components/checkbox'
import Tag from '@/components/tag' import Tag from '@/components/tag'
import Divider from '@/components/divider' import Divider from '@/components/divider'
import ColorKindItem from '../colorKindItem' import ColorKindItem from '../colorKindItem'
import { EnumSaleMode } from '@/common/Enumerate' import { EnumSaleMode } from '@/common/Enumerate'
import { useNeedMemoCallback } from '@/use/useCommon'
import { selectList } from '../../config' import { selectList } from '../../config'
import { Goods, useShoppingContext } from '../../context' import { Goods, ShoppingDispatchType, 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 LoadingCard from '@/components/loadingCard'
type PropsType = { type PropsType = {
itemData?: ShoppingCartData itemData?: ShoppingCartData
@ -37,7 +36,7 @@ enum BackEndSaleModeListFieldMap {
export default memo<PropsType>(props => { export default memo<PropsType>(props => {
const { itemData } = props const { itemData } = props
const { setCurrentCheckedSaleMode } = useShoppingContext() const dispatch = useShoppingDispatch()
const [openDetail, setOpenDetail] = useState(false) const [openDetail, setOpenDetail] = useState(false)
@ -49,57 +48,55 @@ export default memo<PropsType>(props => {
const [selected, setSelect] = useState<EnumSaleMode>(0) const [selected, setSelect] = useState<EnumSaleMode>(0)
const onSelectOrderType = (type: EnumSaleMode) => { const onSelectOrderType = (type: EnumSaleMode) => {
if (isPending) return
setSelect(type) setSelect(type)
setCurrentCheckedSaleMode(type) dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: type })
// 重置预估金额 // 重置预估金额
setSelectedAmount(0) dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
} }
const saleModeList = useRef({ const { currentCheckedPurchaserId, colorStore } = useShoppingState()
bulk_color_list: itemData?.bulk_color_list,
length_cut_color_list: itemData?.length_cut_color_list,
weight_cut_color_list: itemData?.weight_cut_color_list,
})
saleModeList.current = {
bulk_color_list: itemData?.bulk_color_list,
length_cut_color_list: itemData?.length_cut_color_list,
weight_cut_color_list: itemData?.weight_cut_color_list,
}
const { setChangedCheckbox, currentCheckedPurchaserId, setCurrentCheckedPurchaserId, setSelectedAmount, colorStore } = useShoppingContext() console.log('Rerender component: shoppingCartItem')
const memoList = useMemo(() => { // const memoList = useMemo(() => {
// 向 context 中初始化数据 // console.log('ext useMemo')
return itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0 ? ( // const component = itemData?.[BackEndSaleModeListFieldMap[selected]].map(item => {
itemData?.[BackEndSaleModeListFieldMap[selected]].map(item => { // dispatch({
setChangedCheckbox({ // type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
purchaserId: itemData?.purchaser_id!, // data: {
goodsKind: { // purchaserId: itemData?.purchaser_id!,
[item?.id]: { // goodsKind: {
id: item?.id, // [item?.id]: {
estimate_amount: item.estimate_amount, // id: item?.id,
checked: false, // estimate_amount: item.estimate_amount,
product_code: item.product_code, // checked: false,
product_color_code: item.product_color_code, // product_code: item.product_code,
sale_mode: item.sale_mode, // product_color_code: item.product_color_code,
count: selected === EnumSaleMode.Bulk ? item.roll : Number(formatMeterDiv(item.length)), // 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> // },
}) // })
) : ( // return <ColorKindItem purchaserId={itemData.purchaser_id} key={item.id} itemData={item} orderType={selected}></ColorKindItem>
<View className={styles.noList}></View> // })
) // // 向 context 中初始化数据
}, [itemData, selected]) // 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
} }
setSelectedAmount(0) dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
setCurrentCheckedSaleMode(selected) // setSelectedAmount(0)
setCurrentCheckedPurchaserId(itemData?.purchaser_id as number) // setCurrentCheckedSaleMode(selected)
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: selected })
dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID, data: itemData?.purchaser_id as number })
// setCurrentCheckedPurchaserId(itemData?.purchaser_id as number)
} }
// 统计已选面料 // 统计已选面料
@ -144,12 +141,14 @@ export default memo<PropsType>(props => {
) )
}, [colorStore, currentCheckedPurchaserId, selected, itemData]) }, [colorStore, currentCheckedPurchaserId, selected, itemData])
const [isPending, startTransition] = useTransition()
return ( return (
<LayoutBlock <LayoutBlock
circle circle
customClassName={classnames(styles.layout, itemData?.purchaser_id === currentCheckedPurchaserId ? styles.selected : '')} customClassName={classnames(styles.layout, itemData?.purchaser_id === currentCheckedPurchaserId ? styles.selected : '')}
onClick={handleClickLayout}> onClick={handleClickLayout}>
<View className='flex-row justify-between' onClick={handleOpenDetail}> <View className={classNames(styles.checkbox, 'flex-row', 'justify-between')} onClick={handleOpenDetail}>
<View className={styles.topItem}> <View className={styles.topItem}>
<View className='flex-row items-center'> <View className='flex-row items-center'>
<View className={styles.topTitle}>{itemData?.purchaser_name}</View> <View className={styles.topTitle}>{itemData?.purchaser_name}</View>
@ -169,8 +168,10 @@ export default memo<PropsType>(props => {
{/* 减少节点渲染 */} {/* 减少节点渲染 */}
{openDetail && ( {openDetail && (
<> <>
<Divider customClassName={styles.line}></Divider>
<View className={classnames(styles.detailBox, openDetail ? styles.drawerOpen : styles.drawerClose)}> <View className={classnames(styles.detailBox, openDetail ? styles.drawerOpen : styles.drawerClose)}>
<View className={styles.checkbox}>
<Divider customClassName={styles.line}></Divider>
</View>
<View className={styles.orderType}> <View className={styles.orderType}>
<View className={styles.orderTitle}></View> <View className={styles.orderTitle}></View>
<View className={styles.orderTypeDetail}> <View className={styles.orderTypeDetail}>
@ -203,13 +204,73 @@ export default memo<PropsType>(props => {
</Tag> </Tag>
</View> </View>
</View> </View>
<View className={styles.orderContainer}>{memoList}</View> <View className={styles.orderContainer}>
{/* <GoodsList itemData={itemData} selected={selected} /> */}
<GoodsList itemData={itemData} selected={selected} isPending={isPending} startTransition={startTransition} />
</View>
</View> </View>
</> </>
)} )}
</LayoutBlock> </LayoutBlock>
) )
}, useNeedMemoCallback()) })
interface GoodsListPropType {
itemData?: ShoppingCartData
selected: EnumSaleMode
isPending: boolean
startTransition: React.TransitionStartFunction
}
const GoodsList = memo<GoodsListPropType>(props => {
console.log('Rerender component: GoodsList')
const { itemData, selected, isPending, startTransition } = props
const dispatch = useShoppingDispatch()
const [component, setComponent] = useState<JSX.Element | null>(null)
useEffect(() => {
startTransition(() => {
setComponent(
itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0 ? (
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>
})
) : (
<View className={styles.noList}></View>
),
)
})
}, [itemData, selected])
return (
<>
{isPending ? (
<View className='flex-row items-center justify-center' style={{ width: '100%', height: '200px' }}>
<LoadingCard />
</View>
) : (
component
)}
</>
)
})
interface ButtonPropsType { interface ButtonPropsType {
isActive: boolean isActive: boolean

View File

@ -1,4 +1,4 @@
import React, { useRef } from 'react' import React, { Dispatch, useRef } from 'react'
import { useContext } from 'react' import { useContext } from 'react'
/** /**
@ -27,50 +27,110 @@ export type ColorStore = {
export type Goods = { export type Goods = {
id: number id: number
product_code: number // 面料编号 product_code: number // 面料编号
product_color_code: number // 颜色编号 product_color_code: number // 颜色编号
estimate_amount: number // 预估金额 estimate_amount: number // 预估金额
count: number // 已选的条数或米数 count: number // 已选的条数或米数
sale_mode: number sale_mode: number
checked: boolean checked: boolean
} }
// 分组 // 分组
export interface GoodsMeta { export interface GoodsMeta {
purchaserId: number purchaserId: number
// materialChecked: number // 已选 x 种面料
// colorChecked: number // 已选 x 颜色
// lengthOrRollChecked: number // 共 x 条 共 x 米
goodsKind?: { goodsKind?: {
[id: number]: Goods [id: number]: Goods
} }
} }
export interface ShoppingContextValue { export interface ShoppingStateContextValue {
isManageStatus: boolean isManageStatus: boolean
setManageStatus: (isManageStatus: boolean) => void
currentCheckedPurchaserId: number // 当前高亮的客户ID currentCheckedPurchaserId: number // 当前高亮的客户ID
setCurrentCheckedPurchaserId: (purchaserId: number) => void
currentCheckedSaleMode: number currentCheckedSaleMode: number
setCurrentCheckedSaleMode: (saleMode: number) => void
colorStore: ColorStore colorStore: ColorStore
setColorStore: (colorStore: React.SetStateAction<ColorStore>) => void
setChangedCheckbox: (changedGoods: GoodsMeta) => void
selectedAmount: number selectedAmount: number
setSelectedAmount: (amount: React.SetStateAction<number>) => void
} }
export const ShoppingContext = React.createContext<ShoppingContextValue | null>(null) export enum ShoppingDispatchType {
UPDATE_MANAGE_STATUS = 'UPDATE_MANAGE_STATUS',
UPDATE_CURRENT_CHECKED_PURCHASERID = 'UPDATE_CURRENT_CHECKED_PURCHASERID',
UPDATE_CURRENT_CHECKED_SALEMODE = 'UPDATE_CURRENT_CHECKED_SALEMODE',
UPDATE_COLOR_STORE = 'UPDATE_COLOR_STORE',
UPDATE_SELECTED_AMOUNT = 'UPDATE_SELECTED_AMOUNT',
UPDATE_CHANGED_CHECKBOX = 'UPDATE_CHANGED_CHECKBOX',
}
export function useShoppingContext() { export interface ShoppingDispatchContextValue {
const ctx = useContext(ShoppingContext) [ShoppingDispatchType.UPDATE_MANAGE_STATUS]: (isManageStatus: boolean) => void
[ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID]: (purchaserId: number) => void
[ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE]: (saleMode: number) => void
[ShoppingDispatchType.UPDATE_COLOR_STORE]: (colorStore: React.SetStateAction<ColorStore>) => void
[ShoppingDispatchType.UPDATE_SELECTED_AMOUNT]: (amount: React.SetStateAction<number>) => void
[ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX]: (amount: React.SetStateAction<number>) => void
}
export type ShoppingAction = {
type: ShoppingDispatchType
data?: any
}
export function shoppingReducer(state: ShoppingStateContextValue, action: ShoppingAction) {
const { type, data } = action
switch (type) {
case ShoppingDispatchType.UPDATE_MANAGE_STATUS: {
return { ...state, isManageStatus: data }
}
case ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID: {
return { ...state, currentCheckedPurchaserId: data }
}
case ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE: {
return { ...state, currentCheckedSaleMode: data }
}
case ShoppingDispatchType.UPDATE_COLOR_STORE: {
return { ...state, colorStore: data }
}
case ShoppingDispatchType.UPDATE_SELECTED_AMOUNT: {
return { ...state, selectedAmount: data }
}
case ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX: {
return {
...state,
colorStore: {
...state.colorStore,
[data.purchaserId as number]: {
purchaserId: data.purchaserId,
goodsKind: { ...state.colorStore[data.purchaserId]?.goodsKind, ...data.goodsKind },
},
},
}
}
default:
throwError()
}
}
export const ShoppingStateContext = React.createContext<ShoppingStateContextValue | null>(null)
export const ShoppingDispatchContext = React.createContext<Dispatch<ShoppingAction> | null>(null)
export function useShoppingState() {
const ctx = useContext(ShoppingStateContext)
if (!ctx) { if (!ctx) {
throw new Error('没有获取到shopping context') throw new Error('没有获取到shopping context')
} }
return ctx return ctx
} }
export function useShoppingDispatch() {
const ctx = useContext(ShoppingDispatchContext)
if (!ctx) {
throw new Error('没有获取到shopping dispatch')
}
return ctx
}
export function useWatch(purchaserId: GoodsMeta['purchaserId'], id: number) { export function useWatch(purchaserId: GoodsMeta['purchaserId'], id: number) {
const { colorStore } = useShoppingContext() const { colorStore } = useShoppingState()
return id ? colorStore[purchaserId]['goodsKind']![id] : colorStore[purchaserId]['goodsKind'] return id ? colorStore[purchaserId]['goodsKind']![id] : colorStore[purchaserId]['goodsKind']
} }
@ -84,26 +144,5 @@ export interface InternalShoppingCartAction extends ShoppingCartAction {
} }
function throwError(): never { function throwError(): never {
throw new Error('有没有用 ref 这个props') throw new Error('没有这个action.type')
}
export function useShoppingCart(): ShoppingCartAction {
const __INTERNAL__ = useRef<ShoppingCartAction | null>(null)
return {
__INTERNAL__,
setManageStatus(manageStatus: boolean) {
const action = __INTERNAL__.current
if (!action) {
throwError()
}
action.setManageStatus(manageStatus)
},
getManageStatus() {
const action = __INTERNAL__.current
if (!action) {
throwError()
}
return action.getManageStatus()
},
} as InternalShoppingCartAction
} }

View File

@ -1,6 +1,6 @@
import Search from '@/components/search' import Search from '@/components/search'
import { View } from '@tarojs/components' import { View } from '@tarojs/components'
import Taro, { useDidHide, useDidShow } from '@tarojs/taro' import Taro, { useDidShow } from '@tarojs/taro'
import { FC, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { FC, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
import styles from './index.module.scss' import styles from './index.module.scss'
import classnames from 'classnames' import classnames from 'classnames'
@ -12,15 +12,15 @@ import BottomSettleBar from './components/bottomSettleBar'
import BottomEditBar from './components/bottomEditBar' import BottomEditBar from './components/bottomEditBar'
import { ShoppingCartDeleteApi, ShoppingCartListApi } from '@/api/index' import { ShoppingCartDeleteApi, ShoppingCartListApi } from '@/api/index'
import { dataLoadingStatus, debounce, getFilterData } from '@/common/util' import { dataLoadingStatus, debounce, getFilterData } from '@/common/util'
import { ShoppingCart } from './components/shoppingCart/index' import { ShoppingProvider } from './components/shoppingCart/index'
import { Goods, useShoppingContext } from './context' import { Goods, ShoppingDispatchType, useShoppingDispatch, useShoppingState } from './context'
import { alert, goLink, isEmptyObject } from '@/common/common' import { alert, goLink, isEmptyObject } from '@/common/common'
export const Shopping: FC = memo(() => { export const Shopping: FC = memo(() => {
// 计算总的预估金额 // 计算总的预估金额
const handleTriggerCheckbox = useCallback(({ colorStore, changedCheckbox, currentCheckedPurchaserId, setSelectedAmount }) => { const handleTriggerCheckbox = ({ colorStore, currentCheckedPurchaserId, setSelectedAmount }) => {
console.log('handleTriggerCheckbox==>', colorStore, changedCheckbox)
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind'] const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind']
console.log('handleTriggerCheckbox==>', colorStore)
if (targetGoodsKind) { if (targetGoodsKind) {
const result = Object.values(targetGoodsKind).reduce((prev: number, value: Goods) => { const result = Object.values(targetGoodsKind).reduce((prev: number, value: Goods) => {
@ -35,11 +35,11 @@ export const Shopping: FC = memo(() => {
} else { } else {
setSelectedAmount(0) setSelectedAmount(0)
} }
}, []) }
return ( return (
<ShoppingCart onTriggerCheckbox={handleTriggerCheckbox}> <ShoppingProvider onTriggerCheckbox={handleTriggerCheckbox}>
<ShoppingCartContainer /> <ShoppingCartContainer />
</ShoppingCart> </ShoppingProvider>
) )
}) })
@ -48,19 +48,13 @@ interface InternalContainer {}
const ShoppingCartContainer: FC<InternalContainer> = () => { const ShoppingCartContainer: FC<InternalContainer> = () => {
let isFirst = useRef(true) let isFirst = useRef(true)
const { const { isManageStatus, selectedAmount, currentCheckedPurchaserId, currentCheckedSaleMode, colorStore } = useShoppingState()
setChangedCheckbox,
isManageStatus, const dispatch = useShoppingDispatch()
setManageStatus,
selectedAmount,
currentCheckedPurchaserId,
currentCheckedSaleMode,
colorStore,
} = useShoppingContext()
// 管理 // 管理
const onStartToManage = () => { const onStartToManage = () => {
setManageStatus(!isManageStatus) dispatch({ type: ShoppingDispatchType.UPDATE_MANAGE_STATUS, data: !isManageStatus })
} }
const listHeightRef = useRef('auto') const listHeightRef = useRef('auto')
@ -75,7 +69,7 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
fetchData(searchOptions) fetchData(searchOptions)
} }
}) })
console.log('rerender') console.log('Rerender component: ShoppingCartContainer')
useEffect(() => { useEffect(() => {
console.log('useEffect fetchData') console.log('useEffect fetchData')
@ -186,10 +180,18 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
} }
}) })
console.log('tempObject==>', tempObject) console.log('tempObject==>', tempObject)
setChangedCheckbox({ dispatch({
purchaserId: currentCheckedPurchaserId, type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
goodsKind: tempObject, data: {
purchaserId: currentCheckedPurchaserId,
goodsKind: tempObject,
},
}) })
// setChangedCheckbox({
// purchaserId: currentCheckedPurchaserId,
// goodsKind: tempObject,
// })
} }
// 加载刷新数据 // 加载刷新数据
@ -246,5 +248,30 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
</View> </View>
) )
} }
// interface ScrollListPropType {
// height: string
// }
// const ScrollList = memo<ScrollListPropType>((props) => {
// const { height } = props
// const [shoppingCartData, setShoppingCartData] = useState<{ list: ShoppingCartData[]; total: number }>({ list: [], total: 0 })
// //数据加载状态
// const statusMore = useMemo(() => {
// return dataLoadingStatus({ list: shoppingCartData.list, total: shoppingCartData.total, status: state.loading })
// }, [shoppingCartData, state])
// return (
// <View className={classnames('flex-item', 'flex-col', styles['shopping--context'])}>
// <View className={classnames(styles.shopping__list__container, 'flex-item')} style={{ height: height }}>
// <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>
// )
// })
export default Shopping export default Shopping

View File

@ -180,7 +180,7 @@ const UserInfo: FC = () => {
</View> </View>
</View> </View>
<View className={styles.bottomBar}> <View className={styles.bottomBar}>
<Tag type='primary' size='normal' circle plain customStyle={{ marginRight: '10px' }}> <Tag type='primary' size='normal' circle customStyle={{ marginRight: '10px' }}>
{userInfo.userInfo.department_name} {userInfo.userInfo.department_name}
</Tag> </Tag>
<Divider direction='vertical'></Divider> <Divider direction='vertical'></Divider>

View File

@ -52,6 +52,9 @@ $customTabBarHeight: 100px;
.justify-between { .justify-between {
justify-content: space-between justify-content: space-between
} }
.justify-center {
justify-content: center
}
.items-center{ .items-center{
align-items: center; align-items: center;
} }