diff --git a/project.private.config.json b/project.private.config.json index ec9a318..a8be625 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -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 } diff --git a/src/pages/shopping/components/bottomEditBar/index.tsx b/src/pages/shopping/components/bottomEditBar/index.tsx index 9d90f78..8b7c92b 100644 --- a/src/pages/shopping/components/bottomEditBar/index.tsx +++ b/src/pages/shopping/components/bottomEditBar/index.tsx @@ -19,11 +19,11 @@ export default memo((props) => { const selectCallBack = () => { setSelectAll(true) - onSelectCheckbox && onSelectCheckbox(isSelectAll) + onSelectCheckbox && onSelectCheckbox(true) } const closeCallBack = () => { setSelectAll(false) - onSelectCheckbox && onSelectCheckbox(isSelectAll) + onSelectCheckbox && onSelectCheckbox(false) } diff --git a/src/pages/shopping/components/bottomSettleBar/index.tsx b/src/pages/shopping/components/bottomSettleBar/index.tsx index f3dfdd2..274b364 100644 --- a/src/pages/shopping/components/bottomSettleBar/index.tsx +++ b/src/pages/shopping/components/bottomSettleBar/index.tsx @@ -22,7 +22,7 @@ export default memo((props) => { 预估金额: ¥ - {formatPriceDiv(amount)} + {amount} diff --git a/src/pages/shopping/components/colorKindItem/index.tsx b/src/pages/shopping/components/colorKindItem/index.tsx index 9014978..41f8614 100644 --- a/src/pages/shopping/components/colorKindItem/index.tsx +++ b/src/pages/shopping/components/colorKindItem/index.tsx @@ -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 & object orderType: EnumSaleMode } @@ -19,15 +20,14 @@ type PropsType = { const ColorKindItem: FC = 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 = 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 = memo( customClassName={classnames(styles.checkbox, checked ? styles.selected : '')} customTextClass={styles.colorKindItem}> - + - 001# 环保黑 环保黑 环保黑 环保黑 环保黑 环保黑 + + {item.product_code}# {item.product_name} + - 6002#220G - 流线棉拉架卫衣 + {item.product_color_code} + {item.product_color_name} - ¥ 37.50/kg + ¥ {formatPrice(item.sale_price)}/kg getInputValue(e, item)} @@ -98,8 +105,11 @@ const ColorKindItem: FC = 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 } diff --git a/src/pages/shopping/components/shoppingCart/index.tsx b/src/pages/shopping/components/shoppingCart/index.tsx index 86a5356..9717eb7 100644 --- a/src/pages/shopping/components/shoppingCart/index.tsx +++ b/src/pages/shopping/components/shoppingCart/index.tsx @@ -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 = (props) => { onTriggerCheckboxRef.current = onTriggerCheckbox const [colorStore, setColorStore] = useState(() => initialValues || {}) - const [changedCheckbox, setChangedCheckbox] = useState({}) + const [changedCheckbox, setChangedCheckbox] = useState({} as GoodsMeta) // 当前高亮的客户 const [currentCheckedPurchaserId, setCurrentCheckedPurchaserId] = useState(-1) + const [currentCheckedSaleMode, setCurrentCheckedSaleMode] = useState(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 = (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 = (props) => { onTriggerCheckboxRef.current?.({ colorStore, changedCheckbox, + currentCheckedPurchaserId, + setSelectedAmount, }) - }, [colorStore, changedCheckbox]) + }, [colorStore, changedCheckbox, currentCheckedPurchaserId]) return {children} } diff --git a/src/pages/shopping/components/shoppingCartItem/index.tsx b/src/pages/shopping/components/shoppingCartItem/index.tsx index dfb3bef..617a5a6 100644 --- a/src/pages/shopping/components/shoppingCartItem/index.tsx +++ b/src/pages/shopping/components/shoppingCartItem/index.tsx @@ -35,6 +35,8 @@ export default memo((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((props) => { const onSelectOrderType = (type: EnumSaleMode) => { setSelect(type) + setCurrentCheckedSaleMode(type) + // 重置预估金额 + setSelectedAmount(0) } const saleModeList = useRef({ @@ -60,53 +65,20 @@ export default memo((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 + return }) ) : ( 暂无数据 @@ -117,17 +89,42 @@ export default memo((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 ( - + diff --git a/src/pages/shopping/context/index.ts b/src/pages/shopping/context/index.ts index 854027a..a255185 100644 --- a/src/pages/shopping/context/index.ts +++ b/src/pages/shopping/context/index.ts @@ -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 +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) => void + setChangedCheckbox: (changedGoods: GoodsMeta) => void + selectedAmount: number + setSelectedAmount: (amount: React.SetStateAction) => void } export const ShoppingContext = React.createContext(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 { diff --git a/src/pages/shopping/context/shoppingStore.ts b/src/pages/shopping/context/shoppingStore.ts new file mode 100644 index 0000000..b5b5a9f --- /dev/null +++ b/src/pages/shopping/context/shoppingStore.ts @@ -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) + }) + } +} diff --git a/src/pages/shopping/index.module.scss b/src/pages/shopping/index.module.scss index 921dbc6..b9d1bcb 100644 --- a/src/pages/shopping/index.module.scss +++ b/src/pages/shopping/index.module.scss @@ -17,7 +17,7 @@ } .flexBox { display: flex; - width: 150px; + margin-left: 24px; align-items: center; justify-content: flex-end; } diff --git a/src/pages/shopping/index.tsx b/src/pages/shopping/index.tsx index 1d41bcf..ba4f4c6 100644 --- a/src/pages/shopping/index.tsx +++ b/src/pages/shopping/index.tsx @@ -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>({}) - - 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 ( - + ) -} +}) -interface InternalContainer { - checkboxData?: Partial -} +interface InternalContainer {} -const ShoppingCartContainer:FC = (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 = () => { + 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 = (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 ( @@ -126,13 +171,13 @@ const ShoppingCartContainer:FC = (props) => { })} - - {isManageStatus ? ( - - ) : ( - - )} - + + + {isManageStatus ? ( + handleSelectAllCheckbox(isAll)}> + ) : ( + + )} )