rtgk-screen-web/components/screen/Table/index.js

181 lines
4.9 KiB
JavaScript
Raw Normal View History

2024-06-20 11:26:44 +08:00
import React, { useImperativeHandle, useRef, useEffect, useCallback, useState, useMemo } from 'react'
const itemSize = 40;
const Table = React.forwardRef((props, ref) => {
const {columns = [], mainKey = 'id', autoNext = true, pageFinished, dataSource} = props;
const sizeRef = useRef();
const tableRef = useRef();
const [pageSize, setPageSize] = useState(0);
const [page, setPage] = useState(1);
const [data, setData] = useState([])
const totalPage = useMemo(
() => Math.ceil(data.length / pageSize),
[data, pageSize]
);
const currentData = useMemo(
() => data.slice(pageSize * (page - 1), pageSize * page),
[data, pageSize, page]
)
const tableSetting = useCallback(() => {
let { offsetHeight, scrollHeight, offsetWidth, scrollWidth } = tableRef.current;
let pageSize = Math.floor(offsetHeight / itemSize) - 1;
setPageSize(pageSize);
}, [])
const nextPage = useCallback(() => {
if(page + 1 > totalPage){
if(autoNext){
setPage(1);
}else{
pageFinished && pageFinished();
}
}else{
setPage(page + 1);
}
}, [totalPage, page])
useEffect(() => {
let innerWindow = sizeRef.current.contentDocument.defaultView;
innerWindow.addEventListener("resize", tableSetting);
tableSetting();
return () => {
innerWindow.removeEventListener("resize", tableSetting);
}
}, [tableSetting])
useEffect(() => {
if (dataSource) {
setData(dataSource);
setPage(1);
}
}, [dataSource]);
useImperativeHandle(ref, () => ({
nextPage,
setData: data => {
setData(data);
setPage(1);
},
addData: addData => {
setData(data.concat(...addData))
},
updateData: updateData => {
setData(data.map(item => {
let mainValue = item[mainKey];
let update = updateData.find(i => i[mainKey] === mainValue);
if(update) item = update;
return item;
}))
},
deleteData: deleteData => {
setData(data.filter(item => {
let mainValue = item[mainKey];
return !deleteData.find(i => i[mainKey] === mainValue);
}))
},
}), [data, nextPage, mainKey])
return (
<div className="screen-table" ref={tableRef}>
<object
ref={sizeRef}
tabIndex="-1"
type="text/html"
aria-hidden="true"
data="about:blank"
style={{
display: "block",
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
border: "none",
padding: 0,
margin: 0,
opacity: 0,
zIndex: -1000,
pointerEvents: "none",
}}>
</object>
<table>
<thead>
<tr>
{columns.map(({title, width}) => {
let thProps = {key: title};
if(width !== undefined) thProps.style = {width: width + 'px'}
return <th {...thProps}>{title}</th>
})}
</tr>
</thead>
<tbody>
{currentData.map((item, index) => (
<tr key={item[mainKey]} className={index % 2 === 1 ? `delay-${index} stripe`: `delay-${index}`}>
{columns.map(config => {
let {title,code, render} = config;
if(render) return <td key={title}>{render(item[code], config, item)}</td>;
return <td key={title}>{item[code]}</td>
})}
</tr>
))}
</tbody>
</table>
<style jsx>{`
.screen-table{
height: 100%;
overflow: hidden;
text-align: center;
position: relative;
}
.screen-table > table{
width: 100%;
}
.screen-table th,
.screen-table td{
height: ${itemSize}px;
word-break: break-all;
color: rgba(255, 255, 255, 0.85);
font-weight: 400;
}
.screen-table th{
background: rgba(40, 163, 255, 0.25);
}
.screen-table .stripe td{
background: rgba(40, 163, 255, 0.1);
}
.screen-table tbody tr{
animation-name: show;
animation-duration: 0.3s;
animation-iteration-count: 1;
opacity: 0;
animation-fill-mode: forwards;
}
@keyframes show {
from {opacity: 0;}
to {opacity: 1;}
}
`}</style>
<style jsx global>{`
.delay-0{ animation-delay: 0s; }
.delay-1{ animation-delay: 0.2s; }
.delay-2{ animation-delay: 0.4s; }
.delay-3{ animation-delay: 0.6s; }
.delay-4{ animation-delay: 0.8s; }
.delay-5{ animation-delay: 1s; }
.delay-6{ animation-delay: 1.2s; }
.delay-7{ animation-delay: 1.4s; }
.delay-8{ animation-delay: 1.6s; }
.delay-9{ animation-delay: 1.8s; }
`}</style>
</div>
);
})
export default Table;