From 45c656e0edbfeb00e8c92eccc165fcaa053d0ad6 Mon Sep 17 00:00:00 2001 From: xuan Date: Fri, 11 Nov 2022 10:53:48 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20fix(#1000663#25#26#27):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=80=E5=94=AE=E7=BB=9F=E8=AE=A1=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=9A=84=E6=A0=B7=E5=BC=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SelectGroup/index.module.scss | 0 src/components/SelectGroup/index.tsx | 44 +++++ .../index.module.scss | 2 +- .../SelectMarketingDepartment/index.tsx | 24 ++- .../SelectSaleRankingIndicators/index.tsx | 6 +- src/components/SelectSaleType/index.tsx | 25 ++- src/components/SelectTimePicker/index.tsx | 28 +++- src/components/dropDown-item/index.tsx | 20 ++- src/components/filterButton/index.module.scss | 1 + src/components/table/index.module.scss | 2 +- src/components/toolTips/index.module.scss | 3 + src/components/toolTips/index.tsx | 158 +++++++++++++++--- src/pages/saleStatistic/index.module.scss | 5 +- src/pages/saleStatistic/index.tsx | 58 ++++--- 14 files changed, 299 insertions(+), 77 deletions(-) create mode 100644 src/components/SelectGroup/index.module.scss create mode 100644 src/components/SelectGroup/index.tsx diff --git a/src/components/SelectGroup/index.module.scss b/src/components/SelectGroup/index.module.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/components/SelectGroup/index.tsx b/src/components/SelectGroup/index.tsx new file mode 100644 index 0000000..a8a64d1 --- /dev/null +++ b/src/components/SelectGroup/index.tsx @@ -0,0 +1,44 @@ +import React, { FC, MutableRefObject } from "react" +import SelectSaleType from "../SelectSaleType" +import SelectTimePicker from "../SelectTimePicker" +import SelectMarketingDepartment from '../SelectMarketingDepartment' + + +interface PropsType { + children?: React.ReactNode +} + +const GroupItem = [ + SelectMarketingDepartment.name, + SelectSaleType.name, + SelectTimePicker.name +] + +const SelectGroup: FC = (props: PropsType) => { + const {children} = props + + function handleChange(children,childEle) { + return function (value: any){ + childEle.props.onChange(value) + children.forEach((child)=>{ + child.ref?.current.closePopup() + }) + } + } + function handleCloseOverlay(children) { + return function (){ + children.forEach((child)=>{ + child.ref?.current.closePopup() + }) + } + } + + const renderChildren = () => { + return React.Children.map(children, (child) => { + const childEle = child as React.FunctionComponentElement + return React.cloneElement(childEle, {onChange: handleChange(children,childEle), onCloseOverlay: handleCloseOverlay(children)}) + }) + } + return <>{renderChildren()} +} +export default SelectGroup diff --git a/src/components/SelectMarketingDepartment/index.module.scss b/src/components/SelectMarketingDepartment/index.module.scss index f9e161d..a1cb97d 100644 --- a/src/components/SelectMarketingDepartment/index.module.scss +++ b/src/components/SelectMarketingDepartment/index.module.scss @@ -2,5 +2,5 @@ padding: 24px 40px; display: grid; grid-gap: 24px 24px; - grid-template-columns: 1fr 1fr; + grid-template-columns: 1fr 1fr 1fr; } diff --git a/src/components/SelectMarketingDepartment/index.tsx b/src/components/SelectMarketingDepartment/index.tsx index 27409a4..6b2ef2d 100644 --- a/src/components/SelectMarketingDepartment/index.tsx +++ b/src/components/SelectMarketingDepartment/index.tsx @@ -1,4 +1,4 @@ -import { FC, memo, useEffect, useMemo, useState } from 'react' +import { FC, forwardRef, memo, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react' import DropDownItem from '../dropDown-item' import FilterButton from '../filterButton' import { EnumMarketingDepartmentApi } from '@/api/index' @@ -9,6 +9,7 @@ type ChangedValue = string | number interface SelectSaleTypeProps { onChange?: (value: ChangedValue) => void + onCloseOverlay?: () => void } type EnumList = { @@ -17,11 +18,11 @@ type EnumList = { name: string } // 营销部门 -const SelectSaleType: FC = memo((props) => { +const SelectSaleType = memo(forwardRef((props: SelectSaleTypeProps, ref) => { const selectName = '营销部门' - const { onChange } = props + const { onChange,onCloseOverlay } = props console.log(props) const { fetchData } = EnumMarketingDepartmentApi() @@ -42,6 +43,19 @@ const SelectSaleType: FC = memo((props) => { setCurrentValue(value) onChange?.(value) } + const dropDownRef = useRef(null) + + useImperativeHandle( + ref, + () => { + return { + show: dropDownRef.current.show, + showPopup: dropDownRef.current.showPopup, + closePopup: dropDownRef.current.closePopup, + } + }, + [dropDownRef.current], + ) const displayTitle = useMemo(() => { if (currentValue === -1) { @@ -51,7 +65,7 @@ const SelectSaleType: FC = memo((props) => { }, [enumList, currentValue]) return ( - + {!!enumList.length && enumList.map((item: EnumList) => { @@ -64,5 +78,5 @@ const SelectSaleType: FC = memo((props) => { ) -}) +})) export default SelectSaleType diff --git a/src/components/SelectSaleRankingIndicators/index.tsx b/src/components/SelectSaleRankingIndicators/index.tsx index 3da6d54..563be6a 100644 --- a/src/components/SelectSaleRankingIndicators/index.tsx +++ b/src/components/SelectSaleRankingIndicators/index.tsx @@ -11,6 +11,8 @@ type ChangedValue = string | number interface SelectSaleTypeProps { onChange?: (value: ChangedValue) => void + dropDownStyle?: React.CSSProperties + dropDownClassName?: string } type EnumList = { @@ -23,7 +25,7 @@ const SelectSaleRankingIndicators: FC = memo((props) => { const selectName = '排行指标' - const { onChange } = props + const { onChange, dropDownStyle, dropDownClassName } = props console.log(props) const { fetchData } = SaleOrderDataFormdataFormStatus() @@ -53,7 +55,7 @@ const SelectSaleRankingIndicators: FC = memo((props) => { }, [enumList, currentValue]) return ( - + {!!enumList.length && enumList.map((item: EnumList) => { diff --git a/src/components/SelectSaleType/index.tsx b/src/components/SelectSaleType/index.tsx index 528034f..f9e8ec9 100644 --- a/src/components/SelectSaleType/index.tsx +++ b/src/components/SelectSaleType/index.tsx @@ -1,4 +1,4 @@ -import { FC, memo, useEffect, useMemo, useState } from 'react' +import { FC, forwardRef, memo, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react' import DropDownItem from '../dropDown-item' import FilterButton from '../filterButton' import { EnumSalesTypeApi } from '@/api/index' @@ -9,6 +9,7 @@ type ChangedValue = string | number interface SelectSaleTypeProps { onChange?: (value: ChangedValue) => void + onCloseOverlay?: () => void defaultValue?: ChangedValue } @@ -18,9 +19,9 @@ type EnumList = { name: string } // 销售类型 -const SelectSaleType: FC = memo((props) => { +const SelectSaleType = memo(forwardRef((props: SelectSaleTypeProps, ref) => { const selectName = '销售类型' - const { onChange, defaultValue = 0 } = props + const { onChange, defaultValue = 0,onCloseOverlay } = props console.log(props) const { fetchData } = EnumSalesTypeApi() @@ -42,6 +43,20 @@ const SelectSaleType: FC = memo((props) => { onChange?.(value) } + const dropDownRef = useRef(null) + + useImperativeHandle( + ref, + () => { + return { + show: dropDownRef.current.show, + showPopup: dropDownRef.current.showPopup, + closePopup: dropDownRef.current.closePopup, + } + }, + [dropDownRef.current], + ) + const displayTitle = useMemo(() => { if (currentValue === -1) { return selectName @@ -50,7 +65,7 @@ const SelectSaleType: FC = memo((props) => { }, [enumList, currentValue]) return ( - + {!!enumList.length && enumList.map((item: EnumList) => { @@ -63,5 +78,5 @@ const SelectSaleType: FC = memo((props) => { ) -}) +})) export default SelectSaleType diff --git a/src/components/SelectTimePicker/index.tsx b/src/components/SelectTimePicker/index.tsx index b74fd50..77fca1a 100644 --- a/src/components/SelectTimePicker/index.tsx +++ b/src/components/SelectTimePicker/index.tsx @@ -1,7 +1,7 @@ import { formatDateTime } from '@/common/format' import { View, Text } from '@tarojs/components' import dayjs from 'dayjs' -import { FC, memo, useRef, useState } from 'react' +import { FC, forwardRef, memo, useImperativeHandle, useRef, useState } from 'react' import DropDownItem from '../dropDown-item' import FilterButton from '../filterButton' import IconFont from '../iconfont/iconfont' @@ -14,6 +14,7 @@ interface SelectSaleTypeProps { defaultValue?: Key // 默认值 timeOptions?: {[Property: string]: Value} // 支持自定义 时间配置 onChange?: (value: ChangedValue) => void + onCloseOverlay?: () => void } const FilterTimeOptions = { @@ -77,8 +78,8 @@ const FilterTimeOptions = { type Key = keyof typeof FilterTimeOptions type Value = typeof FilterTimeOptions[Key] -const SelectTimePicker: FC = memo((props) => { - const { onChange: change, defaultValue = '0', timeOptions = FilterTimeOptions } = props +const SelectTimePicker = memo(forwardRef((props: SelectSaleTypeProps, ref) => { + const { onChange: change,onCloseOverlay, defaultValue = '0', timeOptions = FilterTimeOptions } = props // rerender 的时候需要更新 ref 的值 const Options = useRef({ ...timeOptions, 'custom': FilterTimeOptions['custom'] }) Options.current = { ...timeOptions, 'custom': FilterTimeOptions['custom'] } @@ -125,14 +126,29 @@ const SelectTimePicker: FC = memo((props) => { setCurrentValue('custom') setShowTime(true) } - + const dropDownRef = useRef(null) + + useImperativeHandle( + ref, + () => { + return { + show: dropDownRef.current.show, + showPopup: dropDownRef.current.showPopup, + closePopup: dropDownRef.current.closePopup, + } + }, + [dropDownRef.current], + ) return ( <> + activeColor='#337fff' + ref={dropDownRef} + onCloseOverlay={onCloseOverlay} + > {Object.entries(Options.current) .slice(0, -1) @@ -152,5 +168,5 @@ const SelectTimePicker: FC = memo((props) => { ) -}) +})) export default SelectTimePicker diff --git a/src/components/dropDown-item/index.tsx b/src/components/dropDown-item/index.tsx index 1c1e13e..e55e4fc 100644 --- a/src/components/dropDown-item/index.tsx +++ b/src/components/dropDown-item/index.tsx @@ -9,6 +9,8 @@ import Iconfont from '../iconfont/iconfont' import Popup from '../popup' import Cell from '../cell' import Taro from '@tarojs/taro' +import classNames from 'classnames' +import { usePropsValue } from '@/use/useCommon' // 弹窗选择向上弹窗还是向下弹窗 type Direction = 'up' | 'down' // 配置 菜单可选项 @@ -19,6 +21,7 @@ export type DropDownOptions = { interface DropDownEvent { change?: (value: DropDownOptions['value']) => void // value 变化时触发 + onCloseOverlay?: () => void } interface PropsType extends DropDownEvent { @@ -35,16 +38,20 @@ interface PropsType extends DropDownEvent { } export default forwardRef((props: PropsType, ref) => { - const { children, direction = 'down', title = '', value, options = [], change, activeColor, showOverlay = true, hasBottomBtn = false } = props + const { children, direction = 'down', title = '', value, options = [], change, activeColor, showOverlay = true, hasBottomBtn = false,customClassName,customStyle,onCloseOverlay } = props + + const [showPopup, setShowPopup] = useState(false) useImperativeHandle(ref, () => ({ + show: showPopup, //暴露出方法给有需要的用 closePopup() { setShowPopup(false) + }, + showPopup() { + setShowPopup(true) } - })) - - const [showPopup, setShowPopup] = useState(false) + }), [showPopup]) const handleClickOption = (value: DropDownOptions['value']) => { change?.(value) @@ -69,12 +76,15 @@ export default forwardRef((props: PropsType, ref) => { } const handleClickTitle = () => { + console.log('handleClickTitle', showPopup); + onCloseOverlay?.() setShowPopup(prev => !prev) } const handleClosePopup = () => { if (hasBottomBtn) return setShowPopup(false) + onCloseOverlay?.() } const [overlayOffsetTop, setOverlayOffsetTop] = useState('unset') @@ -112,7 +122,7 @@ export default forwardRef((props: PropsType, ref) => { return ( - + {title ? title : text} diff --git a/src/components/filterButton/index.module.scss b/src/components/filterButton/index.module.scss index f7eea78..39309f0 100644 --- a/src/components/filterButton/index.module.scss +++ b/src/components/filterButton/index.module.scss @@ -25,6 +25,7 @@ border: 1px solid $color_main; background-color: #eaf2ff; .filterButton--text { + font-weight: 550; color: $color_main; } } diff --git a/src/components/table/index.module.scss b/src/components/table/index.module.scss index d048d3e..9f35e98 100644 --- a/src/components/table/index.module.scss +++ b/src/components/table/index.module.scss @@ -10,7 +10,7 @@ width: 100%; justify-content: center; align-items: center; - padding: 24px 0; + padding: 12px 0; border-bottom: 1px solid #f7f7f7; } diff --git a/src/components/toolTips/index.module.scss b/src/components/toolTips/index.module.scss index 311ceef..8916c76 100644 --- a/src/components/toolTips/index.module.scss +++ b/src/components/toolTips/index.module.scss @@ -22,6 +22,9 @@ box-shadow: 0 0 30px 0 rgba(51, 51, 51, 0.2); border-radius: 8px; &-content { + font-size: 24px; + font-weight: lighter; + color: white; padding: 8px 12px; white-space: nowrap; } diff --git a/src/components/toolTips/index.tsx b/src/components/toolTips/index.tsx index c8fc8f2..2dd0669 100644 --- a/src/components/toolTips/index.tsx +++ b/src/components/toolTips/index.tsx @@ -1,7 +1,8 @@ import { View } from '@tarojs/components' +import { nextTick } from '@tarojs/runtime' import Taro from '@tarojs/taro' import classNames from 'classnames' -import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react' +import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef, useState, useTransition } from 'react' import IconFont from '../iconfont/iconfont' import styles from './index.module.scss' @@ -15,7 +16,19 @@ const convertPx = (px: number) => { return realPx } -type Placement = 'top' | 'right' | 'bottom' | 'left' +type Placement = + | 'top' + | 'top-start' + | 'top-end' + | 'right' + | 'right-start' + | 'right-end' + | 'bottom' + | 'bottom-start' + | 'bottom-end' + | 'left' + | 'left-start' + | 'left-end' interface ToolTipEvent { onVisibleChange?: (visible?: boolean) => void @@ -42,7 +55,9 @@ const popoverStyle = { } const ToolTip = forwardRef((props, ref) => { - const { placement = 'top', defaultVisible = false, onVisibleChange, children, content = '请填入提示信息', customClassName, customStyle, customContentStyle } = props + const id = useId(); + const [,setForceUpdate] = useState({}) + const { placement = 'top-start', defaultVisible = false, onVisibleChange, children, content = '请填入提示信息', customClassName, customStyle, customContentStyle } = props if (!content){ throw new Error('tooltip: content 不能为空') @@ -65,12 +80,14 @@ const ToolTip = forwardRef((props, ref) => { }, [visible], ) + const handleClick = useCallback(() => { setVisible(v => { onVisibleChangeRef.current?.(!v) return !v }) + }, []) const handleClickMark = useCallback(() => { @@ -98,6 +115,22 @@ const ToolTip = forwardRef((props, ref) => { const viewportRef = useRef(viewport) viewportRef.current = viewport + const contextRectRef = useRef(null) + + + useEffect(()=>{ + if(visible && !contextRectRef.current) { + nextTick(()=>{ + const query = Taro.createSelectorQuery() + query.select(`#content-${id}`).boundingClientRect((res)=>{ + console.log('contextRectRef',res); + contextRectRef.current = res + setForceUpdate({}) + }).exec() + }) + } + }, [visible, contextRectRef.current]) + useEffect(() => { console.log('useLayoutEffect') const query = Taro.createSelectorQuery() @@ -111,10 +144,14 @@ const ToolTip = forwardRef((props, ref) => { setViewport(res[1]) viewportRef.current = res[1] }) + }, []) // 箭头 坐标 const arrowCoords = useMemo(() => { + const contextRect = contextRectRef.current + // contextRect 没获取到之前 隐藏 + if(!contextRect) return {top: '9999px'} console.log('getArrowSide==>', getArrowSide, childrenRectRef.current) switch (getArrowSide) { case 'bottom': // 下箭头 @@ -146,44 +183,119 @@ const ToolTip = forwardRef((props, ref) => { bottom: '', } } - }, [getArrowSide, childrenRectRef.current]) + }, [getArrowSide, childrenRectRef.current, contextRectRef.current]) // content 坐标 const contentCoords = useMemo(() => { + const placementSide = placement.split('-')[1] as string // placement = 'top-start' 取 'start' + console.log('placementSide',placementSide); + let coordsStyle = {} + const contextRect = contextRectRef.current + // contextRect 没获取到之前 隐藏 + if(!contextRect) return {top: '9999px'} + console.log('contextRect',contextRect); + const childrenRect = childrenRectRef.current switch (getArrowSide) { case 'bottom': // 下箭头 - return { - left: 0, - top: '', - right: '', + coordsStyle = { bottom: convertPx(arrowSize) - 5, + top: '', + } + if(placementSide === 'start'){ + return { + ...coordsStyle, + left: 0, + right: '', + } + }else if(placementSide === 'end'){ + return { + ...coordsStyle, + left: '', + right: 0, + } + }else{ + return { + ...coordsStyle, + left: - (contextRect?.width / 2 - childrenRect.width / 2) + 'px', + right: '', + } } case 'left': // 左箭头 - return { - left: childrenRectRef.current.width + convertPx(arrowSize) - 5, - top: 0, + coordsStyle = { + left: childrenRect.width + convertPx(arrowSize) - 5, right: '', - bottom: '', + } + if(placementSide === 'start'){ + return { + ...coordsStyle, + top: 0, + bottom: '', + } + }else if(placementSide === 'end'){ + return { + ...coordsStyle, + top: '', + bottom: -childrenRect.height + 'px', + } + }else{ + return { + ...coordsStyle, + top: -(contextRect.height / 2 - childrenRect.height / 2) + 'px', + bottom: '', + } } case 'top': // 上箭头 - return { - left: 0, - top: childrenRectRef.current.height + convertPx(arrowSize) - 5, - right: '', + coordsStyle = { + top: childrenRect.height + convertPx(arrowSize) - 5, bottom: '', } + if(placementSide === 'start'){ + return { + ...coordsStyle, + left: 0, + right: '', + } + }else if(placementSide === 'end'){ + return { + ...coordsStyle, + left: '', + right: 0, + } + }else{ + return { + ...coordsStyle, + left: - (contextRect?.width / 2 - childrenRect.width / 2) + 'px', + right: '', + } + } case 'right': // 右箭头 - return { + coordsStyle = { left: '', - top: 0, right: convertPx(arrowSize) - 5, - bottom: '', + } + if(placementSide === 'start'){ + return { + ...coordsStyle, + top: 0, + bottom: '', + } + }else if(placementSide === 'end'){ + return { + ...coordsStyle, + top: '', + bottom: -childrenRect.height + 'px', + } + }else{ + return { + ...coordsStyle, + top: -(contextRect.height / 2 - childrenRect.height / 2) + 'px', + bottom: '', + } } } - }, [getArrowSide, childrenRectRef.current]) + }, [getArrowSide, childrenRectRef.current, contextRectRef.current]) const ContentComponent = useMemo(() => { - console.log('执行完') return ( @@ -192,9 +304,9 @@ const ToolTip = forwardRef((props, ref) => { {/* content */} - + { {content} - + } ) }, [content, getArrowSide, visible, arrowCoords, contentCoords]) diff --git a/src/pages/saleStatistic/index.module.scss b/src/pages/saleStatistic/index.module.scss index 267413f..135c5e9 100644 --- a/src/pages/saleStatistic/index.module.scss +++ b/src/pages/saleStatistic/index.module.scss @@ -21,21 +21,22 @@ page { } } .title { - margin: 0 10px; font-size: $font_size; color: $color_font_one; + font-weight: bold; } .cell-desc { font-weight: 550; color: $color_font_one; font-size: 34px; + padding: 6px 0; } .totalSummary { display: flex; flex-flow: column nowrap; justify-content: center; align-items: center; - padding: 24px 0; + padding: 12px 0 24px 0; &--title { font-size: $font_size; margin: 0 10px; diff --git a/src/pages/saleStatistic/index.tsx b/src/pages/saleStatistic/index.tsx index 0ae2601..29a74c8 100644 --- a/src/pages/saleStatistic/index.tsx +++ b/src/pages/saleStatistic/index.tsx @@ -17,6 +17,8 @@ import dayjs from 'dayjs' import { memo, useCallback, useEffect, useRef, useState } from 'react' import styles from './index.module.scss' import { OrderForm, ArrangedForm, PaymentAmountForm, ReturnGoodsOrderForm } from './config' +import IconText from '@/components/iconText' +import SelectGroup from '@/components/SelectGroup' //处理金额(后端单位分,转元) const priceformat = (val: number) => { @@ -155,21 +157,26 @@ const saleStatistic = () => { } }, []) + const selectSaleTypeRef = useRef(null) + const selectMarketingDepartmentRef = useRef(null) + const selectTimePickerRef = useRef(null) + return ( - {/* */} - - - + + + true} ref={selectSaleTypeRef}> + true} ref={selectMarketingDepartmentRef}> + true} defaultValue='0' timeOptions={FilterTimeOptions} ref={selectTimePickerRef}> + - + - - 订单 + - + @@ -188,7 +195,7 @@ const saleStatistic = () => { + {value.cellTitle} @@ -201,12 +208,11 @@ const saleStatistic = () => { ) })} - + - - 配布 + - + @@ -225,7 +231,7 @@ const saleStatistic = () => { + {value.cellTitle} @@ -235,17 +241,16 @@ const saleStatistic = () => { desc={value.value.num} customDescClassName={value.value.cls} customClassName={styles['cell-desc']}> - {(index + 1) % 3 === 0 && } + {((index + 1) % 3 === 0 && (index + 1) !== 9) ? : null} ) })} - + - - 货款 + - + @@ -260,7 +265,7 @@ const saleStatistic = () => { + {value.cellTitle} @@ -273,12 +278,11 @@ const saleStatistic = () => { ) })} - + - - 退货 + - + @@ -295,7 +299,7 @@ const saleStatistic = () => { + {value.cellTitle} @@ -559,11 +563,11 @@ const RankingBlock = memo(props => { 销售排行 - + - + {tabsConfig.map(item => { return (