Browse Source

实现持久化

master
YuJian920 3 years ago
parent
commit
c58becd7a0
  1. 59
      src/hook/useDragEnd.ts
  2. 12
      src/hook/useKanban.ts
  3. 17
      src/hook/useTask.ts
  4. 29
      src/pages/Kanban/KanbanColumn/index.tsx
  5. 4
      src/pages/Kanban/SearchPanel/index.tsx
  6. 9
      src/pages/Kanban/index.tsx
  7. 8
      src/type/index.ts
  8. 56
      src/utils/reorder.ts

59
src/hook/useDragEnd.ts

@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
import { useCallback } from "react";
import { DropResult } from "react-beautiful-dnd";
import {
useKanbans,
useKanbanSearchParams,
useReorderKanban,
} from "./useKanban";
import { useReorderTask, useTasks, useTasksSearchParams } from "./useTask";
const useDragEnd = () => {
const { data: kanbans } = useKanbans(useKanbanSearchParams());
const { mutate: reorderKanban } = useReorderKanban();
const { data: allTasks = [] } = useTasks(useTasksSearchParams());
const { mutate: reorderTask } = useReorderTask();
return useCallback(
({ source, destination, type }: DropResult) => {
if (!destination) return;
if (type === "COLUMN") {
const fromId = kanbans?.[source.index].id;
const toId = kanbans?.[destination.index].id;
if (!fromId || !toId || fromId === toId) return;
const dndType = source.index > destination.index ? "before" : "after";
reorderKanban({ fromId, referenceId: toId, type: dndType });
}
if (type === "ROW") {
const fromKanbanId = +source.droppableId;
const toKanbanId = +destination.droppableId;
if (fromKanbanId === toKanbanId) return;
const fromTask = allTasks.filter(
(task) => task.kanbanId === fromKanbanId
)[source.index];
const toTask = allTasks.filter((task) => task.kanbanId === toKanbanId)[
destination.index
];
if (fromTask?.id === toTask?.id) return;
reorderTask({
fromId: fromTask?.id,
referenceId: toTask?.id,
fromKanbanId,
toKanbanId,
type:
fromKanbanId === toKanbanId && destination.index > source.index
? "after"
: "before",
});
}
},
[kanbans, reorderKanban, allTasks, reorderTask]
);
};
export default useDragEnd;

12
src/hook/useKanban.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { useMutation, useQuery, useQueryClient, QueryKey } from "react-query";
import { useLocation } from "react-router";
import { Kanban } from "../type";
import { Kanban, SortProps } from "../type";
import { useProject } from "./useProjects";
import useRequest from "./useRequest";
@ -45,3 +45,13 @@ export const useDeleteKanban = () => { @@ -45,3 +45,13 @@ export const useDeleteKanban = () => {
{ onSuccess: () => queryClient.invalidateQueries("kanbans") }
);
};
export const useReorderKanban = () => {
const request = useRequest();
const queryClient = useQueryClient();
return useMutation((params: SortProps) =>
request("/kanbans/reorder", { method: "POST", data: params }),
{ onSuccess: () => queryClient.invalidateQueries("kanbans") }
);
};

17
src/hook/useTask.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { useCallback, useMemo } from "react";
import { QueryKey, useMutation, useQuery, useQueryClient } from "react-query";
import { Task, TaskType } from "../type";
import { SortProps, Task, TaskType } from "../type";
import useDebounce from "./useDebounce";
import { useProjectIdInUrl } from "./useKanban";
import useRequest from "./useRequest";
@ -30,7 +30,7 @@ export const useTasksTypes = (param?: Partial<Task>) => { @@ -30,7 +30,7 @@ export const useTasksTypes = (param?: Partial<Task>) => {
);
};
export const useTasksSearchParmas = () => {
export const useTasksSearchParams = () => {
const [param, setParam] = useUrlQueryParams([
"name",
"typeId",
@ -62,7 +62,7 @@ export const useAddTask = (queryKey: QueryKey) => { @@ -62,7 +62,7 @@ export const useAddTask = (queryKey: QueryKey) => {
);
};
export const useTasksQueryKey = () => ["tasks", useTasksSearchParmas()];
export const useTasksQueryKey = () => ["tasks", useTasksSearchParams()];
export const useTaskModal = () => {
const [{ editingTaskId }, setEditingTaskId] = useUrlQueryParams([
@ -108,3 +108,14 @@ export const useDeleteTask = () => { @@ -108,3 +108,14 @@ export const useDeleteTask = () => {
{ onSuccess: () => queryClient.invalidateQueries("tasks") }
);
};
export const useReorderTask = () => {
const request = useRequest();
const queryClient = useQueryClient();
return useMutation(
(params: SortProps) =>
request("/tasks/reorder", { method: "POST", data: params }),
{ onSuccess: () => queryClient.invalidateQueries("tasks") }
);
};

29
src/pages/Kanban/KanbanColumn/index.tsx

@ -1,12 +1,13 @@ @@ -1,12 +1,13 @@
import { Button, Card, Dropdown, Menu, Modal } from "antd";
import React from "react";
import { Drag, Drop, DropChild } from "../../../components/DragAndDrop";
import { Row } from "../../../components/lib";
import Mark from "../../../components/Mark";
import { useDeleteKanban } from "../../../hook/useKanban";
import {
useTaskModal,
useTasks,
useTasksSearchParmas,
useTasksSearchParams,
useTasksTypes,
} from "../../../hook/useTask";
import { Kanban, Task } from "../../../type";
@ -33,7 +34,7 @@ const TaskTypeIcon = ({ id }: { id: number }) => { @@ -33,7 +34,7 @@ const TaskTypeIcon = ({ id }: { id: number }) => {
const TaskCard = ({ task }: { task: Task }) => {
const { startEdit } = useTaskModal();
const { name: keyword } = useTasksSearchParmas();
const { name: keyword } = useTasksSearchParams();
return (
<Card
onClick={() => startEdit(task.id)}
@ -78,7 +79,7 @@ const More = ({ kanban }: { kanban: Kanban }) => { @@ -78,7 +79,7 @@ const More = ({ kanban }: { kanban: Kanban }) => {
const KanbanColumn = React.forwardRef<HTMLDivElement, { kanban: Kanban }>(
({ kanban, ...props }, ref) => {
const { data: allTasks } = useTasks(useTasksSearchParmas());
const { data: allTasks } = useTasks(useTasksSearchParams());
const tasks = allTasks?.filter((task) => task.kanbanId === kanban.id);
return (
@ -88,9 +89,25 @@ const KanbanColumn = React.forwardRef<HTMLDivElement, { kanban: Kanban }>( @@ -88,9 +89,25 @@ const KanbanColumn = React.forwardRef<HTMLDivElement, { kanban: Kanban }>(
<More kanban={kanban} key={kanban.id} />
</Row>
<TasksContainer>
{tasks?.map((task) => (
<TaskCard key={task.id} task={task} />
))}
<Drop
type="ROW"
direction="vertical"
droppableId={String(kanban.id)}
>
<DropChild>
{tasks?.map((task, taskIndex) => (
<Drag
key={task.id}
index={taskIndex}
draggableId={"task" + task.id}
>
<div>
<TaskCard task={task} key={task.id} />
</div>
</Drag>
))}
</DropChild>
</Drop>
<CreateTask kanbanId={kanban.id} />
</TasksContainer>
</Container>

4
src/pages/Kanban/SearchPanel/index.tsx

@ -4,10 +4,10 @@ import { Row } from "../../../components/lib"; @@ -4,10 +4,10 @@ import { Row } from "../../../components/lib";
import TaskTypeSelect from "../../../components/TaskTypeSelect";
import UserSelect from "../../../components/UserSelect";
import useSetUrlSearchParam from "../../../hook/useSetUrlSearchParam";
import { useTasksSearchParmas } from "../../../hook/useTask";
import { useTasksSearchParams } from "../../../hook/useTask";
const SearchPanel = () => {
const searchParmas = useTasksSearchParmas();
const searchParmas = useTasksSearchParams();
const setSearchParams = useSetUrlSearchParam();
const reset = () => {

9
src/pages/Kanban/index.tsx

@ -3,12 +3,13 @@ import React from "react"; @@ -3,12 +3,13 @@ import React from "react";
import { DragDropContext } from "react-beautiful-dnd";
import { Drag, Drop, DropChild } from "../../components/DragAndDrop";
import useDocumentTitle from "../../hook/useDocumentTitle";
import useDragEnd from "../../hook/useDragEnd";
import {
useKanbans,
useKanbanSearchParams,
useProjectInUrl,
} from "../../hook/useKanban";
import { useTasks, useTasksSearchParmas } from "../../hook/useTask";
import { useTasks, useTasksSearchParams } from "../../hook/useTask";
import CreateKanban from "./CreateKanban";
import KanbanColumn from "./KanbanColumn";
import SearchPanel from "./SearchPanel";
@ -22,11 +23,13 @@ const Kanban = () => { @@ -22,11 +23,13 @@ const Kanban = () => {
const { data: kanbans, isLoading: kanbanIsLoading } = useKanbans(
useKanbanSearchParams()
);
const { isLoading: taskIsLoading } = useTasks(useTasksSearchParmas());
const { isLoading: taskIsLoading } = useTasks(useTasksSearchParams());
const isLoading = taskIsLoading || kanbanIsLoading;
const onDragEnd = useDragEnd()
return (
<DragDropContext onDragEnd={() => {}}>
<DragDropContext onDragEnd={onDragEnd}>
<ScreenContainer>
<h1>{currentProject?.name}</h1>
<SearchPanel />

8
src/type/index.ts

@ -58,3 +58,11 @@ export type DropChildrenProps = Partial< @@ -58,3 +58,11 @@ export type DropChildrenProps = Partial<
export type DragProps = Omit<DraggableProps, "children"> & {
children: ReactNode;
};
export interface SortProps {
fromId: number;
referenceId: number;
type: "before" | "after";
fromKanbanId?: number;
toKanbanId?: number;
}

56
src/utils/reorder.ts

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
/**
*
* @param fromId id
* @param type 'before' | 'after'
* @param referenceId id
* @param list , tasks, kanbans
*/
export const reorder = ({
fromId,
type,
referenceId,
list,
}: {
list: { id: number }[];
fromId: number;
type: "after" | "before";
referenceId: number;
}) => {
const copiedList = [...list];
// 找到fromId对应项目的下标
const movingItemIndex = copiedList.findIndex((item) => item.id === fromId);
if (!referenceId) {
return insertAfter([...copiedList], movingItemIndex, copiedList.length - 1);
}
const targetIndex = copiedList.findIndex((item) => item.id === referenceId);
const insert = type === "after" ? insertAfter : insertBefore;
return insert([...copiedList], movingItemIndex, targetIndex);
};
/**
* list中from放在to的前边
* @param list
* @param from
* @param to
*/
const insertBefore = (list: unknown[], from: number, to: number) => {
const toItem = list[to];
const removedItem = list.splice(from, 1)[0];
const toIndex = list.indexOf(toItem);
list.splice(toIndex, 0, removedItem);
return list;
};
/**
* list中from放在to的后面
* @param list
* @param from
* @param to
*/
const insertAfter = (list: unknown[], from: number, to: number) => {
const toItem = list[to];
const removedItem = list.splice(from, 1)[0];
const toIndex = list.indexOf(toItem);
list.splice(toIndex + 1, 0, removedItem);
return list;
};
Loading…
Cancel
Save