Merge branch 'dev' of ssh://git.online.zzfzyc.com:10022/mp/spider_cloud_warehouse into 订单页

This commit is contained in:
Haiyi 2022-09-27 10:14:18 +08:00
commit 6c0ecd5ea1
10 changed files with 279 additions and 142 deletions

View File

@ -158,8 +158,8 @@
},
{
"name": "",
"pathName": "pages/collectionDetail/index",
"query": "",
"pathName": "pages/submitOrder/index",
"query": "purchaser_id=642&sale_mode=1&shopping_cart_product_color_list%5B2%5D=58994&shopping_cart_product_color_list%5B3%5D=58995",
"launchMode": "default",
"scene": null
}

View File

@ -19,11 +19,11 @@ export default memo<PropsType>((props) => {
const selectCallBack = () => {
setSelectAll(true)
onSelectCheckbox && onSelectCheckbox(isSelectAll)
onSelectCheckbox && onSelectCheckbox(true)
}
const closeCallBack = () => {
setSelectAll(false)
onSelectCheckbox && onSelectCheckbox(isSelectAll)
onSelectCheckbox && onSelectCheckbox(false)
}

View File

@ -22,7 +22,7 @@ export default memo<PropsType>((props) => {
<Text className={styles.moneyText}></Text>
<Text className={styles.moneyNumber}>
<Text className={styles.unit}>¥</Text>
{formatPriceDiv(amount)}
{amount}
</Text>
</View>
<View className={styles.bottomRight}>

View File

@ -5,12 +5,13 @@ import { FC, memo, ReactNode, useCallback, useEffect, useState } from 'react'
import classnames from 'classnames'
import styles from './index.module.scss'
import { debounce } from '@/common/util'
import { formatPriceDiv } from '@/common/format'
import { formatImgUrl, formatPriceDiv } from '@/common/format'
import { EnumSaleMode } from '@/common/Enumerate'
import { useNeedMemoCallback } from '@/use/useCommon'
import {selectList} from '../../config'
import { selectList } from '../../config'
import { useShoppingContext, useWatch } from '../../context'
type PropsType = {
purchaserId: number
item: Record<string, any> & object
orderType: EnumSaleMode
}
@ -19,15 +20,14 @@ type PropsType = {
const ColorKindItem: FC<PropsType> = memo(
(props) => {
const { item, orderType = EnumSaleMode.Bulk} = props
const { setChangedCheckbox } = useShoppingContext()
console.log('重新渲染 ColorKindItem', item.id, orderType)
const { checked } = useWatch(item?.id)
const { purchaserId, item, orderType = EnumSaleMode.Bulk } = props
console.log('重新渲染 ColorKindItem', item.id, orderType, purchaserId)
const { setChangedCheckbox, colorStore } = useShoppingContext()
// @ts-ignore
const { checked } = useWatch(purchaserId, item?.id)
//格式化金额
const formatPirce = useCallback((price) => {
const formatPrice = useCallback((price) => {
return Number(formatPriceDiv(price))
}, [])
@ -43,21 +43,26 @@ const ColorKindItem: FC<PropsType> = memo(
const handleSelect = () => {
console.log('handleSelect')
setChangedCheckbox({id: item?.id, checked: true})
// onChecked && onChecked({ ...item, checked: true })
setChangedCheckbox({
purchaserId: purchaserId,
goodsKind: { [item.id]: { id: item.id, estimate_amount: item.estimate_amount, checked: true } },
checked: colorStore[purchaserId].checked,
})
}
const handleClose = () => {
setChangedCheckbox({ id: item?.id, checked: false })
// onUnChecked && onUnChecked({ ...item, checked: false })
setChangedCheckbox({
purchaserId: purchaserId,
goodsKind: { [item.id]: { id: item.id, estimate_amount: item.estimate_amount, checked: false } },
checked: colorStore[purchaserId].checked,
})
}
const getInputValue = debounce(async (num, item) => {
if (item.sale_mode === EnumSaleMode.Bulk) {
item.roll = num
}else{
} else {
item.length = num
}
// onChecked && onChecked({ ...item, checked: true })
}, 300)
return (
@ -68,17 +73,19 @@ const ColorKindItem: FC<PropsType> = memo(
customClassName={classnames(styles.checkbox, checked ? styles.selected : '')}
customTextClass={styles.colorKindItem}>
<View className={styles['colorKindItem__left']}>
<Image className={styles['colorKindItem__left--image']} mode='aspectFill' src='https://test.cdn.zzfzyc.com/mall/no_img.png'></Image>
<Image className={styles['colorKindItem__left--image']} mode='aspectFill' src={formatImgUrl(item.product_color_texture_url)}></Image>
</View>
<View className={styles['colorKindItem__center']}>
<Text className={styles['colorKindItem__center--title']}>001# </Text>
<Text className={styles['colorKindItem__center--title']}>
{item.product_code}# {item.product_name}
</Text>
<View className={styles['colorKindItem__center--detail']}>
<Text className={styles['colorKindItem__center--ID']}>6002#220G</Text>
<Text className={styles['colorKindItem__center--description']}>线</Text>
<Text className={styles['colorKindItem__center--ID']}>{item.product_color_code}</Text>
<Text className={styles['colorKindItem__center--description']}>{item.product_color_name}</Text>
</View>
</View>
<View className={styles['colorKindItem__right']}>
<View className={styles['colorKindItem__right--price']}> 37.50/kg</View>
<View className={styles['colorKindItem__right--price']}> {formatPrice(item.sale_price)}/kg</View>
<View className={styles['colorKindItem__right--counter']}>
<Counter
onBlue={(e) => getInputValue(e, item)}
@ -98,8 +105,11 @@ const ColorKindItem: FC<PropsType> = memo(
(preProp, nextProp) => {
const stringifyPreProp = JSON.stringify(preProp.item)
const stringifyNextProp = JSON.stringify(nextProp.item)
console.log('memo==>', preProp, nextProp);
console.log('memo==>', preProp, nextProp)
let needMemoized = true
if (preProp.purchaserId !== nextProp.purchaserId) {
needMemoized = false
}
if (preProp.orderType !== nextProp.orderType) {
needMemoized = false
}

View File

@ -1,8 +1,13 @@
import { FC, ReactNode, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
import { InternalShoppingCartAction, ShoppingCartAction, ShoppingContext, useShoppingCart } from '../../context'
import { ColorMeta, ColorStore, ShoppingContextValue } from '../../context'
import { GoodsMeta, ColorStore, ShoppingContextValue } from '../../context'
export type TriggerCheckboxOptions = { colorStore: ColorStore; changedCheckbox: ColorMeta }
export type TriggerCheckboxOptions = {
colorStore: ColorStore
changedCheckbox: GoodsMeta
currentCheckedPurchaserId: ShoppingContextValue['currentCheckedPurchaserId']
setSelectedAmount: ShoppingContextValue['setSelectedAmount']
}
export interface ShoppingCartPropsType {
initialValues?: ColorStore
@ -23,12 +28,15 @@ export const ShoppingCart: FC<ShoppingCartPropsType> = (props) => {
onTriggerCheckboxRef.current = onTriggerCheckbox
const [colorStore, setColorStore] = useState<ColorStore>(() => initialValues || {})
const [changedCheckbox, setChangedCheckbox] = useState<ColorMeta>({})
const [changedCheckbox, setChangedCheckbox] = useState<GoodsMeta>({} as GoodsMeta)
// 当前高亮的客户
const [currentCheckedPurchaserId, setCurrentCheckedPurchaserId] = useState<number>(-1)
const [currentCheckedSaleMode, setCurrentCheckedSaleMode] = useState<number>(0)
// 是否管理状态
const [isManageStatus, setManageStatus] = useState(false)
const [selectedAmount, setSelectedAmount] = useState(0)
const ctx: ShoppingContextValue = useMemo(() => {
console.log('useMemo ShoppingContextValue')
return {
@ -36,13 +44,26 @@ export const ShoppingCart: FC<ShoppingCartPropsType> = (props) => {
setManageStatus,
currentCheckedPurchaserId, // 当前高亮的客户
setCurrentCheckedPurchaserId, // 设置高亮当前客户
currentCheckedSaleMode,
setCurrentCheckedSaleMode,
colorStore,
setChangedCheckbox(color) {
setColorStore((prev) => ({ ...prev, [color.id as number]: color }))
setChangedCheckbox(color)
setChangedCheckbox(changedGoods) {
console.log('changedGoods==>', colorStore, changedGoods)
setColorStore((prev) => ({
...prev,
[changedGoods.purchaserId as number]: {
purchaserId: changedGoods.purchaserId,
goodsKind: { ...prev[changedGoods.purchaserId]?.goodsKind, ...changedGoods.goodsKind },
checked: changedGoods.checked,
},
}))
setChangedCheckbox(changedGoods)
},
setColorStore,
selectedAmount,
setSelectedAmount,
}
}, [colorStore, currentCheckedPurchaserId, isManageStatus])
}, [colorStore, currentCheckedPurchaserId, isManageStatus, selectedAmount])
// 暴露给外界
useImperativeHandle(
ref.__INTERNAL__,
@ -60,8 +81,10 @@ export const ShoppingCart: FC<ShoppingCartPropsType> = (props) => {
onTriggerCheckboxRef.current?.({
colorStore,
changedCheckbox,
currentCheckedPurchaserId,
setSelectedAmount,
})
}, [colorStore, changedCheckbox])
}, [colorStore, changedCheckbox, currentCheckedPurchaserId])
return <ShoppingContext.Provider value={ctx}>{children}</ShoppingContext.Provider>
}

View File

@ -35,6 +35,8 @@ export default memo<PropsType>((props) => {
console.log('props==>', props)
const { itemData } = props
const { setCurrentCheckedSaleMode } = useShoppingContext()
console.log('重新渲染 shoppingCartItem')
const [openDetail, setOpenDetail] = useState(false)
@ -47,6 +49,9 @@ export default memo<PropsType>((props) => {
const onSelectOrderType = (type: EnumSaleMode) => {
setSelect(type)
setCurrentCheckedSaleMode(type)
// 重置预估金额
setSelectedAmount(0)
}
const saleModeList = useRef({
@ -60,53 +65,20 @@ export default memo<PropsType>((props) => {
weight_cut_color_list: itemData?.weight_cut_color_list,
}
// const handleChecked = useCallback(
// (current: any) => {
// console.log('handleChecked', current)
// const tempList = itemData?.[BackEndSaleModeListFieldMap[selected]].map((item) => {
// if (item.id === current.id) {
// item = current
// }
// return item
// })
// setMockList((pre) => {
// return {
// ...pre,
// [selected]: tempList,
// }
// })
// },
// [mockList, selected],
// )
// const handleUnChecked = useCallback(
// (current: any) => {
// console.log('handleChecked', current)
// const tempList = itemData?.[BackEndSaleModeListFieldMap[selected]].map((item) => {
// if (item.id === current.id) {
// item = current
// }
// return item
// })
// setMockList((pre) => {
// return {
// ...pre,
// [selected]: tempList,
// }
// })
// },
// [mockList, selected],
// )
const { setChangedCheckbox, currentCheckedPurchaserId, setCurrentCheckedPurchaserId, isManageStatus } = useShoppingContext()
const { setChangedCheckbox, currentCheckedPurchaserId, setCurrentCheckedPurchaserId, isManageStatus, setSelectedAmount, colorStore } = useShoppingContext()
const memoList = useMemo(() => {
return itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0 ? (
itemData?.[BackEndSaleModeListFieldMap[selected]].map((item) => {
console.log('memoList itemData', item)
// 初始化选中状态
setChangedCheckbox({ id: item.id, checked: false })
setChangedCheckbox({
purchaserId: itemData.purchaser_id,
goodsKind: { [item.id]: { id: item.id, estimate_amount: item.estimate_amount, checked: false } },
checked: false,
})
return <ColorKindItem key={item.id} item={item} orderType={selected}></ColorKindItem>
return <ColorKindItem purchaserId={itemData.purchaser_id} key={item.id} item={item} orderType={selected}></ColorKindItem>
})
) : (
<View className={styles.noList}></View>
@ -117,17 +89,42 @@ export default memo<PropsType>((props) => {
if (currentCheckedPurchaserId === itemData?.purchaser_id) {
return
}
console.log('handleClickLayout')
setSelectedAmount(0)
setCurrentCheckedSaleMode(selected)
setCurrentCheckedPurchaserId(itemData?.purchaser_id as number)
}
// const { isManager } = useContext(ShoppingContext)
const handleChecked = () => {
console.log('handleChecked')
// 初始化选中状态
setChangedCheckbox({
purchaserId: itemData?.purchaser_id!,
checked: true,
})
}
const handleUnchecked = () => {
console.log('handleUnchecked')
// 初始化选中状态
setChangedCheckbox({
purchaserId: itemData?.purchaser_id!,
checked: false,
})
}
return (
<LayoutBlock
circle
customClassName={classnames(styles.layout, itemData?.purchaser_id === currentCheckedPurchaserId ? styles.selected : '')}
onClick={handleClickLayout}>
<MCheckbox hiddenCheckboxIcon={!isManageStatus} customClassName={styles['checkbox']} customTextClass={styles['checkbox--text']} triggerLabel={false}>
<MCheckbox
hiddenCheckboxIcon={!isManageStatus}
onSelect={handleChecked}
onClose={handleUnchecked}
status={colorStore[itemData?.purchaser_id!]?.checked}
customClassName={styles['checkbox']}
customTextClass={styles['checkbox--text']}
triggerLabel={false}>
<View className='flex-row justify-between' onClick={handleOpenDetail}>
<View className={styles.topItem}>
<View className='flex-row items-center'>

View File

@ -1,30 +1,57 @@
import { EnumSaleMode } from '@/common/Enumerate'
import React, { useRef } from 'react'
import { useContext } from 'react'
/**
* 456: {
* id: 456,
* checked: true
* purchaserId: 456,
* colorKind: {
* 4562: {
* id: 4562,
* checked: false
* }
* }
* },
* 457: {
* id: 457,
* checked: true
* purchaserId: 457,
* colorKind: {
* 4562: {
* id: 4562,
* checked: false
* }
* }
* }
*/
export type ColorStore = Record<string, any>
export type ColorStore = {
[purchaserId: GoodsMeta['purchaserId']]: GoodsMeta
}
export interface ColorMeta {
id?: number
checked?: boolean
export type Goods = {
id: number
estimate_amount: number // 预估金额
checked: boolean
}
// 分组
export interface GoodsMeta {
purchaserId: number
goodsKind?: {
[id: number]: Goods
}
checked: boolean
}
export interface ShoppingContextValue {
isManageStatus: boolean
setManageStatus: (isManageStatus: boolean) => void
currentCheckedPurchaserId: number
currentCheckedPurchaserId: number // 当前高亮的客户ID
setCurrentCheckedPurchaserId: (purchaserId: number) => void
currentCheckedSaleMode: number
setCurrentCheckedSaleMode: (saleMode: number) => void
colorStore: ColorStore
setChangedCheckbox: (color: ColorMeta) => void
setColorStore: (colorStore: React.SetStateAction<ColorStore>) => void
setChangedCheckbox: (changedGoods: GoodsMeta) => void
selectedAmount: number
setSelectedAmount: (amount: React.SetStateAction<number>) => void
}
export const ShoppingContext = React.createContext<ShoppingContextValue | null>(null)
@ -37,10 +64,9 @@ export function useShoppingContext() {
return ctx
}
export function useWatch(id: ColorMeta['id']) {
export function useWatch(purchaserId: GoodsMeta['purchaserId'], id: number) {
const { colorStore } = useShoppingContext()
console.log('colorStore==>', colorStore)
return id ? colorStore[id] : colorStore
return id ? colorStore[purchaserId]['goodsKind']![id] : colorStore[purchaserId]['goodsKind']
}
export interface ShoppingCartAction {

View File

@ -0,0 +1,36 @@
import { GoodsMeta, ColorStore } from '.'
// 用于优化数据流 结合发布订阅 更新组件内部状态可以组件自己处理
export type SubscribeCallback = (changedGoods: GoodsMeta) => void
export class ShoppingStore {
// 全局缓存
private store: ColorStore = {}
// 监听器数组
private observers: SubscribeCallback[] = []
constructor(initialValue: ColorStore) {
initialValue && this.updateStore(initialValue)
}
// 更新全局缓存
private updateStore(nextStore: ColorStore) {
this.store = nextStore
}
// 订阅
subscribe(callback: SubscribeCallback) {
this.observers.push(callback)
// 取消订阅
return () => {
this.observers = this.observers.filter((fn: SubscribeCallback) => {
return callback !== fn // 引用地址
})
}
}
// 通知
notify(changedGoods: GoodsMeta) {
// 循环调用
this.observers.forEach((callback) => {
callback(changedGoods)
})
}
}

View File

@ -17,7 +17,7 @@
}
.flexBox {
display: flex;
width: 150px;
margin-left: 24px;
align-items: center;
justify-content: flex-end;
}

View File

@ -1,7 +1,7 @@
import Search from '@/components/search'
import { View } from '@tarojs/components'
import Taro, { useDidShow } from '@tarojs/taro'
import React, { FC, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
import React, { FC, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
import styles from './index.module.scss'
import classnames from 'classnames'
import IconText from '@/components/iconText'
@ -11,67 +11,62 @@ import BottomBtns from '@/components/BottomBtns'
import { formatPriceDiv } from '@/common/format'
import BottomSettleBar from './components/bottomSettleBar'
import BottomEditBar from './components/bottomEditBar'
import { ShoppingCartListApi } from '@/api/index'
import { ShoppingCartDeleteApi, ShoppingCartListApi } from '@/api/index'
import { dataLoadingStatus } from '@/common/util'
import { ShoppingCart, TriggerCheckboxOptions } from './components/shoppingCart/index'
import { useShoppingCart, useShoppingContext } from './context'
import { GoodsMeta, Goods, useShoppingCart, useShoppingContext } from './context'
import { alert, goLink } from '@/common/common'
export const Shopping: FC = () => {
const [checkboxData, setCheckboxData] = useState<Partial<TriggerCheckboxOptions>>({})
const handleTriggerCheckbox = ({ colorStore, changedCheckbox }) => {
export const Shopping: FC = memo(() => {
// 计算总的预估金额
const handleTriggerCheckbox = useCallback(({ colorStore, changedCheckbox, currentCheckedPurchaserId, setSelectedAmount }) => {
console.log('handleTriggerCheckbox==>', colorStore, changedCheckbox)
setCheckboxData({ colorStore, changedCheckbox })
}
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind']
if (targetGoodsKind) {
const result = Object.values(targetGoodsKind).reduce((prev: number, value: Goods) => {
console.log('value==>', value)
if (value.checked) {
return prev + Number(formatPriceDiv(value.estimate_amount))
}
return prev
}, 0) as number
console.log('result==>', result)
// 同步修改上下文的 预估金额
setSelectedAmount(result)
} else {
setSelectedAmount(0)
}
}, [])
return (
<ShoppingCart onTriggerCheckbox={handleTriggerCheckbox}>
<ShoppingCartContainer checkboxData={checkboxData} />
<ShoppingCartContainer />
</ShoppingCart>
)
}
})
interface InternalContainer {
checkboxData?: Partial<TriggerCheckboxOptions>
}
interface InternalContainer {}
const ShoppingCartContainer:FC<InternalContainer> = (props) => {
const { checkboxData } = props
const { isManageStatus, setManageStatus } = useShoppingContext()
//输入了搜索关键字
const getSearchData = useCallback((e) => {
// pageNum.current.page = 1
// setOrderData(() => ({ list: [], total: 0 }))
// setSearchField((val) => ({ ...val, name: e, size: 10 }))
}, [])
const shoppingCart = useShoppingCart()
console.log('shoppingCart==>', shoppingCart)
const ShoppingCartContainer: FC<InternalContainer> = () => {
const { isManageStatus, setManageStatus, selectedAmount, currentCheckedPurchaserId, currentCheckedSaleMode, colorStore, setColorStore } = useShoppingContext()
// 管理
const onStartToManage = () => {
setManageStatus(!isManageStatus)
// shoppingCart.setManageStatus(!isManageStatus)
}
const [selectedAmount, setSelectedAmount] = useState(0)
// 结算
const handleSettleAccount = () => {}
// 删除
const handleDelete = () => {}
const handleSelectAllCheckbox = (isSelectAll: boolean) => {
console.log('handleSelectAllCheckbox', isSelectAll)
}
const [listHeight, setListHeight] = useState('auto')
const { fetchData, state } = ShoppingCartListApi()
// 输入了搜索关键字
const getSearchData = useCallback((e) => {
fetchData({ short_name_or_phone: e })
// pageNum.current.page = 1
// setOrderData(() => ({ list: [], total: 0 }))
// setSearchField((val) => ({ ...val, name: e, size: 10 }))
}, [])
const [shoppingCartData, setShoppingCartData] = useState<{ list: ShoppingCartData[]; total: number }>({ list: [], total: 0 })
//数据加载状态
@ -102,7 +97,57 @@ const ShoppingCartContainer:FC<InternalContainer> = (props) => {
setShoppingCartData({ list: state.data, total: state.data.length })
}, [state])
// 结算
const handleSettleAccount = () => {
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind']
if (!targetGoodsKind) return
goLink('/pages/submitOrder/index', {
purchaser_id: currentCheckedPurchaserId,
sale_mode: currentCheckedSaleMode,
shopping_cart_product_color_list: Object.values(targetGoodsKind).map((item: Goods) => {
if (item.checked) {
return item.id
}
}),
})
}
const { fetchData: deleteApi } = ShoppingCartDeleteApi()
// TODO: 批量删除商品
const handleDelete = async () => {
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind']
if (targetGoodsKind && Object.values(targetGoodsKind).every((item: Goods) => !item.checked)) {
return Taro.showToast({ title: '请选择商品', icon: 'error' })
}
Taro.showModal({
title: '要取消这些商品吗?',
success: async function (res) {
if (res.confirm) {
const res = await deleteApi()
if (res.success) {
alert.success('取消成功')
fetchData()
} else {
alert.none(res.msg)
}
}
},
})
}
// 全选
const handleSelectAllCheckbox = (isSelectAll: boolean) => {
console.log('handleSelectAllCheckbox', isSelectAll)
const tempObject = colorStore
Object.entries(colorStore).forEach(([key,value])=>{
tempObject[key] = {
...value,
checked: isSelectAll,
}
})
console.log(tempObject)
setColorStore(() => tempObject)
}
return (
<View className={classnames('flex-col', styles.shopping)} id='shoppingContainer'>
@ -126,13 +171,13 @@ const ShoppingCartContainer:FC<InternalContainer> = (props) => {
})}
</InfiniteScroll>
</View>
<View id='bottomBar'>
{isManageStatus ? (
<BottomEditBar onDelete={handleDelete} onSelectCheckbox={handleSelectAllCheckbox}></BottomEditBar>
) : (
<BottomSettleBar onSettleAccount={handleSettleAccount} amount={selectedAmount}></BottomSettleBar>
)}
</View>
</View>
<View id='bottomBar'>
{isManageStatus ? (
<BottomEditBar onDelete={handleDelete} onSelectCheckbox={(isAll) => handleSelectAllCheckbox(isAll)}></BottomEditBar>
) : (
<BottomSettleBar onSettleAccount={handleSettleAccount} amount={selectedAmount}></BottomSettleBar>
)}
</View>
</View>
)