Merge branch 'feature/solarEnergy' into MCUT
This commit is contained in:
		
						commit
						c66ac43c14
					
				
							
								
								
									
										1
									
								
								Frontend/ibms_solar/.env
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Frontend/ibms_solar/.env
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					VITE_API_BASEURL = "http://192.168.0.206:8040"
 | 
				
			||||||
							
								
								
									
										24
									
								
								Frontend/ibms_solar/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Frontend/ibms_solar/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					# Logs
 | 
				
			||||||
 | 
					logs
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					npm-debug.log*
 | 
				
			||||||
 | 
					yarn-debug.log*
 | 
				
			||||||
 | 
					yarn-error.log*
 | 
				
			||||||
 | 
					pnpm-debug.log*
 | 
				
			||||||
 | 
					lerna-debug.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					dist
 | 
				
			||||||
 | 
					dist-ssr
 | 
				
			||||||
 | 
					*.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Editor directories and files
 | 
				
			||||||
 | 
					.vscode/*
 | 
				
			||||||
 | 
					!.vscode/extensions.json
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					*.suo
 | 
				
			||||||
 | 
					*.ntvs*
 | 
				
			||||||
 | 
					*.njsproj
 | 
				
			||||||
 | 
					*.sln
 | 
				
			||||||
 | 
					*.sw?
 | 
				
			||||||
							
								
								
									
										8
									
								
								Frontend/ibms_solar/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Frontend/ibms_solar/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					# React + Vite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Currently, two official plugins are available:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
 | 
				
			||||||
 | 
					- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
 | 
				
			||||||
							
								
								
									
										38
									
								
								Frontend/ibms_solar/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Frontend/ibms_solar/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					import js from '@eslint/js'
 | 
				
			||||||
 | 
					import globals from 'globals'
 | 
				
			||||||
 | 
					import react from 'eslint-plugin-react'
 | 
				
			||||||
 | 
					import reactHooks from 'eslint-plugin-react-hooks'
 | 
				
			||||||
 | 
					import reactRefresh from 'eslint-plugin-react-refresh'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default [
 | 
				
			||||||
 | 
					  { ignores: ['dist'] },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    files: ['**/*.{js,jsx}'],
 | 
				
			||||||
 | 
					    languageOptions: {
 | 
				
			||||||
 | 
					      ecmaVersion: 2020,
 | 
				
			||||||
 | 
					      globals: globals.browser,
 | 
				
			||||||
 | 
					      parserOptions: {
 | 
				
			||||||
 | 
					        ecmaVersion: 'latest',
 | 
				
			||||||
 | 
					        ecmaFeatures: { jsx: true },
 | 
				
			||||||
 | 
					        sourceType: 'module',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    settings: { react: { version: '18.3' } },
 | 
				
			||||||
 | 
					    plugins: {
 | 
				
			||||||
 | 
					      react,
 | 
				
			||||||
 | 
					      'react-hooks': reactHooks,
 | 
				
			||||||
 | 
					      'react-refresh': reactRefresh,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    rules: {
 | 
				
			||||||
 | 
					      ...js.configs.recommended.rules,
 | 
				
			||||||
 | 
					      ...react.configs.recommended.rules,
 | 
				
			||||||
 | 
					      ...react.configs['jsx-runtime'].rules,
 | 
				
			||||||
 | 
					      ...reactHooks.configs.recommended.rules,
 | 
				
			||||||
 | 
					      'react/jsx-no-target-blank': 'off',
 | 
				
			||||||
 | 
					      'react-refresh/only-export-components': [
 | 
				
			||||||
 | 
					        'warn',
 | 
				
			||||||
 | 
					        { allowConstantExport: true },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										14
									
								
								Frontend/ibms_solar/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Frontend/ibms_solar/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8" />
 | 
				
			||||||
 | 
					    <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
				
			||||||
 | 
					    <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
 | 
				
			||||||
 | 
					    <title>Marketing Dashboard - Application Intel - SmartAdmin v4.5.1</title>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <div id="root"></div>
 | 
				
			||||||
 | 
					    <script type="module" src="/src/main.jsx"></script>
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										5571
									
								
								Frontend/ibms_solar/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5571
									
								
								Frontend/ibms_solar/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										38
									
								
								Frontend/ibms_solar/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Frontend/ibms_solar/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "ibms_solar",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "version": "0.0.0",
 | 
				
			||||||
 | 
					  "type": "module",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "dev": "vite",
 | 
				
			||||||
 | 
					    "build": "vite build",
 | 
				
			||||||
 | 
					    "lint": "eslint .",
 | 
				
			||||||
 | 
					    "preview": "vite preview"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "apexcharts": "^3.53.0",
 | 
				
			||||||
 | 
					    "axios": "^1.7.7",
 | 
				
			||||||
 | 
					    "date-fns": "^3.6.0",
 | 
				
			||||||
 | 
					    "react": "^18.3.1",
 | 
				
			||||||
 | 
					    "react-apexcharts": "^1.4.1",
 | 
				
			||||||
 | 
					    "react-datepicker": "^7.3.0",
 | 
				
			||||||
 | 
					    "react-dom": "^18.3.1",
 | 
				
			||||||
 | 
					    "react-icons": "^5.3.0",
 | 
				
			||||||
 | 
					    "react-router-dom": "^6.26.1"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@eslint/js": "^9.9.0",
 | 
				
			||||||
 | 
					    "@types/react": "^18.3.3",
 | 
				
			||||||
 | 
					    "@types/react-dom": "^18.3.0",
 | 
				
			||||||
 | 
					    "@vitejs/plugin-react": "^4.3.1",
 | 
				
			||||||
 | 
					    "autoprefixer": "^10.4.20",
 | 
				
			||||||
 | 
					    "eslint": "^9.9.0",
 | 
				
			||||||
 | 
					    "eslint-plugin-react": "^7.35.0",
 | 
				
			||||||
 | 
					    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
 | 
				
			||||||
 | 
					    "eslint-plugin-react-refresh": "^0.4.9",
 | 
				
			||||||
 | 
					    "globals": "^15.9.0",
 | 
				
			||||||
 | 
					    "postcss": "^8.4.44",
 | 
				
			||||||
 | 
					    "tailwindcss": "^3.4.10",
 | 
				
			||||||
 | 
					    "vite": "^5.4.1"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								Frontend/ibms_solar/postcss.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Frontend/ibms_solar/postcss.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  plugins: {
 | 
				
			||||||
 | 
					    tailwindcss: {},
 | 
				
			||||||
 | 
					    autoprefixer: {},
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								Frontend/ibms_solar/public/vite.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Frontend/ibms_solar/public/vite.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 1.5 KiB  | 
							
								
								
									
										23
									
								
								Frontend/ibms_solar/src/App.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Frontend/ibms_solar/src/App.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { HashRouter, Link, Route, Routes } from "react-router-dom";
 | 
				
			||||||
 | 
					import { SiteProvider } from "@/context";
 | 
				
			||||||
 | 
					import { Home, Energy } from "@/page";
 | 
				
			||||||
 | 
					import { Navbar } from "@/components";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const App = () => (
 | 
				
			||||||
 | 
					  <HashRouter>
 | 
				
			||||||
 | 
					    <SiteProvider>
 | 
				
			||||||
 | 
					      <header>
 | 
				
			||||||
 | 
					        <Navbar />
 | 
				
			||||||
 | 
					      </header>
 | 
				
			||||||
 | 
					      <main className="py-8 w-full bg-zinc-700 min-h-[100vh]">
 | 
				
			||||||
 | 
					        <Routes>
 | 
				
			||||||
 | 
					          <Route path="/" element={<Home />} />
 | 
				
			||||||
 | 
					          <Route path="/energy" element={<Energy />} />
 | 
				
			||||||
 | 
					        </Routes>
 | 
				
			||||||
 | 
					      </main>
 | 
				
			||||||
 | 
					    </SiteProvider>
 | 
				
			||||||
 | 
					  </HashRouter>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default App;
 | 
				
			||||||
							
								
								
									
										5
									
								
								Frontend/ibms_solar/src/assets/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Frontend/ibms_solar/src/assets/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import logo from './logo.png';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export {
 | 
				
			||||||
 | 
					  logo,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								Frontend/ibms_solar/src/assets/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Frontend/ibms_solar/src/assets/logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 12 KiB  | 
							
								
								
									
										261
									
								
								Frontend/ibms_solar/src/components/Navbar.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								Frontend/ibms_solar/src/components/Navbar.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,261 @@
 | 
				
			|||||||
 | 
					import React, { useState, useEffect } from "react";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					import { logo } from "@ASSET";
 | 
				
			||||||
 | 
					import { getCookie } from "@/utils";
 | 
				
			||||||
 | 
					import { GET_AUTHPAGE_API, AUTHPAGES, GET_SUBAUTHPAGE_API } from "@/constant";
 | 
				
			||||||
 | 
					import { AiOutlineClose, AiOutlineMenu } from "react-icons/ai";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  FaHome,
 | 
				
			||||||
 | 
					  FaSolarPanel,
 | 
				
			||||||
 | 
					  FaUserCircle,
 | 
				
			||||||
 | 
					  FaCommentDots,
 | 
				
			||||||
 | 
					  FaCommentSlash,
 | 
				
			||||||
 | 
					} from "react-icons/fa";
 | 
				
			||||||
 | 
					import axios from "axios";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Navbar = () => {
 | 
				
			||||||
 | 
					  const [nav, setNav] = useState(false);
 | 
				
			||||||
 | 
					  const [showErr, setShowErr] = useState(false);
 | 
				
			||||||
 | 
					  const [authPage, setAuthPage] = useState([]);
 | 
				
			||||||
 | 
					  const [subAuthPage, setSubAuthPage] = useState([]);
 | 
				
			||||||
 | 
					  const [user, setUser] = useState(null);
 | 
				
			||||||
 | 
					  const [openDropdowns, setOpenDropdowns] = useState({
 | 
				
			||||||
 | 
					    home: false,
 | 
				
			||||||
 | 
					    pf1: false,
 | 
				
			||||||
 | 
					    user: false,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleNav = () => {
 | 
				
			||||||
 | 
					    setNav(!nav);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const toggleDropdown = (key) => {
 | 
				
			||||||
 | 
					    setOpenDropdowns((prev) => ({
 | 
				
			||||||
 | 
					      ...prev,
 | 
				
			||||||
 | 
					      [key]: !prev[key],
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const toggleErrIcon = () => {
 | 
				
			||||||
 | 
					    setShowErr(!showErr);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const iniFroList = async () => {
 | 
				
			||||||
 | 
					    const res = await axios.post(GET_AUTHPAGE_API);
 | 
				
			||||||
 | 
					    setAuthPage(
 | 
				
			||||||
 | 
					      res.data.data.map((d) => ({
 | 
				
			||||||
 | 
					        ...d,
 | 
				
			||||||
 | 
					        icon: AUTHPAGES(d.authCode),
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getSubList = async () => {
 | 
				
			||||||
 | 
					    const res = await axios.post(GET_SUBAUTHPAGE_API);
 | 
				
			||||||
 | 
					    console.log("res", res);
 | 
				
			||||||
 | 
					    setSubAuthPage(
 | 
				
			||||||
 | 
					      res.data.data.map((d) => ({
 | 
				
			||||||
 | 
					        ...d,
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const navigate = (pageName) => {
 | 
				
			||||||
 | 
					    sessionStorage.setItem("lastPage", pageName);
 | 
				
			||||||
 | 
					    window.location.href = "/file/index.html";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const navigateToSub = (sub) => {
 | 
				
			||||||
 | 
					    let pageAct = JSON.parse(sessionStorage.getItem("pageAct"));
 | 
				
			||||||
 | 
					    pageAct = {
 | 
				
			||||||
 | 
					      ...pageAct,
 | 
				
			||||||
 | 
					      buildList: sub,
 | 
				
			||||||
 | 
					      buiTag: sub.building_tag,
 | 
				
			||||||
 | 
					      buiName: sub.full_name,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    sessionStorage.setItem("lastPage", "dashboard");
 | 
				
			||||||
 | 
					    sessionStorage.setItem("pageAct", JSON.stringify(pageAct));
 | 
				
			||||||
 | 
					    window.location.href = "/file/index.html";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 獲取並初始化導航頁面
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    iniFroList();
 | 
				
			||||||
 | 
					    getSubList();
 | 
				
			||||||
 | 
					    setUser(getCookie("niagara_userid"));
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <nav className="bg-zinc-800 flex justify-between items-center h-16 max-w-full mx-auto px-8 text-white">
 | 
				
			||||||
 | 
					      <Link to="/" className="flex items-center space-x-3 rtl:space-x-reverse">
 | 
				
			||||||
 | 
					        <img src={logo} alt="logo" className="w-[200px] md:w-[272px] object-contain" />
 | 
				
			||||||
 | 
					      </Link>
 | 
				
			||||||
 | 
					      <ul
 | 
				
			||||||
 | 
					        className={
 | 
				
			||||||
 | 
					          nav
 | 
				
			||||||
 | 
					            ? "fixed left-0 top-0 md:flex w-[60%] h-full border-r border-r-gray-900 bg-[#000300] ease-in-out duration-500"
 | 
				
			||||||
 | 
					            : "ease-in-out w-[60%] duration-500 fixed top-0 bottom-0 left-[-100%] md:flex md:left-0 md:relative md:w-auto"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <li className=" hover:text-[#ccbfdf] cursor-pointer">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            onClick={() => toggleDropdown("home")}
 | 
				
			||||||
 | 
					            className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <FaHome />
 | 
				
			||||||
 | 
					            <span className="text-sm md:text-sm ps-2 md:ps-0">首頁</span>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            className={`md:absolute ${
 | 
				
			||||||
 | 
					              openDropdowns.home ? "block" : "hidden"
 | 
				
			||||||
 | 
					            } bg-zinc-600 min-w-[200px] rounded shadow-md  space-y-2`}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <ul className="">
 | 
				
			||||||
 | 
					              <li
 | 
				
			||||||
 | 
					                key="1"
 | 
				
			||||||
 | 
					                onClick={() => navigate("schoolView")}
 | 
				
			||||||
 | 
					                className="text-md ps-4 py-3 hover:bg-zinc-500"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                校園總覽
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					              <li
 | 
				
			||||||
 | 
					                key="2"
 | 
				
			||||||
 | 
					                onClick={() => navigate("elecSingleLine")}
 | 
				
			||||||
 | 
					                className="text-md ps-4 py-3 hover:bg-zinc-500"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                電表單線路
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        {authPage.map((page) => (
 | 
				
			||||||
 | 
					          <li
 | 
				
			||||||
 | 
					            key={page.authCode}
 | 
				
			||||||
 | 
					            className="hover:text-[#ccbfdf] cursor-pointer"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {page.authCode === "PF1" ? (
 | 
				
			||||||
 | 
					              <>
 | 
				
			||||||
 | 
					                <button
 | 
				
			||||||
 | 
					                  onClick={() => toggleDropdown("pf1")}
 | 
				
			||||||
 | 
					                  className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  {page.icon}
 | 
				
			||||||
 | 
					                  <span className="text-sm md:text-sm ps-2 md:ps-0">
 | 
				
			||||||
 | 
					                    {page.subName}
 | 
				
			||||||
 | 
					                  </span>
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					                <div
 | 
				
			||||||
 | 
					                  className={`md:absolute ${
 | 
				
			||||||
 | 
					                    openDropdowns.pf1 ? "block" : "hidden"
 | 
				
			||||||
 | 
					                  } bg-zinc-600 min-w-[200px] rounded shadow-md  space-y-2`}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <ul className="">
 | 
				
			||||||
 | 
					                    {subAuthPage.map((sub) => (
 | 
				
			||||||
 | 
					                      <li
 | 
				
			||||||
 | 
					                        key={sub.building_tag}
 | 
				
			||||||
 | 
					                        onClick={() => navigateToSub(sub)}
 | 
				
			||||||
 | 
					                        className="text-md text-white ps-4 py-3 hover:bg-zinc-500"
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        {sub.full_name}
 | 
				
			||||||
 | 
					                      </li>
 | 
				
			||||||
 | 
					                    ))}
 | 
				
			||||||
 | 
					                  </ul>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </>
 | 
				
			||||||
 | 
					            ) : (
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                onClick={() => navigate(page.showView)}
 | 
				
			||||||
 | 
					                className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                {page.icon}
 | 
				
			||||||
 | 
					                <span className="text-sm md:text-sm ps-2 md:ps-0">
 | 
				
			||||||
 | 
					                  {page.subName}
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					              </button>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					          </li>
 | 
				
			||||||
 | 
					        ))}
 | 
				
			||||||
 | 
					        <li className=" hover:text-[#ccbfdf] cursor-pointer">
 | 
				
			||||||
 | 
					          <Link to="/"
 | 
				
			||||||
 | 
					            className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <FaSolarPanel />
 | 
				
			||||||
 | 
					            <span className="text-sm md:text-sm ps-2 md:ps-0">太陽能管理</span>
 | 
				
			||||||
 | 
					          </Link>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li className="md:hidden hover:text-[#ccbfdf] cursor-pointer">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            onClick={toggleErrIcon}
 | 
				
			||||||
 | 
					            className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {showErr ? <FaCommentSlash /> : <FaCommentDots />}
 | 
				
			||||||
 | 
					            <span className="text-sm md:text-sm ps-2 md:ps-0">{showErr ? "隱藏警告" : "顯示警告"}</span>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li className="md:hidden hover:text-[#ccbfdf] cursor-pointer">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            onClick={() => toggleDropdown("user")}
 | 
				
			||||||
 | 
					            className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <FaUserCircle />
 | 
				
			||||||
 | 
					            <span className="text-sm md:text-sm ps-2 md:ps-0">{ user ? user : "webUser" }</span>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            className={`md:absolute ${
 | 
				
			||||||
 | 
					              openDropdowns.user ? "block" : "hidden"
 | 
				
			||||||
 | 
					            } bg-zinc-600 min-w-[200px] rounded shadow-md  space-y-2`}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <ul className="">
 | 
				
			||||||
 | 
					              <li
 | 
				
			||||||
 | 
					                className="text-md ps-4 py-3 hover:bg-zinc-500"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <a href="/logout">登出</a>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					      {/* Mobile Navigation Icon */}
 | 
				
			||||||
 | 
					      <div onClick={handleNav} className="block md:hidden">
 | 
				
			||||||
 | 
					        {nav ? <AiOutlineClose size={20} /> : <AiOutlineMenu size={20} />}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      {/* user */}
 | 
				
			||||||
 | 
					      <ul className="hidden md:flex">
 | 
				
			||||||
 | 
					        <li className=" hover:text-[#ccbfdf] cursor-pointer">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            onClick={toggleErrIcon}
 | 
				
			||||||
 | 
					            className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {showErr ? <FaCommentSlash /> : <FaCommentDots />}
 | 
				
			||||||
 | 
					            <span className="text-sm md:text-sm ps-2 md:ps-0">
 | 
				
			||||||
 | 
					              {showErr ? "隱藏警告" : "顯示警告"}
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <li className=" hover:text-[#ccbfdf] cursor-pointer">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            onClick={() => toggleDropdown("user")}
 | 
				
			||||||
 | 
					            className="flex md:flex-col justify-start md:justify-center items-center text-2xl md:text-3xl  w-full px-4 border-b border-slate-500 md:border-none py-5 md:py-0"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <FaUserCircle />
 | 
				
			||||||
 | 
					            <span className="text-sm md:text-sm ps-2 md:ps-0">{ user ? user : "webUser" }</span>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            className={`md:absolute right-0 ${
 | 
				
			||||||
 | 
					              openDropdowns.user ? "block" : "hidden"
 | 
				
			||||||
 | 
					            } bg-zinc-600 min-w-[200px] rounded shadow-md space-y-2`}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <ul className="">
 | 
				
			||||||
 | 
					              <li className="text-md ps-4 py-3 hover:bg-zinc-500">
 | 
				
			||||||
 | 
					                <a href="/logout">登出</a>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </nav>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Navbar;
 | 
				
			||||||
							
								
								
									
										393
									
								
								Frontend/ibms_solar/src/components/energy/HistoryData.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								Frontend/ibms_solar/src/components/energy/HistoryData.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,393 @@
 | 
				
			|||||||
 | 
					import React, { useState } from "react";
 | 
				
			||||||
 | 
					import DatePicker from "react-datepicker";
 | 
				
			||||||
 | 
					import "react-datepicker/dist/react-datepicker.css";
 | 
				
			||||||
 | 
					import { zhTW } from "date-fns/locale";
 | 
				
			||||||
 | 
					import Chart from "react-apexcharts";
 | 
				
			||||||
 | 
					import historyData from "@/mock/historyData";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const HistoryData = () => {
 | 
				
			||||||
 | 
					  const [selectedFilter, setSelectedFilter] = useState("day");
 | 
				
			||||||
 | 
					  const [subFilter, setSubFilter] = useState("today");
 | 
				
			||||||
 | 
					  const [selectedDate, setSelectedDate] = useState(new Date());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleFilterChange = (filter, subFilter = null) => {
 | 
				
			||||||
 | 
					    setSelectedFilter(filter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 設置次篩選項並設置對應的日期
 | 
				
			||||||
 | 
					    if (subFilter) {
 | 
				
			||||||
 | 
					      setSubFilter(subFilter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (subFilter || filter) {
 | 
				
			||||||
 | 
					      case "today":
 | 
				
			||||||
 | 
					        setSelectedDate(new Date());
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case "yesterday":
 | 
				
			||||||
 | 
					        setSelectedDate(new Date(Date.now() - 86400000));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case "currentMonth":
 | 
				
			||||||
 | 
					        const now = new Date();
 | 
				
			||||||
 | 
					        setSelectedDate(new Date(now.getFullYear(), now.getMonth(), 1));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case "lastMonth":
 | 
				
			||||||
 | 
					        const lastMonth = new Date();
 | 
				
			||||||
 | 
					        setSelectedDate(
 | 
				
			||||||
 | 
					          new Date(lastMonth.getFullYear(), lastMonth.getMonth() - 1, 1)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case "currentYear":
 | 
				
			||||||
 | 
					        setSelectedDate(new Date(new Date().getFullYear(), 0, 1));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case "lastYear":
 | 
				
			||||||
 | 
					        setSelectedDate(new Date(new Date().getFullYear() - 1, 0, 1));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const renderButtons = () => {
 | 
				
			||||||
 | 
					    const buttonConfigs = {
 | 
				
			||||||
 | 
					      day: ["today", "yesterday"],
 | 
				
			||||||
 | 
					      month: ["currentMonth", "lastMonth"],
 | 
				
			||||||
 | 
					      year: ["currentYear", "lastYear"],
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 根據 selectedFilter 來顯示相應的按鈕組
 | 
				
			||||||
 | 
					    return buttonConfigs[selectedFilter]?.map((filter) => (
 | 
				
			||||||
 | 
					      <button
 | 
				
			||||||
 | 
					        key={filter}
 | 
				
			||||||
 | 
					        className={`text-white px-5 py-2 hover:bg-gray-500 rounded me-2 ${
 | 
				
			||||||
 | 
					          subFilter === filter ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					        }`}
 | 
				
			||||||
 | 
					        onClick={() => handleFilterChange(selectedFilter, filter)}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {filter === "today" && "今日"}
 | 
				
			||||||
 | 
					        {filter === "yesterday" && "昨日"}
 | 
				
			||||||
 | 
					        {filter === "currentMonth" && "本月"}
 | 
				
			||||||
 | 
					        {filter === "lastMonth" && "上個月"}
 | 
				
			||||||
 | 
					        {filter === "currentYear" && "今年"}
 | 
				
			||||||
 | 
					        {filter === "lastYear" && "去年"}
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
 | 
					    ));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 提取各項圖表數據
 | 
				
			||||||
 | 
					  const timestamps = historyData.map((item) => item.timestamp); //時間
 | 
				
			||||||
 | 
					  const tempData = historyData.map((item) => item.temp); //溫度
 | 
				
			||||||
 | 
					  const irrDayHourData = historyData.map((item) => item.irrDayHour); //累積日照
 | 
				
			||||||
 | 
					  const prData = historyData.map((item) => item.pr); //pr
 | 
				
			||||||
 | 
					  const kwhkwpData = historyData.map((item) => item.kwhkwp); //日均發電度數
 | 
				
			||||||
 | 
					  const kwhData = historyData.map((item) => item.kwh); //發電量
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const options = {
 | 
				
			||||||
 | 
					    chart: {
 | 
				
			||||||
 | 
					      type: "line",
 | 
				
			||||||
 | 
					      height: 500,
 | 
				
			||||||
 | 
					      stacked: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    stroke: {
 | 
				
			||||||
 | 
					      width: [0, 0, 0, 4, 4], // 對於 bar 是 0,對於 line 是 4
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    plotOptions: {
 | 
				
			||||||
 | 
					      bar: {
 | 
				
			||||||
 | 
					        columnWidth: "50%",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    colors: ["#008FFB", "#FEB019", "#FF4560", "#00E396", "#775DD0"],
 | 
				
			||||||
 | 
					    labels: timestamps,
 | 
				
			||||||
 | 
					    xaxis: {
 | 
				
			||||||
 | 
					      type: "category",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    yaxis: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        seriesName: "發電量(kWh)",
 | 
				
			||||||
 | 
					        axisTicks: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        axisBorder: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					          color: "#008FFB",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        labels: {
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            colors: "#008FFB",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          formatter: function (value) {
 | 
				
			||||||
 | 
					            return value.toFixed(2); // 格式化Y軸數值,移除多餘的0
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: {
 | 
				
			||||||
 | 
					          text: "kWh",
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            color: "#008FFB",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        seriesName: "日均發電度數",
 | 
				
			||||||
 | 
					        opposite: true,
 | 
				
			||||||
 | 
					        axisTicks: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        axisBorder: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					          color: "#FEB019",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        labels: {
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            colors: "#FEB019",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          formatter: function (value) {
 | 
				
			||||||
 | 
					            return value.toFixed(2); // 格式化Y軸數值,移除多餘的0
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: {
 | 
				
			||||||
 | 
					          text: "kWh/kWp",
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            color: "#FEB019",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        seriesName: "PR(%)",
 | 
				
			||||||
 | 
					        opposite: true,
 | 
				
			||||||
 | 
					        axisTicks: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        axisBorder: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					          color: "#FF4560",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        labels: {
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            colors: "#FF4560",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          formatter: function (value) {
 | 
				
			||||||
 | 
					            return value.toFixed(2); // 格式化Y軸數值,移除多餘的0
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: {
 | 
				
			||||||
 | 
					          text: "PR(%)",
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            color: "#FF4560",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        seriesName: "累積日照量(Wh/m2)",
 | 
				
			||||||
 | 
					        opposite: true,
 | 
				
			||||||
 | 
					        axisTicks: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        axisBorder: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					          color: "#00E396",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        labels: {
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            colors: "#00E396",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          formatter: function (value) {
 | 
				
			||||||
 | 
					            return value.toFixed(2); // 格式化Y軸數值,移除多餘的0
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: {
 | 
				
			||||||
 | 
					          text: "Wh/m2",
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            color: "#00E396",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        seriesName: "溫度(℃)",
 | 
				
			||||||
 | 
					        opposite: true,
 | 
				
			||||||
 | 
					        axisTicks: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        axisBorder: {
 | 
				
			||||||
 | 
					          show: true,
 | 
				
			||||||
 | 
					          color: "#775DD0",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        labels: {
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            colors: "#775DD0",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          formatter: function (value) {
 | 
				
			||||||
 | 
					            return value.toFixed(2); // 格式化Y軸數值,移除多餘的0
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: {
 | 
				
			||||||
 | 
					          text: "℃",
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            color: "#775DD0",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    tooltip: {
 | 
				
			||||||
 | 
					      shared: true,
 | 
				
			||||||
 | 
					      intersect: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    title: {
 | 
				
			||||||
 | 
					      text: "發電量及累積日照量",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    theme: {
 | 
				
			||||||
 | 
					      mode: "dark",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const series = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: "發電量(kWh)",
 | 
				
			||||||
 | 
					      type: "column",
 | 
				
			||||||
 | 
					      data: kwhData,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: "日均發電度數",
 | 
				
			||||||
 | 
					      type: "column",
 | 
				
			||||||
 | 
					      data: kwhkwpData,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: "PR(%)",
 | 
				
			||||||
 | 
					      type: "column",
 | 
				
			||||||
 | 
					      data: prData,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: "累積日照量(Wh/m2)",
 | 
				
			||||||
 | 
					      type: "line",
 | 
				
			||||||
 | 
					      data: irrDayHourData,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: "溫度(℃)",
 | 
				
			||||||
 | 
					      type: "line",
 | 
				
			||||||
 | 
					      data: tempData,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <section className="p-8">
 | 
				
			||||||
 | 
					      <div className="flex items-center mb-8">
 | 
				
			||||||
 | 
					        <div className="inline-flex shadow-sm me-8" role="group">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 rounded-l ${
 | 
				
			||||||
 | 
					              selectedFilter === "day" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleFilterChange("day", "today")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            日
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 ${
 | 
				
			||||||
 | 
					              selectedFilter === "month" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleFilterChange("month", "currentMonth")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            月
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 ${
 | 
				
			||||||
 | 
					              selectedFilter === "year" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleFilterChange("year", "currentYear")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            年
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 rounded-r ${
 | 
				
			||||||
 | 
					              selectedFilter === "historical" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => setSelectedFilter("historical")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            歷年
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {selectedFilter !== "historical" && (
 | 
				
			||||||
 | 
					          <>
 | 
				
			||||||
 | 
					            <div className="inline-flex shadow-sm me-8" role="group">
 | 
				
			||||||
 | 
					              {renderButtons()}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <DatePicker
 | 
				
			||||||
 | 
					              selected={selectedDate}
 | 
				
			||||||
 | 
					              onChange={(date) => setSelectedDate(date)}
 | 
				
			||||||
 | 
					              dateFormat={
 | 
				
			||||||
 | 
					                selectedFilter === "month"
 | 
				
			||||||
 | 
					                  ? "yyyy/MM"
 | 
				
			||||||
 | 
					                  : selectedFilter === "year"
 | 
				
			||||||
 | 
					                  ? "yyyy"
 | 
				
			||||||
 | 
					                  : "yyyy/MM/dd"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              showMonthYearPicker={selectedFilter === "month"}
 | 
				
			||||||
 | 
					              showYearPicker={selectedFilter === "year"}
 | 
				
			||||||
 | 
					              locale={zhTW}
 | 
				
			||||||
 | 
					              className="border border-gray-300 rounded px-4 py-2 me-4"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					        <button className="text-white bg-sky-500 hover:bg-sky-600 rounded px-5 py-2">
 | 
				
			||||||
 | 
					          查詢
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="bg-gray-600  shadow-sm shadow-gray-500 p-3 mb-8">
 | 
				
			||||||
 | 
					        <table className="min-w-full ">
 | 
				
			||||||
 | 
					          <caption className="text-start text-xl p-4 text-white">總結</caption>
 | 
				
			||||||
 | 
					          <thead>
 | 
				
			||||||
 | 
					            <tr className="border-t border-b border-gray-400 text-white ">
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">時間</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">發電量(kWh)</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">日均發電度數</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">累積日照量(Wh/m2)</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">PR(%)</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">溫度(℃)</th>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					          </thead>
 | 
				
			||||||
 | 
					          <tbody>
 | 
				
			||||||
 | 
					            <tr className="text-white">
 | 
				
			||||||
 | 
					              <td className="px-4 py-3">2024-09-04</td>
 | 
				
			||||||
 | 
					              <td className="px-4 py-3">205.00</td>
 | 
				
			||||||
 | 
					              <td className="px-4 py-3">4.38</td>
 | 
				
			||||||
 | 
					              <td className="px-4 py-3">5,691.39</td>
 | 
				
			||||||
 | 
					              <td className="px-4 py-3">76.95</td>
 | 
				
			||||||
 | 
					              <td className="px-4 py-3">0.00</td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					          </tbody>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <Chart options={options} series={series} type="line" height={500} />
 | 
				
			||||||
 | 
					      <div className="bg-gray-600  shadow-sm shadow-gray-500 p-3 mt-6">
 | 
				
			||||||
 | 
					        <table className="min-w-full ">
 | 
				
			||||||
 | 
					          <caption className="text-start text-xl p-4 text-white">
 | 
				
			||||||
 | 
					            詳細資訊
 | 
				
			||||||
 | 
					          </caption>
 | 
				
			||||||
 | 
					          <thead>
 | 
				
			||||||
 | 
					            <tr className="border-t border-b border-gray-400 text-white ">
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">時間</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">發電量(kWh)</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">日均發電度數</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">累積日照量(Wh/m2)</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">PR(%)</th>
 | 
				
			||||||
 | 
					              <th className="px-4 py-3 text-start">溫度(℃)</th>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					          </thead>
 | 
				
			||||||
 | 
					          <tbody>
 | 
				
			||||||
 | 
					            {historyData.map((item, index) => (
 | 
				
			||||||
 | 
					              <tr key={index} className="border-t border-gray-400 text-white">
 | 
				
			||||||
 | 
					                <td className="px-4 py-3">{item.timestamp}</td>
 | 
				
			||||||
 | 
					                <td className="px-4 py-3">{item.kwh}</td>
 | 
				
			||||||
 | 
					                <td className="px-4 py-3">{item.solarhour}</td>
 | 
				
			||||||
 | 
					                <td className="px-4 py-3">{item.irradiance}</td>
 | 
				
			||||||
 | 
					                <td className="px-4 py-3">{item.pr}</td>
 | 
				
			||||||
 | 
					                <td className="px-4 py-3">{item.temp}</td>
 | 
				
			||||||
 | 
					              </tr>
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					          </tbody>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default HistoryData;
 | 
				
			||||||
@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import React, { forwardRef } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const IframeComponent = forwardRef(({ src, onLoad }, ref) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <iframe
 | 
				
			||||||
 | 
					      ref={ref}
 | 
				
			||||||
 | 
					      src={src}
 | 
				
			||||||
 | 
					      width="100%"
 | 
				
			||||||
 | 
					      height="800"
 | 
				
			||||||
 | 
					      className="border-0"
 | 
				
			||||||
 | 
					      title="Solar Management"
 | 
				
			||||||
 | 
					      onLoad={onLoad}
 | 
				
			||||||
 | 
					    ></iframe>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default IframeComponent;
 | 
				
			||||||
							
								
								
									
										234
									
								
								Frontend/ibms_solar/src/components/energy/InverterAnalysis.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								Frontend/ibms_solar/src/components/energy/InverterAnalysis.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,234 @@
 | 
				
			|||||||
 | 
					import React, { useState } from "react";
 | 
				
			||||||
 | 
					import Chart from "react-apexcharts";
 | 
				
			||||||
 | 
					import DatePicker from "react-datepicker";
 | 
				
			||||||
 | 
					import "react-datepicker/dist/react-datepicker.css";
 | 
				
			||||||
 | 
					import { zhTW } from "date-fns/locale";
 | 
				
			||||||
 | 
					import inverterData from "@/mock/inverterData.json";
 | 
				
			||||||
 | 
					import yearData from "@/mock/yearData.json";
 | 
				
			||||||
 | 
					import quarterData from "@/mock/quarterData";
 | 
				
			||||||
 | 
					import monthData from "@/mock/monthData";
 | 
				
			||||||
 | 
					import todayData from "@/mock/todayData";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const InverterAnalysis = () => {
 | 
				
			||||||
 | 
					  const [date, setDate] = useState(new Date());
 | 
				
			||||||
 | 
					  const [activeButton, setActiveButton] = useState(null);
 | 
				
			||||||
 | 
					  const [quarter, setQuarter] = useState("1"); // 用於季度選擇
 | 
				
			||||||
 | 
					  const [barData, setBarData] = useState(todayData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleDateChange = (date) => {
 | 
				
			||||||
 | 
					    setDate(date);
 | 
				
			||||||
 | 
					    setActiveButton(null);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleButtonClick = (buttonType) => {
 | 
				
			||||||
 | 
					    if (buttonType === "today") {
 | 
				
			||||||
 | 
					      setDate(new Date());
 | 
				
			||||||
 | 
					      setBarData(todayData);
 | 
				
			||||||
 | 
					    } else if (buttonType === "yesterday") {
 | 
				
			||||||
 | 
					      setDate(new Date(Date.now() - 86400000));
 | 
				
			||||||
 | 
					    } else if (buttonType === "month") {
 | 
				
			||||||
 | 
					      setDate(new Date(Date.now() - 86400000));
 | 
				
			||||||
 | 
					      setBarData(monthData);
 | 
				
			||||||
 | 
					    } else if (buttonType === "quarter") {
 | 
				
			||||||
 | 
					      setDate(new Date(Date.now() - 86400000));
 | 
				
			||||||
 | 
					      setBarData(quarterData);
 | 
				
			||||||
 | 
					    } else if (buttonType === "year") {
 | 
				
			||||||
 | 
					      setDate(new Date(Date.now() - 86400000));
 | 
				
			||||||
 | 
					      setBarData(yearData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    setActiveButton(buttonType); // 设置激活的按钮
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 生成 x 軸的分類標籤
 | 
				
			||||||
 | 
					  const xCategories = inverterData.xAxisOnTime;
 | 
				
			||||||
 | 
					  // 生成系列數據
 | 
				
			||||||
 | 
					  const series = Object.keys(inverterData.series).map((inverterId) => {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      name: inverterId,
 | 
				
			||||||
 | 
					      data: inverterData.series[inverterId].map((point) => point.value),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  const options = {
 | 
				
			||||||
 | 
					    chart: {
 | 
				
			||||||
 | 
					      type: "heatmap",
 | 
				
			||||||
 | 
					      height: 500,
 | 
				
			||||||
 | 
					      background: "#3f3f46",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    plotOptions: {
 | 
				
			||||||
 | 
					      heatmap: {
 | 
				
			||||||
 | 
					        useFillColorAsStroke: true,
 | 
				
			||||||
 | 
					        colorScale: {
 | 
				
			||||||
 | 
					          ranges: [
 | 
				
			||||||
 | 
					            { from: 0, to: 0.124999, color: "#0000ff", name: "Low" }, // Blue
 | 
				
			||||||
 | 
					            { from: 0.125, to: 0.249999, color: "#5541b5", name: "Moderate" }, // Purple
 | 
				
			||||||
 | 
					            { from: 0.25, to: 0.374999, color: "#ab836b", name: "High" }, // Brown
 | 
				
			||||||
 | 
					            { from: 0.375, to: 0.499999, color: "#dba841", name: "Very High" }, // Yellow
 | 
				
			||||||
 | 
					            { from: 0.5, to: 0.624999, color: "#eda42f", name: "Extreme" }, // Orange
 | 
				
			||||||
 | 
					            { from: 0.625, to: 0.749999, color: "#f4621c", name: "Severe" }, // Dark Orange
 | 
				
			||||||
 | 
					            { from: 0.75, to: 0.874999, color: "#f65017", name: "Critical" }, // Red-Orange
 | 
				
			||||||
 | 
					            { from: 0.875, to: 1, color: "#fb2109", name: "Danger" }, // Red
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    dataLabels: {
 | 
				
			||||||
 | 
					      enabled: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    xaxis: {
 | 
				
			||||||
 | 
					      type: "category",
 | 
				
			||||||
 | 
					      categories: xCategories,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    title: {
 | 
				
			||||||
 | 
					      text: "各逆變器當日均發電度數",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    theme: {
 | 
				
			||||||
 | 
					      mode: "dark",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const barseries = barData
 | 
				
			||||||
 | 
					  ? Object.keys(barData.datasets).map((Id) => {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        name: Id,
 | 
				
			||||||
 | 
					        data: barData.datasets[Id],
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  : [];
 | 
				
			||||||
 | 
					  const baroptions = {
 | 
				
			||||||
 | 
					    chart: {
 | 
				
			||||||
 | 
					      type: "bar",
 | 
				
			||||||
 | 
					      height: 500,
 | 
				
			||||||
 | 
					      background: "#3f3f46",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    xaxis: {
 | 
				
			||||||
 | 
					      type: "category",
 | 
				
			||||||
 | 
					      categories: barData ? barData.labels : [],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    title: {
 | 
				
			||||||
 | 
					      text: "發電量",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    theme: {
 | 
				
			||||||
 | 
					      mode: "dark",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <section className="p-8">
 | 
				
			||||||
 | 
					      <div className="flex items-center mb-8">
 | 
				
			||||||
 | 
					        <div class="inline-flex shadow-sm me-8" role="group">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 rounded-l ${
 | 
				
			||||||
 | 
					              activeButton === "today" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleButtonClick("today")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            今天
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 rounded-r ${
 | 
				
			||||||
 | 
					              activeButton === "yesterday" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleButtonClick("yesterday")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            昨天
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <DatePicker
 | 
				
			||||||
 | 
					          selected={date}
 | 
				
			||||||
 | 
					          onChange={handleDateChange}
 | 
				
			||||||
 | 
					          dateFormat="yyyy/MM/dd"
 | 
				
			||||||
 | 
					          locale={zhTW}
 | 
				
			||||||
 | 
					          className="border border-gray-300 rounded px-4 py-2 me-4"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <button className="text-white bg-sky-500 hover:bg-sky-600 rounded px-5 py-2">
 | 
				
			||||||
 | 
					          查詢
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div id="chart">
 | 
				
			||||||
 | 
					        <Chart options={options} series={series} type="heatmap" height={500} />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="flex items-center mb-8 mt-16">
 | 
				
			||||||
 | 
					        <div class="inline-flex shadow-sm me-8" role="group">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 rounded-l ${
 | 
				
			||||||
 | 
					              activeButton === "today" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleButtonClick("today")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            日
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 ${
 | 
				
			||||||
 | 
					              activeButton === "month" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleButtonClick("month")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            月
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 ${
 | 
				
			||||||
 | 
					              activeButton === "quarter" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleButtonClick("quarter")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            季
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            className={`text-white px-5 py-2 hover:bg-gray-500 rounded-r ${
 | 
				
			||||||
 | 
					              activeButton === "year" ? "bg-sky-500" : "bg-gray-400"
 | 
				
			||||||
 | 
					            }`}
 | 
				
			||||||
 | 
					            onClick={() => handleButtonClick("year")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            年
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <DatePicker
 | 
				
			||||||
 | 
					          selected={date}
 | 
				
			||||||
 | 
					          onChange={handleDateChange}
 | 
				
			||||||
 | 
					          dateFormat={
 | 
				
			||||||
 | 
					            activeButton === "month"
 | 
				
			||||||
 | 
					              ? "yyyy/MM"
 | 
				
			||||||
 | 
					              : activeButton === "year"
 | 
				
			||||||
 | 
					              ? "yyyy"
 | 
				
			||||||
 | 
					              : activeButton === "quarter"
 | 
				
			||||||
 | 
					              ? "yyyy"
 | 
				
			||||||
 | 
					              : "yyyy/MM/dd"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          showMonthYearPicker={activeButton === "month"}
 | 
				
			||||||
 | 
					          showYearPicker={activeButton === "year" || activeButton === "quarter"}
 | 
				
			||||||
 | 
					          className="border border-gray-300 rounded px-4 py-2 me-4"
 | 
				
			||||||
 | 
					          locale={zhTW}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        {activeButton === "quarter" && (
 | 
				
			||||||
 | 
					          <select
 | 
				
			||||||
 | 
					            className="border border-gray-300 rounded px-4 py-2 me-4"
 | 
				
			||||||
 | 
					            value={quarter}
 | 
				
			||||||
 | 
					            onChange={(e) => {
 | 
				
			||||||
 | 
					              setQuarter(e.target.value);
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <option value="1">1-3月</option>
 | 
				
			||||||
 | 
					            <option value="2">4-6月</option>
 | 
				
			||||||
 | 
					            <option value="3">7-9月</option>
 | 
				
			||||||
 | 
					            <option value="4">10-12月</option>
 | 
				
			||||||
 | 
					          </select>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <button className="text-white bg-sky-500 hover:bg-sky-600 rounded px-5 py-2">
 | 
				
			||||||
 | 
					          查詢
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div id="chart">
 | 
				
			||||||
 | 
					        <Chart options={baroptions} series={barseries} type="bar" height={500} />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default InverterAnalysis;
 | 
				
			||||||
							
								
								
									
										7
									
								
								Frontend/ibms_solar/src/components/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Frontend/ibms_solar/src/components/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					import Navbar from "./Navbar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import IframeComponent from "./energy/IframeComponent";
 | 
				
			||||||
 | 
					import HistoryData from "./energy/HistoryData";
 | 
				
			||||||
 | 
					import InverterAnalysis from "./energy/InverterAnalysis";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Navbar, IframeComponent, HistoryData, InverterAnalysis };
 | 
				
			||||||
							
								
								
									
										4
									
								
								Frontend/ibms_solar/src/constant/api_app.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Frontend/ibms_solar/src/constant/api_app.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					const BASEURL = import.meta.env.VITE_API_BASEURL;
 | 
				
			||||||
 | 
					export const POST_LOGIN = `${BASEURL}/api/Login/`;
 | 
				
			||||||
 | 
					export const GET_AUTHPAGE_API = `${BASEURL}/api/GetUsrFroList`;
 | 
				
			||||||
 | 
					export const GET_SUBAUTHPAGE_API = `${BASEURL}/api/Device/GetBuild`;
 | 
				
			||||||
							
								
								
									
										30
									
								
								Frontend/ibms_solar/src/constant/authPage.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Frontend/ibms_solar/src/constant/authPage.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import { FaTv, FaChartPie, FaChartArea, FaChartLine, FaBell, FaServer, FaImage, FaUser } from "react-icons/fa";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AUTHPAGES = (authCode) => {
 | 
				
			||||||
 | 
					  switch (authCode) {
 | 
				
			||||||
 | 
					    case "PF1":
 | 
				
			||||||
 | 
					      return <FaTv />;
 | 
				
			||||||
 | 
					    case "PF2":
 | 
				
			||||||
 | 
					      return <FaChartPie />;
 | 
				
			||||||
 | 
					    case "PF3":
 | 
				
			||||||
 | 
					      return <FaChartArea />;
 | 
				
			||||||
 | 
					    case "PF4":
 | 
				
			||||||
 | 
					      return <FaChartLine />;
 | 
				
			||||||
 | 
					    case "PF5":
 | 
				
			||||||
 | 
					      return <FaBell />;
 | 
				
			||||||
 | 
					    case "PF6":
 | 
				
			||||||
 | 
					      return <FaServer />;
 | 
				
			||||||
 | 
					    case "PF7":
 | 
				
			||||||
 | 
					      return <FaImage />;
 | 
				
			||||||
 | 
					    case "PF8":
 | 
				
			||||||
 | 
					      return <FaUser />;
 | 
				
			||||||
 | 
					    case "PF9":
 | 
				
			||||||
 | 
					      return <FaUser />;
 | 
				
			||||||
 | 
					    case "PF10":
 | 
				
			||||||
 | 
					      return <FaChartArea />;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AUTHPAGES;
 | 
				
			||||||
							
								
								
									
										5
									
								
								Frontend/ibms_solar/src/constant/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Frontend/ibms_solar/src/constant/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import { GET_AUTHPAGE_API, GET_SUBAUTHPAGE_API } from "./api_app";
 | 
				
			||||||
 | 
					import AUTHPAGES from "./authPage";
 | 
				
			||||||
 | 
					import EnergyTABS from "./tabList";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { GET_AUTHPAGE_API, GET_SUBAUTHPAGE_API, AUTHPAGES, EnergyTABS };
 | 
				
			||||||
							
								
								
									
										54
									
								
								Frontend/ibms_solar/src/constant/tabList.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Frontend/ibms_solar/src/constant/tabList.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  FaFileMedicalAlt,
 | 
				
			||||||
 | 
					  FaInfoCircle,
 | 
				
			||||||
 | 
					  FaRegListAlt,
 | 
				
			||||||
 | 
					  FaChartLine,
 | 
				
			||||||
 | 
					  FaHistory,
 | 
				
			||||||
 | 
					  FaExclamationTriangle,
 | 
				
			||||||
 | 
					} from "react-icons/fa";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  IframeComponent,
 | 
				
			||||||
 | 
					  InverterAnalysis,
 | 
				
			||||||
 | 
					  HistoryData,
 | 
				
			||||||
 | 
					} from "../components";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const EnergyTABS = (siteId) => [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: "realtime",
 | 
				
			||||||
 | 
					    icon: <FaFileMedicalAlt />,
 | 
				
			||||||
 | 
					    title: "即時資訊",
 | 
				
			||||||
 | 
					    content: <IframeComponent src={`/ord?file:^Solar/${siteId}_Realtime.px|view:?fullScreen=true`} />,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: "basicInfo",
 | 
				
			||||||
 | 
					    icon: <FaInfoCircle />,
 | 
				
			||||||
 | 
					    title: "基本資料",
 | 
				
			||||||
 | 
					    content: <IframeComponent  src={`/ord?file:^Solar/${siteId}_Info.px|view:?fullScreen=true`} />,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: "monitor",
 | 
				
			||||||
 | 
					    icon: <FaRegListAlt />,
 | 
				
			||||||
 | 
					    title: "逆變器監控",
 | 
				
			||||||
 | 
					    content: <IframeComponent src={`/ord?file:^Solar/${siteId}_Inverter.px|view:?fullScreen=true`} />,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: "analysis",
 | 
				
			||||||
 | 
					    icon: <FaChartLine />,
 | 
				
			||||||
 | 
					    title: "逆變器分析",
 | 
				
			||||||
 | 
					    content: <InverterAnalysis />,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: "history",
 | 
				
			||||||
 | 
					    icon: <FaHistory />,
 | 
				
			||||||
 | 
					    title: "歷史資料",
 | 
				
			||||||
 | 
					    content: <HistoryData />,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: "abnormal",
 | 
				
			||||||
 | 
					    icon: <FaExclamationTriangle />,
 | 
				
			||||||
 | 
					    title: "異常紀錄",
 | 
				
			||||||
 | 
					    content: <div className="text-white p-5 text-md">異常紀錄</div>,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default EnergyTABS;
 | 
				
			||||||
							
								
								
									
										17
									
								
								Frontend/ibms_solar/src/context/SiteContext.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Frontend/ibms_solar/src/context/SiteContext.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import React, { createContext, useState, useContext } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const SiteContext = createContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const SiteProvider = ({ children }) => {
 | 
				
			||||||
 | 
					  const [siteId, setSiteId] = useState(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SiteContext.Provider value={{ siteId, setSiteId }}>
 | 
				
			||||||
 | 
					      {children}
 | 
				
			||||||
 | 
					    </SiteContext.Provider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useSite = () => {
 | 
				
			||||||
 | 
					  return useContext(SiteContext);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										3
									
								
								Frontend/ibms_solar/src/context/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Frontend/ibms_solar/src/context/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					import { SiteProvider, useSite } from './SiteContext.jsx';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { SiteProvider, useSite } ;
 | 
				
			||||||
							
								
								
									
										8
									
								
								Frontend/ibms_solar/src/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Frontend/ibms_solar/src/index.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					@tailwind base;
 | 
				
			||||||
 | 
					@tailwind components;
 | 
				
			||||||
 | 
					@tailwind utilities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* {
 | 
				
			||||||
 | 
					    font-family: 'Inter', sans-serif;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										45
									
								
								Frontend/ibms_solar/src/main.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Frontend/ibms_solar/src/main.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					import { StrictMode } from "react";
 | 
				
			||||||
 | 
					import { createRoot } from "react-dom/client";
 | 
				
			||||||
 | 
					import App from "@/App.jsx";
 | 
				
			||||||
 | 
					import axios from "axios";
 | 
				
			||||||
 | 
					import "@/index.css";
 | 
				
			||||||
 | 
					import { getCookie } from "@/utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 添加請求攔截器
 | 
				
			||||||
 | 
					axios.interceptors.request.use(
 | 
				
			||||||
 | 
					  function (config) {
 | 
				
			||||||
 | 
					    // 在發送請求之前做點什麼
 | 
				
			||||||
 | 
					    const token = getCookie("JWT-Authorization");
 | 
				
			||||||
 | 
					    if (token) {
 | 
				
			||||||
 | 
					      config.headers.Authorization = `Bearer ${token}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return config;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  function (error) {
 | 
				
			||||||
 | 
					    // 對請求錯誤做點什麼
 | 
				
			||||||
 | 
					    return Promise.reject(error);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 添加響應攔截器
 | 
				
			||||||
 | 
					axios.interceptors.response.use(
 | 
				
			||||||
 | 
					  function (response) {
 | 
				
			||||||
 | 
					    // 任何 2xx 范圍內的狀態碼會觸發該函數
 | 
				
			||||||
 | 
					    const { status, data } = response;
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      status,
 | 
				
			||||||
 | 
					      data,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  function (error) {
 | 
				
			||||||
 | 
					    // 任何超出 2xx 范圍的狀態碼都會觸發此函數
 | 
				
			||||||
 | 
					    return Promise.reject(error);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 創建應用並掛載到 DOM
 | 
				
			||||||
 | 
					createRoot(document.getElementById("root")).render(
 | 
				
			||||||
 | 
					  <StrictMode>
 | 
				
			||||||
 | 
					    <App />
 | 
				
			||||||
 | 
					  </StrictMode>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
							
								
								
									
										242
									
								
								Frontend/ibms_solar/src/mock/historyData.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								Frontend/ibms_solar/src/mock/historyData.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,242 @@
 | 
				
			|||||||
 | 
					[
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "02 AM",
 | 
				
			||||||
 | 
					        "kwh": 0,
 | 
				
			||||||
 | 
					        "solarhour": 0,
 | 
				
			||||||
 | 
					        "irradiance": 0,
 | 
				
			||||||
 | 
					        "pr": 0,
 | 
				
			||||||
 | 
					        "avgPR": 0,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 0,
 | 
				
			||||||
 | 
					        "irrDay": 0,
 | 
				
			||||||
 | 
					        "irrDayHour": 0,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "03 AM",
 | 
				
			||||||
 | 
					        "kwh": 0,
 | 
				
			||||||
 | 
					        "solarhour": 0,
 | 
				
			||||||
 | 
					        "irradiance": 0,
 | 
				
			||||||
 | 
					        "pr": 0,
 | 
				
			||||||
 | 
					        "avgPR": 0,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 0,
 | 
				
			||||||
 | 
					        "irrDay": 0,
 | 
				
			||||||
 | 
					        "irrDayHour": 0,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "04 AM",
 | 
				
			||||||
 | 
					        "kwh": 0,
 | 
				
			||||||
 | 
					        "solarhour": 0,
 | 
				
			||||||
 | 
					        "irradiance": 0,
 | 
				
			||||||
 | 
					        "pr": 0,
 | 
				
			||||||
 | 
					        "avgPR": 0,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 0,
 | 
				
			||||||
 | 
					        "irrDay": 0,
 | 
				
			||||||
 | 
					        "irrDayHour": 0,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "05 AM",
 | 
				
			||||||
 | 
					        "kwh": 0,
 | 
				
			||||||
 | 
					        "solarhour": 0,
 | 
				
			||||||
 | 
					        "irradiance": 27.86,
 | 
				
			||||||
 | 
					        "pr": 0,
 | 
				
			||||||
 | 
					        "avgPR": 0,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 0,
 | 
				
			||||||
 | 
					        "irrDay": 0,
 | 
				
			||||||
 | 
					        "irrDayHour": 0,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "06 AM",
 | 
				
			||||||
 | 
					        "kwh": 3,
 | 
				
			||||||
 | 
					        "solarhour": 1.9166666269302368,
 | 
				
			||||||
 | 
					        "irradiance": 91.07,
 | 
				
			||||||
 | 
					        "pr": 54.90191650390625,
 | 
				
			||||||
 | 
					        "avgPR": 54.90191650390625,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 0.06410256773233414,
 | 
				
			||||||
 | 
					        "irrDay": 116.26,
 | 
				
			||||||
 | 
					        "irrDayHour": 116.26,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "07 AM",
 | 
				
			||||||
 | 
					        "kwh": 10,
 | 
				
			||||||
 | 
					        "solarhour": 2.9166667461395264,
 | 
				
			||||||
 | 
					        "irradiance": 268.35,
 | 
				
			||||||
 | 
					        "pr": 72.0918197631836,
 | 
				
			||||||
 | 
					        "avgPR": 72.0918197631836,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 0.2777777910232544,
 | 
				
			||||||
 | 
					        "irrDay": 384.3,
 | 
				
			||||||
 | 
					        "irrDayHour": 268.04,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "08 AM",
 | 
				
			||||||
 | 
					        "kwh": 18,
 | 
				
			||||||
 | 
					        "solarhour": 3.9166667461395264,
 | 
				
			||||||
 | 
					        "irradiance": 469.84,
 | 
				
			||||||
 | 
					        "pr": 77.43690490722656,
 | 
				
			||||||
 | 
					        "avgPR": 77.43690490722656,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 0.6623931527137756,
 | 
				
			||||||
 | 
					        "irrDay": 853.82,
 | 
				
			||||||
 | 
					        "irrDayHour": 469.52,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "09 AM",
 | 
				
			||||||
 | 
					        "kwh": 26,
 | 
				
			||||||
 | 
					        "solarhour": 4.916666507720947,
 | 
				
			||||||
 | 
					        "irradiance": 645.26,
 | 
				
			||||||
 | 
					        "pr": 81.175537109375,
 | 
				
			||||||
 | 
					        "avgPR": 81.175537109375,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 1.2179486751556396,
 | 
				
			||||||
 | 
					        "irrDay": 1499.2,
 | 
				
			||||||
 | 
					        "irrDayHour": 645.38,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "10 AM",
 | 
				
			||||||
 | 
					        "kwh": 27,
 | 
				
			||||||
 | 
					        "solarhour": 5.916666507720947,
 | 
				
			||||||
 | 
					        "irradiance": 710.99,
 | 
				
			||||||
 | 
					        "pr": 81.14289093017578,
 | 
				
			||||||
 | 
					        "avgPR": 81.14289093017578,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 1.7948718070983887,
 | 
				
			||||||
 | 
					        "irrDay": 2210.18,
 | 
				
			||||||
 | 
					        "irrDayHour": 710.98,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "11 AM",
 | 
				
			||||||
 | 
					        "kwh": 21,
 | 
				
			||||||
 | 
					        "solarhour": 6.916666507720947,
 | 
				
			||||||
 | 
					        "irradiance": 593.44,
 | 
				
			||||||
 | 
					        "pr": 79.9531478881836,
 | 
				
			||||||
 | 
					        "avgPR": 79.9531478881836,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 2.2435896396636963,
 | 
				
			||||||
 | 
					        "irrDay": 2806.13,
 | 
				
			||||||
 | 
					        "irrDayHour": 595.95,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "12 PM",
 | 
				
			||||||
 | 
					        "kwh": 30,
 | 
				
			||||||
 | 
					        "solarhour": 7.916666507720947,
 | 
				
			||||||
 | 
					        "irradiance": 866.35,
 | 
				
			||||||
 | 
					        "pr": 78.54755401611328,
 | 
				
			||||||
 | 
					        "avgPR": 78.54755401611328,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 2.884615421295166,
 | 
				
			||||||
 | 
					        "irrDay": 3670.85,
 | 
				
			||||||
 | 
					        "irrDayHour": 864.72,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "13 PM",
 | 
				
			||||||
 | 
					        "kwh": 26,
 | 
				
			||||||
 | 
					        "solarhour": 8.916666984558105,
 | 
				
			||||||
 | 
					        "irradiance": 738.43,
 | 
				
			||||||
 | 
					        "pr": 77.9903793334961,
 | 
				
			||||||
 | 
					        "avgPR": 77.9903793334961,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 3.440171003341675,
 | 
				
			||||||
 | 
					        "irrDay": 4408.71,
 | 
				
			||||||
 | 
					        "irrDayHour": 737.86,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "14 PM",
 | 
				
			||||||
 | 
					        "kwh": 24,
 | 
				
			||||||
 | 
					        "solarhour": 9.916666984558105,
 | 
				
			||||||
 | 
					        "irradiance": 736.83,
 | 
				
			||||||
 | 
					        "pr": 76.79364776611328,
 | 
				
			||||||
 | 
					        "avgPR": 76.79364776611328,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 3.952991485595703,
 | 
				
			||||||
 | 
					        "irrDay": 5145.73,
 | 
				
			||||||
 | 
					        "irrDayHour": 737.02,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "15 PM",
 | 
				
			||||||
 | 
					        "kwh": 20,
 | 
				
			||||||
 | 
					        "solarhour": 10.916666984558105,
 | 
				
			||||||
 | 
					        "irradiance": 545.29,
 | 
				
			||||||
 | 
					        "pr": 76.94789123535156,
 | 
				
			||||||
 | 
					        "avgPR": 76.94789123535156,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 4.38034200668335,
 | 
				
			||||||
 | 
					        "irrDay": 5691.39,
 | 
				
			||||||
 | 
					        "irrDayHour": 545.66,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "timestamp": "16 PM",
 | 
				
			||||||
 | 
					        "kwh": 10,
 | 
				
			||||||
 | 
					        "solarhour": 11.916666984558105,
 | 
				
			||||||
 | 
					        "irradiance": 0,
 | 
				
			||||||
 | 
					        "pr": 76.3684310913086,
 | 
				
			||||||
 | 
					        "avgPR": 76.3684310913086,
 | 
				
			||||||
 | 
					        "temp": 0,
 | 
				
			||||||
 | 
					        "diffSOLARHOUR": 0,
 | 
				
			||||||
 | 
					        "totaltime": "2024-09-04 ",
 | 
				
			||||||
 | 
					        "kwhkwp": 4.594017028808594,
 | 
				
			||||||
 | 
					        "irrDay": 0,
 | 
				
			||||||
 | 
					        "irrDayHour": 0,
 | 
				
			||||||
 | 
					        "generatingCapacity": 0,
 | 
				
			||||||
 | 
					        "days": 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										1165
									
								
								Frontend/ibms_solar/src/mock/inverterData.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1165
									
								
								Frontend/ibms_solar/src/mock/inverterData.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										7
									
								
								Frontend/ibms_solar/src/mock/monthData.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Frontend/ibms_solar/src/mock/monthData.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "labels": ["2024-09-01", "2024-09-02", "2024-09-03"],
 | 
				
			||||||
 | 
					  "datasets": {
 | 
				
			||||||
 | 
					    "031010004010001": [179, 307, 154],
 | 
				
			||||||
 | 
					    "031010004010002": [95, 152, 78]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								Frontend/ibms_solar/src/mock/quarterData.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Frontend/ibms_solar/src/mock/quarterData.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "labels": ["2024-01", "2024-02", "2024-03"],
 | 
				
			||||||
 | 
					  "datasets": {
 | 
				
			||||||
 | 
					    "031010004010001": [2461, 2404, 2955],
 | 
				
			||||||
 | 
					    "031010004010002": [1248, 1227, 1504]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								Frontend/ibms_solar/src/mock/todayData.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Frontend/ibms_solar/src/mock/todayData.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "labels": [
 | 
				
			||||||
 | 
					      "02 AM", "03 AM", "04 AM", "05 AM", "06 AM", 
 | 
				
			||||||
 | 
					      "07 AM", "08 AM", "09 AM", "10 AM", "11 AM"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "datasets": {
 | 
				
			||||||
 | 
					      "031010004010001": [0, 0, 0, 0, 2, 7, 12, 17, 18, 14],
 | 
				
			||||||
 | 
					      "031010004010002": [0, 0, 0, 0, 1, 3, 6, 9, 9, 7]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
							
								
								
									
										11
									
								
								Frontend/ibms_solar/src/mock/yearData.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Frontend/ibms_solar/src/mock/yearData.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "labels": [
 | 
				
			||||||
 | 
					      "2024-01", "2024-02", "2024-03", "2024-04", 
 | 
				
			||||||
 | 
					      "2024-05", "2024-06", "2024-07", "2024-08", "2024-09"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "datasets": {
 | 
				
			||||||
 | 
					      "031010004010001": [2461, 2404, 2955, 2925, 3733, 3887, 5109, 5402, 640],
 | 
				
			||||||
 | 
					      "031010004010002": [1248, 1227, 1504, 1487, 1896, 1983, 2595, 2742, 325]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
							
								
								
									
										68
									
								
								Frontend/ibms_solar/src/page/Energy.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Frontend/ibms_solar/src/page/Energy.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					import React, { useEffect, useState, useRef } from "react";
 | 
				
			||||||
 | 
					import { useNavigate } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useSite } from "@/context";
 | 
				
			||||||
 | 
					import { EnergyTABS } from "@/constant";
 | 
				
			||||||
 | 
					import { FaCheckCircle, FaCloudSunRain } from "react-icons/fa";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Energy = () => {
 | 
				
			||||||
 | 
					  const { siteId, setSiteId } = useSite();
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("realtime");
 | 
				
			||||||
 | 
					  const tabs = EnergyTABS(siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const goback = () => {
 | 
				
			||||||
 | 
					    setSiteId(null);
 | 
				
			||||||
 | 
					    navigate("/");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <section className="">
 | 
				
			||||||
 | 
					      <div className="flex items-center justify-between  px-10 mb-4">
 | 
				
			||||||
 | 
					        <div className="flex items-center">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            className="text-white bg-emerald-500 shadow-md shadow-emerald-500/50 rounded  px-5 py-2 me-2"
 | 
				
			||||||
 | 
					            onClick={goback}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            上一頁
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <FaCheckCircle className="text-teal-400 text-xl mx-2" />
 | 
				
			||||||
 | 
					          <span className="text-white text-xl ">{siteId}</span>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className="flex items-center">
 | 
				
			||||||
 | 
					          <FaCloudSunRain className="text-white text-4xl me-2"/>
 | 
				
			||||||
 | 
					          <span className="text-white text-md">
 | 
				
			||||||
 | 
					            0°C
 | 
				
			||||||
 | 
					            <br />
 | 
				
			||||||
 | 
					            降雨機率: 30%
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="px-6 mt-6">
 | 
				
			||||||
 | 
					        <div className="border-b border-[#ffffff26] ">
 | 
				
			||||||
 | 
					          <ul className="flex flex-wrap text-sm font-medium text-center text-gray-500 dark:text-gray-400">
 | 
				
			||||||
 | 
					            {tabs.map((tab) => (
 | 
				
			||||||
 | 
					              <li className="me-2" key={tab.id}>
 | 
				
			||||||
 | 
					                <button
 | 
				
			||||||
 | 
					                  onClick={() => setActiveTab(tab.id)}
 | 
				
			||||||
 | 
					                  className={`inline-flex items-center justify-center px-4 py-2 ${
 | 
				
			||||||
 | 
					                    activeTab === tab.id
 | 
				
			||||||
 | 
					                      ? "text-gray-200 border-[#ffffff26] border border-b-0"
 | 
				
			||||||
 | 
					                      : "border-transparent hover:text-gray-200 hover:border-[#ffffff26]"
 | 
				
			||||||
 | 
					                  } rounded-t-sm`}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  {tab.icon}
 | 
				
			||||||
 | 
					                  <span className="ms-2">{tab.title}</span>
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					          </ul>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className="border border-[#ffffff26] min-h-[100vh]">
 | 
				
			||||||
 | 
					          {tabs.find((tab) => tab.id === activeTab)?.content}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Energy;
 | 
				
			||||||
							
								
								
									
										46
									
								
								Frontend/ibms_solar/src/page/Home.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Frontend/ibms_solar/src/page/Home.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					import React, { useRef } from "react";
 | 
				
			||||||
 | 
					import { useNavigate } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useSite } from "@/context";
 | 
				
			||||||
 | 
					import { IframeComponent } from "@/components";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Home = () => {
 | 
				
			||||||
 | 
					  const iframeRef = useRef(null);
 | 
				
			||||||
 | 
					  const { setSiteId } = useSite();
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 處理加載後的邏輯
 | 
				
			||||||
 | 
					  const handleIframeLoad = () => {
 | 
				
			||||||
 | 
					    const iframe = iframeRef.current;
 | 
				
			||||||
 | 
					    const currentUrl = iframe.contentWindow.location.href;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (currentUrl.includes("solarEnergyItem")) {
 | 
				
			||||||
 | 
					      const urlParams = new URLSearchParams(currentUrl.split("?")[1]);
 | 
				
			||||||
 | 
					      const id = urlParams.get("siteId");
 | 
				
			||||||
 | 
					      if (id) {
 | 
				
			||||||
 | 
					        setSiteId(id);
 | 
				
			||||||
 | 
					        navigate("/energy");
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        console.log("找不到 siteId 参数");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      console.log("沒有solarEnergyItem");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <section>
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <h1 className="font-light text-[#a5abb1] text-[26px] ms-12 mb-4">
 | 
				
			||||||
 | 
					          太陽能管理
 | 
				
			||||||
 | 
					        </h1>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <IframeComponent
 | 
				
			||||||
 | 
					        ref={iframeRef}
 | 
				
			||||||
 | 
					        src="/ord?file:^Solar/Site.px|view:?fullScreen=true"
 | 
				
			||||||
 | 
					        onLoad={handleIframeLoad}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Home;
 | 
				
			||||||
							
								
								
									
										7
									
								
								Frontend/ibms_solar/src/page/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Frontend/ibms_solar/src/page/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					import Home from './Home';
 | 
				
			||||||
 | 
					import Energy from './Energy';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export {
 | 
				
			||||||
 | 
					  Home,
 | 
				
			||||||
 | 
					  Energy,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										8
									
								
								Frontend/ibms_solar/src/utils/cookieHelpers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Frontend/ibms_solar/src/utils/cookieHelpers.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					export function getCookie(cookieName) {
 | 
				
			||||||
 | 
					  let cookie = {};
 | 
				
			||||||
 | 
					  document.cookie.split(";").forEach(function (el) {
 | 
				
			||||||
 | 
					    let [key, value] = el.split("=");
 | 
				
			||||||
 | 
					    cookie[key.trim()] = value;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return cookie[cookieName];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								Frontend/ibms_solar/src/utils/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Frontend/ibms_solar/src/utils/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					import { getCookie } from "./cookieHelpers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { getCookie };
 | 
				
			||||||
							
								
								
									
										20
									
								
								Frontend/ibms_solar/tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Frontend/ibms_solar/tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					/** @type {import('tailwindcss').Config} */
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  content: ['./src/**/*.{js,jsx}'],
 | 
				
			||||||
 | 
					  theme: {
 | 
				
			||||||
 | 
					    extend: {
 | 
				
			||||||
 | 
					      screens: {
 | 
				
			||||||
 | 
					        xs: '480px',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      fontFamily: {
 | 
				
			||||||
 | 
					        inter: ['Inter var', 'sans-serif'],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      boxShadow: {
 | 
				
			||||||
 | 
					        card: '0 0 1px 0 rgba(189,192,207,0.06),0 10px 16px -1px rgba(189,192,207,0.2)',
 | 
				
			||||||
 | 
					        cardhover: '0 0 1px 0 rgba(189,192,207,0.06),0 10px 16px -1px rgba(189,192,207,0.4)',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  plugins: [],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								Frontend/ibms_solar/vite.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Frontend/ibms_solar/vite.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { fileURLToPath, URL } from "node:url";
 | 
				
			||||||
 | 
					import { defineConfig } from 'vite'
 | 
				
			||||||
 | 
					import react from '@vitejs/plugin-react'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://vitejs.dev/config/
 | 
				
			||||||
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  base: process.env.NODE_ENV === "production" ? "./" : "/",
 | 
				
			||||||
 | 
					  build: {
 | 
				
			||||||
 | 
					    outDir: "../solar_dist",
 | 
				
			||||||
 | 
					    emptyOutDir: true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  plugins: [react()],
 | 
				
			||||||
 | 
					  resolve: {
 | 
				
			||||||
 | 
					    alias: {
 | 
				
			||||||
 | 
					      "@": fileURLToPath(new URL("./src", import.meta.url)),
 | 
				
			||||||
 | 
					      "@ASSET": fileURLToPath(new URL("./src/assets", import.meta.url)),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
@ -2058,7 +2058,7 @@ License: You must have a valid license purchased only from wrapbootstrap.com (li
 | 
				
			|||||||
        function (res) {
 | 
					        function (res) {
 | 
				
			||||||
          if (!res || res.code != "0000" || !res.data) {
 | 
					          if (!res || res.code != "0000" || !res.data) {
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            let strHtml = `<div class="btn-group mx-4">
 | 
					            let strHtml = `<div class="btn-group ml-5">
 | 
				
			||||||
                                                                                              <a href="javascript:;" id="homeBtn" data-toggle="dropdown" data-page="dashboard" data-tabname="topFunBtn" class="text-center">
 | 
					                                                                                              <a href="javascript:;" id="homeBtn" data-toggle="dropdown" data-page="dashboard" data-tabname="topFunBtn" class="text-center">
 | 
				
			||||||
                                                                                                  <i class="fal fa-home fa-2x"></i><br>首頁
 | 
					                                                                                                  <i class="fal fa-home fa-2x"></i><br>首頁
 | 
				
			||||||
                                                                                              </a>
 | 
					                                                                                              </a>
 | 
				
			||||||
@ -2071,7 +2071,7 @@ License: You must have a valid license purchased only from wrapbootstrap.com (li
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            $.each(res.data, function (i, v) {
 | 
					            $.each(res.data, function (i, v) {
 | 
				
			||||||
              if (v.authCode == "PF1") {
 | 
					              if (v.authCode == "PF1") {
 | 
				
			||||||
                strHtml += `<div class="btn-group mx-4" >
 | 
					                strHtml += `<div class="btn-group ml-5" >
 | 
				
			||||||
                                                                                                  <a href="javascript:;" id="sysMonTopBtn" class="text-center dropdown-toggle" data-toggle="dropdown" data-tabname="topFunBtn" class="text-center">
 | 
					                                                                                                  <a href="javascript:;" id="sysMonTopBtn" class="text-center dropdown-toggle" data-toggle="dropdown" data-tabname="topFunBtn" class="text-center">
 | 
				
			||||||
                                                                                                      <i class="fal fa-tv fa-2x"></i><br>${v.subName}
 | 
					                                                                                                      <i class="fal fa-tv fa-2x"></i><br>${v.subName}
 | 
				
			||||||
                                                                                                  </a>
 | 
					                                                                                                  </a>
 | 
				
			||||||
@ -2100,7 +2100,7 @@ License: You must have a valid license purchased only from wrapbootstrap.com (li
 | 
				
			|||||||
                              : v.authCode == "PF8"
 | 
					                              : v.authCode == "PF8"
 | 
				
			||||||
                                ? "fa-user"
 | 
					                                ? "fa-user"
 | 
				
			||||||
                                : "";
 | 
					                                : "";
 | 
				
			||||||
                strHtml += `<div class="btn-group mx-4">
 | 
					                strHtml += `<div class="btn-group ml-5">
 | 
				
			||||||
                                                                                                  <a href="javascript:;" name="topFunBtn" data-tabname="topFunBtn" class="dropdown-toggle no-arrow text-center"
 | 
					                                                                                                  <a href="javascript:;" name="topFunBtn" data-tabname="topFunBtn" class="dropdown-toggle no-arrow text-center"
 | 
				
			||||||
                                                                                                     data-page="${v.showView}">
 | 
					                                                                                                     data-page="${v.showView}">
 | 
				
			||||||
                                                                                                      <i class="fal ${icon} fa-2x"></i><br>${v.subName}
 | 
					                                                                                                      <i class="fal ${icon} fa-2x"></i><br>${v.subName}
 | 
				
			||||||
@ -2108,7 +2108,11 @@ License: You must have a valid license purchased only from wrapbootstrap.com (li
 | 
				
			|||||||
                                                                                              </div>`;
 | 
					                                                                                              </div>`;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					            strHtml += `<div class="btn-group ml-5">
 | 
				
			||||||
 | 
					                        <a href="./solar_dist/index.html" name="topFunBtn" data-tabname="topFunBtn" class="dropdown-toggle no-arrow text-center" >
 | 
				
			||||||
 | 
					                            <i class="fal fa-solar-panel fa-2x"></i><br>太陽能管理
 | 
				
			||||||
 | 
					                        </a>
 | 
				
			||||||
 | 
					                    </div>`
 | 
				
			||||||
            $("#froLisPage").html(strHtml);
 | 
					            $("#froLisPage").html(strHtml);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // $("#homeBtn").YTNavbar("init");
 | 
					            // $("#homeBtn").YTNavbar("init");
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user