Welcome.tsx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. import React, { useEffect, useState } from 'react';
  2. import { Avatar, Button, Card, Col, List, Space, Tag } from 'antd';
  3. import { useModel } from '@umijs/max';
  4. import { PageContainer, ProCard } from '@ant-design/pro-components';
  5. import { ArrowDownOutlined, ArrowUpOutlined, MoreOutlined } from '@ant-design/icons';
  6. import * as echarts from 'echarts';
  7. import ECharts from '@/pages/example/components/ECharts';
  8. import { getDataList } from '@/services/rwa/Welcome';
  9. const Welcome: React.FC = () => {
  10. const { initialState } = useModel('@@initialState');
  11. const menuList = initialState?.menuList;
  12. const cols: React.ReactElement[] = [];
  13. menuList?.forEach((item) => {
  14. cols.push(
  15. <Col key={item.key} span={6}>
  16. <Card bordered={false}>
  17. <Button href={item.path}>{item.name}</Button>
  18. </Card>
  19. </Col>,
  20. );
  21. });
  22. /**
  23. * 顶部任务卡片数据
  24. * 存储8个数据
  25. * 0:今日任务总数
  26. * 1:昨日任务总数
  27. * 2:今日完成总数
  28. * 3:昨日完成总数
  29. * 4:今日未完成总数
  30. * 5:昨日未完成总数
  31. * 6:今日废弃总数
  32. * 7:昨日废弃总数
  33. */
  34. const [taskDataCount, setTaskDataCount] = useState<number[]>([0, 0, 0, 0, 0, 0, 0, 0]);
  35. const [contUuCount, setContUuCount] = useState<any[]>([]);
  36. // 表内业务风险暴露(一级)风险加权资产占比
  37. const [ withinTableAssetType,setWithinTableAssetType] = useState<any[]>([]);
  38. // 表外业务风险暴露(一级)风险加权资产占比
  39. const [ outTableAssetType,setOutTableAssetType] = useState<any[]>([]);
  40. // 前十大机构信用风险加权资产合计
  41. const [top10OrgAssetAccountName,setTop10OrgAssetAccountName] = useState<any[]>([]);
  42. const [top10OrgAssetAccountValue,setTop10OrgAssetAccountValue] = useState<any[]>([]);
  43. // 风险暴露(一级)风险加权资产占比
  44. const [riskExposeAssetRatio,setRiskExposeAssetRatio] = useState<any[]>([]);
  45. // 风险暴露(一级)缓释前风险暴露占比
  46. const [preReleaseRiskExposeAssetRatio,setPreReleaseRiskExposeAssetRatio] = useState<any[]>([]);
  47. // 信用风险缓释工具当期缓释覆盖金额占比
  48. const [creditRiskReleaseTool,setCreditRiskReleaseTool] = useState<any[]>([]);
  49. // 风险暴露分类(一级)当期缓释情况
  50. const [riskExposeClass,setRiskExposeClass] = useState<any[]>([]);
  51. // 存放x轴标签值
  52. const [xLableList,setXLableList] = useState<any[]>([]);
  53. // 缓释数据存放list
  54. const [releaseDataList,setReleaseDataList] = useState<any[]>([]);
  55. // 未缓释数据存放list
  56. const [unReleaseDataList,setUnReleaseDataList] = useState<any[]>([]);
  57. // 缓释比例存放list
  58. const [releaseRatioDataList,setReleaseRatioDataList] = useState<any[]>([]);
  59. /**
  60. * 模拟造数方法,正是环境删掉
  61. * @param minValue
  62. * @param maxValue
  63. * @returns
  64. */
  65. const selectFrom = (minValue: number, maxValue: number) => {
  66. // 通过最大值减去最小值然后加1得到取值的范围可能值的总数
  67. // 例如取2到10之间的整数,10-2 = 8
  68. const choices = maxValue - minValue;
  69. // 然后通过随机数乘以刚才的到的值,
  70. // 例如:Math.random() * 8,由于得到的是小于1的随机数,所以随机最大值0.99*8得到的数始终小于8
  71. // 然后使用floor方法向下取正得到的数最大值就是7,然后再加上最小值
  72. return Math.floor(Math.random() * choices + minValue);
  73. };
  74. const chartSetOption = (
  75. id: string,
  76. title: string,
  77. optionPropss: { seriesName: string; type: 'pie'; data: any[] }[],
  78. color?: string[],
  79. ) => {
  80. const titleProps = {
  81. text: title,
  82. left: 'left',
  83. textStyle: {
  84. fontSize: '20',
  85. },
  86. };
  87. const seriesProps: any[] = [];
  88. optionPropss.forEach((optionProps: { seriesName: string; type: 'pie'; data: any[] }) => {
  89. if (optionProps.type === 'pie') {
  90. seriesProps.push({
  91. name: optionProps.seriesName,
  92. type: optionProps.type,
  93. data: optionProps.data,
  94. radius: '70%',
  95. label: {
  96. show: false,
  97. },
  98. labelLine: {
  99. show: false,
  100. },
  101. itemStyle: {
  102. borderRadius: 10,
  103. borderColor: '#fff',
  104. borderWidth: 2,
  105. },
  106. center: ['30%', '50%'],
  107. });
  108. }
  109. });
  110. const option: Record<string, any> = {
  111. title: titleProps,
  112. tooltip: {
  113. trigger: 'item',
  114. },
  115. legend: {
  116. orient: 'vertical',
  117. left: 'right',
  118. },
  119. series: seriesProps,
  120. };
  121. if (color) {
  122. option!.color = color;
  123. }
  124. const dom = document.getElementById(id);
  125. if (dom) {
  126. let chart = echarts.init(dom);
  127. //销毁图表,否则图表无法重新创建
  128. if (chart) {
  129. try {
  130. chart.dispose();
  131. } catch (e) {}
  132. }
  133. chart = echarts.init(dom);
  134. chart.setOption(option);
  135. }
  136. };
  137. const init = () => {
  138. setTaskDataCount([
  139. selectFrom(1000, 4000),
  140. selectFrom(1000, 4000),
  141. selectFrom(800, 1000),
  142. selectFrom(800, 1000),
  143. selectFrom(800, 1000),
  144. selectFrom(800, 1000),
  145. selectFrom(800, 1000),
  146. selectFrom(800, 1000),
  147. ]);
  148. chartSetOption(
  149. 'contCard-prodUseCount',
  150. '产品使用统计',
  151. [
  152. {
  153. seriesName: '使用数量',
  154. type: 'pie',
  155. data: [
  156. { value: selectFrom(1000, 4000), name: '产品配置标准版本管理' },
  157. { value: selectFrom(1000, 4000), name: '系统管理' },
  158. { value: selectFrom(1000, 4000), name: '平台管理' },
  159. { value: selectFrom(1000, 4000), name: '财务引擎' },
  160. { value: selectFrom(1000, 4000), name: '规则引擎' },
  161. { value: selectFrom(1000, 4000), name: '交易引擎' },
  162. { value: selectFrom(1000, 4000), name: '模型引擎' },
  163. { value: selectFrom(1000, 4000), name: '流程引擎' },
  164. { value: selectFrom(1000, 4000), name: '权限管理' },
  165. { value: selectFrom(1000, 4000), name: '公共机制管理' },
  166. { value: selectFrom(1000, 4000), name: '数据补录' },
  167. { value: selectFrom(1000, 4000), name: '批次配置管理' },
  168. ],
  169. },
  170. ],
  171. [
  172. '#9ED4E8',
  173. '#F49495',
  174. '#FBD88B',
  175. '#B2DC9C',
  176. '#879BD6',
  177. '#FDC537',
  178. '#F833A1',
  179. '#718EF4',
  180. '#49C6FF',
  181. '#72EBCC',
  182. '#B6B7E9',
  183. '#FEDEE0',
  184. ],
  185. );
  186. setContUuCount([
  187. {
  188. title: '超级管理员',
  189. avatar: '/avatar.png',
  190. description: '系统管理:203 | 平台管理:23 | 权限管理:18',
  191. tags: [
  192. { color: '#F53E27', title: '系统管理' },
  193. { color: '#FA7921', title: '平台管理' },
  194. ],
  195. },
  196. {
  197. title: '测试管理员',
  198. },
  199. {
  200. title: '业务管理员',
  201. },
  202. {
  203. title: '维护管理员',
  204. },
  205. ]);
  206. };
  207. useEffect(() => {
  208. init();
  209. //十分钟请求一次后台获取数据
  210. setInterval(init, 1000 * 60 * 3);
  211. getChartData();
  212. }, []);
  213. const getChartData = async () => {
  214. const resData = await getDataList()
  215. // 表内业务风险暴露(一级)风险加权资产占比
  216. setWithinTableAssetType(resData.WithinTableAssetType?.pieData);
  217. // 表外业务风险暴露(一级)风险加权资产占比
  218. setOutTableAssetType(resData.OutTableAssetType?.pieData);
  219. // 前十大机构信用风险加权资产合计
  220. if (resData.Top10OrgAssetAccount?.pieData && resData.Top10OrgAssetAccount?.pieData.length > 0) {
  221. resData.Top10OrgAssetAccount?.pieData.forEach((item,index)=>{
  222. if (item?.name) {
  223. top10OrgAssetAccountName.push(item?.name);
  224. }
  225. if (item.value) {
  226. top10OrgAssetAccountValue.push(item.value);
  227. }
  228. });
  229. setTop10OrgAssetAccountName(...[top10OrgAssetAccountName]);
  230. setTop10OrgAssetAccountValue(...[top10OrgAssetAccountValue]);
  231. } else {
  232. setTop10OrgAssetAccountName([]);
  233. setTop10OrgAssetAccountValue([]);
  234. }
  235. // 风险暴露(一级)风险加权资产占比
  236. setRiskExposeAssetRatio(resData.RiskExposeAssetRatio?.pieData);
  237. // 风险暴露(一级)缓释前风险暴露占比
  238. setPreReleaseRiskExposeAssetRatio(resData.PreReleaseRiskExposeAssetRatio?.pieData);
  239. // 信用风险缓释工具当期缓释覆盖金额占比
  240. setCreditRiskReleaseTool(resData.CreditRiskReleaseTool?.pieData);
  241. // 风险暴露分类(一级)当期缓释情况
  242. if (resData.RiskExposeClass) {
  243. if (resData.RiskExposeClass.xLabels) {
  244. setXLableList(resData.RiskExposeClass.xLabels);
  245. }
  246. if (resData.RiskExposeClass.xData) {
  247. setReleaseDataList(resData.RiskExposeClass.xData);
  248. }
  249. if (resData.RiskExposeClass.yData) {
  250. setUnReleaseDataList(resData.RiskExposeClass.yData);
  251. }
  252. if (resData.RiskExposeClass.zData) {
  253. setReleaseRatioDataList(resData.RiskExposeClass.zData);
  254. }
  255. }
  256. setRiskExposeClass(resData.RiskExposeClass?.pieData);
  257. }
  258. /**
  259. * 任务卡片生成
  260. * @param title 卡片标题
  261. * @param taskIndex 卡片数据索引
  262. * @returns
  263. */
  264. const drawTaskCard = (title: string, taskIndex: number) => {
  265. const today = taskDataCount[taskIndex];
  266. const yesterday = taskDataCount[taskIndex + 1];
  267. return (
  268. <div className="taskCard-content">
  269. <div className="taskCard-title">
  270. {title}
  271. <div className="taskCard-button">
  272. <Button type="text">
  273. <MoreOutlined style={{ fontSize: '20px', fontWeight: 'bold' }} />
  274. </Button>
  275. </div>
  276. </div>
  277. <div className="taskCard-show">
  278. {today >= yesterday ? (
  279. <ArrowUpOutlined className="taskCard-sign taskCard-sign-green" />
  280. ) : (
  281. <ArrowDownOutlined className="taskCard-sign taskCard-sign-red" />
  282. )}
  283. <div className="taskCard-data">{today}</div>
  284. <div className="taskCard-compare">
  285. 较昨日
  286. {today >= yesterday ? (
  287. <span className="taskCard-sign-green">上涨</span>
  288. ) : (
  289. <span className="taskCard-sign-red">下降</span>
  290. )}
  291. {Math.abs(today - yesterday)}个
  292. </div>
  293. </div>
  294. </div>
  295. );
  296. };
  297. const chartOne = {
  298. title: {
  299. text: '表内业务风险暴露(一级)风险加权资产占比',
  300. left: 'center'
  301. },
  302. tooltip: {
  303. trigger: 'item'
  304. },
  305. legend: {
  306. top: '90%',
  307. left: 'center'
  308. },
  309. series: [
  310. {
  311. name: 'Access From',
  312. type: 'pie',
  313. radius: ['40%', '70%'],
  314. avoidLabelOverlap: false,
  315. itemStyle: {
  316. borderRadius: 10,
  317. borderColor: '#fff',
  318. borderWidth: 2
  319. },
  320. label: {
  321. position: 'outer',
  322. alignTo: 'none',
  323. bleedMargin: 5
  324. },
  325. // emphasis: {
  326. // label: {
  327. // show: true,
  328. // fontSize: 10,
  329. // fontWeight: 'bold'
  330. // }
  331. // },
  332. emphasis: {
  333. label: {
  334. show: true,
  335. fontSize: 20,
  336. fontWeight: 'bold'
  337. },
  338. itemStyle: {
  339. shadowBlur: 10,
  340. shadowOffsetX: 0,
  341. shadowColor: 'rgba(0, 0, 0, 0.5)'
  342. }
  343. },
  344. labelLine: {
  345. show: true
  346. },
  347. data: withinTableAssetType
  348. }
  349. ]
  350. };
  351. const chartTwo = {
  352. title: {
  353. text: '表外业务风险暴露(一级)风险加权资产占比',
  354. left: 'center'
  355. },
  356. tooltip: {
  357. trigger: 'item'
  358. },
  359. legend: {
  360. top: '90%',
  361. left: 'center'
  362. },
  363. series: [
  364. {
  365. name: 'Access From',
  366. type: 'pie',
  367. radius: ['40%', '70%'],
  368. avoidLabelOverlap: false,
  369. itemStyle: {
  370. borderRadius: 10,
  371. borderColor: '#fff',
  372. borderWidth: 2
  373. },
  374. label: {
  375. position: 'outer',
  376. alignTo: 'none',
  377. bleedMargin: 5
  378. },
  379. emphasis: {
  380. label: {
  381. show: true,
  382. fontSize: 20,
  383. fontWeight: 'bold'
  384. }
  385. },
  386. labelLine: {
  387. show: true
  388. },
  389. data:outTableAssetType
  390. }
  391. ]
  392. };
  393. const chartThree = {
  394. title: {
  395. text: '前十大机构信用风险加权资产合计',
  396. left: 'center'
  397. },
  398. xAxis: {
  399. type: 'category',
  400. data: top10OrgAssetAccountName
  401. },
  402. yAxis: {
  403. min:0,
  404. max: 250000,
  405. interval: 50000,
  406. type: 'value',
  407. },
  408. series: [
  409. {
  410. data: top10OrgAssetAccountValue,
  411. type: 'bar',
  412. }
  413. ]
  414. };
  415. const chartFour = {
  416. title: {
  417. text: '风险暴露(一级)风险加权资产占比',
  418. left: 'center'
  419. },
  420. tooltip: {
  421. trigger: 'item'
  422. },
  423. legend: {
  424. top: '90%',
  425. left: 'center'
  426. },
  427. series: [
  428. {
  429. name: 'Access From',
  430. type: 'pie',
  431. radius: ['40%', '70%'],
  432. avoidLabelOverlap: false,
  433. itemStyle: {
  434. borderRadius: 10,
  435. borderColor: '#fff',
  436. borderWidth: 2
  437. },
  438. label: {
  439. position: 'outer',
  440. alignTo: 'none',
  441. bleedMargin: 5
  442. },
  443. emphasis: {
  444. label: {
  445. show: true,
  446. fontSize: 20,
  447. fontWeight: 'bold'
  448. }
  449. },
  450. labelLine: {
  451. show: true
  452. },
  453. data: riskExposeAssetRatio
  454. }
  455. ]
  456. };
  457. const chartFive = {
  458. title: {
  459. text: '风险暴露(一级)缓释前风险暴露占比',
  460. left: 'center'
  461. },
  462. tooltip: {
  463. trigger: 'item'
  464. },
  465. legend: {
  466. top: '90%',
  467. left: 'center'
  468. },
  469. series: [
  470. {
  471. name: 'Access From',
  472. type: 'pie',
  473. radius: ['40%', '70%'],
  474. avoidLabelOverlap: false,
  475. itemStyle: {
  476. borderRadius: 10,
  477. borderColor: '#fff',
  478. borderWidth: 2
  479. },
  480. label: {
  481. position: 'outer',
  482. alignTo: 'none',
  483. bleedMargin: 5
  484. },
  485. emphasis: {
  486. label: {
  487. show: true,
  488. fontSize: 20,
  489. fontWeight: 'bold'
  490. }
  491. },
  492. labelLine: {
  493. show: true
  494. },
  495. data: preReleaseRiskExposeAssetRatio
  496. }
  497. ]
  498. };
  499. const chartSix = {
  500. title: {
  501. text: '信用风险缓释工具当期缓释覆盖金额占比',
  502. left: 'center'
  503. },
  504. tooltip: {
  505. trigger: 'item'
  506. },
  507. legend: {
  508. top: '90%',
  509. left: 'center'
  510. },
  511. series: [
  512. {
  513. name: 'Access From',
  514. type: 'pie',
  515. radius: ['40%', '70%'],
  516. avoidLabelOverlap: false,
  517. itemStyle: {
  518. borderRadius: 10,
  519. borderColor: '#fff',
  520. borderWidth: 2
  521. },
  522. label: {
  523. position: 'outer',
  524. alignTo: 'none',
  525. bleedMargin: 5
  526. },
  527. emphasis: {
  528. label: {
  529. show: true,
  530. fontSize: 20,
  531. fontWeight: 'bold'
  532. }
  533. },
  534. labelLine: {
  535. show: true
  536. },
  537. data: creditRiskReleaseTool
  538. }
  539. ]
  540. };
  541. const chartSeven ={
  542. title: {
  543. text: '风险暴露分类(一级)当期缓释情况',
  544. left: 'center'
  545. },
  546. tooltip: {
  547. trigger: 'axis',
  548. axisPointer: {
  549. type: 'cross',
  550. crossStyle: {
  551. color: '#999'
  552. }
  553. }
  554. },
  555. toolbox: {
  556. feature: {
  557. dataView: { show: true, readOnly: true },
  558. magicType: { show: true, type: ['line', 'bar'] },
  559. restore: { show: true },
  560. saveAsImage: { show: true }
  561. }
  562. },
  563. legend: {
  564. top:'90%',
  565. data: ['缓释', '未缓释', '缓释比例']
  566. },
  567. xAxis: [
  568. {
  569. type: 'category',
  570. data: xLableList,
  571. axisPointer: {
  572. type: 'shadow'
  573. }
  574. }
  575. ],
  576. yAxis: [
  577. {
  578. type: 'value',
  579. min: 0,
  580. max: 5000000,
  581. interval: 1000000,
  582. axisLabel: {
  583. formatter: '{value}'
  584. }
  585. },
  586. {
  587. type: 'value',
  588. min: 0,
  589. max: 125,
  590. interval: 25,
  591. axisLabel: {
  592. formatter: '{value}'
  593. }
  594. }
  595. ],
  596. series: [
  597. {
  598. name: '缓释',
  599. type: 'bar',
  600. tooltip: {
  601. valueFormatter: function (value: number) {
  602. return (value as number) + ' 万元';
  603. }
  604. },
  605. stack: 'total',
  606. data:releaseDataList
  607. },
  608. {
  609. name: '未缓释',
  610. type: 'bar',
  611. tooltip: {
  612. valueFormatter: function (value: number) {
  613. return (value as number) + ' 万元';
  614. }
  615. },
  616. stack: 'total',
  617. data: unReleaseDataList
  618. },
  619. {
  620. name: '缓释比例',
  621. type: 'line',
  622. yAxisIndex: 1,
  623. tooltip: {
  624. valueFormatter: function (value: number) {
  625. return (value as number) + ' %';
  626. }
  627. },
  628. data: releaseRatioDataList
  629. }
  630. ]
  631. };
  632. return (
  633. <PageContainer>
  634. <div style={{ display: 'flex', justifyContent: 'space-between' }}><div style={{ flex: 1 }}>
  635. <ECharts
  636. elementId={"chartOne"} height={'400px'} option={chartOne} width={'100%'}></ECharts>
  637. </div>
  638. <div style={{ flex: 1 }}> <ECharts
  639. elementId={"chartTwo"} height={'400px'} option={chartTwo} width={'100%'}></ECharts>
  640. </div>
  641. </div>
  642. <ECharts
  643. elementId={"chartThree"} height={'400px'} option={chartThree} width={'100%'}></ECharts>
  644. <div style={{ display: 'flex', justifyContent: 'space-between' }}><div style={{ flex: 1 }}>
  645. <ECharts
  646. elementId={"chartFour"} height={'400px'} option={chartFour} width={'100%'}></ECharts>
  647. </div>
  648. <div style={{ flex: 1 }}> <ECharts
  649. elementId={"chartFive"} height={'400px'} option={chartFive} width={'100%'}></ECharts>
  650. </div>
  651. </div>
  652. <ECharts
  653. elementId={"chartSix"} height={'400px'} option={chartSix} width={'100%'}></ECharts>
  654. <ECharts
  655. elementId={"chartSeven"} height={'400px'} option={chartSeven} width={'100%'}></ECharts>
  656. </PageContainer>
  657. );
  658. };
  659. export default Welcome;