kirin-ri / memo

0 stars 0 forks source link

azure #27

Open kirin-ri opened 4 months ago

kirin-ri commented 4 months ago

let cpu_rate_per_core_hour = 0.048; // 1 vCPUあたりの料金(USD/時間) let mem_rate_per_gb_hour = 0.012; // 1 GiB RAMあたりの料金(USD/時間)

// 各名前空間のCPU使用量の料金計算 let cpu_cost = KubePodInventory | summarize AvgCPU=avg(TotalCpuUsageNanoCores) by Namespace | extend CPUHours = AvgCPU (datetime_diff('hour', max(TimeGenerated), min(TimeGenerated))) / 1e9 | extend CPUCost = CPUHours cpu_rate_per_core_hour;

// 各名前空間のメモリ使用量の料金計算 let mem_cost = KubePodInventory | summarize AvgMemory=avg(TotalMemoryUsageBytes) by Namespace | extend MemoryHours = AvgMemory (datetime_diff('hour', max(TimeGenerated), min(TimeGenerated))) / (1024 1024 1024) | extend MemoryCost = MemoryHours mem_rate_per_gb_hour;

// CPUとメモリの料金を統合 cpu_cost | join kind=inner (mem_cost) on Namespace | project Namespace, CPUCost, MemoryCost, TotalCost = CPUCost + MemoryCost

kirin-ri commented 3 months ago
import { useState } from "react";

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <span>{message}</span>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* Content Header (Page header) */}
      <section className="content-header">
        <div className="content-header-left">
          {/* 警告弹窗 */}
          {showAlert && (
            <AlertBox
              message="期中に資金がマイナスとなる期間があります"
              onClose={() => setShowAlert(false)}
            />
          )}
        </div>
      </section>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
import { useState } from "react";

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <span>{message}</span>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <AlertBox
          message="期中に資金がマイナスとなる期間があります"
          onClose={() => setShowAlert(false)}
        />
      )}
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 10px 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.alert-box span {
  flex-grow: 1;
}

.close-btn {
  background-color: transparent;
  border: none;
  color: red;
  cursor: pointer;
  font-size: 1rem;
  padding: 5px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.alert-box span {
  flex-grow: 1;
}

.close-btn {
  background-color: transparent;
  border: none;
  color: red;
  cursor: pointer;
  font-size: 1rem;
  padding: 5px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
import { useState } from "react";

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
        <span>{message}</span>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="content-header alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: center; /* 中心对齐 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-box .alert-icon {
  color: red;
  font-size: 1.5rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.alert-box span {
  flex-grow: 1;
  text-align: center; /* 文本居中 */
}

.close-btn {
  background-color: transparent;
  border: 1px solid red;
  border-radius: 15px; /* 椭圆形 */
  color: red;
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
import { useState } from "react";

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <span className="alert-message">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          {message}
        </span>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="content-header alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: space-between; /* 确保内容两端对齐 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-message {
  display: flex;
  align-items: center;
  flex-grow: 1;
  text-align: center; /* 文本居中 */
}

.alert-box .alert-icon {
  color: red;
  font-size: 1.5rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.close-btn {
  background-color: transparent;
  border: 1px solid red;
  border-radius: 15px; /* 椭圆形 */
  color: red;
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
import { useState } from "react";

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <span className="alert-message">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          {message}
        </span>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: center; /* 确保内容居中对齐 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-message {
  display: flex;
  align-items: center;
  justify-content: center; /* 文本居中对齐 */
}

.alert-box .alert-icon {
  color: red;
  font-size: 1.5rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.close-btn {
  background-color: transparent;
  border: 1px solid red;
  border-radius: 15px; /* 椭圆形 */
  color: red;
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
import { useState } from "react";

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <span className="alert-message">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          {message}
        </span>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: space-between; /* 确保内容两端对齐 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-message {
  display: flex;
  align-items: center;
  justify-content: center; /* 文本居中对齐 */
}

.alert-box .alert-icon {
  color: red;
  font-size: 1.5rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.close-btn {
  background-color: red;
  border: none;
  border-radius: 15px; /* 椭圆形 */
  color: black; /* 按钮文字颜色 */
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: space-between; /* 确保按钮在右侧 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-content {
  display: flex;
  align-items: center;
  justify-content: center; /* 确保内容居中 */
  flex-grow: 1;
}

.alert-icon {
  color: red;
  font-size: 1.5rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.alert-message {
  text-align: center; /* 文本居中对齐 */
}

.close-btn {
  background-color: red;
  border: none;
  border-radius: 15px; /* 椭圆形 */
  color: black; /* 按钮文字颜色 */
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: space-between; /* 确保按钮在右侧 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-content {
  display: flex;
  align-items: center;
  justify-content: center; /* 确保内容居中 */
  flex-grow: 1;
  text-align: center; /* 确保文本居中对齐 */
}

.alert-icon {
  color: red;
  font-size: 1.5rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.alert-message {
  white-space: nowrap; /* 确保文本不换行 */
}

.close-btn {
  background-color: red;
  border: none;
  border-radius: 15px; /* 椭圆形 */
  color: black; /* 按钮文字颜色 */
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}
kirin-ri commented 3 months ago
import { useState } from "react";

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
import { Line } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);

// 在EmptyPage组件内添加数据和图表
const data = {
  labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
  datasets: [
    {
      label: '資金繰り表',
      data: [65, 59, 80, 81, 56, 55, 40],
      fill: false,
      backgroundColor: 'rgb(255, 99, 132)',
      borderColor: 'rgba(255, 99, 132, 0.2)',
    },
  ],
};

return (
  <div className="content-wrapper metrics-details">
    {/* 现有的代码 */}
    {showAlert && (
      <div className="alert-container">
        <AlertBox
          message="期中に資金がマイナスとなる期間があります"
          onClose={() => setShowAlert(false)}
        />
      </div>
    )}
    {/* 資金繰り表のグラフ */}
    <div className="graph-container">
      <Line data={data} />
    </div>
  </div>
);
kirin-ri commented 3 months ago
.graph-container {
  position: absolute;
  bottom: 10px; /* 距离底部的距离 */
  left: 10px; /* 距离左侧的距离 */
  width: 300px; /* 图表宽度 */
  height: 200px; /* 图表高度 */
}
kirin-ri commented 3 months ago
.graph-container {
  position: absolute;
  bottom: 20px; /* 距离底部的距离 */
  left: 20px; /* 距离左侧的距离 */
  width: 90%; /* 图表宽度 */
  height: 400px; /* 图表高度 */
  padding: 20px;
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
kirin-ri commented 3 months ago

gurafu

kirin-ri commented 3 months ago
  position: relative;
  margin-top: 20px;
  width: 90%; /* 图表宽度 */
  height: 400px; /* 图表高度 */
  padding: 20px;
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
kirin-ri commented 3 months ago
import React, { useState } from "react";
import { Bar, Line } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [25, 35, 30, 20, 25, 30, 35, 25, 30, 20, 25, 30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: function(context) {
          const index = context.dataIndex;
          const value = context.dataset.data[index];
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      }
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Bar data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
ERROR in src/app2/components/pages/emptyPage.tsx:50:40
TS7006: Parameter 'context' implicitly has an 'any' type.
    48 |         pointRadius: 6,
    49 |         pointHoverRadius: 8,
  > 50 |         pointBackgroundColor: function(context) {
       |                                        ^^^^^^^
    51 |           const index = context.dataIndex;
    52 |           const value = context.dataset.data[index];
    53 |           return value < 0 ? 'red' : 'black';

ERROR in src/app2/components/pages/emptyPage.tsx:71:27
TS7006: Parameter 'context' implicitly has an 'any' type.
    69 |       tooltip: {
    70 |         callbacks: {
  > 71 |           label: function(context) {
       |                           ^^^^^^^
    72 |             const label = context.dataset.label || '';
    73 |             const value = context.raw;
    74 |             return `${label}: ${value}`;

ERROR in src/app2/components/pages/emptyPage.tsx:104:14
TS2322: Type '{ labels: string[]; datasets: ({ type: "bar"; label: string; data: number[]; backgroundColor: string; borderColor?: undefined; fill?: undefined; tension?: undefined; borderWidth?: undefined; pointStyle?: undefined; pointRadius?: undefined; pointHoverRadius?: undefined; pointBackgroundColor?: undefined; } | { ...; })...' is not assignable to type 'ChartData<"bar", number[], string>'.
  Types of property 'datasets' are incompatible.
    Type '({ type: "bar"; label: string; data: number[]; backgroundColor: string; borderColor?: undefined; fill?: undefined; tension?: undefined; borderWidth?: undefined; pointStyle?: undefined; pointRadius?: undefined; pointHoverRadius?: undefined; pointBackgroundColor?: undefined; } | { ...; })[]' is not assignable to type 'ChartDataset<"bar", number[]>[]'.
      Type '{ type: "bar"; label: string; data: number[]; backgroundColor: string; borderColor?: undefined; fill?: undefined; tension?: undefined; borderWidth?: undefined; pointStyle?: undefined; pointRadius?: undefined; pointHoverRadius?: undefined; pointBackgroundColor?: undefined; } | { ...; }' is not assignable to type 'ChartDataset<"bar", number[]>'.
        Type '{ type: "line"; label: string; data: number[]; borderColor: string; backgroundColor: string; fill: boolean; tension: number; borderWidth: number; pointStyle: string; pointRadius: number; pointHoverRadius: number; pointBackgroundColor: (context: any) => "black" | "red"; }' is not assignable to type 'ChartDataset<"bar", number[]>'.
          Type '{ type: "line"; label: string; data: number[]; borderColor: string; backgroundColor: string; fill: boolean; tension: number; borderWidth: number; pointStyle: string; pointRadius: number; pointHoverRadius: number; pointBackgroundColor: (context: any) => "black" | "red"; }' is not assignable to type '_DeepPartialObject<{ type: "bar"; } & BarControllerDatasetOptions>'.
            Types of property 'type' are incompatible.
              Type '"line"' is not assignable to type '"bar"'.
    102 |       {/* 資金繰り表のグラフ */}
    103 |       <div className="graph-container">
  > 104 |         <Bar data={data} options={options} />
        |              ^^^^
    105 |       </div>
    106 |     </div>
    107 |   );
kirin-ri commented 3 months ago
import React, { useState } from "react";
import { Bar } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [25, 35, 30, 20, 25, 30, 35, 25, 30, 20, 25, 30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      }
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Bar data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
ERROR in src/app2/components/pages/emptyPage.tsx:104:14
TS2322: Type '{ labels: string[]; datasets: ({ type: "bar"; label: string; data: number[]; backgroundColor: string; borderColor?: undefined; fill?: undefined; tension?: undefined; borderWidth?: undefined; pointStyle?: undefined; pointRadius?: undefined; pointHoverRadius?: undefined; pointBackgroundColor?: undefined; } | { ...; })...' is not assignable to type 'ChartData<"bar", number[], string>'.
  Types of property 'datasets' are incompatible.
    Type '({ type: "bar"; label: string; data: number[]; backgroundColor: string; borderColor?: undefined; fill?: undefined; tension?: undefined; borderWidth?: undefined; pointStyle?: undefined; pointRadius?: undefined; pointHoverRadius?: undefined; pointBackgroundColor?: undefined; } | { ...; })[]' is not assignable to type 'ChartDataset<"bar", number[]>[]'.
      Type '{ type: "bar"; label: string; data: number[]; backgroundColor: string; borderColor?: undefined; fill?: undefined; tension?: undefined; borderWidth?: undefined; pointStyle?: undefined; pointRadius?: undefined; pointHoverRadius?: undefined; pointBackgroundColor?: undefined; } | { ...; }' is not assignable to type 'ChartDataset<"bar", number[]>'.
        Type '{ type: "line"; label: string; data: number[]; borderColor: string; backgroundColor: string; fill: boolean; tension: number; borderWidth: number; pointStyle: string; pointRadius: number; pointHoverRadius: number; pointBackgroundColor: (context: ScriptableContext<'line'>) => "black" | "red"; }' is not assignable to type 'ChartDataset<"bar", number[]>'.
          Type '{ type: "line"; label: string; data: number[]; borderColor: string; backgroundColor: string; fill: boolean; tension: number; borderWidth: number; pointStyle: string; pointRadius: number; pointHoverRadius: number; pointBackgroundColor: (context: ScriptableContext<'line'>) => "black" | "red"; }' is not assignable to type '_DeepPartialObject<{ type: "bar"; } & BarControllerDatasetOptions>'.
            Types of property 'type' are incompatible.
              Type '"line"' is not assignable to type '"bar"'.
    102 |       {/* 資金繰り表のグラフ */}
    103 |       <div className="graph-container">
  > 104 |         <Bar data={data} options={options} />
        |              ^^^^
    105 |       </div>
    106 |     </div>
    107 |   );
kirin-ri commented 3 months ago
import React, { useState } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [25, 35, 30, 20, 25, 30, 35, 25, 30, 20, 25, 30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      }
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Chart type="bar" data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
import React, { useState } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      }
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Chart type="bar" data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
import React, { useState, useEffect } from "react";
import { Chart, ChartJSOrUndefined } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示
  const chartRef = React.useRef<ChartJSOrUndefined<'bar', number[], string>>(null);

  useEffect(() => {
    const chart = chartRef.current;
    if (chart) {
      chart.options.plugins.tooltip.enabled = false; // Disable default tooltip
      chart.options.plugins.afterDraw = (chart) => {
        const ctx = chart.ctx;
        chart.data.datasets[2].data.forEach((value, index) => {
          if (value < 0) {
            const meta = chart.getDatasetMeta(2).data[index];
            const x = meta.x;
            const y = meta.y;
            ctx.fillStyle = 'red';
            ctx.font = 'bold 12px Arial';
            ctx.fillText('!', x - 5, y - 10);
          }
        });
      };
      chart.update();
    }
  }, [chartRef]);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        enabled: false,
        callbacks: {
          label: function (context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      }
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Chart ref={chartRef} type="bar" data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
ERROR in src/app2/components/pages/emptyPage.tsx:3:17
TS2305: Module '"react-chartjs-2"' has no exported member 'ChartJSOrUndefined'.
    1 | import { BarElement, CategoryScale, Chart as ChartJS, Legend, LinearScale, LineElement, PointElement, ScriptableContext, Title, Tooltip } from 'chart.js';
    2 | import React, { useEffect, useState } from "react";
  > 3 | import { Chart, ChartJSOrUndefined } from 'react-chartjs-2';
      |                 ^^^^^^^^^^^^^^^^^^
    4 |
    5 | ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);
    6 |

ERROR in src/app2/components/pages/emptyPage.tsx:16:42
TS7006: Parameter 'chart' implicitly has an 'any' type.
    14 |     if (chart) {
    15 |       chart.options.plugins.tooltip.enabled = false; // Disable default tooltip
  > 16 |       chart.options.plugins.afterDraw = (chart) => {
       |                                          ^^^^^
    17 |         const ctx = chart.ctx;
    18 |         chart.data.datasets[2].data.forEach((value, index) => {
    19 |           if (value < 0) {

ERROR in src/app2/components/pages/emptyPage.tsx:18:46
TS7006: Parameter 'value' implicitly has an 'any' type.
    16 |       chart.options.plugins.afterDraw = (chart) => {
    17 |         const ctx = chart.ctx;
  > 18 |         chart.data.datasets[2].data.forEach((value, index) => {
       |                                              ^^^^^
    19 |           if (value < 0) {
    20 |             const meta = chart.getDatasetMeta(2).data[index];
    21 |             const x = meta.x;

ERROR in src/app2/components/pages/emptyPage.tsx:18:53
TS7006: Parameter 'index' implicitly has an 'any' type.
    16 |       chart.options.plugins.afterDraw = (chart) => {
    17 |         const ctx = chart.ctx;
  > 18 |         chart.data.datasets[2].data.forEach((value, index) => {
       |                                                     ^^^^^
    19 |           if (value < 0) {
    20 |             const meta = chart.getDatasetMeta(2).data[index];
    21 |             const x = meta.x;
kirin-ri commented 3 months ago
import React, { useState, useEffect, useRef } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示
  const chartRef = useRef<ChartJS | null>(null);

  useEffect(() => {
    const chart = chartRef.current;
    if (chart) {
      const ctx = chart.ctx;
      chart.data.datasets[2].data.forEach((value, index) => {
        if (value < 0) {
          const meta = chart.getDatasetMeta(2).data[index];
          const x = meta.x;
          const y = meta.y;
          ctx.fillStyle = 'red';
          ctx.font = 'bold 12px Arial';
          ctx.fillText('!', x - 5, y - 10);
        }
      });
    }
  }, [chartRef]);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      },
      afterDraw: (chart: ChartJS) => {
        const ctx = chart.ctx;
        chart.data.datasets[2].data.forEach((value, index) => {
          if (value < 0) {
            const meta = chart.getDatasetMeta(2).data[index];
            const x = meta.x;
            const y = meta.y;
            ctx.fillStyle = 'red';
            ctx.font = 'bold 12px Arial';
            ctx.fillText('!', x - 5, y - 10);
          }
        });
      }
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Chart ref={chartRef} type="bar" data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
ERROR in src/app2/components/pages/emptyPage.tsx:17:13
TS2531: Object is possibly 'null'.
    15 |       const ctx = chart.ctx;
    16 |       chart.data.datasets[2].data.forEach((value, index) => {
  > 17 |         if (value < 0) {
       |             ^^^^^
    18 |           const meta = chart.getDatasetMeta(2).data[index];
    19 |           const x = meta.x;
    20 |           const y = meta.y;

ERROR in src/app2/components/pages/emptyPage.tsx:99:15
TS2531: Object is possibly 'null'.
     97 |         const ctx = chart.ctx;
     98 |         chart.data.datasets[2].data.forEach((value, index) => {
  >  99 |           if (value < 0) {
        |               ^^^^^
    100 |             const meta = chart.getDatasetMeta(2).data[index];
    101 |             const x = meta.x;
    102 |             const y = meta.y;
kirin-ri commented 3 months ago
import React, { useState, useEffect, useRef } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示
  const chartRef = useRef<ChartJS | null>(null);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      },
      afterDraw: (chart: ChartJS) => {
        const ctx = chart.ctx;
        if (ctx && chart.data.datasets[2].data) {
          (chart.data.datasets[2].data as number[]).forEach((value, index) => {
            if (value < 0) {
              const meta = chart.getDatasetMeta(2).data[index];
              const x = meta.x;
              const y = meta.y;
              ctx.fillStyle = 'red';
              ctx.font = 'bold 12px Arial';
              ctx.fillText('!', x - 5, y - 10);
            }
          });
        }
      }
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Chart ref={chartRef} type="bar" data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
import React, { useState, useEffect, useRef } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示
  const chartRef = useRef<ChartJS | null>(null);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      },
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  useEffect(() => {
    const chart = chartRef.current;
    if (chart) {
      const ctx = chart.ctx;
      chart.data.datasets[2].data.forEach((value, index) => {
        if (value < 0) {
          const meta = chart.getDatasetMeta(2).data[index];
          const x = meta.x;
          const y = meta.y;
          ctx.fillStyle = 'red';
          ctx.font = 'bold 12px Arial';
          ctx.fillText('!', x - 5, y - 10);
        }
      });
    }
  }, [data]);

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Chart ref={chartRef} type="bar" data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
ERROR in src/app2/components/pages/emptyPage.tsx:92:13
TS2531: Object is possibly 'null'.
    90 |       const ctx = chart.ctx;
    91 |       chart.data.datasets[2].data.forEach((value, index) => {
  > 92 |         if (value < 0) {
       |             ^^^^^
    93 |           const meta = chart.getDatasetMeta(2).data[index];
    94 |           const x = meta.x;
    95 |           const y = meta.y;
kirin-ri commented 3 months ago
import React, { useState, useEffect, useRef } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示
  const chartRef = useRef<ChartJS | null>(null);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      },
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  useEffect(() => {
    const chart = chartRef.current;
    if (chart) {
      const ctx = chart.ctx;
      if (ctx && chart.data.datasets[2].data) {
        (chart.data.datasets[2].data as number[]).forEach((value, index) => {
          if (value < 0) {
            const meta = chart.getDatasetMeta(2).data[index];
            if (meta) {
              const x = meta.x;
              const y = meta.y;
              ctx.fillStyle = 'red';
              ctx.font = 'bold 12px Arial';
              ctx.fillText('!', x - 5, y - 10);
            }
          }
        });
      }
    }
  }, [data]);

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      {/* 資金繰り表のグラフ */}
      <div className="graph-container">
        <Chart ref={chartRef} type="bar" data={data} options={options} />
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
const options = {
  responsive: true,
  plugins: {
    legend: {
      position: 'top' as const,
      labels: {
        font: {
          size: 16 // 修改图例文字大小
        }
      }
    },
    title: {
      display: true,
      text: '期中資金繰り表',
      font: {
        size: 24 // 修改标题文字大小
      }
    },
    tooltip: {
      callbacks: {
        label: function(context: any) {
          const label = context.dataset.label || '';
          const value = context.raw;
          return `${label}: ${value}`;
        }
      }
    },
  },
  scales: {
    y: {
      beginAtZero: true,
    }
  }
};
kirin-ri commented 3 months ago
.graph-container {
  left:50px;
  position: relative;
  margin-top: 20px;
  width: 1200px; /* 图表宽度 */
  height: 700px; /* 图表高度 */
  padding: 20px;
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
kirin-ri commented 3 months ago
.content-wrapper {
  display: flex;
  justify-content: flex-start; /* 保持内容在左侧 */
  padding: 0; /* 确保没有内边距 */
  position: relative; /* 确保相对定位 */
}

.graph-container {
  position: relative;
  margin-top: 20px;
  max-width: 1200px; /* 图表最大宽度 */
  width: 100%; /* 图表宽度随屏幕变化 */
  height: auto; /* 图表高度自动调整 */
  padding: 20px;
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  flex: 1; /* 让图表容器填满剩余空间 */
}
kirin-ri commented 3 months ago
// データセット一覧コンポーネント
const ViewListDataset = (props: {
  item: ApiDefs.ApiMap;
  tagList: ApiDefs.Tag[];
}) => {
  const deployApi = [] as any;
  const unDeployApi = [] as any;
  Object.keys(props.item).map((val: any) => {
    if (props.item[val].provide) {
      deployApi.push(
        <DatasetCard
          physical_name={val}
          api={props.item[val]}
          tagList={props.tagList}
          key={`dataset-card-${val}`}
        />
      );
    } else {
      unDeployApi.push(
        <DatasetCard
          physical_name={val}
          api={props.item[val]}
          tagList={props.tagList}
          key={`dataset-card-${val}`}
        />
      );
    }
  });
  return (
    <>
      <div className="m-2 border shadow-sm">
        <div
          className="card-header collapsed"
          data-toggle="collapse"
          data-target="#deployApiList"
          id="deployApiListHeader"
        >
          <div className="api-name-font mr-auto">使用中データセット</div>
        </div>
        <div className="card-body collapse" id="deployApiList">
          {deployApi}
        </div>
      </div>
      <div className="ml-2 mr-2 mb-2 border shadow-sm">
        <div
          className="card-header collapsed"
          data-toggle="collapse"
          data-target="#undeployApiList"
          id="undeployApiListHeader"
        >
          <div className="api-name-font mr-auto">未使用データセット</div>
        </div>
        <div className="card-body collapse" id="undeployApiList">
          {unDeployApi}
        </div>
      </div>
    </>
  );
};
kirin-ri commented 3 months ago
const CollapsiblePanel = ({ title, content }: { title: string; content: string }) => {
  const [isOpen, setIsOpen] = useState(false);

  const togglePanel = () => {
    setIsOpen(!isOpen);
  };

  return (
    <div className="collapsible-panel">
      <div className="panel-header" onClick={togglePanel}>
        <div className="panel-title">{title}</div>
        <div className="panel-icon">{isOpen ? '-' : '+'}</div>
      </div>
      {isOpen && <div className="panel-content">{content}</div>}
    </div>
  );
};
kirin-ri commented 3 months ago
import React, { useState, useRef } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

const EmptyPage = () => {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示
  const chartRef = useRef<ChartJS | null>(null);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: true,
        text: '期中資金繰り表',
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      },
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      <div className="main-content">
        {/* 資金繰り表のグラフ */}
        <div className="graph-container">
          <Chart ref={chartRef} type="bar" data={data} options={options} />
        </div>
        {/* 可折叠面板 */}
        <div className="collapsible-panels">
          <CollapsiblePanel title="test1" content="abcdef" />
          <CollapsiblePanel title="test2" content="abcdef" />
          <CollapsiblePanel title="test3" content="abcdef" />
        </div>
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
.collapsible-panels {
  margin-left: 20px; /* 确保与图表有间距 */
  width: 300px; /* 可根据需要调整宽度 */
}

.collapsible-panel {
  margin-bottom: 10px; /* 面板之间的间距 */
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background-color: #f1f1f1;
  cursor: pointer;
  border-radius: 5px;
}

.panel-title {
  font-weight: bold;
}

.panel-icon {
  font-size: 1.2rem;
}

.panel-content {
  padding: 10px;
  background-color: #ffffff;
  border: 1px solid #f1f1f1;
  border-radius: 0 0 5px 5px;
}
kirin-ri commented 3 months ago
.collapsible-panels {
  margin-left: 20px; /* 确保与图表有间距 */
  width: 300px; /* 可根据需要调整宽度 */
}

.collapsible-panel {
  margin-bottom: 10px; /* 面板之间的间距 */
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background-color: #f1f1f1;
  cursor: pointer;
  border-radius: 5px;
}

.panel-title {
  font-weight: bold;
}

.panel-icon {
  font-size: 1.2rem;
}

.panel-content {
  padding: 10px;
  background-color: #ffffff;
  border: 1px solid #f1f1f1;
  border-radius: 0 0 5px 5px;
}
kirin-ri commented 3 months ago
      <div className="main-content">
        {/* 資金繰り表のグラフ */}
        <div className="graph-container">
          <Chart ref={chartRef} type="bar" data={data} options={options} />
        </div>
        {/* 可折叠面板 */}
        <div className="collapsible-panels">
          <CollapsiblePanel title="test1" content="abcdef" />
          <CollapsiblePanel title="test2" content="abcdef" />
          <CollapsiblePanel title="test3" content="abcdef" />
        </div>
      </div>
kirin-ri commented 3 months ago
.main-content {
  display: flex;
  flex-direction: row; /* 使内容在一行内显示 */
}
kirin-ri commented 3 months ago
  const chartRef = React.useRef<ChartJSOrUndefined<'bar', number[], string>>(null);

  useEffect(() => {
    const chart = chartRef.current;
    if (chart) {
      chart.options.plugins.tooltip.enabled = false; // Disable default tooltip
      chart.options.plugins.afterDraw = (chart) => {
        const ctx = chart.ctx;
        chart.data.datasets[2].data.forEach((value, index) => {
          if (value < 0) {
            const meta = chart.getDatasetMeta(2).data[index];
            const x = meta.x;
            const y = meta.y;
            ctx.fillStyle = 'red';
            ctx.font = 'bold 12px Arial';
            ctx.fillText('!', x - 5, y - 10);
          }
        });
      };
      chart.update();
    }
  }, [chartRef]);
kirin-ri commented 3 months ago
import { BarElement, CategoryScale, Chart as ChartJS, Legend, LinearScale, LineElement, PointElement, ScriptableContext, Title, Tooltip } from 'chart.js';
import { useState } from "react";
import { Chart } from 'react-chartjs-2';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

function EmptyPage() {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示

  const chartRef = React.useRef<ChartJSOrUndefined<'bar', number[], string>>(null);

  useEffect(() => {
    const chart = chartRef.current;
    if (chart) {
      chart.options.plugins.tooltip.enabled = false; // Disable default tooltip
      chart.options.plugins.afterDraw = (chart) => {
        const ctx = chart.ctx;
        chart.data.datasets[2].data.forEach((value, index) => {
          if (value < 0) {
            const meta = chart.getDatasetMeta(2).data[index];
            const x = meta.x;
            const y = meta.y;
            ctx.fillStyle = 'red';
            ctx.font = 'bold 12px Arial';
            ctx.fillText('!', x - 5, y - 10);
          }
        });
      };
      chart.update();
    }
  }, [chartRef]);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
        labels: {
          font: {
            size: 16 // 修改图例文字大小
          }
        }
      },
      title: {
        display: true,
        text: '期中資金繰り表',
        font: {
          size: 24 // 修改标题文字大小
        }
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      },
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  const CollapsiblePanel = ({ title, content }: { title: string; content: string }) => {
    const [isOpen, setIsOpen] = useState(false);

    const togglePanel = () => {
      setIsOpen(!isOpen);
    };

    return (
      <div className="collapsible-panel">
        <div className="panel-header" onClick={togglePanel}>
          <div className="panel-title">{title}</div>
        </div>
        {isOpen && <div className="panel-content">{content}</div>}
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      <div className="main-content">
        {/* 資金繰り表のグラフ */}
        <div className="graph-container">
          <Chart ref={chartRef} type="bar" data={data} options={options} />
        </div>
        {/* 可折叠面板 */}
        <div className="collapsible-panels">
          <CollapsiblePanel title="test1" content="abcdef" />
          <CollapsiblePanel title="test2" content="abcdef" />
          <CollapsiblePanel title="test3" content="abcdef" />
        </div>
      </div>
    </div>
  );
}

export default EmptyPage;
kirin-ri commented 3 months ago
import React, { useState, useEffect, useRef } from "react";
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend, ScriptableContext } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend);

const EmptyPage = () => {
  const test = '資金繰り表';
  const [showAlert, setShowAlert] = useState(true); // 控制警告弹窗的显示
  const chartRef = useRef<ChartJS | null>(null);

  useEffect(() => {
    const chart = chartRef.current;
    if (chart) {
      const ctx = chart.ctx;
      if (ctx && chart.data.datasets[2].data) {
        (chart.data.datasets[2].data as number[]).forEach((value, index) => {
          if (value < 0) {
            const meta = chart.getDatasetMeta(2).data[index];
            if (meta) {
              const x = meta.x;
              const y = meta.y;
              ctx.fillStyle = 'red';
              ctx.font = 'bold 12px Arial';
              ctx.fillText('!', x - 5, y - 10);
            }
          }
        });
      }
    }
  }, []);

  const AlertBox = ({ message, onClose }: { message: string; onClose: () => void }) => {
    return (
      <div className="alert-box">
        <div className="alert-content">
          <i className="fa fa-exclamation-circle alert-icon" aria-hidden="true"></i>
          <span className="alert-message">{message}</span>
        </div>
        <button className="close-btn" onClick={onClose}>非表示</button>
      </div>
    );
  };

  const data = {
    labels: ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月', '2月', '3月'],
    datasets: [
      {
        type: 'bar' as const,
        label: '収入',
        data: [20, 30, 25, 15, 30, 25, 20, 30, 25, 30, 20, 25],
        backgroundColor: 'rgba(153, 102, 255, 0.5)',
      },
      {
        type: 'bar' as const,
        label: '支出',
        data: [-25, -35, -30, -20, -25, -30, -35, -25, -30, -20, -25, -30],
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        type: 'line' as const,
        label: '資金繰り',
        data: [10, -5, -10, 5, 10, -15, 20, -10, 15, 5, -5, 10],
        borderColor: 'black',
        backgroundColor: 'black',
        fill: false,
        tension: 0.1,
        borderWidth: 2,
        pointStyle: 'rectRot',
        pointRadius: 6,
        pointHoverRadius: 8,
        pointBackgroundColor: (context: ScriptableContext<'line'>) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index] as number;
          return value < 0 ? 'red' : 'black';
        }
      }
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
        labels: {
          font: {
            size: 16 // 修改图例文字大小
          }
        }
      },
      title: {
        display: true,
        text: '期中資金繰り表',
        font: {
          size: 24 // 修改标题文字大小
        }
      },
      tooltip: {
        callbacks: {
          label: function(context: any) {
            const label = context.dataset.label || '';
            const value = context.raw;
            return `${label}: ${value}`;
          }
        }
      },
    },
    scales: {
      y: {
        beginAtZero: true,
      }
    }
  };

  const CollapsiblePanel = ({ title, content }: { title: string; content: string }) => {
    const [isOpen, setIsOpen] = useState(false);

    const togglePanel = () => {
      setIsOpen(!isOpen);
    };

    return (
      <div className="collapsible-panel">
        <div className="panel-header" onClick={togglePanel}>
          <div className="panel-title">{title}</div>
        </div>
        {isOpen && <div className="panel-content">{content}</div>}
      </div>
    );
  };

  return (
    <div className="content-wrapper metrics-details">
      <section className="page-cover">
        <div className="page-cover-title-frame">
          <h1>{test}</h1>
        </div>
      </section>
      {/* 警告弹窗 */}
      {showAlert && (
        <div className="alert-container">
          <AlertBox
            message="期中に資金がマイナスとなる期間があります"
            onClose={() => setShowAlert(false)}
          />
        </div>
      )}
      <div className="main-content">
        {/* 資金繰り表のグラフ */}
        <div className="graph-container">
          <Chart ref={chartRef} type="bar" data={data} options={options} />
        </div>
        {/* 可折叠面板 */}
        <div className="collapsible-panels">
          <CollapsiblePanel title="test1" content="abcdef" />
          <CollapsiblePanel title="test2" content="abcdef" />
          <CollapsiblePanel title="test3" content="abcdef" />
        </div>
      </div>
    </div>
  );
};

export default EmptyPage;
kirin-ri commented 3 months ago
.collapsible-panels {
  margin-left: 20px; /* 确保与图表有间距 */
  width: 300px; /* 可根据需要调整宽度 */
}

.collapsible-panel {
  margin-bottom: 10px; /* 面板之间的间距 */
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background-color: #f1f1f1;
  cursor: pointer;
  border-radius: 5px;
}

.panel-title {
  font-weight: bold;
}

.panel-icon {
  font-size: 1.2rem;
}

.panel-content {
  padding: 10px;
  background-color: #ffffff;
  border: 1px solid #f1f1f1;
  border-radius: 0 0 5px 5px;
}
kirin-ri commented 3 months ago
.content-wrapper {
  padding: 0; /* 确保没有内边距 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: space-between; /* 确保按钮在右侧 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-content {
  display: flex;
  align-items: center;
  justify-content: center; /* 确保内容居中 */
  flex-grow: 1;
}

.alert-icon {
  color: red;
  font-size: 2rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.alert-message {
  text-align: center; /* 文本居中对齐 */
  font-size: 1.2rem
}

.close-btn {
  background-color: transparent;
  border: 1px solid red;
  border-radius: 15px; /* 椭圆形 */
  color: red;
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}

.graph-container {
  left:50px;
  position: relative;
  margin-top: 20px;
  max-width: 50%; /* 图表宽度 */
  height: auto; /* 图表高度 */
  padding: 20px;
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.collapsible-panels {
  margin-left: 20px; /* 确保与图表有间距 */
  width: 300px; /* 可根据需要调整宽度 */
}

.collapsible-panel {
  margin-bottom: 10px; /* 面板之间的间距 */
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background-color: #f1f1f1;
  cursor: pointer;
  border-radius: 5px;
}

.panel-title {
  font-weight: bold;
}

.panel-icon {
  font-size: 1.2rem;
}

.panel-content {
  padding: 10px;
  background-color: #ffffff;
  border: 1px solid #f1f1f1;
  border-radius: 0 0 5px 5px;
}
kirin-ri commented 3 months ago
.content-wrapper {
  display: flex;
  flex-direction: column;
  padding: 0; /* 确保没有内边距 */
  position: relative; /* 确保相对定位 */
}

.main-content {
  display: flex;
  flex-direction: row; /* 使内容在一行内显示 */
  justify-content: flex-start; /* 确保内容在左侧 */
  align-items: flex-start; /* 确保内容在顶部对齐 */
}

.page-cover {
  margin: 0; /* 确保没有外边距 */
}

.page-cover-title-frame {
  margin: 0; /* 确保没有外边距 */
  padding: 0; /* 确保没有内边距 */
}

.alert-container {
  padding: 0;
  margin: 0;
}

.alert-box {
  background-color: white;
  color: black;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  margin: 0; /* 确保没有外边距 */
  display: flex;
  justify-content: space-between; /* 确保按钮在右侧 */
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: relative;
}

.alert-content {
  display: flex;
  align-items: center;
  justify-content: center; /* 确保内容居中 */
  flex-grow: 1;
}

.alert-icon {
  color: red;
  font-size: 2rem; /* 调整感叹号的大小 */
  margin-right: 10px; /* 感叹号与文字之间的间距 */
}

.alert-message {
  text-align: center; /* 文本居中对齐 */
  font-size: 1.2rem;
}

.close-btn {
  background-color: transparent;
  border: 1px solid red;
  border-radius: 15px; /* 椭圆形 */
  color: red;
  cursor: pointer;
  font-size: 1rem;
  padding: 5px 10px;
  margin-left: 10px;
}

.graph-container {
  margin-top: 20px;
  max-width: 50%; /* 图表宽度 */
  height: auto; /* 图表高度 */
  padding: 20px;
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.collapsible-panels {
  margin-left: 20px; /* 确保与图表有间距 */
  width: 300px; /* 可根据需要调整宽度 */
  display: flex;
  flex-direction: column;
}