feat: 时间线
This commit is contained in:
parent
198c7132d1
commit
d074849556
|
@ -13,7 +13,9 @@
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "6.8.0",
|
"react-router-dom": "6.8.0",
|
||||||
"@arco-design/web-react": "2.45.0"
|
"@arco-design/web-react": "2.45.0",
|
||||||
|
"@ricons/fluent": "0.12.0",
|
||||||
|
"dayjs": "1.11.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.27",
|
"@types/react": "^18.0.27",
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
@import "normalize.css";
|
@import "normalize.css";
|
||||||
@import "@arco-design/web-react/dist/css/arco.css";
|
@import "@arco-design/web-react/dist/css/arco.css";
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
.bs-card {
|
.bs-card {
|
||||||
|
overflow: hidden;
|
||||||
.arco-card-body {
|
.arco-card-body {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.mini {
|
||||||
|
.arco-card-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.cover {
|
.cover {
|
||||||
background-size: 105%;
|
background-size: 105%;
|
||||||
|
|
|
@ -1,29 +1,36 @@
|
||||||
import { Card } from "@arco-design/web-react";
|
import { Card } from "@arco-design/web-react";
|
||||||
import { url } from "inspector";
|
import { MouseEventHandler } from "react";
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
const { Meta } = Card;
|
const { Meta } = Card;
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
imgUrl: string;
|
imgUrl: string;
|
||||||
title: string;
|
title: string;
|
||||||
desc: string;
|
meta?: {
|
||||||
action: string;
|
desc?: string;
|
||||||
|
action?: string;
|
||||||
|
};
|
||||||
styles?: {};
|
styles?: {};
|
||||||
|
onClick?: MouseEventHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BsCard(props: IProps) {
|
function BsCard(props: IProps) {
|
||||||
return (
|
const { imgUrl, title, meta, styles, ...rest } = props;
|
||||||
|
return meta ? (
|
||||||
<Card
|
<Card
|
||||||
|
{...rest}
|
||||||
className="bs-card"
|
className="bs-card"
|
||||||
hoverable
|
hoverable
|
||||||
style={{ ...props.styles }}
|
style={{ ...styles }}
|
||||||
cover={
|
cover={
|
||||||
<div
|
<div
|
||||||
className="cover"
|
className="cover"
|
||||||
style={{ backgroundImage: `url('${props.imgUrl}')` }}
|
style={{
|
||||||
|
backgroundImage: `url('${imgUrl}')`,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="mask">
|
<div className="mask">
|
||||||
<p>{props.title}</p>
|
<p>{title}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -31,12 +38,25 @@ function BsCard(props: IProps) {
|
||||||
<Meta
|
<Meta
|
||||||
description={
|
description={
|
||||||
<div className="bottom-des">
|
<div className="bottom-des">
|
||||||
<span className="bs-ellipsis">{props.desc}</span>
|
<span className="bs-ellipsis">{meta?.desc}</span>
|
||||||
<a>{props.action}</a>
|
<a>{meta?.action}</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
) : (
|
||||||
|
<Card {...rest} className="bs-card mini" hoverable style={{ ...styles }}>
|
||||||
|
<div
|
||||||
|
className="cover"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url('${imgUrl}')`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="mask">
|
||||||
|
<p>{title}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
.timescroll {
|
.timescroll {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 20px;
|
width: 40px;
|
||||||
height: 200px;
|
|
||||||
&:hover {
|
|
||||||
.caret {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.caret {
|
.caret {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
right: 0;
|
right: 0;
|
||||||
color: var(--color-fill-4);
|
color: var(--color-text-3);
|
||||||
&.up {
|
&.up {
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
@ -25,24 +24,35 @@
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
top: 24px;
|
top: 24px;
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
width: 4px;
|
width: 3px;
|
||||||
background: var(--color-fill-2);
|
background: var(--color-fill-2);
|
||||||
|
&:hover {
|
||||||
|
.cursor.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
.cursor {
|
.cursor {
|
||||||
|
transition: opacity 0.25s ease;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 8px;
|
left: 50%;
|
||||||
height: 8px;
|
transform: translateX(-50%);
|
||||||
border: 1px solid #333;
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border: 2px solid;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
&.active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.node {
|
.node {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 4px;
|
width: 3px;
|
||||||
height: 4px;
|
height: 3px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
&.bingo {
|
&.bingo {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
background: var(--color-fill-4);
|
background: var(--color-text-3);
|
||||||
&::before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: attr(data-year);
|
content: attr(data-year);
|
||||||
|
@ -50,7 +60,8 @@
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
right: 10px;
|
right: 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--color-fill-4);
|
color: var(--color-text-3);
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.empty {
|
&.empty {
|
||||||
|
@ -59,4 +70,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.caret {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,59 @@
|
||||||
import { useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
|
|
||||||
function TimeScroll() {
|
interface IProps {
|
||||||
const [cursor, setCursor] = useState({
|
className: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TimeScroll(props: IProps) {
|
||||||
|
const [cursorStatic, setCursorStatic] = useState({
|
||||||
top: 0,
|
top: 0,
|
||||||
|
color: "var(--color-fill-4)",
|
||||||
});
|
});
|
||||||
const onMouseMove = (e: any) => {
|
const [cursorActive, setCursorActive] = useState({
|
||||||
const diffY = e.screenY - e.clientY;
|
top: 0,
|
||||||
console.log(e)
|
color: "var(--color-border-3)",
|
||||||
setCursor({ top: diffY });
|
});
|
||||||
|
const [intervalPixel, setIntervalPixel] = useState<number>();
|
||||||
|
const cursorActiveRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const cursorStaticRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const orbitRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击打圈圈 cursorStatic
|
||||||
|
*/
|
||||||
|
const onMouseDown = (ev: any) => {
|
||||||
|
const orbitClient = orbitRef.current!.getBoundingClientRect();
|
||||||
|
let mouseY = (ev || window.event).clientY; //鼠标按下的位置
|
||||||
|
if (mouseY > orbitClient.top && mouseY < orbitClient.bottom)
|
||||||
|
setCursorStatic((p) => ({ ...p, top: mouseY - orbitClient.top - 4 }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动圈圈 coursorActive
|
||||||
|
*/
|
||||||
|
const onMouseMove = (ev: any) => {
|
||||||
|
const orbitClient = orbitRef.current!.getBoundingClientRect();
|
||||||
|
const mouseY = (ev || window.event).clientY;
|
||||||
|
if (mouseY > orbitClient.top && mouseY < orbitClient.bottom)
|
||||||
|
setCursorActive((p) => ({ ...p, top: mouseY - orbitClient.top - 4 }));
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.data) {
|
||||||
|
const years = [...new Set(props.data.map((i: any) => i.year))];
|
||||||
|
const avg = orbitRef.current!.clientHeight / years.length;
|
||||||
|
setIntervalPixel(avg);
|
||||||
|
}
|
||||||
|
}, [props.data, orbitRef.current]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="timescroll" onMouseMove={onMouseMove}>
|
<div
|
||||||
|
className={`timescroll ${props.className}`}
|
||||||
|
onMouseMove={onMouseMove}
|
||||||
|
onMouseDown={onMouseDown}
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
className="caret up"
|
className="caret up"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -19,24 +61,33 @@ function TimeScroll() {
|
||||||
>
|
>
|
||||||
<path d="M8 20l8-10l8 10z" fill="currentColor"></path>
|
<path d="M8 20l8-10l8 10z" fill="currentColor"></path>
|
||||||
</svg>
|
</svg>
|
||||||
<div className="orbit">
|
<div className="orbit" ref={orbitRef}>
|
||||||
<span className="cursor" style={{ top: cursor.top }}></span>
|
<span
|
||||||
|
ref={cursorStaticRef}
|
||||||
|
className="cursor static"
|
||||||
|
style={{ ...cursorStatic }}
|
||||||
|
></span>
|
||||||
|
<span
|
||||||
|
ref={cursorActiveRef}
|
||||||
|
className="cursor active"
|
||||||
|
style={{ ...cursorActive }}
|
||||||
|
></span>
|
||||||
|
{props.data.map((item: any, index: number) => {
|
||||||
|
return item.data.length > 0 ? (
|
||||||
<div
|
<div
|
||||||
|
key={index}
|
||||||
className="node bingo"
|
className="node bingo"
|
||||||
style={{ top: "20px" }}
|
style={{ top: intervalPixel * index + "px" }}
|
||||||
data-year="2021"
|
data-year={item.year}
|
||||||
></div>
|
></div>
|
||||||
<div className="node empty" style={{ top: "40px" }}></div>
|
) : (
|
||||||
<div
|
<div
|
||||||
className="node bingo"
|
key={index}
|
||||||
style={{ top: "60px" }}
|
className="node empty"
|
||||||
data-year="2020"
|
style={{ top: intervalPixel * index + "px" }}
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
className="node bingo"
|
|
||||||
style={{ top: "80px" }}
|
|
||||||
data-year="2019"
|
|
||||||
></div>
|
></div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<svg
|
<svg
|
||||||
className="caret down"
|
className="caret down"
|
||||||
|
|
|
@ -1,11 +1,85 @@
|
||||||
.course {
|
.course {
|
||||||
padding: 100px 0 40px 0;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 100px 0 0 0;
|
||||||
|
height: 100vh;
|
||||||
.recommends {
|
.recommends {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 1fr 1fr;
|
grid-template-columns: 2fr 1fr 1fr;
|
||||||
grid-column-gap: 20px;
|
grid-column-gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-bar {
|
||||||
|
padding: 40px 0 20px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
.table-action {
|
||||||
|
line-height: 1;
|
||||||
|
> span {
|
||||||
|
transition: all 0.25s;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 20px;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-text-1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
color: rgb(var(--primary-6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.timeline {
|
.timeline {
|
||||||
margin-top: 40px;
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
.thumbnail {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 100px;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
> section {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
.time {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
}
|
||||||
|
.statistic {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
color: var(--color-text-3);
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-column-gap: 10px;
|
||||||
|
grid-row-gap: 10px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||||
|
.bs-card {
|
||||||
|
border-radius: 3px;
|
||||||
|
.cover {
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
.mask {
|
||||||
|
p {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.timescroll {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,51 @@
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import Player from "../../components/Player";
|
import Player from "../../components/Player";
|
||||||
import { useMount } from "../../hook";
|
import { useMount } from "../../hook";
|
||||||
import { Select, Message } from "@arco-design/web-react";
|
import { Select, Message, Space, Tooltip } from "@arco-design/web-react";
|
||||||
const Option = Select.Option;
|
const Option = Select.Option;
|
||||||
const options = ["全部", "最新的"];
|
const options = ["全部", "最新的"];
|
||||||
import BsCard from "../../components/Card";
|
import BsCard from "../../components/Card";
|
||||||
import TimeScroll from "../../components/TimeScroll";
|
import TimeScroll from "../../components/TimeScroll";
|
||||||
|
import Tab20Regular from "@ricons/fluent/Tab20Regular";
|
||||||
|
import Table20Regular from "@ricons/fluent/Table20Regular";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { recommendListDefault, courseTimeListDefault } from "./mock";
|
||||||
|
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
useMount(() => {});
|
useMount(() => {});
|
||||||
|
|
||||||
|
const [actions, setActions] = useState([
|
||||||
|
{
|
||||||
|
key: "tab",
|
||||||
|
icon: Tab20Regular,
|
||||||
|
active: false,
|
||||||
|
tip: "单格排列",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "table",
|
||||||
|
icon: Table20Regular,
|
||||||
|
active: true,
|
||||||
|
tip: "缩略",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [recommendList, setRecommendList] = useState(recommendListDefault);
|
||||||
|
|
||||||
|
const [courseTimeList, setCourseTimeList] = useState(courseTimeListDefault);
|
||||||
|
|
||||||
|
const onClickActionItem = (action: any) => {
|
||||||
|
setActions((p) => p.map((a) => ({ ...a, active: a.key === action.key })));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container course">
|
<div className="container course">
|
||||||
<div className="recommends">
|
<div className="recommends">
|
||||||
<BsCard
|
{recommendList.map((item, index) => (
|
||||||
imgUrl={
|
<BsCard {...item} key={index} />
|
||||||
"https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp"
|
))}
|
||||||
}
|
|
||||||
title={"这个非常OK啊"}
|
|
||||||
desc={"推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容"}
|
|
||||||
action={"开始学习"}
|
|
||||||
/>
|
|
||||||
<BsCard
|
|
||||||
imgUrl={
|
|
||||||
"https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/e278888093bef8910e829486fb45dd69.png~tplv-uwbnlip3yd-webp.webp"
|
|
||||||
}
|
|
||||||
title={"这个非常OK啊"}
|
|
||||||
desc={"推荐内容"}
|
|
||||||
action={"开始学习"}
|
|
||||||
/>
|
|
||||||
<BsCard
|
|
||||||
imgUrl={
|
|
||||||
"https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/8361eeb82904210b4f55fab888fe8416.png~tplv-uwbnlip3yd-webp.webp"
|
|
||||||
}
|
|
||||||
title={"这个非常OK啊"}
|
|
||||||
desc={"推荐内容"}
|
|
||||||
action={"开始学习"}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="timeline">
|
|
||||||
|
<div className="action-bar">
|
||||||
<Select
|
<Select
|
||||||
placeholder="排序规则"
|
placeholder="排序规则"
|
||||||
style={{ width: 154 }}
|
style={{ width: 154 }}
|
||||||
|
@ -55,7 +62,36 @@ export default function Index() {
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<TimeScroll />
|
<div className="table-action">
|
||||||
|
{actions.map((action) => (
|
||||||
|
<Tooltip key={action.key} content={action.tip}>
|
||||||
|
<span
|
||||||
|
className={action.active ? "active" : ""}
|
||||||
|
onClick={() => onClickActionItem(action)}
|
||||||
|
>
|
||||||
|
<action.icon />
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="timeline">
|
||||||
|
<div className="thumbnail">
|
||||||
|
{courseTimeList.map((item, index) => (
|
||||||
|
<section key={index}>
|
||||||
|
<div className="time">
|
||||||
|
{item.year}年{item.month}月
|
||||||
|
</div>
|
||||||
|
<div className="statistic">{item.data.length} 个视频</div>
|
||||||
|
<div className="grid">
|
||||||
|
{item.data.map((d: any) => (
|
||||||
|
<BsCard key={d.time} imgUrl={d.img} title={d.title} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<TimeScroll className="timescroll" data={courseTimeList} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
83
apps/web-main/src/view/Course/mock.ts
Normal file
83
apps/web-main/src/view/Course/mock.ts
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
export const recommendListDefault = [
|
||||||
|
{
|
||||||
|
imgUrl:
|
||||||
|
"https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
title: "这个非常OK啊",
|
||||||
|
desc: "推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容",
|
||||||
|
action: "开始学习",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
imgUrl:
|
||||||
|
"https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/e278888093bef8910e829486fb45dd69.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
title: "这个非常OK啊",
|
||||||
|
desc: "推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容",
|
||||||
|
action: "开始学习",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
imgUrl:
|
||||||
|
"https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
title: "这个非常OK啊",
|
||||||
|
desc: "推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容推荐内容",
|
||||||
|
action: "开始学习",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const courseTimeList = [
|
||||||
|
{
|
||||||
|
title: "这个非常OK啊1",
|
||||||
|
time: "1661990400000",
|
||||||
|
img: "https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "这个非常OK啊2",
|
||||||
|
time: "1630454400000",
|
||||||
|
img: "https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "这个非常OK啊333",
|
||||||
|
time: "1625097600000",
|
||||||
|
img: "https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "这个非常OK啊444",
|
||||||
|
time: "1625184000000",
|
||||||
|
img: "https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "这个非常OK啊3",
|
||||||
|
time: "1598918400000",
|
||||||
|
img: "https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const process = (before: any[]) => {
|
||||||
|
const after: any = {};
|
||||||
|
// 提取月份,塞入数据
|
||||||
|
before.forEach((item) => {
|
||||||
|
const year = dayjs(+item.time).year();
|
||||||
|
const month = dayjs(+item.time).month() + 1;
|
||||||
|
if (!(year in after)) after[year] = { [month]: [] };
|
||||||
|
if (!(month in after[year])) after[year][month] = [];
|
||||||
|
after[year][month].push(item);
|
||||||
|
});
|
||||||
|
// 年月为key,倒叙排列
|
||||||
|
const compare = (key: string) => (a: any, b: any) => b[key] - a[key];
|
||||||
|
const ymArray = Object.keys(after)
|
||||||
|
.reverse()
|
||||||
|
.map((year) =>
|
||||||
|
Object.keys(after[year]).map((month) => ({
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
index: +`${year}.${+month > 10 ? month : "0" + month}`,
|
||||||
|
data: after[year][month],
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
.flat()
|
||||||
|
.sort(compare("index"));
|
||||||
|
|
||||||
|
return ymArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const courseTimeListDefault = process(courseTimeList);
|
|
@ -178,10 +178,12 @@ importers:
|
||||||
apps/web-main:
|
apps/web-main:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@arco-design/web-react': 2.45.0
|
'@arco-design/web-react': 2.45.0
|
||||||
|
'@ricons/fluent': 0.12.0
|
||||||
'@types/react': ^18.0.27
|
'@types/react': ^18.0.27
|
||||||
'@types/react-dom': ^18.0.10
|
'@types/react-dom': ^18.0.10
|
||||||
'@types/react-router-dom': 5.3.3
|
'@types/react-router-dom': 5.3.3
|
||||||
'@vitejs/plugin-react': ^3.1.0
|
'@vitejs/plugin-react': ^3.1.0
|
||||||
|
dayjs: 1.11.7
|
||||||
less: ^4.1.3
|
less: ^4.1.3
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
|
@ -191,6 +193,8 @@ importers:
|
||||||
vite-tsconfig-paths: 4.0.5
|
vite-tsconfig-paths: 4.0.5
|
||||||
dependencies:
|
dependencies:
|
||||||
'@arco-design/web-react': registry.npmmirror.com/@arco-design/web-react/2.45.0_5ndqzdd6t4rivxsukjv3i3ak2q
|
'@arco-design/web-react': registry.npmmirror.com/@arco-design/web-react/2.45.0_5ndqzdd6t4rivxsukjv3i3ak2q
|
||||||
|
'@ricons/fluent': registry.npmmirror.com/@ricons/fluent/0.12.0
|
||||||
|
dayjs: registry.npmmirror.com/dayjs/1.11.7
|
||||||
less: registry.npmmirror.com/less/4.1.3
|
less: registry.npmmirror.com/less/4.1.3
|
||||||
react: registry.npmmirror.com/react/18.2.0
|
react: registry.npmmirror.com/react/18.2.0
|
||||||
react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0
|
react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0
|
||||||
|
@ -3801,6 +3805,12 @@ packages:
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
registry.npmmirror.com/@ricons/fluent/0.12.0:
|
||||||
|
resolution: {integrity: sha512-q+mPtxwTCZBeNmIrnKQxHc08f4OvJOxaR1AiGbpJpTMAzm/b8ZdrL14wm5ArYJq+uDNpLynfBYi3CTWsHjRRgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@ricons/fluent/-/fluent-0.12.0.tgz}
|
||||||
|
name: '@ricons/fluent'
|
||||||
|
version: 0.12.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmmirror.com/@rollup/plugin-commonjs/24.0.1_rollup@3.17.2:
|
registry.npmmirror.com/@rollup/plugin-commonjs/24.0.1_rollup@3.17.2:
|
||||||
resolution: {integrity: sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz}
|
resolution: {integrity: sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz}
|
||||||
id: registry.npmmirror.com/@rollup/plugin-commonjs/24.0.1
|
id: registry.npmmirror.com/@rollup/plugin-commonjs/24.0.1
|
||||||
|
|
Loading…
Reference in New Issue
Block a user