fix: tree gantt block does not display correctly (#2123)
* fix: tree gantt block display error * fix: tree gantt block display error * refactor: code improve * refactor: code improve
This commit is contained in:
parent
6d80593f27
commit
f042a2307a
@ -1,9 +1,9 @@
|
|||||||
import { useField } from '@formily/react';
|
import { useField } from '@formily/react';
|
||||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||||
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
|
||||||
import { TableBlockProvider } from './TableBlockProvider';
|
|
||||||
import { useACLRoleContext } from '../acl/ACLProvider';
|
import { useACLRoleContext } from '../acl/ACLProvider';
|
||||||
import { useCollection } from '../collection-manager/hooks';
|
import { useCollection } from '../collection-manager/hooks';
|
||||||
|
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
||||||
|
import { TableBlockProvider } from './TableBlockProvider';
|
||||||
|
|
||||||
export const GanttBlockContext = createContext<any>({});
|
export const GanttBlockContext = createContext<any>({});
|
||||||
|
|
||||||
@ -13,15 +13,15 @@ const formatData = (
|
|||||||
tasks: any[] = [],
|
tasks: any[] = [],
|
||||||
projectId: any = undefined,
|
projectId: any = undefined,
|
||||||
hideChildren = false,
|
hideChildren = false,
|
||||||
checkPermassion?: Function,
|
checkPermassion?: (any) => boolean,
|
||||||
) => {
|
) => {
|
||||||
data.forEach((item: any) => {
|
data.forEach((item: any) => {
|
||||||
const disable = checkPermassion(item);
|
const disable = checkPermassion(item);
|
||||||
const percent = item[fieldNames.progress] * 100;
|
const percent = item[fieldNames.progress] * 100;
|
||||||
if (item.children && item.children.length) {
|
if (item.children && item.children.length) {
|
||||||
tasks.push({
|
tasks.push({
|
||||||
start: new Date(item[fieldNames.start]),
|
start: new Date(item[fieldNames.start] ?? undefined),
|
||||||
end: new Date(item[fieldNames.end]),
|
end: new Date(item[fieldNames.end] ?? undefined),
|
||||||
name: item[fieldNames.title],
|
name: item[fieldNames.title],
|
||||||
id: item.id + '',
|
id: item.id + '',
|
||||||
type: 'project',
|
type: 'project',
|
||||||
|
@ -1,29 +1,50 @@
|
|||||||
import { ArrayField, createForm } from '@formily/core';
|
import { ArrayField, createForm } from '@formily/core';
|
||||||
import { FormContext, useField, useFieldSchema } from '@formily/react';
|
import { FormContext, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { boolean } from 'mathjs';
|
||||||
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { useCollectionManager } from '../collection-manager';
|
import { useCollectionManager } from '../collection-manager';
|
||||||
import { useFilterBlock } from '../filter-provider/FilterProvider';
|
import { useFilterBlock } from '../filter-provider/FilterProvider';
|
||||||
import { useRecord } from '../record-provider';
|
import { useRecord } from '../record-provider';
|
||||||
import { FixedBlockWrapper, SchemaComponentOptions, removeNullCondition } from '../schema-component';
|
import { FixedBlockWrapper, removeNullCondition, SchemaComponentOptions } from '../schema-component';
|
||||||
import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider';
|
import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider';
|
||||||
import { mergeFilter } from './SharedFilterProvider';
|
|
||||||
import { findFilterTargets } from './hooks';
|
import { findFilterTargets } from './hooks';
|
||||||
|
import { mergeFilter } from './SharedFilterProvider';
|
||||||
|
|
||||||
export const TableBlockContext = createContext<any>({});
|
export const TableBlockContext = createContext<any>({});
|
||||||
|
export function getIdsWithChildren(nodes) {
|
||||||
|
const ids = [];
|
||||||
|
if (nodes) {
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (node?.children && node.children.length > 0) {
|
||||||
|
ids.push(node.id);
|
||||||
|
ids.push(...getIdsWithChildren(node?.children));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
interface Props {
|
interface Props {
|
||||||
params?: any;
|
params?: any;
|
||||||
showIndex?: boolean;
|
showIndex?: boolean;
|
||||||
dragSort?: boolean;
|
dragSort?: boolean;
|
||||||
rowKey?: string;
|
rowKey?: string;
|
||||||
childrenColumnName: any;
|
childrenColumnName: any;
|
||||||
|
fieldNames?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InternalTableBlockProvider = (props: Props) => {
|
const InternalTableBlockProvider = (props: Props) => {
|
||||||
const { params, showIndex, dragSort, rowKey, childrenColumnName } = props;
|
const { params, showIndex, dragSort, rowKey, childrenColumnName, fieldNames } = props;
|
||||||
const field: any = useField();
|
const field: any = useField();
|
||||||
const { resource, service } = useBlockRequestContext();
|
const { resource, service } = useBlockRequestContext();
|
||||||
const [expandFlag, setExpandFlag] = useState(false);
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { treeTable } = fieldSchema?.['x-decorator-props'] || {};
|
||||||
|
const [expandFlag, setExpandFlag] = useState(fieldNames ? true : false);
|
||||||
|
const allIncludesChildren = useMemo(() => {
|
||||||
|
if (treeTable !== false) {
|
||||||
|
const keys = getIdsWithChildren(service?.data?.data);
|
||||||
|
return keys || [];
|
||||||
|
}
|
||||||
|
}, [service?.loading]);
|
||||||
return (
|
return (
|
||||||
<FixedBlockWrapper>
|
<FixedBlockWrapper>
|
||||||
<TableBlockContext.Provider
|
<TableBlockContext.Provider
|
||||||
@ -37,6 +58,7 @@ const InternalTableBlockProvider = (props: Props) => {
|
|||||||
rowKey,
|
rowKey,
|
||||||
expandFlag,
|
expandFlag,
|
||||||
childrenColumnName,
|
childrenColumnName,
|
||||||
|
allIncludesChildren,
|
||||||
setExpandFlag: () => setExpandFlag(!expandFlag),
|
setExpandFlag: () => setExpandFlag(!expandFlag),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -133,7 +133,6 @@ export const Gantt: any = (props: any) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
tableCtx.field.onExpandClick = handleTableExpanderClick;
|
tableCtx.field.onExpandClick = handleTableExpanderClick;
|
||||||
tableCtx.field.onRowSelect = handleRowSelect;
|
tableCtx.field.onRowSelect = handleRowSelect;
|
||||||
tableCtx.setExpandFlag(true);
|
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
expandAndCollapseAll?.(!expandFlag);
|
expandAndCollapseAll?.(!expandFlag);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { ReactChild } from 'react';
|
|
||||||
import { cx } from '@emotion/css';
|
import { cx } from '@emotion/css';
|
||||||
import { Task } from '../../types/public-types';
|
|
||||||
import { addToDate } from '../../helpers/date-helper';
|
|
||||||
import { gridRowLine, gridRow, gridTick, gridHeightRow } from './style';
|
|
||||||
import { uid } from '@nocobase/utils/client';
|
import { uid } from '@nocobase/utils/client';
|
||||||
|
import React, { ReactChild } from 'react';
|
||||||
|
import { addToDate } from '../../helpers/date-helper';
|
||||||
|
import { Task } from '../../types/public-types';
|
||||||
|
import { gridHeightRow, gridRow, gridRowLine, gridTick } from './style';
|
||||||
|
|
||||||
export type GridBodyProps = {
|
export type GridBodyProps = {
|
||||||
tasks: Task[];
|
tasks: Task[];
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
|
||||||
import { cx } from '@emotion/css';
|
import { cx } from '@emotion/css';
|
||||||
|
import React from 'react';
|
||||||
import { getProgressPoint } from '../../../helpers/bar-helper';
|
import { getProgressPoint } from '../../../helpers/bar-helper';
|
||||||
|
import { TaskItemProps } from '../task-item';
|
||||||
import { BarDisplay } from './bar-display';
|
import { BarDisplay } from './bar-display';
|
||||||
import { BarProgressHandle } from './bar-progress-handle';
|
import { BarProgressHandle } from './bar-progress-handle';
|
||||||
import { TaskItemProps } from '../task-item';
|
|
||||||
import { barWrapper } from './style';
|
import { barWrapper } from './style';
|
||||||
|
|
||||||
export const BarSmall: React.FC<TaskItemProps> = ({
|
export const BarSmall: React.FC<TaskItemProps> = ({
|
||||||
|
@ -102,7 +102,9 @@ export const TaskItem: React.FC<TaskItemProps> = (props) => {
|
|||||||
className={isProjectBar ? cx(projectLabel) : isTextInside ? cx(barLabel) : cx(barLabel) && cx(barLabelOutside)}
|
className={isProjectBar ? cx(projectLabel) : isTextInside ? cx(barLabel) : cx(barLabel) && cx(barLabelOutside)}
|
||||||
ref={textRef}
|
ref={textRef}
|
||||||
>
|
>
|
||||||
{isProjectBar ? `${task.name}: ${getYmd(task.start)} ~ ${getYmd(task.end)}` : task.name}
|
{isProjectBar && getYmd(task.start) && getYmd(task.end)
|
||||||
|
? `${task.name}: ${getYmd(task.start)} ~ ${getYmd(task.end)}`
|
||||||
|
: task.name}
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Task } from '../types/public-types';
|
|
||||||
import { BarTask, TaskTypeInternal } from '../types/bar-task';
|
import { BarTask, TaskTypeInternal } from '../types/bar-task';
|
||||||
import { BarMoveAction } from '../types/gantt-task-actions';
|
import { BarMoveAction } from '../types/gantt-task-actions';
|
||||||
|
import { Task } from '../types/public-types';
|
||||||
|
|
||||||
export const convertToBarTasks = (
|
export const convertToBarTasks = (
|
||||||
tasks: Task[],
|
tasks: Task[],
|
||||||
@ -161,7 +161,7 @@ const convertToBar = (
|
|||||||
let typeInternal: TaskTypeInternal = task.type;
|
let typeInternal: TaskTypeInternal = task.type;
|
||||||
if (typeInternal === 'task' && x2 - x1 < handleWidth * 2) {
|
if (typeInternal === 'task' && x2 - x1 < handleWidth * 2) {
|
||||||
typeInternal = 'smalltask';
|
typeInternal = 'smalltask';
|
||||||
x2 = x1 + handleWidth * 2;
|
x2 = x1 > 0 ? x1 + handleWidth * 2 : x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [progressWidth, progressX] = progressWithByParams(x1, x2, task.progress, rtl);
|
const [progressWidth, progressX] = progressWithByParams(x1, x2, task.progress, rtl);
|
||||||
@ -244,20 +244,19 @@ const convertToMilestone = (
|
|||||||
|
|
||||||
const taskXCoordinate = (xDate: Date, dates: Date[], columnWidth: number) => {
|
const taskXCoordinate = (xDate: Date, dates: Date[], columnWidth: number) => {
|
||||||
const index = dates.findIndex((d) => d?.getTime() >= xDate?.getTime()) - 1;
|
const index = dates.findIndex((d) => d?.getTime() >= xDate?.getTime()) - 1;
|
||||||
|
|
||||||
const remainderMillis = xDate?.getTime() - dates[index]?.getTime();
|
const remainderMillis = xDate?.getTime() - dates[index]?.getTime();
|
||||||
const percentOfInterval = remainderMillis / (dates[index + 1]?.getTime() - dates[index]?.getTime());
|
const percentOfInterval = remainderMillis / (dates[index + 1]?.getTime() - dates[index]?.getTime());
|
||||||
const x = index * columnWidth + percentOfInterval * columnWidth;
|
const x = index * columnWidth + percentOfInterval * columnWidth;
|
||||||
return x;
|
return isNaN(x) ? 0 : x;
|
||||||
};
|
};
|
||||||
const taskXCoordinateRTL = (xDate: Date, dates: Date[], columnWidth: number) => {
|
const taskXCoordinateRTL = (xDate: Date, dates: Date[], columnWidth: number) => {
|
||||||
let x = taskXCoordinate(xDate, dates, columnWidth);
|
let x = taskXCoordinate(xDate, dates, columnWidth);
|
||||||
x += columnWidth;
|
x += columnWidth;
|
||||||
return x;
|
return isNaN(x) ? 0 : x;
|
||||||
};
|
};
|
||||||
const taskYCoordinate = (index: number, rowHeight: number, taskHeight: number) => {
|
const taskYCoordinate = (index: number, rowHeight: number, taskHeight: number) => {
|
||||||
const y = index * rowHeight + (rowHeight - taskHeight) / 2;
|
const y = index * rowHeight + (rowHeight - taskHeight) / 2;
|
||||||
return y;
|
return isNaN(y) ? 0 : y;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const progressWithByParams = (taskX1: number, taskX2: number, progress: number, rtl: boolean) => {
|
export const progressWithByParams = (taskX1: number, taskX2: number, progress: number, rtl: boolean) => {
|
||||||
|
@ -57,5 +57,7 @@ export const sortTasks = (taskA: Task, taskB: Task) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getYmd = (date: Date) => {
|
export const getYmd = (date: Date) => {
|
||||||
return date.getFullYear() + '/' + `${date.getMonth() + 1}` + '/' + date.getDate();
|
if (!isNaN(date.getTime())) {
|
||||||
|
return date.getFullYear() + '/' + `${date.getMonth() + 1}` + '/' + date.getDate();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,7 @@ import { SortableContext, useSortable } from '@dnd-kit/sortable';
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { ArrayField, Field } from '@formily/core';
|
import { ArrayField, Field } from '@formily/core';
|
||||||
import { spliceArrayState } from '@formily/core/esm/shared/internals';
|
import { spliceArrayState } from '@formily/core/esm/shared/internals';
|
||||||
import { RecursionField, Schema, observer, useField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
import { action, reaction } from '@formily/reactive';
|
import { action, reaction } from '@formily/reactive';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Table as AntdTable, TableColumnProps } from 'antd';
|
import { Table as AntdTable, TableColumnProps } from 'antd';
|
||||||
@ -19,7 +19,7 @@ import {
|
|||||||
useTableSelectorContext,
|
useTableSelectorContext,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
||||||
import { extractIndex, getIdsWithChildren, isCollectionFieldComponent, isColumnComponent } from './utils';
|
import { extractIndex, isCollectionFieldComponent, isColumnComponent } from './utils';
|
||||||
|
|
||||||
const useArrayField = (props) => {
|
const useArrayField = (props) => {
|
||||||
const field = useField<ArrayField>();
|
const field = useField<ArrayField>();
|
||||||
@ -213,18 +213,14 @@ export const Table: any = observer(
|
|||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const isTableSelector = schema?.parent?.['x-decorator'] === 'TableSelectorProvider';
|
const isTableSelector = schema?.parent?.['x-decorator'] === 'TableSelectorProvider';
|
||||||
const ctx = isTableSelector ? useTableSelectorContext() : useTableBlockContext();
|
const ctx = isTableSelector ? useTableSelectorContext() : useTableBlockContext();
|
||||||
const { expandFlag } = ctx;
|
const { expandFlag, allIncludesChildren } = ctx;
|
||||||
const onRowDragEnd = useMemoizedFn(others.onRowDragEnd || (() => {}));
|
const onRowDragEnd = useMemoizedFn(others.onRowDragEnd || (() => {}));
|
||||||
const paginationProps = usePaginationProps(pagination1, pagination2);
|
const paginationProps = usePaginationProps(pagination1, pagination2);
|
||||||
// const requiredValidator = field.required || required;
|
|
||||||
const { treeTable } = schema?.parent?.['x-decorator-props'] || {};
|
|
||||||
const [expandedKeys, setExpandesKeys] = useState([]);
|
const [expandedKeys, setExpandesKeys] = useState([]);
|
||||||
const [allIncludesChildren, setAllIncludesChildren] = useState([]);
|
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>(field?.data?.selectedRowKeys || []);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>(field?.data?.selectedRowKeys || []);
|
||||||
const [selectedRow, setSelectedRow] = useState([]);
|
const [selectedRow, setSelectedRow] = useState([]);
|
||||||
const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || [];
|
const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || [];
|
||||||
const isRowSelect = rowSelection?.type !== 'none';
|
const isRowSelect = rowSelection?.type !== 'none';
|
||||||
|
|
||||||
let onRow = null,
|
let onRow = null,
|
||||||
highlightRow = '';
|
highlightRow = '';
|
||||||
|
|
||||||
@ -244,21 +240,6 @@ export const Table: any = observer(
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// field.setValidator((value) => {
|
|
||||||
// if (requiredValidator) {
|
|
||||||
// return Array.isArray(value) && value.length > 0 ? null : 'The field value is required';
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// });
|
|
||||||
// }, [requiredValidator]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (treeTable !== false) {
|
|
||||||
const keys = getIdsWithChildren(field.value?.slice?.());
|
|
||||||
setAllIncludesChildren(keys);
|
|
||||||
}
|
|
||||||
}, [field.value]);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (expandFlag) {
|
if (expandFlag) {
|
||||||
setExpandesKeys(allIncludesChildren);
|
setExpandesKeys(allIncludesChildren);
|
||||||
|
@ -17,16 +17,3 @@ export function extractIndex(str) {
|
|||||||
});
|
});
|
||||||
return numbers.join('.');
|
return numbers.join('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getIdsWithChildren(nodes) {
|
|
||||||
const ids = [];
|
|
||||||
if (nodes) {
|
|
||||||
for (const node of nodes) {
|
|
||||||
if (node?.children && node.children.length > 0) {
|
|
||||||
ids.push(node.id);
|
|
||||||
ids.push(...getIdsWithChildren(node?.children));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user