mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 21:14:21 +08:00
精简看板顶部操作并移除看板配置区
This commit is contained in:
@@ -83,6 +83,11 @@ interface DragState {
|
|||||||
containerSize: number
|
containerSize: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getFirstLeafId = (node: LayoutNode): string => {
|
||||||
|
if (node.type === "leaf") return node.id
|
||||||
|
return getFirstLeafId(node.first)
|
||||||
|
}
|
||||||
|
|
||||||
const makeId = () =>
|
const makeId = () =>
|
||||||
typeof crypto !== "undefined" && "randomUUID" in crypto
|
typeof crypto !== "undefined" && "randomUUID" in crypto
|
||||||
? crypto.randomUUID()
|
? crypto.randomUUID()
|
||||||
@@ -345,6 +350,9 @@ export const BoardManager: React.FC<BoardManagerProps> = ({ canManage }) => {
|
|||||||
const [errorMap, setErrorMap] = useState<Record<string, string>>({})
|
const [errorMap, setErrorMap] = useState<Record<string, string>>({})
|
||||||
const [dragState, setDragState] = useState<DragState | null>(null)
|
const [dragState, setDragState] = useState<DragState | null>(null)
|
||||||
const [editingListId, setEditingListId] = useState<string | null>(null)
|
const [editingListId, setEditingListId] = useState<string | null>(null)
|
||||||
|
const [selectedLeafNodeId, setSelectedLeafNodeId] = useState<string | null>(null)
|
||||||
|
const [renameVisible, setRenameVisible] = useState(false)
|
||||||
|
const [renameValue, setRenameValue] = useState("")
|
||||||
|
|
||||||
const panelRefs = useRef<Record<string, HTMLDivElement | null>>({})
|
const panelRefs = useRef<Record<string, HTMLDivElement | null>>({})
|
||||||
|
|
||||||
@@ -511,6 +519,15 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
if (!activeBoardId && boards.length > 0) setActiveBoardId(boards[0].id)
|
if (!activeBoardId && boards.length > 0) setActiveBoardId(boards[0].id)
|
||||||
}, [activeBoardId, boards])
|
}, [activeBoardId, boards])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!activeBoard) {
|
||||||
|
setSelectedLeafNodeId(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const firstLeafId = getFirstLeafId(activeBoard.layout)
|
||||||
|
setSelectedLeafNodeId((prev) => prev || firstLeafId)
|
||||||
|
}, [activeBoard?.id, activeBoard?.layout])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeBoard) return
|
if (!activeBoard) return
|
||||||
runAllInBoard(activeBoard).catch(() => void 0)
|
runAllInBoard(activeBoard).catch(() => void 0)
|
||||||
@@ -567,6 +584,18 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openRenameModal = () => {
|
||||||
|
if (!activeBoard) return
|
||||||
|
setRenameValue(activeBoard.name)
|
||||||
|
setRenameVisible(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitRenameBoard = () => {
|
||||||
|
if (!activeBoard) return
|
||||||
|
updateBoardName(activeBoard.id, renameValue.trim() || t("board.untitledBoard"))
|
||||||
|
setRenameVisible(false)
|
||||||
|
}
|
||||||
|
|
||||||
const addBoard = () => {
|
const addBoard = () => {
|
||||||
if (!canManage) return
|
if (!canManage) return
|
||||||
const newBoard = createDefaultBoard()
|
const newBoard = createDefaultBoard()
|
||||||
@@ -628,6 +657,11 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const splitSelectedLeaf = (direction: SplitDirection) => {
|
||||||
|
if (!activeBoard || !selectedLeafNodeId) return
|
||||||
|
addListBySplit(activeBoard.id, selectedLeafNodeId, direction)
|
||||||
|
}
|
||||||
|
|
||||||
const removeList = (boardId: string, listId: string) => {
|
const removeList = (boardId: string, listId: string) => {
|
||||||
if (!canManage) return
|
if (!canManage) return
|
||||||
|
|
||||||
@@ -874,10 +908,18 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
const renderLeafPanel = (board: BoardConfig, leaf: LayoutLeafNode): React.JSX.Element => {
|
const renderLeafPanel = (board: BoardConfig, leaf: LayoutLeafNode): React.JSX.Element => {
|
||||||
const list = board.lists.find((item) => item.id === leaf.listId)
|
const list = board.lists.find((item) => item.id === leaf.listId)
|
||||||
if (!list) return <Empty description={t("common.noData")} />
|
if (!list) return <Empty description={t("common.noData")} />
|
||||||
|
const isSelected = selectedLeafNodeId === leaf.id
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
style={{ height: "100%", backgroundColor: "var(--ss-card-bg)", border: "1px solid var(--ss-border-color)" }}
|
onClick={() => setSelectedLeafNodeId(leaf.id)}
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
backgroundColor: "var(--ss-card-bg)",
|
||||||
|
border: isSelected ? "1px solid var(--ant-color-primary, #1677ff)" : "1px solid var(--ss-border-color)",
|
||||||
|
boxShadow: isSelected ? "0 8px 18px rgba(22, 119, 255, 0.14)" : undefined,
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
styles={{ body: { height: "100%", display: "flex", flexDirection: "column", padding: 12 } }}
|
styles={{ body: { height: "100%", display: "flex", flexDirection: "column", padding: 12 } }}
|
||||||
title={<span style={{ fontWeight: 600 }}>{list.name}</span>}
|
title={<span style={{ fontWeight: 600 }}>{list.name}</span>}
|
||||||
extra={
|
extra={
|
||||||
@@ -888,12 +930,6 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
<Button size="small" onClick={() => setEditingListId(list.id)} icon={<EditOutlined />}>
|
<Button size="small" onClick={() => setEditingListId(list.id)} icon={<EditOutlined />}>
|
||||||
{t("board.editList")}
|
{t("board.editList")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="small" disabled={!canManage} onClick={() => addListBySplit(board.id, leaf.id, "horizontal")}>
|
|
||||||
{t("board.splitHorizontal")}
|
|
||||||
</Button>
|
|
||||||
<Button size="small" disabled={!canManage} onClick={() => addListBySplit(board.id, leaf.id, "vertical")}>
|
|
||||||
{t("board.splitVertical")}
|
|
||||||
</Button>
|
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={t("board.removeListConfirm")}
|
title={t("board.removeListConfirm")}
|
||||||
onConfirm={() => removeList(board.id, list.id)}
|
onConfirm={() => removeList(board.id, list.id)}
|
||||||
@@ -996,6 +1032,23 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
<Tag color={canManage ? "success" : "default"}>{canManage ? t("board.editable") : t("board.readonly")}</Tag>
|
<Tag color={canManage ? "success" : "default"}>{canManage ? t("board.editable") : t("board.readonly")}</Tag>
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
|
<Button
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={() => splitSelectedLeaf("horizontal")}
|
||||||
|
disabled={!canManage || !activeBoard || !selectedLeafNodeId}
|
||||||
|
>
|
||||||
|
{t("board.splitHorizontal")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={() => splitSelectedLeaf("vertical")}
|
||||||
|
disabled={!canManage || !activeBoard || !selectedLeafNodeId}
|
||||||
|
>
|
||||||
|
{t("board.splitVertical")}
|
||||||
|
</Button>
|
||||||
|
<Button icon={<EditOutlined />} onClick={openRenameModal} disabled={!canManage || !activeBoard}>
|
||||||
|
{t("board.renameBoard")}
|
||||||
|
</Button>
|
||||||
<Button icon={<ReloadOutlined />} loading={loading} onClick={fetchBoards}>
|
<Button icon={<ReloadOutlined />} loading={loading} onClick={fetchBoards}>
|
||||||
{t("common.refresh")}
|
{t("common.refresh")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1016,34 +1069,17 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
|
|
||||||
{activeBoard ? (
|
{activeBoard ? (
|
||||||
<Space direction="vertical" size={16} style={{ width: "100%" }}>
|
<Space direction="vertical" size={16} style={{ width: "100%" }}>
|
||||||
<Card
|
<Space>
|
||||||
title={t("board.boardConfig")}
|
<Button onClick={() => runAllInBoard(activeBoard)} icon={<PlayCircleOutlined />}>
|
||||||
extra={
|
{t("board.runAll")}
|
||||||
<Space>
|
</Button>
|
||||||
<Button onClick={() => runAllInBoard(activeBoard)} icon={<PlayCircleOutlined />}>
|
<Popconfirm title={t("board.removeBoardConfirm")} onConfirm={() => removeBoard(activeBoard.id)} disabled={!canManage}>
|
||||||
{t("board.runAll")}
|
<Button danger icon={<DeleteOutlined />} disabled={!canManage}>
|
||||||
</Button>
|
{t("board.removeBoard")}
|
||||||
<Popconfirm title={t("board.removeBoardConfirm")} onConfirm={() => removeBoard(activeBoard.id)} disabled={!canManage}>
|
</Button>
|
||||||
<Button danger icon={<DeleteOutlined />} disabled={!canManage}>
|
</Popconfirm>
|
||||||
{t("board.removeBoard")}
|
{saving && <Typography.Text type="secondary">{t("board.saving")}</Typography.Text>}
|
||||||
</Button>
|
</Space>
|
||||||
</Popconfirm>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
style={{ backgroundColor: "var(--ss-card-bg)" }}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
value={activeBoard.name}
|
|
||||||
onChange={(e) => updateBoardName(activeBoard.id, e.target.value.trim())}
|
|
||||||
placeholder={t("board.boardNamePlaceholder")}
|
|
||||||
disabled={!canManage}
|
|
||||||
/>
|
|
||||||
{saving && (
|
|
||||||
<Typography.Text type="secondary" style={{ display: "block", marginTop: 8 }}>
|
|
||||||
{t("board.saving")}
|
|
||||||
</Typography.Text>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{renderBoardWorkspace()}
|
{renderBoardWorkspace()}
|
||||||
</Space>
|
</Space>
|
||||||
@@ -1054,6 +1090,17 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={t("board.renameBoard")}
|
||||||
|
open={renameVisible}
|
||||||
|
onCancel={() => setRenameVisible(false)}
|
||||||
|
onOk={submitRenameBoard}
|
||||||
|
okText={t("common.confirm")}
|
||||||
|
cancelText={t("common.cancel")}
|
||||||
|
>
|
||||||
|
<Input value={renameValue} onChange={(e) => setRenameValue(e.target.value)} placeholder={t("board.boardNamePlaceholder")} />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
title={t("board.sqlEditorTitle")}
|
title={t("board.sqlEditorTitle")}
|
||||||
open={Boolean(editingList)}
|
open={Boolean(editingList)}
|
||||||
|
|||||||
@@ -568,6 +568,7 @@
|
|||||||
"removeBoardConfirm": "Delete current board?",
|
"removeBoardConfirm": "Delete current board?",
|
||||||
"boardConfig": "Board Config",
|
"boardConfig": "Board Config",
|
||||||
"boardNamePlaceholder": "Enter board name",
|
"boardNamePlaceholder": "Enter board name",
|
||||||
|
"renameBoard": "Rename Board",
|
||||||
"newBoard": "New Board",
|
"newBoard": "New Board",
|
||||||
"untitledBoard": "Untitled Board",
|
"untitledBoard": "Untitled Board",
|
||||||
"addList": "Add Student List",
|
"addList": "Add Student List",
|
||||||
|
|||||||
@@ -568,6 +568,7 @@
|
|||||||
"removeBoardConfirm": "确认删除当前看板?",
|
"removeBoardConfirm": "确认删除当前看板?",
|
||||||
"boardConfig": "看板配置",
|
"boardConfig": "看板配置",
|
||||||
"boardNamePlaceholder": "输入看板名称",
|
"boardNamePlaceholder": "输入看板名称",
|
||||||
|
"renameBoard": "重命名看板",
|
||||||
"newBoard": "新看板",
|
"newBoard": "新看板",
|
||||||
"untitledBoard": "未命名看板",
|
"untitledBoard": "未命名看板",
|
||||||
"addList": "新增学生列表",
|
"addList": "新增学生列表",
|
||||||
|
|||||||
Reference in New Issue
Block a user