Commit c95a21b7 authored by chenshouchao's avatar chenshouchao

feat: 完成表格组件的封装

parent 16485b8e
// 分页组件 // 分页组件
import Pagination from "@mui/material/Pagination"; import Pagination from "@mui/material/Pagination";
import MySelect from "./MySelect";
import { ThemeProvider, createTheme } from "@mui/material/styles"; import { ThemeProvider, createTheme } from "@mui/material/styles";
const theme = createTheme({ const theme = createTheme({
components: { components: {
MuiPagination: { MuiPagination: {
...@@ -31,26 +33,74 @@ type IMyPaginationProps = { ...@@ -31,26 +33,74 @@ type IMyPaginationProps = {
page: number; page: number;
pageChange: any; pageChange: any;
count: number; count: number;
totalElements?: number;
type?: "simple" | "complex";
rowsPerPage?: number; // 每页多少条数据
handleChangeRowsPerPage?: any;
}; };
const MyPagination = (props: IMyPaginationProps) => { const MyPagination = (props: IMyPaginationProps) => {
const { page, pageChange, count } = props; const {
page,
pageChange,
count,
type = "simple",
rowsPerPage = 10,
handleChangeRowsPerPage,
totalElements = 0,
} = props;
const handlePageChange = (e: any, value: number) => { const handlePageChange = (e: any, value: number) => {
pageChange && pageChange(value); pageChange && pageChange(value);
}; };
const rowsPerPageChange = (e: any) => {
handleChangeRowsPerPage(Number(e));
};
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
{type === "complex" && (
<>
<span
style={{
marginRight: "20px",
fontSize: "14px",
color: "rgba(30, 38, 51, 1)",
}}
>
总计:{totalElements}
</span>
<MySelect
style={{ marginRight: "20px" }}
value={String(rowsPerPage)}
onChange={(e) => rowsPerPageChange(e)}
size={"small"}
options={[
{
label: "10/页",
value: "10",
},
{
label: "20/页",
value: "20",
},
{
label: "50/页",
value: "50",
},
{
label: "100/页",
value: "100",
},
]}
></MySelect>
</>
)}
<Pagination <Pagination
page={page + 1} // 请求接口的页码是从0开始的 page={page + 1} // 请求接口的页码是从0开始的
count={count + 1} count={count + 1}
shape="rounded" shape="rounded"
onChange={handlePageChange} onChange={handlePageChange}
// sx={{
// padding: "20px 0",
// display: "flex",
// justifyContent: "flex-end",
// }}
/> />
</ThemeProvider> </ThemeProvider>
); );
......
...@@ -11,7 +11,10 @@ import MyPagination from "@/components/mui/MyPagination"; ...@@ -11,7 +11,10 @@ import MyPagination from "@/components/mui/MyPagination";
import ascIcon from "@/assets/project/ascIcon.svg"; import ascIcon from "@/assets/project/ascIcon.svg";
import descIcon from "@/assets/project/descIcon.svg"; import descIcon from "@/assets/project/descIcon.svg";
import sortIcon from "@/assets/project/sort.svg"; import sortIcon from "@/assets/project/sort.svg";
import NoData from "../BusinessComponents/NoData";
import CircularProgress from "@mui/material/CircularProgress";
import { createTheme, ThemeProvider } from "@mui/material"; import { createTheme, ThemeProvider } from "@mui/material";
import noFile from "@/assets/project/noFile.svg";
type Order = "asc" | "desc"; // 升序为asc,降序为desc。 type Order = "asc" | "desc"; // 升序为asc,降序为desc。
...@@ -24,6 +27,7 @@ interface IMyTableProps { ...@@ -24,6 +27,7 @@ interface IMyTableProps {
rows: Array<any>; // 表格数据 rows: Array<any>; // 表格数据
headCells: Array<any>; // 表头配置 headCells: Array<any>; // 表头配置
key?: string; // 表格数据的key key?: string; // 表格数据的key
loading?: boolean;
hasCheckbox?: boolean; // 是否有复选框 hasCheckbox?: boolean; // 是否有复选框
selectItems?: Array<any>; // 选中的项 selectItems?: Array<any>; // 选中的项
setSelectItems?: any; // 设置选中的项 setSelectItems?: any; // 设置选中的项
...@@ -33,17 +37,21 @@ interface IMyTableProps { ...@@ -33,17 +37,21 @@ interface IMyTableProps {
page?: number; // 当前页 page?: number; // 当前页
pageChange?: any; // 页码改变 pageChange?: any; // 页码改变
count?: number; // 总页数 count?: number; // 总页数
randerTooterContent?: any; // 分页左侧内容渲染 totalElements?: number; // 数据总量 不止是列表渲染的长度
sortState?: sortState; // 排序状态 sortState?: sortState; // 排序状态
setSortState?: any; // 设置排序状态 setSortState?: any; // 设置排序状态
paginationType?: "simple" | "complex"; // 分页组件的类型 simple简介式 complex复杂、带每页数量切换、总数等
rowsPerPage?: number; // 每页多少条数据
handleChangeRowsPerPage?: any; // 每页多少条数据变化
nodataText?: any; // 无数据文案
} }
const MyTable = (props: IMyTableProps) => { const MyTable = (props: IMyTableProps) => {
// tode loading nodata
const { const {
rows, rows,
headCells, headCells,
key = "id", key = "id",
loading = false,
hasCheckbox = false, hasCheckbox = false,
selectItems = [], selectItems = [],
setSelectItems, setSelectItems,
...@@ -52,14 +60,25 @@ const MyTable = (props: IMyTableProps) => { ...@@ -52,14 +60,25 @@ const MyTable = (props: IMyTableProps) => {
page = 0, page = 0,
pageChange = () => {}, pageChange = () => {},
count = 1, count = 1,
randerTooterContent = null,
sortState, sortState,
setSortState, setSortState,
paginationType = "simple",
rowsPerPage = 10,
handleChangeRowsPerPage,
totalElements = 0,
nodataText,
} = props; } = props;
const theme = useMemo(() => { const theme = useMemo(() => {
return createTheme({ return createTheme({
components: { components: {
MuiTable: {
styleOverrides: {
root: {
// minHeight: "100px",
},
},
},
MuiTableHead: { MuiTableHead: {
styleOverrides: { styleOverrides: {
root: { root: {
...@@ -74,6 +93,7 @@ const MyTable = (props: IMyTableProps) => { ...@@ -74,6 +93,7 @@ const MyTable = (props: IMyTableProps) => {
MuiTableRow: { MuiTableRow: {
styleOverrides: { styleOverrides: {
root: { root: {
opacity: loading ? 0.5 : 1,
":hover": { ":hover": {
background: "rgba(245, 246, 247, 1)", background: "rgba(245, 246, 247, 1)",
}, },
...@@ -100,6 +120,8 @@ const MyTable = (props: IMyTableProps) => { ...@@ -100,6 +120,8 @@ const MyTable = (props: IMyTableProps) => {
MuiPaper: { MuiPaper: {
styleOverrides: { styleOverrides: {
root: { root: {
minHeight: "200px",
position: "relative",
"&.MuiTableContainer-root": { "&.MuiTableContainer-root": {
boxShadow: "none", boxShadow: "none",
}, },
...@@ -111,7 +133,7 @@ const MyTable = (props: IMyTableProps) => { ...@@ -111,7 +133,7 @@ const MyTable = (props: IMyTableProps) => {
root: { root: {
fontSize: "14px", fontSize: "14px",
lineHeight: "22px", lineHeight: "22px",
color: "rgba(86, 92, 102, 1)", color: "rgba(30, 38, 51, 1)",
padding: "16px", padding: "16px",
borderBottom: "1px solid rgba(240, 242, 245, 1)", borderBottom: "1px solid rgba(240, 242, 245, 1)",
}, },
...@@ -120,8 +142,12 @@ const MyTable = (props: IMyTableProps) => { ...@@ -120,8 +142,12 @@ const MyTable = (props: IMyTableProps) => {
MuiTableBody: { MuiTableBody: {
styleOverrides: { styleOverrides: {
root: { root: {
position: "relative",
"& .MuiTableRow-root:nth-last-of-type(1) .MuiTableCell-root": { "& .MuiTableRow-root:nth-last-of-type(1) .MuiTableCell-root": {
borderBottom: "none", // 有分页的话 表格最后一行就不要下边框
borderBottom: hasTableFooter
? "none"
: "1px solid rgba(240, 242, 245, 1)",
}, },
}, },
}, },
...@@ -154,9 +180,26 @@ const MyTable = (props: IMyTableProps) => { ...@@ -154,9 +180,26 @@ const MyTable = (props: IMyTableProps) => {
}, },
}, },
}, },
MuiCircularProgress: {
styleOverrides: {
root: {
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0,
margin: "auto",
// top: "50%",
// left: "50%",
// transform: "translate(-50%, -50%)",
zIndex: 1,
},
},
},
}, },
}); });
}, [hasCheckbox]); }, [hasCheckbox, hasTableFooter, loading]);
const onSelectAllClick = useCallback(() => { const onSelectAllClick = useCallback(() => {
return (e: any) => { return (e: any) => {
...@@ -271,6 +314,42 @@ const MyTable = (props: IMyTableProps) => { ...@@ -271,6 +314,42 @@ const MyTable = (props: IMyTableProps) => {
]); ]);
const randerTableBody = useMemo(() => { const randerTableBody = useMemo(() => {
if (rows.length === 0) {
if (loading) {
return null;
}
return (
<tbody>
<tr>
<td>
<img
src={noFile}
alt=""
style={{
position: "absolute",
top: "100px",
left: "50%",
transform: "translate(-50%, 0)",
}}
/>
<span
style={{
position: "absolute",
top: "165px",
left: "50%",
transform: "translate(-50%, 0)",
fontSize: "14px",
lineHeight: "22px",
color: "#8a9099",
}}
>
{nodataText || "暂无数据"}
</span>
</td>
</tr>
</tbody>
);
}
return ( return (
<TableBody> <TableBody>
{rows.map((row) => ( {rows.map((row) => (
...@@ -298,7 +377,16 @@ const MyTable = (props: IMyTableProps) => { ...@@ -298,7 +377,16 @@ const MyTable = (props: IMyTableProps) => {
))} ))}
</TableBody> </TableBody>
); );
}, [rows, key, hasCheckbox, selectItems, onSelectRowClick, headCells]); }, [
rows,
key,
hasCheckbox,
selectItems,
onSelectRowClick,
headCells,
nodataText,
loading,
]);
const randerTableFooter = useMemo(() => { const randerTableFooter = useMemo(() => {
if (hasTableFooter) { if (hasTableFooter) {
...@@ -307,25 +395,50 @@ const MyTable = (props: IMyTableProps) => { ...@@ -307,25 +395,50 @@ const MyTable = (props: IMyTableProps) => {
style={{ style={{
padding: "20px 0", padding: "20px 0",
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "flex-end",
alignItems: "center", alignItems: "center",
borderTop: "1px solid rgba(240, 242, 245, 1)", borderTop: "1px solid rgba(240, 242, 245, 1)",
}} }}
> >
<div>{randerTooterContent}</div> <MyPagination
<MyPagination page={page} pageChange={pageChange} count={count} /> page={page}
pageChange={pageChange}
count={count}
totalElements={totalElements}
type={paginationType}
rowsPerPage={rowsPerPage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
/>
</div> </div>
); );
} else { } else {
return null; return null;
} }
}, [hasTableFooter, page, count, pageChange, randerTooterContent]); }, [
hasTableFooter,
page,
count,
pageChange,
paginationType,
rowsPerPage,
handleChangeRowsPerPage,
totalElements,
]);
const randerCircularProgress = useMemo(() => {
if (loading) {
return <CircularProgress></CircularProgress>;
} else {
return null;
}
}, [loading]);
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
{!fixedHead && ( {!fixedHead && (
<> <>
<TableContainer component={Paper}> <TableContainer component={Paper}>
{randerCircularProgress}
<Table> <Table>
{randerTableHead} {randerTableHead}
{randerTableBody} {randerTableBody}
...@@ -336,7 +449,12 @@ const MyTable = (props: IMyTableProps) => { ...@@ -336,7 +449,12 @@ const MyTable = (props: IMyTableProps) => {
)} )}
{fixedHead && ( {fixedHead && (
<div <div
style={{ height: "100%", display: "flex", flexDirection: "column" }} style={{
height: "100%",
display: "flex",
flexDirection: "column",
position: "relative",
}}
> >
<TableContainer component={Paper}> <TableContainer component={Paper}>
<Table>{randerTableHead}</Table> <Table>{randerTableHead}</Table>
...@@ -345,6 +463,7 @@ const MyTable = (props: IMyTableProps) => { ...@@ -345,6 +463,7 @@ const MyTable = (props: IMyTableProps) => {
<Table>{randerTableBody}</Table> <Table>{randerTableBody}</Table>
</TableContainer> </TableContainer>
{randerTableFooter} {randerTableFooter}
{randerCircularProgress}
</div> </div>
)} )}
</ThemeProvider> </ThemeProvider>
......
...@@ -6,6 +6,7 @@ import MyTable from "@/components/mui/MyTableNew"; ...@@ -6,6 +6,7 @@ import MyTable from "@/components/mui/MyTableNew";
const MyTableDemo = () => { const MyTableDemo = () => {
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const [count, setCount] = useState(5); const [count, setCount] = useState(5);
const [rowsPerPage, setRowsPerPage] = useState(10);
const pageChange = (value: number) => { const pageChange = (value: number) => {
setPage(value - 1); setPage(value - 1);
}; };
...@@ -112,6 +113,34 @@ const MyTableDemo = () => { ...@@ -112,6 +113,34 @@ const MyTableDemo = () => {
id: "12", id: "12",
}, },
]; ];
const buttonHeadCells = [
{
id: "a",
label: "属性a",
width: "25%",
},
{
id: "b",
label: "属性b",
width: "25%",
},
{
id: "c",
label: "属性c",
width: "25%",
},
{
id: "d",
label: "属性d",
width: "25%",
},
{
id: "caozuo",
label: "操作",
width: "25%",
},
];
const headCells = [ const headCells = [
{ {
id: "a", id: "a",
...@@ -161,8 +190,8 @@ const MyTableDemo = () => { ...@@ -161,8 +190,8 @@ const MyTableDemo = () => {
]; ];
const [selectItems, setSelectItems] = useState(["1"]); const [selectItems, setSelectItems] = useState(["1"]);
const randerButton = () => { const handleDelete = (e: string) => {
return <MyButton text="下载"></MyButton>; console.log(e);
}; };
console.log(selectItems); console.log(selectItems);
...@@ -171,8 +200,21 @@ const MyTableDemo = () => { ...@@ -171,8 +200,21 @@ const MyTableDemo = () => {
<h2>常规表格</h2> <h2>常规表格</h2>
<div> <div>
<MyTable <MyTable
rows={rows} // rows={rows.map((row) => {
headCells={headCells} // return {
// ...row,
// caozuo: (
// <MyButton
// text="删除"
// onClick={() => {
// handleDelete(row.id);
// }}
// ></MyButton>
// ),
// };
// })}
rows={[]}
headCells={buttonHeadCells}
selectItems={selectItems} selectItems={selectItems}
setSelectItems={setSelectItems} setSelectItems={setSelectItems}
/> />
...@@ -210,6 +252,10 @@ const MyTableDemo = () => { ...@@ -210,6 +252,10 @@ const MyTableDemo = () => {
page={page} page={page}
count={count} count={count}
pageChange={pageChange} pageChange={pageChange}
paginationType={"complex"}
rowsPerPage={rowsPerPage}
handleChangeRowsPerPage={setRowsPerPage}
totalElements={12}
/> />
</div> </div>
<h2>带分页且固定表头(需要指定每列宽度 不然对不齐)的表格</h2> <h2>带分页且固定表头(需要指定每列宽度 不然对不齐)的表格</h2>
...@@ -227,22 +273,7 @@ const MyTableDemo = () => { ...@@ -227,22 +273,7 @@ const MyTableDemo = () => {
pageChange={pageChange} pageChange={pageChange}
/> />
</div> </div>
<h2>表格底部带按钮 有分页才能用</h2>
<div style={{ height: "300px" }}>
<MyTable
rows={rows}
headCells={headCells}
hasCheckbox={true}
selectItems={selectItems}
setSelectItems={setSelectItems}
fixedHead={true}
hasTableFooter={true}
page={page}
count={count}
pageChange={pageChange}
randerTooterContent={randerButton()}
/>
</div>
<h2> <h2>
带排序表格(headCells中sort为true, 传入sortState、setSortState字段) 带排序表格(headCells中sort为true, 传入sortState、setSortState字段)
</h2> </h2>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment