import React, { useRef, useState, useEffect } from 'react'; import classnames from 'classnames'; import { CnIcon } from '@alife/cn-ui'; import { SowingWallProps, WallProps, BasketProps, } from 'src/types/op-sowing-wall'; import Button from '../op-button'; import OPTag from '../op-tag'; import './index.scss'; // 常见播种墙规格:4*6、5*6、5*15(AE) const MIN_WIDTH = 70; // 格口最小尺寸 const MAX_WIDTH = 260; // 格口最大尺寸 export default function SowingWall(props: SowingWallProps) { const { header = {}, sowingWall = {} } = props; const { title = '', tagList = [], action = () => {} } = header; const { basketNoType, baskets = [], rows = 3, cols = 4, itemWidth: _itemWidth, hasSubTitle, // 是否展示副标题,当有副标题时,篮号下面会多出一个 灰色条 类似 老组件中的 OPSowingWall2 onClick = () => {}, getBasketNo: _getBasketNo, } = sowingWall as WallProps; const hasSubTitleHeight = 34; // lineHeight 1.5 * fontSize 20 + gap 4 = 34 const sowingWallRef = useRef(null); const [itemWidth, setItemWidth] = useState(_itemWidth || 85); // 格口宽度 const [bodyClass, setBodyClass] = useState({}); // 设置格口状态 const getItemStatus = (item: BasketProps | undefined) => { let type = 'empty'; if (item) { const { status, highlighted } = item; type = 'filled'; if (highlighted) { type = 'current'; } if (status) { type = status?.toLowerCase(); } // if (customColor) { // type = customColor; // } } return `item-${type}`; }; // 设置内容及样式 const getContent = (basket: BasketProps | undefined) => { if (!basket) { return ''; } const { status, highlighted, planNum = 0, actualNum = 0, content = '', } = basket; if (content) { return content; } if (highlighted) { return `${actualNum}/${planNum}`; } if (status === 'FINISHED') { return ( ); } if (status === 'LACK') { return actualNum - planNum; } if (status === 'INTERCEPTED') { return '拦截'; } return ''; }; // 设置篮号 const getBasketNo = (rowIndex: number, colIndex: number) => { if (typeof _getBasketNo === 'function') { return _getBasketNo(rowIndex, colIndex); } if (basketNoType === 2) { return `${cols * rowIndex + (colIndex + 1)}`; } return `${String.fromCharCode(rowIndex + 65)}${colIndex + 1}`; }; // 渲染格口 const renderItem = (rowIndex: number, colIndex: number) => { const basketNo = getBasketNo(rowIndex, colIndex); const findItem = baskets.find((basket) => basket.basketNo === basketNo); const itemStatus = getItemStatus(findItem); const content = getContent(findItem); const fontSize = itemWidth / 2; let newFontSize = fontSize; // 根据实际内容长度重新计算字体大小 // 模拟计算文本宽度像素(不精确) if (typeof content === 'string' && content) { const px = content?.split('')?.reduce((acc, cur) => { const isChinese = cur?.match(/[一-龥]/g); const width = isChinese ? fontSize : fontSize / 2; return acc + width; }, 0); // 如果模拟宽度超出容器大小,重新设定字体大小 if (px > itemWidth) { newFontSize = (itemWidth / px) * fontSize - 2; } } return (
{ if (findItem) { onClick(findItem, rowIndex, colIndex); } }} > {/*
*/}
{content}
{hasSubTitle ? findItem?.subTitle : basketNo}
{hasSubTitle &&
{basketNo || '-'}
}
); }; // 计算格口size(70-260)宽高等同 useEffect(() => { if (!_itemWidth && sowingWallRef?.current) { const { width, height } = sowingWallRef.current.getBoundingClientRect(); // 播种墙容器宽度 // 根据容器宽度计算出的格口宽度,8=左右间距 const calcByWidth = (width - (cols - 1) * 8) / cols; // 根据容器高度计算出的格口高度,12=上下间距(底部多留一个间距) const calcByHeight = (height - rows * (12 + (hasSubTitle ? hasSubTitleHeight : 0))) / rows; const newBodyClass = { center: true, }; let resultWidth = Math.min(calcByWidth, calcByHeight); // 取小 if (resultWidth > MAX_WIDTH) { resultWidth = MAX_WIDTH; } if (resultWidth < MIN_WIDTH) { resultWidth = MIN_WIDTH; } // 横向滚动 if (calcByWidth < MIN_WIDTH) { newBodyClass.center = false; } setItemWidth(resultWidth); setBodyClass(newBodyClass); console.log('播种墙宽高', width, height); console.log('计算格口宽高:', calcByWidth, calcByHeight); console.log('最终格口宽高:', resultWidth); } }, [sowingWallRef, cols, rows]); useEffect(() => { const cur = baskets.find((item) => item.highlighted); if (cur) { // todo 判断是否在可视区域,不在的话需要滚动展示 } }, [baskets]); return (
{title && (
{title} {tagList.map((tag) => { return ; })}
)}
{Array.from({ length: rows }).map((rowItem, rowIndex) => { return (
{Array.from({ length: cols }).map((colItem, colIndex) => renderItem(rowIndex, colIndex), )}
); })}
); }