選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

370 行
11 KiB

  1. "use client";
  2. import * as React from "react";
  3. import Grid from "@mui/material/Grid";
  4. import { useState, useEffect, useMemo } from "react";
  5. import Paper from "@mui/material/Paper";
  6. import { TFunction } from "i18next";
  7. import { useTranslation } from "react-i18next";
  8. import { Card, CardHeader } from "@mui/material";
  9. import CustomSearchForm from "../CustomSearchForm/CustomSearchForm";
  10. import CustomDatagrid from "../CustomDatagrid/CustomDatagrid";
  11. import ReactApexChart from "react-apexcharts";
  12. import { ApexOptions } from "apexcharts";
  13. import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid";
  14. import ReportProblemIcon from "@mui/icons-material/ReportProblem";
  15. import dynamic from "next/dynamic";
  16. import "../../app/global.css";
  17. import { AnyARecord, AnyCnameRecord } from "dns";
  18. import SearchBox, { Criterion } from "../SearchBox";
  19. import ProgressByClientSearch from "@/components/ProgressByClientSearch";
  20. import { Suspense } from "react";
  21. import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch";
  22. import { Input, Label } from "reactstrap";
  23. import Select, { components } from "react-select";
  24. import {fetchTeamCombo,fetchTeamCashFlowChartData} from "@/app/api/teamCashflow";
  25. const CompanyTeamCashFlow: React.FC = () => {
  26. const todayDate = new Date();
  27. const [selectionModel, setSelectionModel]: any[] = React.useState([]);
  28. const [teamOptions, setTeamOptions]: any[] = React.useState([]);
  29. const [teamId, setTeamId]:any = React.useState(null);
  30. const [monthlyIncomeList, setMonthlyIncomeList]: any[] = React.useState([]);
  31. const [monthlyCumulativeIncomeList, setMonthlyCumulativeIncomeList]: any[] = React.useState([]);
  32. const [monthlyExpenditureList, setMonthlyExpenditureList]: any[] = React.useState([]);
  33. const [monthlyCumulativeExpenditureList, setMonthlyCumulativeExpenditureList]: any[] = React.useState([]);
  34. const [monthlyChartLeftMax, setMonthlyChartLeftMax]: any[] = React.useState(0);
  35. const [monthlyChartRightMax, setMonthlyChartRightMax]: any[] = React.useState(0);
  36. const [cashFlowYear, setCashFlowYear]: any[] = React.useState(
  37. todayDate.getFullYear(),
  38. );
  39. const fetchChartData = async () => {
  40. const cashFlowMonthlyChartData:any = await fetchTeamCashFlowChartData(cashFlowYear,teamId);
  41. console.log(cashFlowMonthlyChartData[0])
  42. const monthlyIncome = []
  43. const cumulativeIncome = []
  44. const monthlyExpenditure = []
  45. const cumulativeExpenditure = []
  46. var leftMax = 0
  47. var rightMax = 0
  48. // if (cashFlowMonthlyChartData.length !== 0) {
  49. for (var i = 0; i < cashFlowMonthlyChartData[0].teamCashFlowIncome.length; i++) {
  50. if (leftMax < cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income || leftMax < cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure){
  51. leftMax = Math.max(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income,cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure)
  52. }
  53. monthlyIncome.push(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income)
  54. cumulativeIncome.push(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].cumulativeIncome)
  55. }
  56. for (var i = 0; i < cashFlowMonthlyChartData[0].teamCashFlowExpenditure.length; i++) {
  57. if (rightMax < cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income || rightMax < cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure){
  58. rightMax = Math.max(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income,cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure)
  59. }
  60. monthlyExpenditure.push(cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure)
  61. cumulativeExpenditure.push(cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].cumulativeExpenditure)
  62. }
  63. setMonthlyIncomeList(monthlyIncome)
  64. setMonthlyCumulativeIncomeList(cumulativeIncome)
  65. setMonthlyExpenditureList(monthlyExpenditure)
  66. setMonthlyCumulativeExpenditureList(cumulativeExpenditure)
  67. setMonthlyChartLeftMax(leftMax)
  68. setMonthlyChartRightMax(rightMax)
  69. // } else {
  70. // setMonthlyIncomeList([0,0,0,0,0,0,0,0,0,0,0,0])
  71. // setMonthlyCumulativeIncomeList([0,0,0,0,0,0,0,0,0,0,0,0])
  72. // setMonthlyExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0])
  73. // setMonthlyCumulativeExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0])
  74. // }
  75. }
  76. const fetchComboData = async () => {
  77. const teamComboList = []
  78. const teamCombo = await fetchTeamCombo();
  79. for (var i = 0; i < teamCombo.records.length; i++) {
  80. teamComboList.push({value: teamCombo.records[i].id, label: teamCombo.records[i].label})
  81. }
  82. setTeamOptions(teamComboList)
  83. }
  84. useEffect(() => {
  85. fetchComboData()
  86. }, []);
  87. useEffect(() => {
  88. fetchChartData()
  89. }, [cashFlowYear,teamId]);
  90. const columns = [
  91. {
  92. id: "projectCode",
  93. field: "projectCode",
  94. headerName: "Project Code",
  95. flex: 1,
  96. },
  97. {
  98. id: "projectName",
  99. field: "projectName",
  100. headerName: "Project Name",
  101. flex: 1,
  102. },
  103. {
  104. id: "team",
  105. field: "team",
  106. headerName: "Team",
  107. flex: 1,
  108. },
  109. {
  110. id: "teamLeader",
  111. field: "teamLeader",
  112. headerName: "Team Leader",
  113. flex: 1,
  114. },
  115. {
  116. id: "startDate",
  117. field: "startDate",
  118. headerName: "Start Date",
  119. flex: 1,
  120. },
  121. {
  122. id: "targetEndDate",
  123. field: "targetEndDate",
  124. headerName: "Target End Date",
  125. flex: 1,
  126. },
  127. {
  128. id: "client",
  129. field: "client",
  130. headerName: "Client",
  131. flex: 1,
  132. },
  133. {
  134. id: "subsidiary",
  135. field: "subsidiary",
  136. headerName: "Subsidiary",
  137. flex: 1,
  138. },
  139. ];
  140. const ledgerColumns = [
  141. {
  142. id: "date",
  143. field: "date",
  144. headerName: "Date",
  145. flex: 0.5,
  146. },
  147. {
  148. id: "expenditure",
  149. field: "expenditure",
  150. headerName: "Expenditure (HKD)",
  151. flex: 0.6,
  152. },
  153. {
  154. id: "income",
  155. field: "income",
  156. headerName: "Income (HKD)",
  157. flex: 0.6,
  158. },
  159. {
  160. id: "cashFlowBalance",
  161. field: "cashFlowBalance",
  162. headerName: "Cash Flow Balance (HKD)",
  163. flex: 0.6,
  164. },
  165. {
  166. id: "remarks",
  167. field: "remarks",
  168. headerName: "Remarks",
  169. flex: 1,
  170. },
  171. ];
  172. const options: ApexOptions = {
  173. chart: {
  174. height: 350,
  175. type: "line",
  176. },
  177. stroke: {
  178. width: [0, 0, 2, 2],
  179. },
  180. plotOptions: {
  181. bar: {
  182. horizontal: false,
  183. distributed: false,
  184. },
  185. },
  186. dataLabels: {
  187. enabled: false,
  188. },
  189. xaxis: {
  190. categories: [
  191. "Q1",
  192. "Q2",
  193. "Q3",
  194. "Q4",
  195. "Q5",
  196. "Q6",
  197. "Q7",
  198. "Q8",
  199. "Q9",
  200. "Q10",
  201. "Q11",
  202. "Q12",
  203. ],
  204. },
  205. yaxis: [
  206. {
  207. title: {
  208. text: "Monthly Income and Expenditure(HKD)",
  209. },
  210. min: 0,
  211. max: monthlyChartLeftMax,
  212. tickAmount: 5,
  213. labels: {
  214. formatter: function (val) {
  215. return val.toLocaleString()
  216. }
  217. }
  218. },
  219. {
  220. show: false,
  221. seriesName: "Monthly_Expenditure",
  222. title: {
  223. text: "Monthly Expenditure (HKD)",
  224. },
  225. min: 0,
  226. max: monthlyChartLeftMax,
  227. tickAmount: 5,
  228. },
  229. {
  230. seriesName: "Cumulative_Income",
  231. opposite: true,
  232. title: {
  233. text: "Cumulative Income and Expenditure(HKD)",
  234. },
  235. min: 0,
  236. max: monthlyChartRightMax,
  237. tickAmount: 5,
  238. labels: {
  239. formatter: function (val) {
  240. return val.toLocaleString()
  241. }
  242. }
  243. },
  244. {
  245. show: false,
  246. seriesName: "Cumulative_Expenditure",
  247. opposite: true,
  248. title: {
  249. text: "Cumulative Expenditure (HKD)",
  250. },
  251. min: 0,
  252. max: monthlyChartRightMax,
  253. tickAmount: 5,
  254. },
  255. ],
  256. grid: {
  257. borderColor: "#f1f1f1",
  258. },
  259. annotations: {},
  260. series: [
  261. {
  262. name: "Monthly_Income",
  263. type: "column",
  264. color: "#ffde91",
  265. data: monthlyIncomeList,
  266. },
  267. {
  268. name: "Monthly_Expenditure",
  269. type: "column",
  270. color: "#82b59a",
  271. data: monthlyExpenditureList,
  272. },
  273. {
  274. name: "Cumulative_Income",
  275. type: "line",
  276. color: "#EE6D7A",
  277. data: monthlyCumulativeIncomeList,
  278. },
  279. {
  280. name: "Cumulative_Expenditure",
  281. type: "line",
  282. color: "#7cd3f2",
  283. data: monthlyCumulativeExpenditureList,
  284. },
  285. ],
  286. };
  287. return (
  288. <>
  289. <Grid item sm>
  290. <div style={{ display: "inline-block", width: "100%" }}>
  291. <Grid item xs={12} md={12} lg={12}>
  292. <Card>
  293. <CardHeader
  294. className="text-slate-500"
  295. title="Company and Team Cash Flow by Month"
  296. />
  297. <div style={{ display: "inline-block", width: "99%" }}>
  298. <div className="inline-block">
  299. <Label className="text-slate-500 font-medium ml-6">
  300. Period:&nbsp;
  301. </Label>
  302. <Input
  303. id={"cashFlowYear"}
  304. value={cashFlowYear}
  305. readOnly={true}
  306. bsSize="lg"
  307. className="rounded-md text-base w-12"
  308. />
  309. </div>
  310. <div className="inline-block ml-1">
  311. <button
  312. onClick={() => setCashFlowYear(cashFlowYear - 1)}
  313. className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"
  314. >
  315. &lt;
  316. </button>
  317. </div>
  318. <div className="inline-block ml-1">
  319. <button
  320. onClick={() => setCashFlowYear(cashFlowYear + 1)}
  321. className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"
  322. >
  323. &gt;
  324. </button>
  325. </div>
  326. <div className="inline-block ml-2">
  327. <Label className="text-slate-500 font-medium">
  328. Team:&nbsp;
  329. </Label>
  330. </div>
  331. <div className="inline-block ml-1 w-60">
  332. <Select
  333. placeholder="All Team"
  334. options={teamOptions}
  335. isClearable={true}
  336. onChange={(selectedOption:any) => {
  337. if (selectedOption === null) {
  338. setTeamId(null);
  339. } else {
  340. setTeamId(selectedOption.value);
  341. }
  342. }}
  343. />
  344. </div>
  345. <ReactApexChart
  346. options={options}
  347. series={options.series}
  348. type="line"
  349. height="500"
  350. />
  351. </div>
  352. </Card>
  353. </Grid>
  354. </div>
  355. </Grid>
  356. </>
  357. );
  358. };
  359. export default CompanyTeamCashFlow;