362 lines
11 KiB
JavaScript
362 lines
11 KiB
JavaScript
import React, {
|
||
useState,
|
||
useImperativeHandle,
|
||
useRef,
|
||
useCallback,
|
||
useEffect,
|
||
useMemo,
|
||
} from "react";
|
||
import InfoCard from "./InfoCard";
|
||
import Row from "../Row";
|
||
|
||
const gutter = 20;
|
||
const cardBottom = 20;
|
||
|
||
const InfoCardList = React.forwardRef((props, ref) => {
|
||
const {
|
||
mainKey,
|
||
speed = 50,
|
||
span = 4,
|
||
withClassify = false,
|
||
autoNext = true,
|
||
classifyKey = { name: "name", children: "children" },
|
||
pageFinished,
|
||
type = "move",
|
||
extraColumnsOpt,
|
||
...otherProps
|
||
} = props;
|
||
|
||
const sizeRef = useRef();
|
||
const infoCardListRef = useRef();
|
||
const pageBoxRef = useRef();
|
||
const pageRef = useRef(1);
|
||
|
||
const [data, setData] = useState([]);
|
||
const [energy, setEnergy] = useState([]);
|
||
const [autoScroll, setAutoScroll] = useState([0, 0]);
|
||
|
||
const classifyRef = useRef([]);
|
||
const classifyBoxRef = useRef();
|
||
|
||
const pageSize = useMemo(() => Math.floor(24 / span), [span]);
|
||
const totalPage = useMemo(() => {
|
||
if (withClassify) {
|
||
let { children } = classifyKey;
|
||
let size = 0;
|
||
classifyRef.current = [];
|
||
data.forEach((item) => {
|
||
let itemPageSize = Math.ceil((item[children].length || 0) / pageSize);
|
||
size += itemPageSize;
|
||
classifyRef.current.push(size);
|
||
});
|
||
return size;
|
||
} else return Math.ceil(data.length / pageSize);
|
||
}, [data, pageSize, withClassify, classifyKey]);
|
||
const [pageHeight, setPageHeight] = useState(0);
|
||
|
||
const setActiveClassify = useCallback(
|
||
(page) => {
|
||
if (!classifyBoxRef.current) return;
|
||
let classifyIndex =
|
||
classifyRef.current.findIndex((maxPageSize) => page <= maxPageSize) ||
|
||
0;
|
||
let { name } = classifyKey;
|
||
let oprationname = data?.[classifyIndex]?.[name].split("】")[1];
|
||
let text = oprationname === undefined ? "" : "- " + oprationname;
|
||
if (text) {
|
||
classifyBoxRef.current.style.display = "block";
|
||
classifyBoxRef.current.innerText = text;
|
||
} else classifyBoxRef.current.style.display = "none";
|
||
},
|
||
[data]
|
||
);
|
||
|
||
const setPageBoxCss = useCallback(
|
||
(page) => {
|
||
pageRef.current = page;
|
||
setActiveClassify(page);
|
||
pageBoxRef.current.style.transition =
|
||
page === 1 ? "none" : "transform 0.3s";
|
||
pageBoxRef.current.style.transform = `translateY(${
|
||
-(page - 1) * (pageHeight + cardBottom)
|
||
}px)`;
|
||
},
|
||
[pageHeight, setActiveClassify]
|
||
);
|
||
|
||
const nextPage = useCallback(() => {
|
||
// console.log();
|
||
let page = pageRef.current;
|
||
if (page + 1 > totalPage) {
|
||
if (autoNext) {
|
||
setPageBoxCss(1);
|
||
} else {
|
||
pageFinished && pageFinished();
|
||
}
|
||
} else {
|
||
setPageBoxCss(page + 1);
|
||
}
|
||
}, [totalPage]);
|
||
|
||
const moveChecking = useCallback(() => {
|
||
let { offsetWidth, scrollWidth } = infoCardListRef.current;
|
||
setAutoScroll([offsetWidth, scrollWidth]);
|
||
}, [data]);
|
||
const pageChecking = useCallback(() => {
|
||
let { scrollHeight, offsetHeight } = sizeRef.current;
|
||
setPageHeight(scrollHeight);
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (type === "move") {
|
||
let innerWindow = sizeRef.current.contentDocument.defaultView;
|
||
innerWindow.addEventListener("resize", moveChecking);
|
||
moveChecking();
|
||
return () => {
|
||
innerWindow.removeEventListener("resize", moveChecking);
|
||
};
|
||
}
|
||
}, [moveChecking]);
|
||
|
||
useEffect(() => {
|
||
if (type === "page") {
|
||
let innerWindow = sizeRef.current.contentDocument.defaultView;
|
||
innerWindow.addEventListener("resize", pageChecking);
|
||
pageChecking();
|
||
return () => {
|
||
innerWindow.removeEventListener("resize", pageChecking);
|
||
};
|
||
}
|
||
}, [pageChecking]);
|
||
|
||
useEffect(() => {
|
||
setPageBoxCss(1);
|
||
}, [data, setPageBoxCss]);
|
||
|
||
useImperativeHandle(
|
||
ref,
|
||
() => ({
|
||
setData: (data) => {
|
||
setData(data);
|
||
setPageBoxCss(1);
|
||
},
|
||
setEnergy:(data)=>{
|
||
setEnergy(data);
|
||
},
|
||
nextPage,
|
||
}),
|
||
[nextPage]
|
||
);
|
||
|
||
return (
|
||
<div className="infoCardList" ref={infoCardListRef}>
|
||
{type === "move" && (
|
||
<div className="box move">
|
||
{data.map((item) => {
|
||
return (
|
||
<div key={item[mainKey]} className="item">
|
||
<InfoCard {...otherProps} data={item} />
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
)}
|
||
{type === "page" && (
|
||
<div className="page-content">
|
||
{withClassify === true && (
|
||
<div className="classify" ref={classifyBoxRef}></div>
|
||
)}
|
||
<div className="classifycenter -mt-14 w-full text-center ">
|
||
<label className="bg-[#1890ff] p-1 pt-0.5 pb-0.5">能源信息</label>
|
||
</div>
|
||
<div className="classifycenterval grid grid-cols-2 gap-1 place-items-start -mt-7 w-full">
|
||
{console.log("ernergy",energy)}
|
||
{/* {props.energy ?? `日期:${props.energy[0]} 水: ${props.energy[0].water} 电: ${1} 气: ${1}`} */}
|
||
{
|
||
energy.map(x=>{
|
||
return (
|
||
<span className={ energy.indexOf(x)===0?`flex-1 mr-20 justify-self-end`:`flex-1 ml-20 justify-self-start`}> 日期:{x.time} 水: {x.water} 电: {x.electricity} 气: {x.gas}</span>
|
||
)
|
||
})}
|
||
</div>
|
||
<div className="page-box">
|
||
<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>
|
||
<div className="page" ref={pageBoxRef}>
|
||
{withClassify === false && (
|
||
<Row className="height-100" gutter={20}>
|
||
{data.map((item) => {
|
||
let extraColumns = [];
|
||
if (extraColumnsOpt) {
|
||
let { key, name, val, max } = extraColumnsOpt;
|
||
let extraData = item[key];
|
||
extraData.forEach((i, index) => {
|
||
if (index < max)
|
||
extraColumns.push({ title: i[name], text: i[val] });
|
||
});
|
||
}
|
||
return (
|
||
<Row.Col span={span} key={item[mainKey]}>
|
||
<div className="item height-100">
|
||
<InfoCard
|
||
{...otherProps}
|
||
extraColumns={extraColumns}
|
||
data={item}
|
||
cardWidth={false}
|
||
/>
|
||
</div>
|
||
</Row.Col>
|
||
);
|
||
})}
|
||
</Row>
|
||
)}
|
||
{withClassify === true &&
|
||
data.map((item) => {
|
||
let { name, children } = classifyKey;
|
||
return (
|
||
<Row gutter={20} key={item[name]}>
|
||
{item[children].map((item) => {
|
||
let extraColumns = [];
|
||
if (extraColumnsOpt) {
|
||
let { key, name, val, max } = extraColumnsOpt;
|
||
let extraData = item[key];
|
||
extraData.forEach((i, index) => {
|
||
if (index < max)
|
||
extraColumns.push({
|
||
title: i[name],
|
||
text: i[val],
|
||
});
|
||
});
|
||
}
|
||
return (
|
||
<Row.Col span={span} key={item[mainKey]}>
|
||
<div className="item">
|
||
<InfoCard
|
||
{...otherProps}
|
||
extraColumns={extraColumns}
|
||
data={item}
|
||
cardWidth={false}
|
||
/>
|
||
</div>
|
||
</Row.Col>
|
||
);
|
||
})}
|
||
</Row>
|
||
);
|
||
})}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
<style jsx>{`
|
||
.infoCardList {
|
||
height: 100%;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
.infoCardList > .box {
|
||
height: 100%;
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
}
|
||
.infoCardList > .box > .item {
|
||
height: 100%;
|
||
padding-right: ${gutter}px;
|
||
}
|
||
.infoCardList > .box.move {
|
||
animation: move ${autoScroll[1] / speed}s linear infinite;
|
||
animation-fill-mode: forwards;
|
||
transform: translateX(0px);
|
||
}
|
||
@keyframes move {
|
||
from {
|
||
transform: translateX(${autoScroll[0]}px);
|
||
}
|
||
to {
|
||
transform: translateX(${-autoScroll[1]}px);
|
||
}
|
||
}
|
||
.infoCardList .page {
|
||
height: 100%;
|
||
}
|
||
.infoCardList .page :global(.col) {
|
||
margin-bottom: ${cardBottom}px;
|
||
}
|
||
.infoCardList .page .item {
|
||
height: ${pageHeight}px;
|
||
}
|
||
|
||
.infoCardList .page-content {
|
||
height: 100%;
|
||
padding-top: 55px;
|
||
padding-bottom: 15px;
|
||
position: relative;
|
||
}
|
||
.infoCardList .classify {
|
||
position: absolute;
|
||
z-index: 100;
|
||
font-weight: 600;
|
||
font-size: 1.125rem;
|
||
left: 100px;
|
||
top: 0px;
|
||
// background: #15579f;
|
||
// border-radius: 3px;
|
||
// transition: all .3s;
|
||
}
|
||
.infoCardList .classifycenter label {
|
||
font-weight: 600;
|
||
font-size: 1.125rem;
|
||
}
|
||
.infoCardList .classifycenter {
|
||
position: absolute;
|
||
z-index: 100;
|
||
|
||
// left: 48.5%;
|
||
// padding: 2px 5px;
|
||
// top: -3px;
|
||
// background: #1890ff;
|
||
// border-radius: 3px;
|
||
// transition: all .3s;
|
||
}
|
||
.infoCardList .classifycenterval {
|
||
position: absolute;
|
||
z-index: 100;
|
||
font-weight: 600;
|
||
font-size: 1.125rem;
|
||
// left: 19%;
|
||
// top: 20px;
|
||
// padding: 2px 5px;
|
||
// border-radius: 3px;
|
||
// transition: all .3s;
|
||
}
|
||
.infoCardList .page-box {
|
||
height: 100%;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
`}</style>
|
||
</div>
|
||
);
|
||
});
|
||
|
||
export default InfoCardList;
|