feat: add score prediction and clear actions to BattleTable
- Add "Clear Current Round" and "Clear All Groups" buttons to reset specific or entire match results. - Implement a summary Table showing current scores, predicted scores after the latest round, and score differentials. - Import necessary Ant Design components (Button, Table) and icons (ClearOutlined). - Refactor `buildMatchGroupTable` to return full arrays instead of filtering out falsy values. - Disable row hover effect in GroupMember table for cleaner appearance.
This commit is contained in:
parent
bb4ca8ae40
commit
56159de837
@ -1,9 +1,10 @@
|
|||||||
import type { BasePlayer } from "../types";
|
import type { BasePlayer } from "../types";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { calculate, getRoundTable } from "../utils/common";
|
import { calculate, getRoundTable } from "../utils/common";
|
||||||
import { Card, Divider, Flex, Space } from "antd";
|
import { Button, Card, Divider, Flex, Space, Table } from "antd";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
|
import { ClearOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
const StyledContainer = styled(Flex)`
|
const StyledContainer = styled(Flex)`
|
||||||
.winer {
|
.winer {
|
||||||
@ -67,7 +68,7 @@ function BattleTable({
|
|||||||
});
|
});
|
||||||
return cloneDeep([left, right]);
|
return cloneDeep([left, right]);
|
||||||
});
|
});
|
||||||
return roundTable.filter(Boolean);
|
return roundTable;
|
||||||
}, []);
|
}, []);
|
||||||
const [matchGroupTable, setMatchGroupTable] = useState<ReturnType<typeof buildMatchGroupTable>>([]);
|
const [matchGroupTable, setMatchGroupTable] = useState<ReturnType<typeof buildMatchGroupTable>>([]);
|
||||||
|
|
||||||
@ -82,6 +83,29 @@ function BattleTable({
|
|||||||
}
|
}
|
||||||
setMatchGroupTable(buildMatchGroupTable(playerList));
|
setMatchGroupTable(buildMatchGroupTable(playerList));
|
||||||
}, []);
|
}, []);
|
||||||
|
const handleClear = useCallback((left?: (BasePlayer | null | undefined)[], right?: (BasePlayer | null | undefined)[]) => {
|
||||||
|
left?.forEach((l, i) => {
|
||||||
|
const r = right?.[i];
|
||||||
|
const key = `${l?.uid}-${r?.uid}`;
|
||||||
|
resultMap.delete(key);
|
||||||
|
});
|
||||||
|
setMatchGroupTable(buildMatchGroupTable(playerList));
|
||||||
|
}, [matchGroupTable, playerList]);
|
||||||
|
const handleClearAll = useCallback(() => {
|
||||||
|
matchGroupTable.forEach(([left, right]) => {
|
||||||
|
left?.forEach((l, i) => {
|
||||||
|
const r = right?.[i];
|
||||||
|
const key = `${l?.uid}-${r?.uid}`;
|
||||||
|
resultMap.delete(key);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setMatchGroupTable(buildMatchGroupTable(playerList));
|
||||||
|
}, [matchGroupTable, playerList]);
|
||||||
|
const scoreDiff = useMemo(() => {
|
||||||
|
const [left = [], right = []] = matchGroupTable?.[matchGroupTable.length - 1] ?? [];
|
||||||
|
const newScoreMap = Object.fromEntries([...left, ...right].map(e => [e?.uid, e?.score]));
|
||||||
|
return newScoreMap;
|
||||||
|
}, [playerList, matchGroupTable]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const roundTable = buildMatchGroupTable(playerList);
|
const roundTable = buildMatchGroupTable(playerList);
|
||||||
setMatchGroupTable(roundTable);
|
setMatchGroupTable(roundTable);
|
||||||
@ -91,7 +115,12 @@ function BattleTable({
|
|||||||
<StyledContainer vertical gap={12} justify="center" align="center">
|
<StyledContainer vertical gap={12} justify="center" align="center">
|
||||||
{matchGroupTable.map(([left, right], i) => {
|
{matchGroupTable.map(([left, right], i) => {
|
||||||
return (
|
return (
|
||||||
<Card size="small" key={`round-${i}`} title={`Round: ${i + 1}`}>
|
<Card
|
||||||
|
size="small"
|
||||||
|
key={`round-${i}`}
|
||||||
|
title={`Round: ${i + 1}`}
|
||||||
|
extra={<Button type="link" onClick={() => handleClear(left, right)} icon={<ClearOutlined />}>清除本轮</Button>}
|
||||||
|
>
|
||||||
{left?.map((l, i) => {
|
{left?.map((l, i) => {
|
||||||
const r = right?.[i];
|
const r = right?.[i];
|
||||||
const key = `${l?.uid}-${r?.uid}`;
|
const key = `${l?.uid}-${r?.uid}`;
|
||||||
@ -115,6 +144,30 @@ function BattleTable({
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
<Table
|
||||||
|
title={() => (
|
||||||
|
<Flex align="center" justify="space-between">
|
||||||
|
<span>积分增减预测</span>
|
||||||
|
<Button type="link" icon={<ClearOutlined />} onClick={handleClearAll}>清除本组所有</Button>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
showHeader={false}
|
||||||
|
pagination={false}
|
||||||
|
rowHoverable={false}
|
||||||
|
size="small"
|
||||||
|
dataSource={playerList}
|
||||||
|
rowKey={e => e.uid}
|
||||||
|
style={{ minWidth: 300 }}
|
||||||
|
columns={[
|
||||||
|
{ dataIndex: 'name' },
|
||||||
|
{ dataIndex: 'score' },
|
||||||
|
{ dataIndex: 'uid', render: (uid, { score }) => scoreDiff[uid] || score },
|
||||||
|
{ dataIndex: 'uid', align: 'right', render: (uid, { score }) => {
|
||||||
|
const diff = +(scoreDiff[uid] || score) - +score;
|
||||||
|
return diff > 0 ? `+${diff}` : diff;
|
||||||
|
} },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ export const GroupMember: React.FC<Props> = props => {
|
|||||||
rowKey={e => `${e.id}-${e.name}-${e.score}`}
|
rowKey={e => `${e.id}-${e.name}-${e.score}`}
|
||||||
showHeader={false}
|
showHeader={false}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
|
rowHoverable={false}
|
||||||
dataSource={props.players}
|
dataSource={props.players}
|
||||||
columns={[
|
columns={[
|
||||||
{ dataIndex: '_', render: (_, __, i) => `(${i + 1})` },
|
{ dataIndex: '_', render: (_, __, i) => `(${i + 1})` },
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user