#
luxiaotao1123
2024-11-04 7f70cb15d035f0c233b9e62b9e43aa985317c908
zy-acs-flow/src/page/mission/MissionListContent.jsx
@@ -1,242 +1,77 @@
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd';
import { Box } from '@mui/material';
import isEqual from 'lodash/isEqual';
import { useEffect, useState } from 'react';
import { DataProvider, useDataProvider, useListContext } from 'react-admin';
import { Deal } from '../types';
import { DealColumn } from './MissionColumn';
import { DealsByStage, getDealsByStage } from './stages';
import { useConfigurationContext } from '../root/ConfigurationContext';
import { DragDropContext } from '@hello-pangea/dnd';
import { Box, LinearProgress } from '@mui/material';
import {
    useDataProvider,
    useListContext,
    useNotify,
    useRefresh,
    useTranslate,
} from 'react-admin';
import { MissionColumn } from './MissionColumn';
import request from '@/utils/request';
import { CUSTOM_PAGES_DATA_INTERVAL } from '@/config/setting';
export const MissionListContent = () => {
    const { dealStages } = useConfigurationContext();
    const { data: unorderedDeals, isPending, refetch } = useListContext();
    const translate = useTranslate();
    const notify = useNotify();
    const refresh = useRefresh();
    const dataProvider = useDataProvider();
    const { data, isPending, refetch } = useListContext();
    const [dealsByStage, setDealsByStage] = useState(
        getDealsByStage([], dealStages)
    );
    const [stages, setStages] = useState([]);
    useEffect(() => {
        if (unorderedDeals) {
            const newDealsByStage = getDealsByStage(unorderedDeals, dealStages);
            if (!isEqual(newDealsByStage, dealsByStage)) {
                setDealsByStage(newDealsByStage);
            }
        const httpStages = async () => {
            request.post('/mission/posType/list').then(res => {
                const { code, msg, data } = res.data;
                if (code === 200) {
                    setStages(data);
                } else {
                    notify(msg || 'common.response.fail', { type: 'error', messageArgs: { _: msg } });
                }
            }).catch(error => {
                notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
            })
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [unorderedDeals]);
        httpStages();
    }, [notify]);
    if (isPending) return null;
    useEffect(() => {
        const intervalId = setInterval(() => {
            refetch();
        }, CUSTOM_PAGES_DATA_INTERVAL);
        return () => clearInterval(intervalId);
    }, [refetch])
    if (isPending) return <LinearProgress />;
    const onDragEnd = result => {
        const { destination, source } = result;
        if (!destination) {
            return;
        }
        const { droppableId: sourceStage, index: sourceIdx } = source;
        const { droppableId: destinationStage, index: destinationIdx } = destination;
        if (
            destination.droppableId === source.droppableId &&
            destination.index === source.index
        ) {
        if (destinationStage === sourceStage
            && destinationIdx === sourceIdx) {
            return;
        }
        const sourceStage = source.droppableId;
        const destinationStage = destination.droppableId;
        const sourceDeal = dealsByStage[sourceStage][source.index];
        const destinationDeal = dealsByStage[destinationStage][
            destination.index
        ] ?? {
            stage: destinationStage,
            index: undefined, // undefined if dropped after the last item
        };
        // compute local state change synchronously
        setDealsByStage(
            updateDealStageLocal(
                sourceDeal,
                { stage: sourceStage, index: source.index },
                { stage: destinationStage, index: destination.index },
                dealsByStage
            )
        );
        // persist the changes
        updateDealStage(sourceDeal, destinationDeal, dataProvider).then(() => {
            refetch();
        });
    };
    return (
        <DragDropContext onDragEnd={onDragEnd}>
            <Box display="flex">
                {dealStages.map(stage => (
                    <DealColumn
                        stage={stage.value}
                        deals={dealsByStage[stage.value]}
                        key={stage.value}
                {stages.map(stage => (
                    <MissionColumn
                        key={stage}
                        stage={stage}
                        missions={data.filter(item => item.posType === stage)}
                    />
                ))}
            </Box>
        </DragDropContext>
    );
};
const updateDealStageLocal = (
    sourceDeal,
    source,
    destination,
    dealsByStage
) => {
    if (source.stage === destination.stage) {
        // moving deal inside the same column
        const column = dealsByStage[source.stage];
        column.splice(source.index, 1);
        column.splice(destination.index ?? column.length + 1, 0, sourceDeal);
        return {
            ...dealsByStage,
            [destination.stage]: column,
        };
    } else {
        // moving deal across columns
        const sourceColumn = dealsByStage[source.stage];
        const destinationColumn = dealsByStage[destination.stage];
        sourceColumn.splice(source.index, 1);
        destinationColumn.splice(
            destination.index ?? destinationColumn.length + 1,
            0,
            sourceDeal
        );
        return {
            ...dealsByStage,
            [source.stage]: sourceColumn,
            [destination.stage]: destinationColumn,
        };
    }
};
const updateDealStage = async (
    source,
    destination,
    dataProvider
) => {
    if (source.stage === destination.stage) {
        // moving deal inside the same column
        // Fetch all the deals in this stage (because the list may be filtered, but we need to update even non-filtered deals)
        const { data: columnDeals } = await dataProvider.getList('deals', {
            sort: { field: 'index', order: 'ASC' },
            pagination: { page: 1, perPage: 100 },
            filter: { stage: source.stage },
        });
        const destinationIndex = destination.index ?? columnDeals.length + 1;
        if (source.index > destinationIndex) {
            // deal moved up, eg
            // dest   src
            //  <------
            // [4, 7, 23, 5]
            await Promise.all([
                // for all deals between destinationIndex and source.index, increase the index
                ...columnDeals
                    .filter(
                        deal =>
                            deal.index >= destinationIndex &&
                            deal.index < source.index
                    )
                    .map(deal =>
                        dataProvider.update('deals', {
                            id: deal.id,
                            data: { index: deal.index + 1 },
                            previousData: deal,
                        })
                    ),
                // for the deal that was moved, update its index
                dataProvider.update('deals', {
                    id: source.id,
                    data: { index: destinationIndex },
                    previousData: source,
                }),
            ]);
        } else {
            // deal moved down, e.g
            // src   dest
            //  ------>
            // [4, 7, 23, 5]
            await Promise.all([
                // for all deals between source.index and destinationIndex, decrease the index
                ...columnDeals
                    .filter(
                        deal =>
                            deal.index <= destinationIndex &&
                            deal.index > source.index
                    )
                    .map(deal =>
                        dataProvider.update('deals', {
                            id: deal.id,
                            data: { index: deal.index - 1 },
                            previousData: deal,
                        })
                    ),
                // for the deal that was moved, update its index
                dataProvider.update('deals', {
                    id: source.id,
                    data: { index: destinationIndex },
                    previousData: source,
                }),
            ]);
        }
    } else {
        // moving deal across columns
        // Fetch all the deals in both stages (because the list may be filtered, but we need to update even non-filtered deals)
        const [{ data: sourceDeals }, { data: destinationDeals }] =
            await Promise.all([
                dataProvider.getList('deals', {
                    sort: { field: 'index', order: 'ASC' },
                    pagination: { page: 1, perPage: 100 },
                    filter: { stage: source.stage },
                }),
                dataProvider.getList('deals', {
                    sort: { field: 'index', order: 'ASC' },
                    pagination: { page: 1, perPage: 100 },
                    filter: { stage: destination.stage },
                }),
            ]);
        const destinationIndex =
            destination.index ?? destinationDeals.length + 1;
        await Promise.all([
            // decrease index on the deals after the source index in the source columns
            ...sourceDeals
                .filter(deal => deal.index > source.index)
                .map(deal =>
                    dataProvider.update('deals', {
                        id: deal.id,
                        data: { index: deal.index - 1 },
                        previousData: deal,
                    })
                ),
            // increase index on the deals after the destination index in the destination columns
            ...destinationDeals
                .filter(deal => deal.index >= destinationIndex)
                .map(deal =>
                    dataProvider.update('deals', {
                        id: deal.id,
                        data: { index: deal.index + 1 },
                        previousData: deal,
                    })
                ),
            // change the dragged deal to take the destination index and column
            dataProvider.update('deals', {
                id: source.id,
                data: {
                    index: destinationIndex,
                    stage: destination.stage,
                },
                previousData: source,
            }),
        ]);
    }
};