trithuc-mvc-react 3.1.1 → 3.1.2
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.
package/api/index.js
CHANGED
|
@@ -67,6 +67,35 @@ export const getDatasFromTable = async ({ tableName, page, pageSize, data }) =>
|
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
export const getDatasFromTableDropdownlist = async ({ tableName, page, pageSize, data }) => {
|
|
71
|
+
try {
|
|
72
|
+
let res;
|
|
73
|
+
// Trường hợp dùng tableName với MVC4
|
|
74
|
+
if (!apiUrl) {
|
|
75
|
+
res = await api.get(`${getBaseUrl()}/Admin/${tableName}/LoadData`, {
|
|
76
|
+
params: {
|
|
77
|
+
json: JSON.stringify(data),
|
|
78
|
+
page,
|
|
79
|
+
pageSize
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
// Trường hợp dùng api .NET Core
|
|
84
|
+
res = await api.get(`${getBaseUrl()}/${apiUrl}/${tableName}/Dropdownlist`, {
|
|
85
|
+
params: {
|
|
86
|
+
PageNumber: page,
|
|
87
|
+
PageSize: pageSize,
|
|
88
|
+
...data
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return res.data;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("Error fetching data:", error);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
70
99
|
export const getDataFromTable = async ({ tableName, id }) => {
|
|
71
100
|
try {
|
|
72
101
|
if (!apiUrl) {
|
|
@@ -27,7 +27,7 @@ const ExportExcelButton = ({ tableName, data, size = "small" }) => {
|
|
|
27
27
|
onClick={() => {
|
|
28
28
|
handleExportExcel(tableName, data);
|
|
29
29
|
}}
|
|
30
|
-
sx={{ ml: 0.5, mr: 0.5 }}
|
|
30
|
+
sx={{ ml: 0.5, mr: 0.5, minWidth: "73px" }}
|
|
31
31
|
>
|
|
32
32
|
Excel
|
|
33
33
|
</Button>
|
|
@@ -39,7 +39,7 @@ const ExportExcelButton = ({ tableName, data, size = "small" }) => {
|
|
|
39
39
|
onClick={() => {
|
|
40
40
|
handleExportExcel(tableName, data);
|
|
41
41
|
}}
|
|
42
|
-
sx={{ ml: 0.5, mr: 0.5 }}
|
|
42
|
+
sx={{ ml: 0.5, mr: 0.5, minWidth: "73px" }}
|
|
43
43
|
>
|
|
44
44
|
Excel
|
|
45
45
|
</Button>
|
|
@@ -48,7 +48,16 @@ export const TableRowRenderSM = ({
|
|
|
48
48
|
|
|
49
49
|
return (
|
|
50
50
|
<TableRow hover key={row[selectedField]} selected={selected} sx={{ width: "100%" }}>
|
|
51
|
-
<TableCell
|
|
51
|
+
<TableCell
|
|
52
|
+
colSpan={columns.length}
|
|
53
|
+
align="left"
|
|
54
|
+
sx={{
|
|
55
|
+
maxWidth: "100%", // Giới hạn tối đa theo container
|
|
56
|
+
wordBreak: "break-word", // Xuống dòng khi vượt quá
|
|
57
|
+
whiteSpace: "normal", // Cho phép xuống dòng
|
|
58
|
+
overflowWrap: "break-word" // Hỗ trợ xuống dòng trong các trình duyệt cũ
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
52
61
|
{columns.map(({ field, label, type = "text", valueGetter = (row) => row[field], renderCell, valueFormat = (e) => e }) => {
|
|
53
62
|
const value = renderCell ? renderCell(row) : valueFormat(valueGetter(row));
|
|
54
63
|
return (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button, Card, Grid, IconButton, Stack, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material";
|
|
1
|
+
import { Box, Button, Card, Grid, IconButton, Stack, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material";
|
|
2
2
|
|
|
3
3
|
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
|
|
@@ -16,6 +16,7 @@ import DataTableSM from "./DataTableSM";
|
|
|
16
16
|
import ExportExcelButton from "./ExportExcelButton";
|
|
17
17
|
import { FilterGod } from "./FilterGod";
|
|
18
18
|
import HuongDanButton from "./HuongDanButton";
|
|
19
|
+
import { useRef } from "react";
|
|
19
20
|
|
|
20
21
|
DataManagement.propTypes = {
|
|
21
22
|
columns: PropTypes.array,
|
|
@@ -58,7 +59,8 @@ DataManagement.propTypes = {
|
|
|
58
59
|
disableEditor: PropTypes.bool,
|
|
59
60
|
onAddClick: PropTypes.func,
|
|
60
61
|
onEditClick: PropTypes.func,
|
|
61
|
-
tabPanel: PropTypes.node
|
|
62
|
+
tabPanel: PropTypes.node,
|
|
63
|
+
titleAddButton: PropTypes.string
|
|
62
64
|
};
|
|
63
65
|
const getDefaultValues = (filters = []) => {
|
|
64
66
|
const defaultValues = {};
|
|
@@ -98,7 +100,8 @@ function DataManagement({
|
|
|
98
100
|
sx: {}
|
|
99
101
|
}
|
|
100
102
|
},
|
|
101
|
-
defaultRowsPerPage = 5
|
|
103
|
+
defaultRowsPerPage = 5,
|
|
104
|
+
titleAddButton = "Thêm"
|
|
102
105
|
}) {
|
|
103
106
|
const [openEditorDialog, setOpenEditorDialog] = useState(false);
|
|
104
107
|
const [selectedEditItem, setSelectedEditItem] = useState(null);
|
|
@@ -161,7 +164,8 @@ function DataManagement({
|
|
|
161
164
|
onEditClick,
|
|
162
165
|
hasTabpanel,
|
|
163
166
|
backParentNavigator,
|
|
164
|
-
defaultRowsPerPage
|
|
167
|
+
defaultRowsPerPage,
|
|
168
|
+
titleAddButton
|
|
165
169
|
};
|
|
166
170
|
}, [
|
|
167
171
|
reserPage,
|
|
@@ -185,79 +189,183 @@ function DataManagement({
|
|
|
185
189
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm")); // Xác định màn hình nhỏ
|
|
186
190
|
const methods = useForm({ defaultValues: getDefaultValues(filters) });
|
|
187
191
|
const { reset, setValue } = methods;
|
|
192
|
+
|
|
193
|
+
const titleText = title || "";
|
|
194
|
+
const [titleWidth, setTitleWidth] = useState(0);
|
|
195
|
+
const [minWidthValue, setMinWidthValue] = useState(0); // Thêm state cho minWidthValue
|
|
196
|
+
|
|
197
|
+
// Đo chiều rộng của titleText khi render lần đầu
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
const titleElement = document.createElement("span");
|
|
200
|
+
titleElement.style.font = "normal 16px Arial"; // Đảm bảo phông chữ và kích thước giống như bạn dùng trong UI
|
|
201
|
+
titleElement.style.visibility = "hidden"; // Ẩn element tạm thời
|
|
202
|
+
titleElement.textContent = titleText;
|
|
203
|
+
|
|
204
|
+
document.body.appendChild(titleElement);
|
|
205
|
+
setTitleWidth(titleElement.offsetWidth); // Lấy chiều rộng của title
|
|
206
|
+
document.body.removeChild(titleElement); // Xóa element sau khi đo xong
|
|
207
|
+
}, [titleText]);
|
|
208
|
+
|
|
209
|
+
// Khi titleWidth thay đổi, tính toán minWidthValue
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
if (titleWidth > 0) {
|
|
212
|
+
const calculatedMinWidth = Math.max(titleWidth, 150); // Đảm bảo minWidthValue không nhỏ hơn 150px
|
|
213
|
+
setMinWidthValue(calculatedMinWidth);
|
|
214
|
+
}
|
|
215
|
+
}, [titleWidth]); // Phụ thuộc vào titleWidth để đảm bảo minWidthValue được cập nhật khi chiều rộng title thay đổi
|
|
216
|
+
|
|
217
|
+
const rightBoxRef = useRef(null); // Tham chiếu đến khối phải
|
|
218
|
+
const [rightBoxMinWidth, setRightBoxMinWidth] = useState(0); // Lưu chiều rộng của khối phải
|
|
219
|
+
|
|
220
|
+
// Đo chiều rộng của khối phải khi component render và khi thay đổi kích thước cửa sổ
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
// Hàm xử lý resize
|
|
223
|
+
const handleResize = () => {
|
|
224
|
+
const currentWindowWidth = window.innerWidth;
|
|
225
|
+
|
|
226
|
+
// Đo chiều rộng của khối phải trực tiếp từ ref
|
|
227
|
+
const rightBoxWidth = rightBoxRef.current ? rightBoxRef.current.offsetWidth : 0;
|
|
228
|
+
|
|
229
|
+
// Cập nhật chiều rộng khối phải (rightBoxMinWidth) tùy theo kích thước của cửa sổ và khối
|
|
230
|
+
if (currentWindowWidth - (minWidthValue + 30) < rightBoxWidth) {
|
|
231
|
+
// console.log(
|
|
232
|
+
// `currentWindowWidth - minWidthValue 1: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
|
|
233
|
+
// );
|
|
234
|
+
setRightBoxMinWidth(currentWindowWidth - 30); // Điều chỉnh chiều rộng khối phải nếu không đủ không gian
|
|
235
|
+
} else {
|
|
236
|
+
// console.log(
|
|
237
|
+
// `currentWindowWidth - minWidthValue 2: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
|
|
238
|
+
// );
|
|
239
|
+
setRightBoxMinWidth(rightBoxWidth); // Nếu đủ không gian, dùng chiều rộng khối phải
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Lần render đầu tiên, tính toán chiều rộng khối phải
|
|
244
|
+
const initialResize = () => {
|
|
245
|
+
const rightBoxWidth = rightBoxRef.current ? rightBoxRef.current.offsetWidth : 0;
|
|
246
|
+
const currentWindowWidth = window.innerWidth;
|
|
247
|
+
|
|
248
|
+
// Cập nhật giá trị minWidth ngay khi render lần đầu
|
|
249
|
+
if (currentWindowWidth - (minWidthValue + 30) < rightBoxWidth) {
|
|
250
|
+
// console.log(
|
|
251
|
+
// `currentWindowWidth - minWidthValue 3: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
|
|
252
|
+
// );
|
|
253
|
+
setRightBoxMinWidth(currentWindowWidth - 30); // Điều chỉnh chiều rộng khối phải nếu không đủ không gian
|
|
254
|
+
} else {
|
|
255
|
+
// console.log(
|
|
256
|
+
// `currentWindowWidth - minWidthValue 4: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
|
|
257
|
+
// );
|
|
258
|
+
setRightBoxMinWidth(rightBoxWidth); // Nếu đủ không gian, dùng chiều rộng của khối phải
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Gọi hàm tính toán ngay khi render lần đầu
|
|
263
|
+
if (minWidthValue > 0) {
|
|
264
|
+
initialResize();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Lắng nghe sự kiện thay đổi kích thước cửa sổ
|
|
268
|
+
window.addEventListener("resize", handleResize);
|
|
269
|
+
|
|
270
|
+
// Dọn dẹp sự kiện khi component bị hủy
|
|
271
|
+
return () => {
|
|
272
|
+
window.removeEventListener("resize", handleResize);
|
|
273
|
+
};
|
|
274
|
+
}, [minWidthValue]); // Phụ thuộc vào minWidthValue để tính toán khi nó được cập nhật
|
|
275
|
+
|
|
276
|
+
// In các giá trị trong console để kiểm tra
|
|
277
|
+
// useEffect(() => {
|
|
278
|
+
// console.log("minWidthValue:", minWidthValue);
|
|
279
|
+
// console.log("rightBoxMinWidth:", rightBoxMinWidth);
|
|
280
|
+
// }, [rightBoxMinWidth]);
|
|
281
|
+
|
|
188
282
|
return (
|
|
189
283
|
<>
|
|
190
284
|
<DataTableContext.Provider value={values}>
|
|
191
285
|
<FormProvider {...methods}>
|
|
192
|
-
<Stack
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
|
|
286
|
+
<Stack
|
|
287
|
+
direction="row"
|
|
288
|
+
sx={{
|
|
289
|
+
mb: upXL ? 1 : 1,
|
|
290
|
+
flexWrap: "wrap",
|
|
291
|
+
alignItems: "center",
|
|
292
|
+
gap: 1,
|
|
293
|
+
...slotProps?.header?.sx
|
|
294
|
+
}}
|
|
295
|
+
>
|
|
296
|
+
{/* Khối trái */}
|
|
297
|
+
<Box
|
|
298
|
+
sx={{
|
|
299
|
+
flexGrow: 1,
|
|
300
|
+
Width: `${minWidthValue}px`,
|
|
301
|
+
textAlign: "left",
|
|
302
|
+
whiteSpace: "normal",
|
|
303
|
+
wordBreak: "break-word"
|
|
304
|
+
}}
|
|
305
|
+
>
|
|
306
|
+
<Typography variant="h4">{titleText}</Typography>
|
|
307
|
+
</Box>
|
|
308
|
+
|
|
309
|
+
{/* Khối phải */}
|
|
310
|
+
<Box
|
|
311
|
+
ref={rightBoxRef} // Tham chiếu đến phần tử này
|
|
312
|
+
sx={{
|
|
313
|
+
display: "flex",
|
|
314
|
+
flexWrap: "nowrap",
|
|
315
|
+
justifyContent: "flex-end",
|
|
316
|
+
alignItems: "center",
|
|
317
|
+
flexShrink: 0,
|
|
318
|
+
// minWidth: "300px", // Đảm bảo chiều rộng tối thiểu
|
|
319
|
+
width: rightBoxMinWidth ? `${rightBoxMinWidth}px` : "auto" // Sử dụng chiều rộng đo được
|
|
320
|
+
}}
|
|
321
|
+
>
|
|
322
|
+
<HuongDanButton tableName={tableName} size={elementSize} />
|
|
323
|
+
<Tooltip title="Làm mới">
|
|
324
|
+
<IconButton
|
|
325
|
+
variant="outlined"
|
|
326
|
+
color="primary"
|
|
327
|
+
size={elementSize}
|
|
328
|
+
onClick={() => {
|
|
329
|
+
setDataSearch({ ...defaults });
|
|
330
|
+
[...filters].forEach((filter) => {
|
|
331
|
+
filter?.onChange?.();
|
|
332
|
+
});
|
|
333
|
+
reset();
|
|
334
|
+
setValue("Search");
|
|
335
|
+
}}
|
|
336
|
+
>
|
|
337
|
+
<Refresh fontSize="inherit" />
|
|
338
|
+
</IconButton>
|
|
339
|
+
</Tooltip>
|
|
340
|
+
|
|
341
|
+
{titleButtons?.map((button, index) => (
|
|
342
|
+
<div key={index}>{button}</div>
|
|
343
|
+
))}
|
|
344
|
+
|
|
345
|
+
<ExportExcelButton tableName={tableName} data={dataSearch} size={elementSize} />
|
|
346
|
+
|
|
347
|
+
{canCreate && !disableAdd && (
|
|
348
|
+
<Button
|
|
349
|
+
size={elementSize}
|
|
350
|
+
variant="contained"
|
|
351
|
+
startIcon={<Add fontSize="inherit" />}
|
|
352
|
+
onClick={(e) => {
|
|
353
|
+
if (!disableEditor) {
|
|
354
|
+
setOpenEditorDialog(true);
|
|
355
|
+
setSelectedEditItem(null);
|
|
356
|
+
}
|
|
357
|
+
onAddClick(e);
|
|
358
|
+
}}
|
|
359
|
+
sx={{
|
|
360
|
+
ml: 0.5,
|
|
361
|
+
mr: 0.5,
|
|
362
|
+
minWidth: "73px"
|
|
363
|
+
}}
|
|
364
|
+
>
|
|
365
|
+
{titleAddButton}
|
|
366
|
+
</Button>
|
|
367
|
+
)}
|
|
368
|
+
</Box>
|
|
261
369
|
</Stack>
|
|
262
370
|
|
|
263
371
|
<Card className="custom-card-DataManagement">
|