Skip to content

Commit d6e9e39

Browse files
committed
refactor(platform): optimize table
1 parent 01176c2 commit d6e9e39

9 files changed

Lines changed: 502 additions & 125 deletions

File tree

packages/platform/src/app/Routes.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ export const AppRoutes = React.memo(() => {
9393
title: t('Login', { ns: 'title' }),
9494
},
9595
},
96+
{
97+
path: '/',
98+
element: <AppHomeRoute />,
99+
},
96100
{
97101
path: '/',
98102
element: <AppLayout />,
@@ -101,10 +105,6 @@ export const AppRoutes = React.memo(() => {
101105
canActivateChild: [tokenGuard],
102106
},
103107
children: [
104-
{
105-
index: true,
106-
element: <AppHomeRoute />,
107-
},
108108
{
109109
path: 'dashboard',
110110
children: [

packages/platform/src/app/components/detail-view/DetailView.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export interface AppDetailViewProps extends Omit<React.HTMLAttributes<HTMLDivEle
99
content: React.ReactNode;
1010
isEmpty?: boolean;
1111
center?: boolean;
12-
noWrapper?: boolean;
1312
}[];
1413
aCol?: number | true | Partial<Record<'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', number | true>>;
1514
aGutter?: number | [number?, number?];
@@ -79,7 +78,7 @@ export function AppDetailView(props: AppDetailViewProps): JSX.Element | null {
7978
[`gy-${gutterY}`]: gutterY,
8079
})}
8180
>
82-
{aList.map(({ label, content: _content, isEmpty: _isEmpty, center, noWrapper }) => {
81+
{aList.map(({ label, content: _content, isEmpty: _isEmpty, center }) => {
8382
const isEmpty = isUndefined(_isEmpty)
8483
? (isString(_content) && _content.length === 0) || isUndefined(_content) || isNull(_content)
8584
: _isEmpty;
@@ -101,7 +100,7 @@ export function AppDetailView(props: AppDetailViewProps): JSX.Element | null {
101100
>
102101
{label}
103102
</div>
104-
{noWrapper ? content : <div className="app-detail-view__item-content">{content}</div>}
103+
<div className="app-detail-view__item-content">{content}</div>
105104
</div>
106105
);
107106
})}

packages/platform/src/app/components/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,8 @@ export { AppRouteHeader } from './route-header';
2424
export type { AppStatusDotProps } from './status-dot';
2525
export { AppStatusDot } from './status-dot';
2626

27+
export type { AppTableProps } from './table';
28+
export { AppTable } from './table';
29+
2730
export type { AppTableFilterProps } from './table-filter';
2831
export { AppTableFilter } from './table-filter';

packages/platform/src/app/components/table/Table.tsx

Lines changed: 384 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Table';
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { isUndefined } from 'lodash';
22
import { Navigate } from 'react-router-dom';
33

4+
import { LOGIN_PATH } from '../config/other';
45
import { useMenu } from '../core';
56

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

9-
return isUndefined(firstCanActive) ? null : <Navigate to={firstCanActive.path} replace />;
10+
return <Navigate to={isUndefined(firstCanActive) ? LOGIN_PATH : firstCanActive.path} replace />;
1011
}

packages/platform/src/app/routes/list/standard-table/StandardTable.tsx

Lines changed: 97 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import type { DSelectItem } from '@react-devui/ui/components/select';
44
import { isUndefined } from 'lodash';
55
import { useEffect, useState } from 'react';
66
import { useTranslation } from 'react-i18next';
7-
import { Link } from 'react-router-dom';
87

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

13-
import { AppRouteHeader, AppStatusDot, AppTableFilter } from '../../../components';
12+
import { AppRouteHeader, AppStatusDot, AppTable, AppTableFilter } from '../../../components';
1413
import { useHttp } from '../../../core';
1514
import { useAPI, useQueryParams } from '../../../hooks';
1615
import { AppRoute, DialogService } from '../../../utils';
@@ -42,7 +41,7 @@ export default AppRoute(() => {
4241
page: 1,
4342
pageSize: 10,
4443
});
45-
const [deviceQuery, setDeviceQuery] = useImmer(deviceQuerySaved);
44+
const [deviceQuery, setDeviceQuery] = useImmer<DeviceQueryParams>({ ...deviceQuerySaved, model: [] });
4645
const queryEmptyStatus = (() => {
4746
const getEmptyStatus = (query: DeviceQueryParams) => ({
4847
keyword: query.keyword.length === 0,
@@ -64,13 +63,13 @@ export default AppRoute(() => {
6463
const allDeviceSelected =
6564
deviceTable.selected.size === 0 ? false : deviceTable.selected.size === deviceTable.list.length ? true : 'mixed';
6665

67-
const [modelList, setModelList] = useState<DSelectItem<string>[]>();
68-
6966
const [paramsOfDeleteModal, setParamsOfDeleteModal] = useImmer<{
7067
visible: boolean;
7168
device: DeviceData;
7269
}>();
7370

71+
const [modelList, setModelList] = useState<DSelectItem<string>[]>();
72+
7473
useMount(() => {
7574
modelApi.list().subscribe({
7675
next: (res) => {
@@ -81,13 +80,21 @@ export default AppRoute(() => {
8180
disabled: model.disabled,
8281
}))
8382
);
83+
setDeviceQuery((draft) => {
84+
draft.model = deviceQuerySaved.model;
85+
});
8486
},
8587
});
8688
});
8789

8890
const [updateDeviceTable, setUpdateDeviceTable] = useState(0);
8991
useEffect(() => {
90-
setDeviceQuerySaved(deviceQuery);
92+
if (updateDeviceTable !== 0) {
93+
setDeviceQuerySaved(deviceQuery);
94+
setDeviceTable((draft) => {
95+
draft.loading = true;
96+
});
97+
}
9198

9299
const apiQuery: StandardQueryParams = {
93100
page: deviceQuery.page,
@@ -96,10 +103,6 @@ export default AppRoute(() => {
96103
if (deviceQuery.sort) {
97104
apiQuery.sort = deviceQuery.sort;
98105
}
99-
100-
setDeviceTable((draft) => {
101-
draft.loading = true;
102-
});
103106
deviceApi.list<DeviceData>(apiQuery).subscribe({
104107
next: (res) => {
105108
setDeviceQuery((draft) => {
@@ -196,9 +199,9 @@ export default AppRoute(() => {
196199
<DSelect
197200
style={{ width: '16em' }}
198201
dList={modelList ?? []}
202+
dModel={deviceQuery.model}
199203
dLoading={isUndefined(modelList)}
200204
dPlaceholder="Model"
201-
dModel={deviceQuery.model}
202205
dMultiple
203206
dClearable
204207
onModelChange={(value) => {
@@ -255,113 +258,90 @@ export default AppRoute(() => {
255258
}
256259
}}
257260
/>
258-
<DTable style={{ overflow: 'auto hidden' }}>
259-
<table style={{ minWidth: 1200 }}>
260-
<thead>
261-
<tr>
262-
<DTable.Th dWidth={60} dAlign="center">
263-
<DCheckbox
264-
dModel={allDeviceSelected !== 'mixed' ? allDeviceSelected : undefined}
265-
dIndeterminate={allDeviceSelected === 'mixed'}
266-
onModelChange={(checked) => {
267-
setDeviceTable((draft) => {
268-
draft.selected = new Set(checked ? draft.list.map((data) => data.id) : []);
269-
});
270-
}}
271-
></DCheckbox>
272-
</DTable.Th>
273-
<DTable.Th
274-
dSort={{
275-
options: ['ascend', 'descend'],
276-
active: deviceQuery.sort === 'id' ? 'ascend' : deviceQuery.sort === '-id' ? 'descend' : null,
277-
onSort: (order) => {
278-
setDeviceQuery((draft) => {
279-
draft.sort = order === 'ascend' ? 'id' : order === 'descend' ? '-id' : null;
280-
});
281-
setUpdateDeviceTable((n) => n + 1);
282-
},
261+
<AppTable
262+
aData={deviceTable.list}
263+
aColumns={[
264+
{
265+
th: (
266+
<DCheckbox
267+
dModel={allDeviceSelected !== 'mixed' ? allDeviceSelected : undefined}
268+
dIndeterminate={allDeviceSelected === 'mixed'}
269+
onModelChange={(checked) => {
270+
setDeviceTable((draft) => {
271+
draft.selected = new Set(checked ? draft.list.map((data) => data.id) : []);
272+
});
283273
}}
274+
></DCheckbox>
275+
),
276+
td: (data) => (
277+
<DCheckbox
278+
dModel={deviceTable.selected.has(data.id)}
279+
onModelChange={(checked) => {
280+
setDeviceTable((draft) => {
281+
if (checked) {
282+
draft.selected.add(data.id);
283+
} else {
284+
draft.selected.delete(data.id);
285+
}
286+
});
287+
}}
288+
></DCheckbox>
289+
),
290+
width: 60,
291+
align: 'center',
292+
checkbox: true,
293+
},
294+
{
295+
th: 'NAME',
296+
td: 'name',
297+
title: true,
298+
},
299+
{
300+
th: 'MODEL',
301+
td: 'model',
302+
},
303+
{
304+
th: 'PRICE',
305+
td: 'price',
306+
},
307+
{
308+
th: 'STATUS',
309+
td: (data) => (
310+
<AppStatusDot
311+
aTheme={data.status === 0 ? 'success' : data.status === 1 ? 'warning' : 'danger'}
312+
aWave={data.status === 2}
284313
>
285-
ID
286-
</DTable.Th>
287-
<DTable.Th>NAME</DTable.Th>
288-
<DTable.Th>MODEL</DTable.Th>
289-
<DTable.Th>PRICE</DTable.Th>
290-
<DTable.Th>STATUS</DTable.Th>
291-
<DTable.Th>CREATE TIME</DTable.Th>
292-
<DTable.Th dWidth={140} dFixed={{ top: 0, right: 0 }}>
293-
ACTIONS
294-
</DTable.Th>
295-
</tr>
296-
</thead>
297-
<tbody>
298-
{deviceTable.list.length === 0 ? (
299-
<DTable.Empty />
300-
) : (
301-
deviceTable.list.map((data) => (
302-
<tr key={data.id}>
303-
<DTable.Td dWidth={60} dAlign="center">
304-
<DCheckbox
305-
dModel={deviceTable.selected.has(data.id)}
306-
onModelChange={(checked) => {
307-
setDeviceTable((draft) => {
308-
if (checked) {
309-
draft.selected.add(data.id);
310-
} else {
311-
draft.selected.delete(data.id);
312-
}
313-
});
314-
}}
315-
></DCheckbox>
316-
</DTable.Td>
317-
<DTable.Td>{data.id}</DTable.Td>
318-
<DTable.Td>{data.name}</DTable.Td>
319-
<DTable.Td>{data.model}</DTable.Td>
320-
<DTable.Td>{data.price}</DTable.Td>
321-
<DTable.Td dNowrap>
322-
<AppStatusDot
323-
aTheme={data.status === 0 ? 'success' : data.status === 1 ? 'warning' : 'danger'}
324-
aWave={data.status === 2}
325-
>
326-
{data.status === 0 ? 'Normal' : data.status === 1 ? 'Failure' : 'Alarm'}
327-
</AppStatusDot>
328-
</DTable.Td>
329-
<DTable.Td>{new Date(data.create_time).toLocaleString()}</DTable.Td>
330-
<DTable.Td dWidth={140} dFixed={{ right: 0 }} dNowrap>
331-
<Link className="app-link" to={`/list/standard-table/${data.id}`}>
332-
View
333-
</Link>
334-
<DSeparator dVertical></DSeparator>
335-
<DDropdown
336-
dList={[
337-
{ id: 'edit', label: 'Edit', type: 'item' },
338-
{ id: 'delete', label: 'Delete', type: 'item' },
339-
]}
340-
dPlacement="bottom-right"
341-
onItemClick={(action) => {
342-
switch (action) {
343-
case 'edit':
344-
openDeviceModal(data);
345-
break;
346-
347-
case 'delete':
348-
setParamsOfDeleteModal({ visible: true, device: data });
349-
break;
350-
351-
default:
352-
break;
353-
}
354-
}}
355-
>
356-
<DButton dType="link">More</DButton>
357-
</DDropdown>
358-
</DTable.Td>
359-
</tr>
360-
))
361-
)}
362-
</tbody>
363-
</table>
364-
</DTable>
314+
{data.status === 0 ? 'Normal' : data.status === 1 ? 'Failure' : 'Alarm'}
315+
</AppStatusDot>
316+
),
317+
nowrap: true,
318+
},
319+
{
320+
th: 'CREATE TIME',
321+
td: (data) => new Date(data.create_time).toLocaleString(),
322+
},
323+
]}
324+
aActions={{
325+
actions: (data) => [
326+
{ text: 'View', link: `/list/standard-table/${data.id}` },
327+
{
328+
text: 'Edit',
329+
onclick: () => {
330+
openDeviceModal(data);
331+
},
332+
},
333+
{
334+
text: 'Delete',
335+
onclick: () => {
336+
setParamsOfDeleteModal({ visible: true, device: data });
337+
},
338+
},
339+
],
340+
width: 140,
341+
}}
342+
aScroll={{ x: 1200 }}
343+
aLabelWidth={72}
344+
/>
365345
<div className="mt-3 d-flex align-items-center justify-content-between flex-wrap" style={{ gap: '10px 12px' }}>
366346
<div>
367347
<DButton className="me-2" disabled={allDeviceSelected === false} dType="secondary">

packages/platform/src/startup/i18n/resources.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
"language": {
1111
"Change language": "Change language"
1212
},
13+
"table": {
14+
"ACTIONS": "ACTIONS",
15+
"More": "More"
16+
},
1317
"table-filter": {
1418
"Search": "Search",
1519
"Reset": "Reset",
@@ -100,6 +104,10 @@
100104
"language": {
101105
"Change language": "改变语言"
102106
},
107+
"table": {
108+
"ACTIONS": "操作",
109+
"More": "更多"
110+
},
103111
"table-filter": {
104112
"Search": "查询",
105113
"Reset": "重置",

packages/platform/src/styles/components/detail-view.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
}
3535

3636
@include e(item-content) {
37+
flex-grow: 1;
3738
word-break: break-all;
3839
}
3940
}

0 commit comments

Comments
 (0)