Skip to content

Commit 976d189

Browse files
committed
feat: 转让历史
1 parent cb7396f commit 976d189

5 files changed

Lines changed: 480 additions & 2 deletions

File tree

8.92 KB
Loading

src/components/stateless/StatisticCard/index.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import styles from './index.module.less'
55
import iconQuestion from './icons/question.png'
66
import iconBook from './icons/book.png'
77
import iconWallet from './icons/wallet.png'
8+
import iconRate from './icons/rate.png'
89

910
const defaultIcons = {
1011
book: iconBook,
1112
wallet: iconWallet,
1213
question: iconQuestion,
14+
rate: iconRate,
1315
}
1416

1517
const StatisticCard = ({
@@ -27,7 +29,7 @@ const StatisticCard = ({
2729
title: '同比增长',
2830
value: 20,
2931
unit: '%',
30-
icon: 'wallet',
32+
icon: 'rate',
3133
showTooltip: false,
3234
},
3335
],
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
import React, { useState, useEffect, useRef, useLayoutEffect } from 'react'
2+
import { Button } from 'antd'
3+
import styles from './index.module.less'
4+
5+
/**
6+
* 转让历史组件
7+
* @param {Object} props - 组件属性
8+
* @param {number} [props.defaultDisplayCount=3] - 默认显示的子项数量
9+
*/
10+
const TransferHistory = ({ defaultDisplayCount = 3 }) => {
11+
const [expanded, setExpanded] = useState(false)
12+
const [leftLineHeight, setLeftLineHeight] = useState('100%')
13+
const leftLineRef = useRef(null)
14+
const itemRefs = useRef([])
15+
const contentWrapperRef = useRef(null)
16+
17+
// 初始化引用数组
18+
useEffect(() => {
19+
itemRefs.current = []
20+
}, [])
21+
22+
// 模拟数据
23+
const transferData = [
24+
{
25+
name: '转让历史',
26+
id: '1',
27+
level: 1,
28+
children: [
29+
{
30+
name: '山东AI科技股份有限公司',
31+
id: '1-1',
32+
level: 2,
33+
children: [
34+
{ name: '科技股份有限公司第一公司', value: '2022年8月8号', id: '1-1-1', level: 3 },
35+
{ name: '科技股份有限公司第二公司', value: '2023年6月6号', id: '1-1-2', level: 3 },
36+
{ name: '科技股份有限公司第三公司', value: '2024年9月9号', id: '1-1-3', level: 3 },
37+
],
38+
ratio: '85%',
39+
},
40+
{
41+
name: '广东发展有限公司',
42+
id: '1-2',
43+
level: 2,
44+
children: [{ name: '广东发展有限公司分公司', value: '2024年5月1号', id: '1-2-1', level: 3 }],
45+
ratio: '55%',
46+
},
47+
{
48+
name: '科技发展股份有限公司',
49+
id: '1-3',
50+
level: 2,
51+
children: [
52+
{ name: '科技股份有限公司一', value: '2022年7月31号', id: '1-3-1', level: 3 },
53+
{ name: '科技股份有限公司二', value: '2023年8月1号', id: '1-3-2', level: 3 },
54+
],
55+
ratio: '35%',
56+
},
57+
{
58+
name: '第四家公司',
59+
id: '1-4',
60+
level: 2,
61+
children: [{ name: '受让方第四分公司', value: '2021年8月20号', id: '1-4-1', level: 3 }],
62+
ratio: '25%',
63+
},
64+
{
65+
name: '第五家公司',
66+
id: '1-5',
67+
level: 2,
68+
children: [{ name: '受让方第五分公司', value: '2020年6月6号', id: '1-5-1', level: 3 }],
69+
ratio: '15%',
70+
},
71+
],
72+
},
73+
]
74+
75+
/**
76+
* 计算左侧线条高度(不包含按钮高度)
77+
*/
78+
const calculateLineHeight = () => {
79+
if (!transferData || !transferData[0] || !transferData[0].children || transferData[0].children.length === 0) {
80+
setLeftLineHeight('0px')
81+
return
82+
}
83+
84+
// 根据展开状态计算显示的子项数量
85+
const displayCount = expanded
86+
? transferData[0].children.length
87+
: Math.min(defaultDisplayCount, transferData[0].children.length)
88+
const lastIndex = displayCount - 1
89+
90+
// 确保元素已渲染
91+
if (!itemRefs.current[0] || !itemRefs.current[lastIndex] || !leftLineRef.current) {
92+
return
93+
}
94+
95+
// 获取第一个和最后一个子项的高度
96+
const firstItemHeight = itemRefs.current[0].offsetHeight
97+
const lastItemHeight = itemRefs.current[lastIndex].offsetHeight
98+
99+
// 计算实际内容高度(仅包含子项容器,不包含按钮)
100+
// 使用getBoundingClientRect获取精确高度
101+
const firstItemRect = itemRefs.current[0].getBoundingClientRect()
102+
const lastItemRect = itemRefs.current[lastIndex].getBoundingClientRect()
103+
104+
// 计算线条高度:从第一个子项的中心到最后一个子项的中心
105+
const lineHeight = lastItemRect.top + lastItemRect.height / 2 - (firstItemRect.top + firstItemRect.height / 2)
106+
107+
setLeftLineHeight(`${lineHeight}px`)
108+
}
109+
110+
/**
111+
* 切换展开/折叠状态
112+
*/
113+
const toggleExpand = () => {
114+
setExpanded(!expanded)
115+
}
116+
117+
// 使用useLayoutEffect确保在DOM更新后立即计算
118+
useLayoutEffect(() => {
119+
calculateLineHeight()
120+
}, [expanded])
121+
122+
// 组件挂载后计算线条高度
123+
useLayoutEffect(() => {
124+
calculateLineHeight()
125+
126+
// 添加窗口大小变化时的重新计算
127+
const handleResize = () => {
128+
calculateLineHeight()
129+
}
130+
131+
window.addEventListener('resize', handleResize)
132+
return () => {
133+
window.removeEventListener('resize', handleResize)
134+
}
135+
}, [expanded])
136+
137+
return (
138+
<div className={styles.transferHistoryContainer}>
139+
{transferData.map((item, index) => (
140+
<div key={index} className={styles.historyItem}>
141+
{item.level === 1 && (
142+
<div className={styles.levelOne}>
143+
<div className={styles.levelName}>{item.name}</div>
144+
</div>
145+
)}
146+
147+
{/* 主体内容区域 */}
148+
<div className={styles.contentWrapper} ref={contentWrapperRef}>
149+
<div className={styles.leftContent}>
150+
<div className={styles.levelTwo}>
151+
<div className={styles.verticalConnector} style={{ height: leftLineHeight }}></div>
152+
<div className={styles.leftLine} ref={leftLineRef}>
153+
{item.children && item.children.length > 0 && (
154+
<>
155+
{/* 控制显示的子项数量 */}
156+
{(item.children.length > defaultDisplayCount && !expanded
157+
? item.children.slice(0, defaultDisplayCount)
158+
: item.children
159+
).map((cItem, cIndex) => (
160+
<div
161+
key={cIndex}
162+
className={`${styles.subItemContainer} ${styles.subItemLine}`}
163+
ref={(el) => (itemRefs.current[cIndex] = el)}
164+
>
165+
{/* 第二级菜单 */}
166+
<div className={styles.subItem}>{cItem.name}</div>
167+
168+
{/* 第三级菜单 */}
169+
{cItem.children && cItem.children.length > 0 && (
170+
<>
171+
{cItem.children.map((tItem, tIndex) => (
172+
<div
173+
key={tIndex}
174+
className={
175+
tIndex === cItem.children.length - 1
176+
? `${styles.tertiaryItem} ${styles.lastTertiaryItem}`
177+
: styles.tertiaryItem
178+
}
179+
>
180+
{tIndex < cItem.children.length && (
181+
<>
182+
<div className={styles.transferInfo}>
183+
<div>
184+
转让<span style={{ color: '#EF4A10' }}>20%</span>股权
185+
</div>
186+
<div>受让方:{tItem.name}</div>
187+
</div>
188+
<div className={styles.infoConnector}></div>
189+
<div
190+
className={
191+
cItem.children.length - 2 === tIndex
192+
? styles.horizontalConnector
193+
: `${styles.horizontalConnector} ${styles.lastConnector}`
194+
}
195+
></div>
196+
<div className={styles.transferYear}>{tItem.value}</div>
197+
</>
198+
)}
199+
</div>
200+
))}
201+
<div className={styles.currentHolding}>
202+
<div>现持有股权:</div>
203+
<div style={{ color: '#EF4A10' }}>{cItem.ratio}</div>
204+
</div>
205+
</>
206+
)}
207+
</div>
208+
))}
209+
</>
210+
)}
211+
</div>
212+
</div>
213+
214+
{item.children && item.children.length > defaultDisplayCount && (
215+
<div className={styles.expandButtonContainer}>
216+
<Button type="link" onClick={toggleExpand} className={styles.expandButton}>
217+
{expanded ? '收起部分公司' : '展开全部公司'}
218+
<i className={expanded ? 'anticon anticon-up' : 'anticon anticon-down'}></i>
219+
</Button>
220+
</div>
221+
)}
222+
</div>
223+
</div>
224+
</div>
225+
))}
226+
</div>
227+
)
228+
}
229+
230+
export default TransferHistory

0 commit comments

Comments
 (0)