import React, { useMemo, useState, useCallback, memo } from "react"; import "./index.css"; import { TickerListProps, TickerDisplayItemProps } from "./interface"; import { StarIcon } from "@icons/StarIcon"; import SearchInput from "./SearchInput"; import TradeTabs from "./TradeTabs"; import BasicCustomTable, { ColumnProps } from "./BasicCustomTable"; import Symbol from "./Symbol"; import Cell from "./Cell"; import LineChart from "./LineChart"; import { formatFloor, formatMoney, formatMillionMoney, getDecimalNumber, toDefaultNumber } from "@utils/FormatNumber"; import { filter, ifElse } from "ramda"; import { toSearchByKeyword } from "./searchUtil"; import { TradeTypeEnum } from "@shared/types"; /**24h涨跌符号 */ const formatChangeMark = (value: number) => { if (value > 0) { return "+"; } if (value < 0) { return "-"; } return ""; }; /**表示自选 */ const FAV = "FAV"; /** * 市场列表组件 * * * ### 引用方法 * ```tsx * import { TickerList } from "@atomintl/exchange-ui" * ``` */ const TickerList: React.FC = props => { const { currentSymbol, tradeType, tickerTradeTabList, margin, rfColor = true, dataSource, symbolPriceChartMaps, favoritePairs, onChangeLikes, onChangeTickerPair } = props; /**tab默认选中项 */ const [tradeTabActiveKey, setTradeTabActiveKey] = useState(tradeType); /**搜索框的值 */ const [searchValue, setSearchValue] = useState(""); /**切换更新交易对 */ const toUpdateTickerPair = useCallback( (record: TickerDisplayItemProps) => { onChangeTickerPair(record); }, [onChangeTickerPair] ); /**获取涨跌颜色:* 紅漲綠跌true * 綠漲紅跌false*/ const getRfColor = useCallback((ud: string, rfColor?: boolean) => { const isAdd = ud === "+"; if (rfColor) { return isAdd ? "!text-red-7" : "!text-green"; } return isAdd ? "!text-green" : "!text-red-7"; }, []); /** lineChart的线条颜色 */ const getLineChartColor = useCallback((color: string) => { if (color.indexOf("text-red-7") > -1) { return "#FF3B30"; } if (color.indexOf("text-green") > -1) { return "#34C759"; } return "#007AFF"; }, []); /**table列表 */ const columns: ColumnProps[] = useMemo( () => [ { code: "base", name: "合约", features: { sortable: true }, render: (_value, row: TickerDisplayItemProps) => ( onChangeLikes(row.symbol, !row.like)} onClick={() => toUpdateTickerPair(row)} className={"nts-column"} /> ) }, { code: "latestPrice", name: "最新价格", features: { sortable: true }, width: 125, render: (_value, row: TickerDisplayItemProps) => ( toUpdateTickerPair(row)}> {formatMoney(formatFloor(_value, row.tickSizeScale))} ) }, { code: "change", name: "24h涨跌", features: { sortable: true }, width: 100, render: (_value, row: TickerDisplayItemProps) => ( toUpdateTickerPair(row)} > {row.changeMark} {formatFloor(Math.abs(_value || 0), 2)}% ) }, { code: "volume", name: "成交量", align: "right", features: { sortable: true }, width: 100, render: (_value, row: TickerDisplayItemProps) => ( toUpdateTickerPair(row)}> {formatMoney(formatMillionMoney(_value, row.volumeScale))} ) } // 暂时去掉这个线。无api,和产品Wayne Yao沟通了 // { // code: "symbol", // name: "30m价格趋势", // width: 110, // align: "right", // render: (_value, row: TickerDisplayItemProps) => ( // // ) // } ], [margin, rfColor, symbolPriceChartMaps] ); const isFutures = useMemo( () => tradeType === TradeTypeEnum.Inverse || tradeType === TradeTypeEnum.Linear, [tradeType] ); /**循环设置涨跌符号 * 涨(+)/跌(-) */ const tickerDataSource = useMemo(() => { const newList: TickerDisplayItemProps[] = []; if (dataSource?.length) { for (let index = 0; index < dataSource.length; index++) { const item = dataSource[index]; const tickSizeScale = item.tickSizeScale ?? 8; const volumeScale = item.volumeScale ?? 2; newList.push( Object.assign(item, { changeMark: formatChangeMark(toDefaultNumber(item.change)), like: favoritePairs.includes(item.symbol), tickSizeScale, volumeScale }) ); } } return newList; }, [dataSource, favoritePairs]); /**用户自选的 */ const likeList = useMemo(() => filter(item => item.like || false, tickerDataSource), [tickerDataSource]); /**用户是否有自选 */ // const hasFAV = useMemo(() => likeList.length > 0, [likeList]); /**tab的自选标记星号 */ const tabsList = useMemo(() => { if (tickerTradeTabList.length) { return tickerTradeTabList.map(item => item.value === FAV ? { label: ( <> {item.label} ), value: item.value } : item ); } return tickerTradeTabList; }, [tickerTradeTabList]); /**类型筛选 */ const tickerList = useMemo(() => { // 自选 if (tradeTabActiveKey === FAV) { return likeList; } // 合约匹配业务类型/现货杠杆匹配quote const key = isFutures ? "tradeType" : "quote"; return filter(item => item[key] === tradeTabActiveKey, tickerDataSource); }, [tickerDataSource, likeList, tradeTabActiveKey, isFutures]); /**搜索筛选 */ const displayTickerList = useMemo(() => { if (!!searchValue) { return toSearchByKeyword(searchValue, tradeTabActiveKey, tickerList); } return tickerList; }, [tickerList, searchValue, tradeTabActiveKey]); /**更新搜索框的值 */ const onChangeSearchValue = useCallback((e: React.ChangeEvent) => { setSearchValue(e.target.value); }, []); return (
) => event.stopPropagation()}>
setSearchValue("")} />
setTradeTabActiveKey(key)} />
); }; TickerList.defaultProps = { tradeType: TradeTypeEnum.Linear, margin: 1, rfColor: false, favoritePairs: [], dataSource: [] }; export { TickerListProps } from "./interface"; export default memo(TickerList);