2
0

Heatmap.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import { useEffect, useState } from "react";
  2. import { useIntl } from "react-intl";
  3. import { message, Select, Tooltip, Typography } from "antd";
  4. import { get } from "../../request";
  5. import type { IUserOperationDailyResponse } from "../../api/Exp";
  6. interface IOptions {
  7. value: string;
  8. label: string;
  9. }
  10. interface IDailyData {
  11. date: string;
  12. commits: number;
  13. year: number;
  14. month: number;
  15. day: number;
  16. week: number;
  17. }
  18. interface IWidget {
  19. studioName?: string;
  20. }
  21. const HeatmapWidget = ({ studioName }: IWidget) => {
  22. const [dailyData, setDailyData] = useState<IDailyData[]>([]);
  23. const [year, setYear] = useState<IOptions[]>([]);
  24. const thisYear = new Date().getFullYear();
  25. const [currYear, setCurrYear] = useState<string>(thisYear.toString());
  26. const intl = useIntl();
  27. useEffect(() => {
  28. get<IUserOperationDailyResponse>(
  29. `/v2/user-operation-daily?view=user-year&studio_name=${studioName}&year=2021`
  30. ).then((json) => {
  31. if (json.ok) {
  32. //找到起止年份
  33. if (json.data.rows.length > 0) {
  34. const yearStart = new Date(json.data.rows[0].date_int).getFullYear();
  35. const yearEnd = new Date(
  36. json.data.rows[json.data.rows.length - 1].date_int
  37. ).getFullYear();
  38. const yearOption: IOptions[] = [];
  39. for (let index = yearStart; index <= yearEnd; index++) {
  40. yearOption.push({
  41. value: index.toString(),
  42. label: index.toString(),
  43. });
  44. }
  45. setYear(yearOption);
  46. }
  47. const data = json.data.rows.map((item) => {
  48. const date = new Date(item.date_int);
  49. const oneJan = new Date(date.getFullYear(), 0, 1);
  50. const week = Math.ceil(
  51. ((date.getTime() - oneJan.getTime()) / 86400000 +
  52. oneJan.getDay() +
  53. 1) /
  54. 7
  55. );
  56. return {
  57. date:
  58. date.getFullYear() +
  59. "-" +
  60. (date.getMonth() + 1) +
  61. "-" +
  62. date.getDate(),
  63. year: date.getFullYear(),
  64. month: date.getMonth() + 1,
  65. day: date.getDay(),
  66. week: week,
  67. commits: Math.floor(item.duration / 1000 / 60),
  68. };
  69. });
  70. console.log("data", data);
  71. setDailyData(data);
  72. } else {
  73. message.error(json.message);
  74. }
  75. });
  76. }, [studioName]);
  77. const yAxisLabel = new Array(7).fill(1).map((_item, id) => {
  78. return (
  79. <div key={id} style={{ display: "inline-block", width: "5em" }}>
  80. <Typography.Text>
  81. {intl.formatMessage({ id: `labels.week.${id}` })}
  82. </Typography.Text>
  83. </div>
  84. );
  85. });
  86. const dayColor = ["#9be9a8", "#40c463", "#30a14e", "#216e39"];
  87. const weeks = new Array(54).fill(1);
  88. const heatmap = weeks.map((_item, week) => {
  89. const days = new Array(7).fill(1);
  90. return (
  91. <div key={week}>
  92. {days.map((_itemDay, day) => {
  93. const currDate = dailyData.find(
  94. (value) =>
  95. value.year === parseInt(currYear) &&
  96. value.week === week &&
  97. value.day === day
  98. );
  99. const time = currDate?.commits;
  100. const color = time
  101. ? time > 100
  102. ? dayColor[3]
  103. : time > 50
  104. ? dayColor[2]
  105. : time > 20
  106. ? dayColor[1]
  107. : time > 0
  108. ? dayColor[0]
  109. : "rgba(0,0,0,0)"
  110. : "rgba(0,0,0,0)";
  111. return (
  112. <div
  113. key={day}
  114. style={{
  115. display: "inline-block",
  116. width: 12,
  117. height: 12,
  118. backgroundColor: `rgba(128,128,128,0.2)`,
  119. margin: 0,
  120. borderRadius: 2,
  121. outline: "1px solid gray",
  122. }}
  123. >
  124. <Tooltip
  125. placement="top"
  126. title={`${currDate?.date}/${currDate?.commits}分钟`}
  127. >
  128. <div
  129. style={{
  130. width: 12,
  131. height: 12,
  132. backgroundColor: color,
  133. }}
  134. ></div>
  135. </Tooltip>
  136. </div>
  137. );
  138. })}
  139. </div>
  140. );
  141. });
  142. return (
  143. <div style={{ width: 1000 }}>
  144. <div style={{ textAlign: "right" }} key="toolbar">
  145. <Select
  146. defaultValue={thisYear.toString()}
  147. style={{ width: 120 }}
  148. onChange={(value: string) => {
  149. console.log(`selected ${value}`);
  150. setCurrYear(value);
  151. }}
  152. options={year}
  153. />
  154. </div>
  155. <div style={{ display: "flex" }} key="map">
  156. <div style={{ width: "5em" }} key="label">
  157. {yAxisLabel}
  158. </div>
  159. {heatmap}
  160. </div>
  161. </div>
  162. );
  163. };
  164. export default HeatmapWidget;