trithuc-mvc-react 3.5.0 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "../../api";
|
|
24
24
|
import TableRowsLoader from "../table/TableRowsLoader";
|
|
25
25
|
import { TableHead } from "./TableHead";
|
|
26
|
-
|
|
26
|
+
import { numberThousandsSeparator } from "@/helpers/data-table";
|
|
27
27
|
import { URL_APPLICATION_API } from "@/constants";
|
|
28
28
|
import { usePermission } from "../../hooks";
|
|
29
29
|
import { TableRowRender } from "./TableRowRender";
|
|
@@ -313,7 +313,7 @@ const DataTable = ({ multipleActions = [], page, setPage = () => {}, disableEdit
|
|
|
313
313
|
{total > 0 && (
|
|
314
314
|
<Grid alignSelf={"center"} sx={{ pl: 2 }}>
|
|
315
315
|
<Typography variant="body1">
|
|
316
|
-
Tổng số lượng: <span>{total}</span>
|
|
316
|
+
Tổng số lượng: <span>{numberThousandsSeparator.format(total)}</span>
|
|
317
317
|
</Typography>
|
|
318
318
|
</Grid>
|
|
319
319
|
)}
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
getDatasFromTable
|
|
23
23
|
} from "../../api";
|
|
24
24
|
import TableRowsLoader from "../table/TableRowsLoader";
|
|
25
|
-
|
|
25
|
+
import { numberThousandsSeparator } from "@/helpers/data-table";
|
|
26
26
|
import { URL_APPLICATION_API } from "@/constants";
|
|
27
27
|
import { usePermission } from "../../hooks";
|
|
28
28
|
import { TableRowRenderSM } from "./TableRowRenderSM";
|
|
@@ -355,7 +355,7 @@ const DataTableSM = ({ multipleActions = [], page, setPage = () => {}, disableEd
|
|
|
355
355
|
{total > 0 && (
|
|
356
356
|
<Grid alignSelf={"center"} sx={{ pl: 2 }}>
|
|
357
357
|
<Typography variant="body1">
|
|
358
|
-
Tổng số lượng: <span>{total}</span>
|
|
358
|
+
Tổng số lượng: <span>{numberThousandsSeparator.format(total)}</span>
|
|
359
359
|
</Typography>
|
|
360
360
|
</Grid>
|
|
361
361
|
)}
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { EditOutlined } from "@mui/icons-material";
|
|
2
2
|
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
|
3
3
|
import RemoveRedEyeOutlinedIcon from "@mui/icons-material/RemoveRedEyeOutlined";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Box,
|
|
6
|
+
Button,
|
|
7
|
+
Grid,
|
|
8
|
+
Switch,
|
|
9
|
+
TableCell,
|
|
10
|
+
TableRow,
|
|
11
|
+
Toolbar,
|
|
12
|
+
Tooltip,
|
|
13
|
+
Typography,
|
|
14
|
+
useMediaQuery
|
|
15
|
+
} from "@mui/material";
|
|
5
16
|
import { styled, useTheme } from "@mui/material/styles";
|
|
6
17
|
import { useMemo } from "react";
|
|
7
18
|
import { usePermission } from "../../hooks";
|
|
@@ -137,130 +148,197 @@ export const TableRowRenderSM = ({
|
|
|
137
148
|
)}
|
|
138
149
|
|
|
139
150
|
{/* Các nút thao tác */}
|
|
140
|
-
<Box
|
|
151
|
+
<Box
|
|
152
|
+
mt={2}
|
|
153
|
+
pt={1}
|
|
154
|
+
borderTop="1px solid"
|
|
155
|
+
borderColor="divider"
|
|
156
|
+
display="flex"
|
|
157
|
+
flexDirection="column"
|
|
158
|
+
gap={1}
|
|
159
|
+
>
|
|
141
160
|
{!disableCellThaoTac && (
|
|
142
161
|
<>
|
|
143
|
-
<Box display="grid" gridTemplateColumns={isMobile ? "repeat(3, 1fr)" : "auto"} gap={
|
|
162
|
+
<Box display="grid" gridTemplateColumns={isMobile ? "repeat(3, 1fr)" : "auto"} gap={0.5}>
|
|
144
163
|
{!disableEdit && canEdit && (
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
164
|
+
<Tooltip title="Cập nhật" arrow placement="top">
|
|
165
|
+
<span>
|
|
166
|
+
<Button
|
|
167
|
+
fullWidth
|
|
168
|
+
size={isMobile ? "small" : "medium"}
|
|
169
|
+
variant="contained"
|
|
170
|
+
color="primary"
|
|
171
|
+
onClick={() => onEdit(row)}
|
|
172
|
+
startIcon={<EditOutlined />}
|
|
173
|
+
sx={{
|
|
174
|
+
...modernButtonStyle,
|
|
175
|
+
minHeight: 36,
|
|
176
|
+
paddingX: 1,
|
|
177
|
+
gap: 0.5,
|
|
178
|
+
whiteSpace: "normal",
|
|
158
179
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
180
|
+
"& .MuiButton-startIcon": {
|
|
181
|
+
marginRight: 0.5,
|
|
182
|
+
marginLeft: 0,
|
|
183
|
+
alignSelf: "center"
|
|
184
|
+
},
|
|
185
|
+
"& .MuiButton-startIcon svg": {
|
|
186
|
+
fontSize: 18
|
|
187
|
+
}
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
<span
|
|
191
|
+
style={{
|
|
192
|
+
display: "-webkit-box",
|
|
193
|
+
WebkitLineClamp: 2,
|
|
194
|
+
WebkitBoxOrient: "vertical",
|
|
195
|
+
overflow: "hidden",
|
|
196
|
+
textOverflow: "ellipsis",
|
|
197
|
+
lineHeight: 1.25,
|
|
198
|
+
textAlign: "center"
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
Cập nhật
|
|
202
|
+
</span>
|
|
203
|
+
</Button>
|
|
204
|
+
</span>
|
|
205
|
+
</Tooltip>
|
|
172
206
|
)}
|
|
173
207
|
|
|
174
208
|
{canView && !tableActions?.some(({ permissionType }) => permissionType === "view") && (
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
209
|
+
<Tooltip title="Xem" arrow placement="top">
|
|
210
|
+
<span>
|
|
211
|
+
<Button
|
|
212
|
+
fullWidth
|
|
213
|
+
size={isMobile ? "small" : "medium"}
|
|
214
|
+
variant="outlined"
|
|
215
|
+
color="info"
|
|
216
|
+
onClick={() => onView(row)}
|
|
217
|
+
startIcon={<RemoveRedEyeOutlinedIcon />}
|
|
218
|
+
sx={{
|
|
219
|
+
...modernButtonStyle,
|
|
220
|
+
minHeight: 36,
|
|
221
|
+
paddingX: 1,
|
|
222
|
+
gap: 0.5,
|
|
223
|
+
whiteSpace: "normal",
|
|
188
224
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
225
|
+
"& .MuiButton-startIcon": {
|
|
226
|
+
marginRight: 0.5,
|
|
227
|
+
marginLeft: 0,
|
|
228
|
+
alignSelf: "center"
|
|
229
|
+
},
|
|
230
|
+
"& .MuiButton-startIcon svg": {
|
|
231
|
+
fontSize: 18
|
|
232
|
+
}
|
|
233
|
+
}}
|
|
234
|
+
>
|
|
235
|
+
<span
|
|
236
|
+
style={{
|
|
237
|
+
display: "-webkit-box",
|
|
238
|
+
WebkitLineClamp: 2,
|
|
239
|
+
WebkitBoxOrient: "vertical",
|
|
240
|
+
overflow: "hidden",
|
|
241
|
+
textOverflow: "ellipsis",
|
|
242
|
+
lineHeight: 1.25,
|
|
243
|
+
textAlign: "center"
|
|
244
|
+
}}
|
|
245
|
+
>
|
|
246
|
+
Xem
|
|
247
|
+
</span>
|
|
248
|
+
</Button>
|
|
249
|
+
</span>
|
|
250
|
+
</Tooltip>
|
|
202
251
|
)}
|
|
203
252
|
|
|
204
253
|
{!disableDelete && canDelete && (
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
size={isMobile ? "small" : "medium"}
|
|
208
|
-
variant="outlined"
|
|
209
|
-
color="error"
|
|
210
|
-
onClick={() => onDelete(row[selectedField])}
|
|
211
|
-
startIcon={<DeleteOutlineIcon />}
|
|
212
|
-
sx={{
|
|
213
|
-
...modernButtonStyle,
|
|
214
|
-
|
|
215
|
-
// compact mobile
|
|
216
|
-
minHeight: 36,
|
|
217
|
-
paddingX: 1,
|
|
218
|
-
|
|
219
|
-
// icon - text spacing
|
|
220
|
-
gap: 0.5,
|
|
221
|
-
"& .MuiButton-startIcon": {
|
|
222
|
-
marginRight: 0.5,
|
|
223
|
-
marginLeft: 0
|
|
224
|
-
},
|
|
225
|
-
"& .MuiButton-startIcon svg": {
|
|
226
|
-
fontSize: 18
|
|
227
|
-
}
|
|
228
|
-
}}
|
|
229
|
-
>
|
|
230
|
-
Xóa
|
|
231
|
-
</Button>
|
|
232
|
-
)}
|
|
233
|
-
|
|
234
|
-
{tableActionsOnTable.map(
|
|
235
|
-
({ title, onClick, element, visible = true }, idx) =>
|
|
236
|
-
(typeof visible === "function" ? visible(row) : visible) && (
|
|
254
|
+
<Tooltip title="Xóa" arrow placement="top">
|
|
255
|
+
<span>
|
|
237
256
|
<Button
|
|
238
|
-
key={idx}
|
|
239
257
|
fullWidth
|
|
240
|
-
size="small"
|
|
258
|
+
size={isMobile ? "small" : "medium"}
|
|
241
259
|
variant="outlined"
|
|
242
|
-
|
|
243
|
-
|
|
260
|
+
color="error"
|
|
261
|
+
onClick={() => onDelete(row[selectedField])}
|
|
262
|
+
startIcon={<DeleteOutlineIcon />}
|
|
244
263
|
sx={{
|
|
245
264
|
...modernButtonStyle,
|
|
246
|
-
|
|
247
|
-
// compact mobile
|
|
248
265
|
minHeight: 36,
|
|
249
266
|
paddingX: 1,
|
|
250
|
-
|
|
251
|
-
// icon - text spacing
|
|
252
267
|
gap: 0.5,
|
|
268
|
+
whiteSpace: "normal",
|
|
269
|
+
|
|
253
270
|
"& .MuiButton-startIcon": {
|
|
254
271
|
marginRight: 0.5,
|
|
255
|
-
marginLeft: 0
|
|
272
|
+
marginLeft: 0,
|
|
273
|
+
alignSelf: "center"
|
|
256
274
|
},
|
|
257
275
|
"& .MuiButton-startIcon svg": {
|
|
258
276
|
fontSize: 18
|
|
259
277
|
}
|
|
260
278
|
}}
|
|
261
279
|
>
|
|
262
|
-
|
|
280
|
+
<span
|
|
281
|
+
style={{
|
|
282
|
+
display: "-webkit-box",
|
|
283
|
+
WebkitLineClamp: 2,
|
|
284
|
+
WebkitBoxOrient: "vertical",
|
|
285
|
+
overflow: "hidden",
|
|
286
|
+
textOverflow: "ellipsis",
|
|
287
|
+
lineHeight: 1.25,
|
|
288
|
+
textAlign: "center"
|
|
289
|
+
}}
|
|
290
|
+
>
|
|
291
|
+
Xóa
|
|
292
|
+
</span>
|
|
263
293
|
</Button>
|
|
294
|
+
</span>
|
|
295
|
+
</Tooltip>
|
|
296
|
+
)}
|
|
297
|
+
|
|
298
|
+
{tableActionsOnTable.map(
|
|
299
|
+
({ title, onClick, element, visible = true }, idx) =>
|
|
300
|
+
(typeof visible === "function" ? visible(row) : visible) && (
|
|
301
|
+
<Tooltip key={idx} title={title} arrow placement="top">
|
|
302
|
+
<span>
|
|
303
|
+
<Button
|
|
304
|
+
fullWidth
|
|
305
|
+
size="small"
|
|
306
|
+
variant="outlined"
|
|
307
|
+
onClick={() => onClick(row)}
|
|
308
|
+
startIcon={element}
|
|
309
|
+
sx={{
|
|
310
|
+
...modernButtonStyle,
|
|
311
|
+
minHeight: 36,
|
|
312
|
+
paddingX: 1,
|
|
313
|
+
gap: 0.5,
|
|
314
|
+
whiteSpace: "normal",
|
|
315
|
+
|
|
316
|
+
"& .MuiButton-startIcon": {
|
|
317
|
+
marginRight: 0.5,
|
|
318
|
+
marginLeft: 0,
|
|
319
|
+
alignSelf: "center"
|
|
320
|
+
},
|
|
321
|
+
"& .MuiButton-startIcon svg": {
|
|
322
|
+
fontSize: 18
|
|
323
|
+
}
|
|
324
|
+
}}
|
|
325
|
+
>
|
|
326
|
+
<span
|
|
327
|
+
style={{
|
|
328
|
+
display: "-webkit-box",
|
|
329
|
+
WebkitLineClamp: 2,
|
|
330
|
+
WebkitBoxOrient: "vertical",
|
|
331
|
+
overflow: "hidden",
|
|
332
|
+
textOverflow: "ellipsis",
|
|
333
|
+
lineHeight: 1.25,
|
|
334
|
+
textAlign: "center"
|
|
335
|
+
}}
|
|
336
|
+
>
|
|
337
|
+
{title === "xem chi tiết" ? "Xem" : title}
|
|
338
|
+
</span>
|
|
339
|
+
</Button>
|
|
340
|
+
</span>
|
|
341
|
+
</Tooltip>
|
|
264
342
|
)
|
|
265
343
|
)}
|
|
266
344
|
</Box>
|
package/helpers/data-table.js
CHANGED
|
@@ -1,23 +1,63 @@
|
|
|
1
1
|
import moment from "moment";
|
|
2
2
|
import { DEFAULT_DATE_FORMAT } from "../constants";
|
|
3
|
+
export const currencyFormatter = new Intl.NumberFormat("vi-VN", {
|
|
4
|
+
style: "currency",
|
|
5
|
+
currency: "VND"
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const numberFormatter = new Intl.NumberFormat("vi-VN", {
|
|
9
|
+
maximumFractionDigits: 3 // Số thập phân tối đa
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const decimalsFormatter = new Intl.NumberFormat("vi-VN", {
|
|
13
|
+
maximumFractionDigits: 2 // Số thập phân tối đa
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Format phần nghìn với dấu chấm
|
|
17
|
+
export const numberThousandsSeparator = new Intl.NumberFormat("vi-VN", {
|
|
18
|
+
minimumFractionDigits: 0,
|
|
19
|
+
maximumFractionDigits: 0
|
|
20
|
+
});
|
|
3
21
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
22
|
+
// Format phần nghìn với dấu phẩy
|
|
23
|
+
export const numberThousandsComma = new Intl.NumberFormat("en-US", {
|
|
24
|
+
minimumFractionDigits: 0,
|
|
25
|
+
maximumFractionDigits: 0
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const numberThousandsSeparatorWithOneDigits = new Intl.NumberFormat("vi-VN", {
|
|
29
|
+
minimumFractionDigits: 1,
|
|
30
|
+
maximumFractionDigits: 1
|
|
7
31
|
});
|
|
8
|
-
export const numberFormatter = new Intl.NumberFormat('vi-VN');
|
|
9
32
|
|
|
10
33
|
export const vndFormat = {
|
|
11
|
-
|
|
12
|
-
|
|
34
|
+
type: "number",
|
|
35
|
+
valueFormat: (value) => currencyFormatter.format(value)
|
|
13
36
|
};
|
|
14
37
|
|
|
15
38
|
export const numberFormat = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
39
|
+
type: "number",
|
|
40
|
+
valueFormat: (value) => numberFormatter.format(value)
|
|
41
|
+
};
|
|
19
42
|
export const dateFormat = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
43
|
+
type: "date",
|
|
44
|
+
valueFormat: (value) => {
|
|
45
|
+
return value && moment(value).format(DEFAULT_DATE_FORMAT);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
export const formatNumber = (value) => {
|
|
49
|
+
return numberFormatter.format(value);
|
|
50
|
+
};
|
|
51
|
+
//format thời gian từ giây sang phút
|
|
52
|
+
export const formatTime = (seconds) => {
|
|
53
|
+
const minutes = Math.floor(seconds / 60);
|
|
54
|
+
const remainingSeconds = seconds % 60;
|
|
55
|
+
return `${minutes}:${remainingSeconds < 10 ? "0" : ""}${remainingSeconds}`;
|
|
56
|
+
};
|
|
57
|
+
//Hàm thay thế phần tử cuối cùng của đường dẫn
|
|
58
|
+
export const replaceLastSegment = (path, newSegment) => {
|
|
59
|
+
const lastSlashIndex = path?.lastIndexOf("/");
|
|
60
|
+
if (lastSlashIndex === -1) return path; // Nếu không có dấu '/', trả về chuỗi gốc
|
|
61
|
+
const newPath = path?.substring(0, lastSlashIndex + 1) + newSegment;
|
|
62
|
+
return newPath;
|
|
63
|
+
};
|