Skip to content

Commit

Permalink
refactor(platform): optimize table
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Mar 14, 2023
1 parent 01176c2 commit d6e9e39
Show file tree
Hide file tree
Showing 9 changed files with 502 additions and 125 deletions.
8 changes: 4 additions & 4 deletions packages/platform/src/app/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export const AppRoutes = React.memo(() => {
title: t('Login', { ns: 'title' }),
},
},
{
path: '/',
element: <AppHomeRoute />,
},
{
path: '/',
element: <AppLayout />,
Expand All @@ -101,10 +105,6 @@ export const AppRoutes = React.memo(() => {
canActivateChild: [tokenGuard],
},
children: [
{
index: true,
element: <AppHomeRoute />,
},
{
path: 'dashboard',
children: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export interface AppDetailViewProps extends Omit<React.HTMLAttributes<HTMLDivEle
content: React.ReactNode;
isEmpty?: boolean;
center?: boolean;
noWrapper?: boolean;
}[];
aCol?: number | true | Partial<Record<'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', number | true>>;
aGutter?: number | [number?, number?];
Expand Down Expand Up @@ -79,7 +78,7 @@ export function AppDetailView(props: AppDetailViewProps): JSX.Element | null {
[`gy-${gutterY}`]: gutterY,
})}
>
{aList.map(({ label, content: _content, isEmpty: _isEmpty, center, noWrapper }) => {
{aList.map(({ label, content: _content, isEmpty: _isEmpty, center }) => {
const isEmpty = isUndefined(_isEmpty)
? (isString(_content) && _content.length === 0) || isUndefined(_content) || isNull(_content)
: _isEmpty;
Expand All @@ -101,7 +100,7 @@ export function AppDetailView(props: AppDetailViewProps): JSX.Element | null {
>
{label}
</div>
{noWrapper ? content : <div className="app-detail-view__item-content">{content}</div>}
<div className="app-detail-view__item-content">{content}</div>
</div>
);
})}
Expand Down
3 changes: 3 additions & 0 deletions packages/platform/src/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@ export { AppRouteHeader } from './route-header';
export type { AppStatusDotProps } from './status-dot';
export { AppStatusDot } from './status-dot';

export type { AppTableProps } from './table';
export { AppTable } from './table';

export type { AppTableFilterProps } from './table-filter';
export { AppTableFilter } from './table-filter';
384 changes: 384 additions & 0 deletions packages/platform/src/app/components/table/Table.tsx

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/platform/src/app/components/table/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Table';
3 changes: 2 additions & 1 deletion packages/platform/src/app/routes/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { isUndefined } from 'lodash';
import { Navigate } from 'react-router-dom';

import { LOGIN_PATH } from '../config/other';
import { useMenu } from '../core';

export default function Home(): JSX.Element | null {
const [{ firstCanActive }] = useMenu();

return isUndefined(firstCanActive) ? null : <Navigate to={firstCanActive.path} replace />;
return <Navigate to={isUndefined(firstCanActive) ? LOGIN_PATH : firstCanActive.path} replace />;
}
214 changes: 97 additions & 117 deletions packages/platform/src/app/routes/list/standard-table/StandardTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import type { DSelectItem } from '@react-devui/ui/components/select';
import { isUndefined } from 'lodash';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';

import { useImmer, useMount } from '@react-devui/hooks';
import { DownOutlined, PlusOutlined } from '@react-devui/icons';
import { DButton, DCard, DCheckbox, DDropdown, DModal, DPagination, DSelect, DSeparator, DSpinner, DTable } from '@react-devui/ui';
import { DButton, DCard, DCheckbox, DDropdown, DModal, DPagination, DSelect, DSpinner } from '@react-devui/ui';

import { AppRouteHeader, AppStatusDot, AppTableFilter } from '../../../components';
import { AppRouteHeader, AppStatusDot, AppTable, AppTableFilter } from '../../../components';
import { useHttp } from '../../../core';
import { useAPI, useQueryParams } from '../../../hooks';
import { AppRoute, DialogService } from '../../../utils';
Expand Down Expand Up @@ -42,7 +41,7 @@ export default AppRoute(() => {
page: 1,
pageSize: 10,
});
const [deviceQuery, setDeviceQuery] = useImmer(deviceQuerySaved);
const [deviceQuery, setDeviceQuery] = useImmer<DeviceQueryParams>({ ...deviceQuerySaved, model: [] });
const queryEmptyStatus = (() => {
const getEmptyStatus = (query: DeviceQueryParams) => ({
keyword: query.keyword.length === 0,
Expand All @@ -64,13 +63,13 @@ export default AppRoute(() => {
const allDeviceSelected =
deviceTable.selected.size === 0 ? false : deviceTable.selected.size === deviceTable.list.length ? true : 'mixed';

const [modelList, setModelList] = useState<DSelectItem<string>[]>();

const [paramsOfDeleteModal, setParamsOfDeleteModal] = useImmer<{
visible: boolean;
device: DeviceData;
}>();

const [modelList, setModelList] = useState<DSelectItem<string>[]>();

useMount(() => {
modelApi.list().subscribe({
next: (res) => {
Expand All @@ -81,13 +80,21 @@ export default AppRoute(() => {
disabled: model.disabled,
}))
);
setDeviceQuery((draft) => {
draft.model = deviceQuerySaved.model;
});
},
});
});

const [updateDeviceTable, setUpdateDeviceTable] = useState(0);
useEffect(() => {
setDeviceQuerySaved(deviceQuery);
if (updateDeviceTable !== 0) {
setDeviceQuerySaved(deviceQuery);
setDeviceTable((draft) => {
draft.loading = true;
});
}

const apiQuery: StandardQueryParams = {
page: deviceQuery.page,
Expand All @@ -96,10 +103,6 @@ export default AppRoute(() => {
if (deviceQuery.sort) {
apiQuery.sort = deviceQuery.sort;
}

setDeviceTable((draft) => {
draft.loading = true;
});
deviceApi.list<DeviceData>(apiQuery).subscribe({
next: (res) => {
setDeviceQuery((draft) => {
Expand Down Expand Up @@ -196,9 +199,9 @@ export default AppRoute(() => {
<DSelect
style={{ width: '16em' }}
dList={modelList ?? []}
dModel={deviceQuery.model}
dLoading={isUndefined(modelList)}
dPlaceholder="Model"
dModel={deviceQuery.model}
dMultiple
dClearable
onModelChange={(value) => {
Expand Down Expand Up @@ -255,113 +258,90 @@ export default AppRoute(() => {
}
}}
/>
<DTable style={{ overflow: 'auto hidden' }}>
<table style={{ minWidth: 1200 }}>
<thead>
<tr>
<DTable.Th dWidth={60} dAlign="center">
<DCheckbox
dModel={allDeviceSelected !== 'mixed' ? allDeviceSelected : undefined}
dIndeterminate={allDeviceSelected === 'mixed'}
onModelChange={(checked) => {
setDeviceTable((draft) => {
draft.selected = new Set(checked ? draft.list.map((data) => data.id) : []);
});
}}
></DCheckbox>
</DTable.Th>
<DTable.Th
dSort={{
options: ['ascend', 'descend'],
active: deviceQuery.sort === 'id' ? 'ascend' : deviceQuery.sort === '-id' ? 'descend' : null,
onSort: (order) => {
setDeviceQuery((draft) => {
draft.sort = order === 'ascend' ? 'id' : order === 'descend' ? '-id' : null;
});
setUpdateDeviceTable((n) => n + 1);
},
<AppTable
aData={deviceTable.list}
aColumns={[
{
th: (
<DCheckbox
dModel={allDeviceSelected !== 'mixed' ? allDeviceSelected : undefined}
dIndeterminate={allDeviceSelected === 'mixed'}
onModelChange={(checked) => {
setDeviceTable((draft) => {
draft.selected = new Set(checked ? draft.list.map((data) => data.id) : []);
});
}}
></DCheckbox>
),
td: (data) => (
<DCheckbox
dModel={deviceTable.selected.has(data.id)}
onModelChange={(checked) => {
setDeviceTable((draft) => {
if (checked) {
draft.selected.add(data.id);
} else {
draft.selected.delete(data.id);
}
});
}}
></DCheckbox>
),
width: 60,
align: 'center',
checkbox: true,
},
{
th: 'NAME',
td: 'name',
title: true,
},
{
th: 'MODEL',
td: 'model',
},
{
th: 'PRICE',
td: 'price',
},
{
th: 'STATUS',
td: (data) => (
<AppStatusDot
aTheme={data.status === 0 ? 'success' : data.status === 1 ? 'warning' : 'danger'}
aWave={data.status === 2}
>
ID
</DTable.Th>
<DTable.Th>NAME</DTable.Th>
<DTable.Th>MODEL</DTable.Th>
<DTable.Th>PRICE</DTable.Th>
<DTable.Th>STATUS</DTable.Th>
<DTable.Th>CREATE TIME</DTable.Th>
<DTable.Th dWidth={140} dFixed={{ top: 0, right: 0 }}>
ACTIONS
</DTable.Th>
</tr>
</thead>
<tbody>
{deviceTable.list.length === 0 ? (
<DTable.Empty />
) : (
deviceTable.list.map((data) => (
<tr key={data.id}>
<DTable.Td dWidth={60} dAlign="center">
<DCheckbox
dModel={deviceTable.selected.has(data.id)}
onModelChange={(checked) => {
setDeviceTable((draft) => {
if (checked) {
draft.selected.add(data.id);
} else {
draft.selected.delete(data.id);
}
});
}}
></DCheckbox>
</DTable.Td>
<DTable.Td>{data.id}</DTable.Td>
<DTable.Td>{data.name}</DTable.Td>
<DTable.Td>{data.model}</DTable.Td>
<DTable.Td>{data.price}</DTable.Td>
<DTable.Td dNowrap>
<AppStatusDot
aTheme={data.status === 0 ? 'success' : data.status === 1 ? 'warning' : 'danger'}
aWave={data.status === 2}
>
{data.status === 0 ? 'Normal' : data.status === 1 ? 'Failure' : 'Alarm'}
</AppStatusDot>
</DTable.Td>
<DTable.Td>{new Date(data.create_time).toLocaleString()}</DTable.Td>
<DTable.Td dWidth={140} dFixed={{ right: 0 }} dNowrap>
<Link className="app-link" to={`/list/standard-table/${data.id}`}>
View
</Link>
<DSeparator dVertical></DSeparator>
<DDropdown
dList={[
{ id: 'edit', label: 'Edit', type: 'item' },
{ id: 'delete', label: 'Delete', type: 'item' },
]}
dPlacement="bottom-right"
onItemClick={(action) => {
switch (action) {
case 'edit':
openDeviceModal(data);
break;

case 'delete':
setParamsOfDeleteModal({ visible: true, device: data });
break;

default:
break;
}
}}
>
<DButton dType="link">More</DButton>
</DDropdown>
</DTable.Td>
</tr>
))
)}
</tbody>
</table>
</DTable>
{data.status === 0 ? 'Normal' : data.status === 1 ? 'Failure' : 'Alarm'}
</AppStatusDot>
),
nowrap: true,
},
{
th: 'CREATE TIME',
td: (data) => new Date(data.create_time).toLocaleString(),
},
]}
aActions={{
actions: (data) => [
{ text: 'View', link: `/list/standard-table/${data.id}` },
{
text: 'Edit',
onclick: () => {
openDeviceModal(data);
},
},
{
text: 'Delete',
onclick: () => {
setParamsOfDeleteModal({ visible: true, device: data });
},
},
],
width: 140,
}}
aScroll={{ x: 1200 }}
aLabelWidth={72}
/>
<div className="mt-3 d-flex align-items-center justify-content-between flex-wrap" style={{ gap: '10px 12px' }}>
<div>
<DButton className="me-2" disabled={allDeviceSelected === false} dType="secondary">
Expand Down
8 changes: 8 additions & 0 deletions packages/platform/src/startup/i18n/resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
"language": {
"Change language": "Change language"
},
"table": {
"ACTIONS": "ACTIONS",
"More": "More"
},
"table-filter": {
"Search": "Search",
"Reset": "Reset",
Expand Down Expand Up @@ -100,6 +104,10 @@
"language": {
"Change language": "改变语言"
},
"table": {
"ACTIONS": "操作",
"More": "更多"
},
"table-filter": {
"Search": "查询",
"Reset": "重置",
Expand Down
1 change: 1 addition & 0 deletions packages/platform/src/styles/components/detail-view.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
}

@include e(item-content) {
flex-grow: 1;
word-break: break-all;
}
}

0 comments on commit d6e9e39

Please sign in to comment.