first commit

This commit is contained in:
koko 2025-04-17 14:17:29 +08:00
commit 6cf4ecacf5
31 changed files with 4278 additions and 0 deletions

24
.gitignore vendored Normal file
View 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?

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# EMS前台
## Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).

10
auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
}

31
components.d.ts vendored Normal file
View File

@ -0,0 +1,31 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
// biome-ignore lint: disable
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCard: typeof import('element-plus/es')['ElCard']
ElCol: typeof import('element-plus/es')['ElCol']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElInput: typeof import('element-plus/es')['ElInput']
ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElRow: typeof import('element-plus/es')['ElRow']
ElStatistic: typeof import('element-plus/es')['ElStatistic']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
EnergyBar: typeof import('./src/components/EnergyBar.vue')['default']
EnergyLine: typeof import('./src/components/EnergyLine.vue')['default']
EnergySankey: typeof import('./src/components/EnergySankey.vue')['default']
Navbar: typeof import('./src/components/Navbar.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!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" />
<title>EMS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

2263
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

27
package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "ems_front",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"echarts": "^5.6.0",
"element-plus": "^2.9.6",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@types/node": "^22.13.11",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/tsconfig": "^0.7.0",
"typescript": "~5.7.2",
"unplugin-auto-import": "^19.1.1",
"unplugin-vue-components": "^28.4.1",
"vite": "^6.2.0",
"vue-tsc": "^2.2.4"
}
}

1
public/vite.svg Normal file
View 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

5
src/App.vue Normal file
View File

@ -0,0 +1,5 @@
<script setup lang="ts"></script>
<template>
<router-view></router-view>
</template>
<style></style>

BIN
src/assets/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

1
src/assets/vue.svg Normal file
View 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="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@ -0,0 +1,82 @@
<script setup>
import { ref, onMounted, watch, onUnmounted } from "vue";
import * as echarts from "echarts";
const chartContainer = ref(null);
let chartInstance = null;
const props = defineProps({
chartData: {
type: Object,
required: true,
},
});
const initChart = () => {
chartInstance = echarts.init(chartContainer.value);
const option = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
legend: {
data: props.chartData.series.map((item) => item.name),
bottom: "0%",
},
grid: {
top: "5%",
left: "5%",
right: "5%",
bottom: "10%",
containLabel: true,
},
xAxis: {
type: "category",
data: props.chartData.categories || [],
},
yAxis: {
type: "value",
},
series: props.chartData.series.map((item) => ({
...item,
stack: "total",
})),
};
chartInstance.setOption(option);
};
onMounted(() => {
initChart();
});
watch(
() => props.chartData,
(newChartData) => {
if (chartInstance) {
chartInstance.setOption({
xAxis: {
data: newChartData.categories || [],
},
series: newChartData.series.map((item) => ({
...item,
stack: "total",
})),
});
}
},
{ deep: true }
);
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
}
});
</script>
<template>
<div ref="chartContainer" style="width: 100%; height: 250px"></div>
</template>

View File

@ -0,0 +1,105 @@
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as echarts from "echarts"; // echarts
//
const data = {
categories: [
"16:22:29",
"16:22:37",
"16:22:47",
"16:23:00",
"16:23:08",
"16:23:18",
],
series: [
{
name: "即時趨勢",
type: "line",
data: [320, 310, 300, 305, 310, 300],
smooth: true,
lineStyle: {
width: 3,
},
},
{
name: "契約容量",
type: "line",
data: [400, 400, 400, 400, 400, 400],
smooth: true,
lineStyle: {
width: 3,
},
},
{
name: "警戒容量",
type: "line",
data: [350, 350, 350, 350, 350, 350],
smooth: true,
lineStyle: {
width: 3,
},
},
{
name: "偵測值",
type: "line",
data: [280, 300, 290, 295, 300, 290],
smooth: true,
lineStyle: {
width: 3,
},
},
],
};
const demand_chart = ref(null);
const defaultChartOption = ref({
tooltip: {
trigger: "axis",
},
legend: {
data: data.series.map((s) => s.name),
orient: "horizontal",
bottom: "0%",
},
grid: {
top: "10%",
left: "0%",
right: "5%",
bottom: "10%",
containLabel: true,
},
xAxis: {
type: "category",
data: data.categories,
},
yAxis: {
type: "value",
},
series: data.series,
});
let chartInstance = null; //
onMounted(() => {
chartInstance = echarts.init(demand_chart.value);
chartInstance.setOption(defaultChartOption.value);
window.addEventListener("resize", () => {
chartInstance.resize();
});
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
}
window.removeEventListener("resize", () => {
chartInstance.resize();
});
});
</script>
<template>
<div ref="demand_chart" style="width: 100%; height: 200px"></div>
</template>
<style scoped></style>

View File

@ -0,0 +1,76 @@
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as echarts from "echarts";
const chartContainer = ref(null);
let chart = null;
onMounted(() => {
initChart();
});
const initChart = () => {
chart = echarts.init(chartContainer.value);
const option = {
tooltip: {
trigger: "item",
triggerOn: "mousemove",
},
series: [
{
type: "sankey",
layout: "none",
emphasis: {
focus: "adjacency",
},
data: [
{ name: "總用電" },
{ name: "照明" },
{ name: "空調" },
{ name: "設備A" },
{ name: "設備B" },
{ name: "其他" },
],
links: [
{ source: "總用電", target: "照明", value: 100 },
{ source: "總用電", target: "空調", value: 150 },
{ source: "總用電", target: "設備A", value: 80 },
{ source: "總用電", target: "設備B", value: 120 },
{ source: "總用電", target: "其他", value: 50 },
],
lineStyle: {
color: "gradient",
opacity: 0.7,
curveness: 0.5,
},
itemStyle: {
borderWidth: 0,
},
},
],
};
chart.setOption(option); //
// 調
window.addEventListener("resize", () => {
chart.resize();
});
};
//
onUnmounted(() => {
if (chart) {
chart.dispose();
}
window.removeEventListener("resize", () => {
chart.resize();
});
});
</script>
<template>
<div ref="chartContainer" style="width: 100%; height: 200px"></div>
</template>
<style scoped></style>

43
src/components/Navbar.vue Normal file
View File

@ -0,0 +1,43 @@
<template>
<el-menu
:default-active="activeIndex"
class="el-menu-demo"
mode="horizontal"
@select="handleSelect"
>
<el-menu-item index="chart">能源圖表 </el-menu-item>
<el-sub-menu index="elecPricing">
<template #title>電價表</template>
<el-menu-item index="elecPricingSimple">住宅型</el-menu-item>
<el-menu-item index="elecPricingStandard">標準型</el-menu-item>
</el-sub-menu>
</el-menu>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";
const router = useRouter();
const activeIndex = ref("chart"); // Set initial active index
const handleSelect = (key: string, keyPath: string[]) => {
console.log(key, keyPath);
switch (key) {
case "chart":
router.push({ name: "EnergyChart" });
activeIndex.value = "chart";
break;
case "elecPricingSimple":
router.push({ name: "ElecPricingSimple" });
activeIndex.value = "elecPricingSimple";
break;
case "elecPricingStandard":
router.push({ name: "ElecPricingStandard" });
activeIndex.value = "elecPricingStandard";
break;
}
};
</script>
<style scoped></style>

8
src/main.ts Normal file
View File

@ -0,0 +1,8 @@
import { createApp } from 'vue'
import './reset.css'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')

31
src/reset.css Normal file
View File

@ -0,0 +1,31 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
margin: 0;
min-width: 320px;
min-height: 100vh;
}
#app {
width: 100%;
height: 100%;
}
body {
line-height: 1;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
}

44
src/router/index.ts Normal file
View File

@ -0,0 +1,44 @@
import { createRouter, createWebHistory } from "vue-router";
import type { RouteRecordRaw } from "vue-router";
const routes: Array<RouteRecordRaw> = [
{
path: "/:catchAll(.*)",
name: "Home",
component: () => import("../views/Home.vue"),
children: [
{
path: "",
name: "EnergyChart",
component: () => import("../views/EnergyChart.vue"),
},
{
path: "elecPricingSimple",
name: "ElecPricingSimple",
component: () => import("../views/ElecPriceRes.vue"),
},
{
path: "elecPricingStandard",
name: "ElecPricingStandard",
component: () => import("../views/ElecPriceStd.vue"),
},
],
},
{
path: "/register",
name: "Register",
component: () => import("../views/Register.vue"),
},
// {
// path: "/:catchAll(.*)",
// name: "404",
// component: () => import("../views/404.vue"),
// },
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;

79
src/style.css Normal file
View File

@ -0,0 +1,79 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

10
src/views/404.vue Normal file
View File

@ -0,0 +1,10 @@
<template>
<el-result title="404" icon="warning" sub-title="Sorry, request error">
<template #extra>
<el-button type="primary" @click="$router.push('/')">返回首頁</el-button>
</template>
</el-result>
</template>
<style scoped>
</style>

399
src/views/ElecPriceRes.vue Normal file
View File

@ -0,0 +1,399 @@
<template>
<el-row :gutter="20">
<el-col :span="24">
<h2>
適合每月用電800度~5,300度之住宅及1,600~5,300度之小商店評估選用
</h2>
</el-col>
<el-col :span="12">
<table class="">
<thead>
<tr>
<th colspan="8">
<div style="display: flex; justify-content: space-between">
簡易型時間電價二段式
<el-button-group>
<el-button
type="warning"
plain
:icon="Edit"
v-if="!sim2isEditing"
@click.stop.prevent="sim2isEditing = true"
>編輯</el-button
>
<template v-else>
<el-button
type="warning"
plain
:icon="CircleCheck"
@click.stop.prevent="sim2isEditing = false"
>確認</el-button
>
<el-button
type="warning"
plain
:icon="CircleClose"
@click.stop.prevent="onCancel('sim2')"
>取消</el-button
>
</template>
</el-button-group>
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="6" class="bg-teal-800 bg-opacity-20">分類</td>
<td class="bg-teal-800 bg-opacity-20">夏月<br />(6/1~9/30)</td>
<td class="bg-teal-800 bg-opacity-20">
非夏月<br />(夏月以外的時間)
</td>
</tr>
<tr>
<td class="bg-brown" width="40">基本電費</td>
<td colspan="4" class="bg-brown">按戶計收</td>
<td class="bg-brown" width="40">每戶每月</td>
<td colspan="2" class="bg-brown">
<el-input
type="number"
v-model.number="sim2Value[0]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="6">流動電費</td>
<td rowspan="4" width="80">週一~週五</td>
<td rowspan="2" class="bg-red" width="30">尖峰時間</td>
<td class="bg-lightred">夏月</td>
<td class="bg-lightred">09:00 ~ 24:00</td>
<td rowspan="5">每度</td>
<td class="bg-lightred">
<el-input
type="number"
v-model.number="sim2Value[1]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</td>
<td class="bg-lightred">-</td>
</tr>
<tr>
<td class="bg-lightred">非夏月</td>
<td class="bg-lightred">06:00 ~ 11:00<br />14:00 ~ 24:00</td>
<td class="bg-lightred">-</td>
<td class="bg-lightred">
<el-input
type="number"
v-model.number="sim2Value[2]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="2" class="bg-green">離峰時間</td>
<td class="bg-lightgreen">夏月</td>
<td class="bg-lightgreen">00:00 ~ 09:00</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim2Value[3]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</td>
<td class="bg-lightgreen">-</td>
</tr>
<tr>
<td class="bg-lightgreen">非夏月</td>
<td class="bg-lightgreen">00:00 ~ 06:00<br />11:00 ~ 14:00</td>
<td class="bg-lightgreen">-</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim2Value[4]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</td>
</tr>
<tr>
<td>週六週日及離峰日</td>
<td class="bg-green">離峰時間</td>
<td colspan="2" class="bg-lightgreen">全日</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim2Value[5]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim2Value[6]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4">每月總度數超過2000度之部分</td>
<td>每度</td>
<td colspan="2" class="">
<div class="">
<el-input
type="number"
v-model.number="sim2Value[7]"
style="width: 140px"
:disabled="!sim2isEditing"
/>
</div>
</td>
</tr>
</tbody>
</table>
</el-col>
<el-col :span="12">
<table class="">
<thead>
<tr>
<th colspan="8" class="">
<div style="display: flex; justify-content: space-between">
簡易型時間電價三段式
<el-button-group>
<el-button
type="warning"
plain
:icon="Edit"
v-if="!sim3isEditing"
@click.stop.prevent="sim3isEditing = true"
>編輯</el-button
>
<template v-else>
<el-button
type="warning"
plain
:icon="CircleCheck"
@click.stop.prevent="sim3isEditing = false"
>確認</el-button
>
<el-button
type="warning"
plain
:icon="CircleClose"
@click.stop.prevent="onCancel('sim3')"
>取消</el-button
>
</template>
</el-button-group>
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="6" class="bg-">分類</td>
<td class="">夏月<br />(6/1~9/30)</td>
<td class="">非夏月<br />(夏月以外的時間)</td>
</tr>
<tr>
<td class="bg-brown" width="40">基本電費</td>
<td colspan="4" class="bg-brown">按戶計收</td>
<td class="bg-brown" width="40">每戶每月</td>
<td colspan="2" class="bg-brown">
<el-input
type="number"
v-model.number="sim3Value[0]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="7">流動電費</td>
<td rowspan="5">週一~週五</td>
<td class="bg-red" width="40">尖峰時間</td>
<td class="bg-lightred">夏月</td>
<td class="bg-lightred" width="110">16:00 ~ 22:00</td>
<td rowspan="6">每度</td>
<td class="bg-lightred">
<el-input
type="number"
v-model.number="sim3Value[1]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
<td class="bg-lightred">-</td>
</tr>
<tr>
<td rowspan="2" class="bg-yellow">半尖峰時間</td>
<td class="bg-lightyellow">夏月</td>
<td class="bg-lightyellow">09:00 ~ 16:00<br />22:00~24:00</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="sim3Value[2]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
<td class="bg-lightyellow">-</td>
</tr>
<tr>
<td class="bg-lightyellow">非夏月</td>
<td class="bg-lightyellow">06:00 ~ 11:00<br />14:00 ~ 24:00</td>
<td class="bg-lightyellow">-</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="sim3Value[3]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="2" class="bg-green">離峰時間</td>
<td class="bg-lightgreen">夏月</td>
<td class="bg-lightgreen">00:00 ~ 09:00</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim3Value[4]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
<td class="bg-lightgreen">-</td>
</tr>
<tr>
<td class="bg-lightgreen">非夏月</td>
<td class="bg-lightgreen">00:00 ~ 06:00<br />11:00 ~ 14:00</td>
<td class="bg-lightgreen">-</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim3Value[5]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
</tr>
<tr>
<td>週六週日及離峰日</td>
<td colspan="2" class="bg-green">離峰時間</td>
<td class="bg-lightgreen">全日</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim3Value[6]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="sim3Value[7]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4">每月總度數超過2000度之部分</td>
<td>每度</td>
<td colspan="2" class="!text-start">
<div class="flex items-center">
<el-input
type="number"
v-model.number="sim3Value[8]"
style="width: 140px"
:disabled="!sim3isEditing"
/>
</div>
</td>
</tr>
</tbody>
</table>
</el-col>
</el-row>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { Edit, CircleClose, CircleCheck } from "@element-plus/icons-vue";
const sim2isEditing = ref(false);
const sim3isEditing = ref(false);
const sim2Value = ref([75, 5.01, 4.78, 1.96, 1.89, 1.96, 1.89, 1.02]);
const sim3Value = ref([75, 6.92, 4.54, 4.33, 1.96, 1.89, 1.96, 1.89, 1.02]);
const onCancel = (sheet: string) => {
if(sheet == "sim2"){
sim2isEditing.value = false;
sim2Value.value = [75, 5.01, 4.78, 1.96, 1.89, 1.96, 1.89, 1.02];
}else{
sim3isEditing.value = false;
sim3Value.value = [75, 6.92, 4.54, 4.33, 1.96, 1.89, 1.96, 1.89, 1.02];
}
};
</script>
<style scoped>
h2 {
font-size: 1.2em;
font-weight: bold;
text-align: center;
margin-bottom: 30px;
}
th,
td {
border: 1px solid #9c9a97;
padding: 0.7rem;
text-align: center;
font-weight: 600;
background: #e9e2d1;
}
th {
font-size: 1.2em;
line-height: 2;
background: #f3ac0a;
color: #fff;
}
td {
font-size: 1em;
line-height: 1.2;
}
.bg-brown {
background: #d8cdb2;
}
.bg-red {
background: #ce1c45;
color: #fff;
}
.bg-lightred {
background: #fee5dd;
}
.bg-green {
background: #4da62c;
color: #fff;
}
.bg-lightgreen {
background: #dae9c9;
}
.bg-yellow {
background: #eeb612;
color: #fff;
}
.bg-lightyellow {
background: #f3e5a3;
}
</style>

664
src/views/ElecPriceStd.vue Normal file
View File

@ -0,0 +1,664 @@
<template>
<el-row :gutter="20">
<el-col :span="24">
<h2>適合每月用電超過5,300度之住宅及小商店評估選用</h2>
</el-col>
<el-col :span="12">
<table class="">
<thead>
<tr>
<th colspan="8" class="">
<div style="display: flex; justify-content: space-between">
標準型時間電價二段式
<el-button-group>
<el-button
type="warning"
plain
:icon="Edit"
v-if="!stand2isEditing"
@click.stop.prevent="stand2isEditing = true"
>編輯</el-button
>
<template v-else>
<el-button
type="warning"
plain
:icon="CircleCheck"
@click.stop.prevent="stand2isEditing = false"
>確認</el-button
>
<el-button
type="warning"
plain
:icon="CircleClose"
@click.stop.prevent="onCancel('stand2')"
>取消</el-button
>
</template>
</el-button-group>
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="6" class="">分類</td>
<td class="">夏月<br />(6/1~9/30)</td>
<td class="">非夏月<br />(夏月以外的時間)</td>
</tr>
<tr>
<td rowspan="6" class="bg-brown">基本電費</td>
<td colspan="2" rowspan="2" class="bg-brown">按戶計收</td>
<td colspan="2" class="bg-brown">單相</td>
<td rowspan="2" class="bg-brown">每戶每月</td>
<td colspan="2" class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[0]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td colspan="2" class="bg-brown">三相</td>
<td colspan="2" class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[1]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">經常契約</td>
<td rowspan="4" class="bg-brown">每瓩每月</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[2]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[3]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">非夏日契約</td>
<td class="bg-brown">-</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[4]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">週六半尖峰契約</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[5]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[6]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">離峰契約</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[7]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand2Value[8]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="9">流動電費</td>
<td rowspan="4">週一~週五</td>
<td rowspan="2" class="bg-red">尖峰時間</td>
<td class="bg-lightred" width="50">夏月</td>
<td class="bg-lightred" width="120">09:00 ~ 24:00</td>
<td rowspan="9">每度</td>
<td class="bg-lightred">
<el-input
type="number"
v-model.number="stand2Value[9]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-lightred">-</td>
</tr>
<tr>
<td class="bg-lightred">非夏月</td>
<td class="bg-lightred">06:00 ~ 11:00<br />14:00~24:00</td>
<td class="bg-lightred">-</td>
<td class="bg-lightred">
<el-input
type="number"
v-model.number="stand2Value[10]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="2" class="bg-green">離峰時間</td>
<td class="bg-lightgreen">夏月</td>
<td class="bg-lightgreen">00:00 ~ 09:00</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand2Value[11]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-lightgreen">-</td>
</tr>
<tr>
<td class="bg-lightgreen">非夏月</td>
<td class="bg-lightgreen">
00:00 ~ 06:00<br />
11:00 ~ 14:00
</td>
<td class="bg-lightgreen">-</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand2Value[12]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="4">週六</td>
<td rowspan="2" class="bg-yellow">半尖峰時間</td>
<td class="bg-lightyellow">夏月</td>
<td class="bg-lightyellow">09:00 ~ 24:00</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="stand2Value[13]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-lightyellow">-</td>
</tr>
<tr>
<td class="bg-lightyellow">非夏月</td>
<td class="bg-lightyellow">
06:00 ~ 11:00<br />
14:00 ~ 24:00
</td>
<td class="bg-lightyellow">-</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="stand2Value[14]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="2" class="bg-green">離峰時間</td>
<td class="bg-lightgreen">夏月</td>
<td class="bg-lightgreen">00:00 ~ 09:00</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand2Value[15]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-lightgreen">-</td>
</tr>
<tr>
<td class="bg-lightgreen">非夏月</td>
<td class="bg-lightgreen">00:00 ~ 06:00<br />11:00 ~ 14:00</td>
<td class="bg-lightgreen">-</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand2Value[16]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
<tr>
<td>週六週日及離峰日</td>
<td class="bg-green">離峰時間</td>
<td colspan="2" class="bg-lightgreen">全日</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand2Value[17]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand2Value[18]"
style="width: 140px"
:disabled="!stand2isEditing"
/>
</td>
</tr>
</tbody>
</table>
</el-col>
<el-col :span="12">
<table class="">
<thead>
<tr>
<th colspan="8" class="">
<div style="display: flex; justify-content: space-between">
標準型時間電價三段式
<el-button-group>
<el-button
type="warning"
plain
:icon="Edit"
v-if="!stand3isEditing"
@click.stop.prevent="stand3isEditing = true"
>編輯</el-button
>
<template v-else>
<el-button
type="warning"
plain
:icon="CircleCheck"
@click.stop.prevent="stand3isEditing = false"
>確認</el-button
>
<el-button
type="warning"
plain
:icon="CircleClose"
@click.stop.prevent="onCancel('stand3')"
>取消</el-button
>
</template>
</el-button-group>
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="6" class="">分類</td>
<td class="">夏月<br />(6/1~9/30)</td>
<td class="">非夏月<br />(夏月以外的時間)</td>
</tr>
<tr>
<td rowspan="6" class="bg-brown">基本電費</td>
<td colspan="2" rowspan="2" class="bg-brown">按戶計收</td>
<td colspan="2" class="bg-brown">單相</td>
<td rowspan="2" class="bg-brown">每戶每月</td>
<td colspan="2" class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[0]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td colspan="2" class="bg-brown">三相</td>
<td colspan="2" class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[1]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">經常契約</td>
<td rowspan="4" class="bg-brown">每瓩每月</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[2]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[3]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">非夏日契約</td>
<td class="bg-brown">-</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[4]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">週六半尖峰契約</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[5]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[6]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td colspan="4" class="bg-brown">離峰契約</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[7]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-brown">
<el-input
type="number"
v-model.number="stand3Value[8]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="10">流動電費</td>
<td rowspan="5">週一~週五</td>
<td class="bg-red">尖峰時間</td>
<td class="bg-lightred" width="50">夏月</td>
<td class="bg-lightred" width="120">16:00 ~ 22:00</td>
<td rowspan="10">每度</td>
<td class="bg-lightred">
<el-input
type="number"
v-model.number="stand3Value[9]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-lightred">-</td>
</tr>
<tr>
<td rowspan="2" class="bg-yellow">半尖峰時間</td>
<td class="bg-lightyellow">夏月</td>
<td class="bg-lightyellow">09:00 ~ 16:00<br />22:00 ~ 24:00</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="stand3Value[10]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-lightyellow">-</td>
</tr>
<tr>
<td class="bg-lightyellow">非夏月</td>
<td class="bg-lightyellow">06:00 ~ 11:00<br />14:00 ~ 24:00</td>
<td class="bg-lightyellow">-</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="stand3Value[11]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="2" class="bg-green">離峰時間</td>
<td class="bg-lightgreen">夏月</td>
<td class="bg-lightgreen">00:00 ~ 09:00</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand3Value[12]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-lightgreen">-</td>
</tr>
<tr>
<td class="bg-lightgreen">非夏月</td>
<td class="bg-lightgreen">
00:00 ~ 06:00<br />
11:00 ~ 14:00
</td>
<td class="bg-lightgreen">-</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand3Value[13]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="4">週六</td>
<td rowspan="2" class="bg-yellow">半尖峰時間</td>
<td class="bg-lightyellow">夏月</td>
<td class="bg-lightyellow">09:00 ~ 24:00</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="stand3Value[14]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-lightyellow">-</td>
</tr>
<tr>
<td class="bg-lightyellow">非夏月</td>
<td class="bg-lightyellow">
06:00 ~ 11:00<br />
14:00 ~ 24:00
</td>
<td class="bg-lightyellow">-</td>
<td class="bg-lightyellow">
<el-input
type="number"
v-model.number="stand3Value[15]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td rowspan="2" class="bg-green">離峰時間</td>
<td class="bg-lightgreen">夏月</td>
<td class="bg-lightgreen">00:00 ~ 09:00</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand3Value[16]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-lightgreen">-</td>
</tr>
<tr>
<td class="bg-lightgreen">非夏月</td>
<td class="bg-lightgreen">00:00 ~ 06:00<br />11:00 ~ 14:00</td>
<td class="bg-lightgreen">-</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand3Value[17]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
<tr>
<td>週日及離峰日</td>
<td class="bg-green">離峰時間</td>
<td colspan="2" class="bg-lightgreen">全日</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand3Value[18]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
<td class="bg-lightgreen">
<el-input
type="number"
v-model.number="stand3Value[19]"
style="width: 140px"
:disabled="!stand3isEditing"
/>
</td>
</tr>
</tbody>
</table>
</el-col>
</el-row>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { Edit, CircleClose, CircleCheck } from "@element-plus/icons-vue";
const stand2isEditing = ref(false);
const stand3isEditing = ref(false);
const stand2Value = ref([
129.1, 262.5, 236.2, 173.2, 173.2, 47.2, 34.6, 47.2, 34.6, 5.54, 5.39, 2.27,
2.15, 2.76, 2.65, 2.27, 2.15, 2.27, 2.15,
]);
const stand3Value = ref([
129.1, 262.5, 236.2, 173.2, 173.2, 173.2, 47.2, 34.6, 47.2, 34.6, 8.12, 5.02,
4.86, 2.23, 2.12, 2.5, 2.4, 2.23, 2.12, 2.23, 2.12,
]);
const onCancel = (sheet: string) => {
if(sheet == "stand2"){
stand2isEditing.value = false;
stand2Value.value = [
129.1, 262.5, 236.2, 173.2, 173.2, 47.2, 34.6, 47.2, 34.6, 5.54, 5.39, 2.27,
2.15, 2.76, 2.65, 2.27, 2.15, 2.27, 2.15,
];
}else{
stand3isEditing.value = false;
stand3Value.value = [
129.1, 262.5, 236.2, 173.2, 173.2, 173.2, 47.2, 34.6, 47.2, 34.6, 8.12, 5.02,
4.86, 2.23, 2.12, 2.5, 2.4, 2.23, 2.12, 2.23, 2.12,
];
}
};
</script>
<style scoped>
h2 {
font-size: 1.2em;
font-weight: bold;
text-align: center;
margin-bottom: 30px;
}
th,
td {
border: 1px solid #9c9a97;
padding: 0.7rem;
text-align: center;
font-weight: 600;
background: #e9e2d1;
}
th {
font-size: 1.2em;
line-height: 2;
background: #f3ac0a;
color: #fff;
}
td {
font-size: 1em;
line-height: 1.2;
}
.bg-brown {
background: #d8cdb2;
}
.bg-red {
background: #ce1c45;
color: #fff;
}
.bg-lightred {
background: #fee5dd;
}
.bg-green {
background: #4da62c;
color: #fff;
}
.bg-lightgreen {
background: #dae9c9;
}
.bg-yellow {
background: #eeb612;
color: #fff;
}
.bg-lightyellow {
background: #f3e5a3;
}
</style>

226
src/views/EnergyChart.vue Normal file
View File

@ -0,0 +1,226 @@
<template>
<el-row :gutter="20">
<el-col :span="10">
<el-card style="border-radius: 8px">
<h3 class="">用電即時分佈</h3>
<EnergySankey />
</el-card>
</el-col>
<el-col :span="14">
<h3 class="" style="margin-top: 15px">即時需量</h3>
<EnergyLine />
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-row style="padding-right: 15px">
<el-col :span="12" v-for="(item, index) in statisticData">
<el-card
style="
width: 100%;
padding: 5px;
max-width: 480px;
border-radius: 0;
"
:key="index"
:class="{ 'bg-info': index == 0 || index == 3 || index == 4 }"
shadow="hover"
>
<el-statistic
:title="item.title"
:value="item.value"
:suffix="item.unit"
/>
</el-card>
</el-col>
</el-row>
</el-col>
<el-col :span="8">
<el-card style="border-radius: 8px; height: 100%">
<h3 class="">每月用電分析</h3>
<EnergyBar :chartData="monthlyElectricityData" />
</el-card>
</el-col>
<el-col :span="8">
<el-card style="border-radius: 8px; height: 100%">
<h3 class="">每月碳排當量 (kgCO2e)</h3>
<EnergyBar :chartData="monthlyCarbonData" />
</el-card>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-card style="border-radius: 8px; height: 100%">
<h3 class="">每月計費度數 (kWh)</h3>
<EnergyBar :chartData="monthlyBillingData" />
</el-card>
</el-col>
<el-col :span="16">
<el-card style="border-radius: 8px">
<h3 class="">區間計費度數 2025-03-01 ~ 2025-03-12</h3>
<EnergyBar :chartData="areaBillingData" />
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import { onMounted, ref, computed } from "vue";
import EnergySankey from "../components/EnergySankey.vue";
import EnergyLine from "../components/EnergyLine.vue";
import EnergyBar from "../components/EnergyBar.vue";
const statisticData = ref([
{ title: "今年電費累計", value: 58792.56, unit: "元" },
{ title: "區間電費", value: 1234.78, unit: "元" },
{ title: "今年碳排當量累計", value: 3456.23, unit: "公斤" },
{ title: "區間碳排當量", value: 15.67, unit: "公斤" },
{ title: "今年用電度數", value: 1890.45, unit: "kWh" },
{ title: "區間用電度數", value: 123.9, unit: "kWh" },
]);
//
const monthlyElectricityData = ref({
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
series: [
{
name: "基本電量",
type: "bar",
data: [120, 100, 110, 130, 150, 160, 140, 150, 130, 120, 110, 130],
},
{
name: "流動電量",
type: "bar",
data: [80, 60, 70, 90, 100, 110, 90, 100, 80, 70, 60, 80],
},
{
name: "總電量",
type: "bar",
data: [200, 160, 180, 220, 250, 270, 230, 250, 210, 190, 170, 210],
},
],
});
//
const monthlyCarbonData = ref({
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
series: [
{
name: "碳排當量",
type: "bar",
data: [50, 40, 45, 55, 60, 65, 55, 60, 50, 45, 40, 50],
},
],
});
// (kWh)
const monthlyBillingData = ref({
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
series: [
{
name: "尖峰",
type: "bar",
data: [120, 100, 110, 130, 150, 160, 140, 150, 130, 120, 110, 130],
},
{
name: "半尖峰",
type: "bar",
data: [80, 60, 70, 90, 100, 110, 90, 100, 80, 70, 60, 80],
},
{
name: "離峰",
type: "bar",
data: [200, 160, 180, 220, 250, 270, 230, 250, 210, 190, 170, 210],
},
],
});
//
const areaBillingData = ref({
categories: [
"03-01",
"03-02",
"03-03",
"03-04",
"03-05",
"03-06",
"03-07",
"03-08",
"03-09",
"03-10",
"03-11",
"03-12",
],
series: [
{
name: "尖峰",
type: "bar",
data: [120, 100, 110, 130, 150, 160, 140, 150, 130, 120, 110, 130],
},
{
name: "半尖峰",
type: "bar",
data: [80, 60, 70, 90, 100, 110, 90, 100, 80, 70, 60, 80],
},
{
name: "離峰",
type: "bar",
data: [200, 160, 180, 220, 250, 270, 230, 250, 210, 190, 170, 210],
},
],
});
</script>
<style scoped>
.el-row {
margin-bottom: 20px;
}
h3 {
margin: 0;
font-weight: 700;
font-size: 15px;
color: #141414;
}
.bg-info {
background: rgb(224, 239, 255);
}
</style>

18
src/views/Home.vue Normal file
View File

@ -0,0 +1,18 @@
<template>
<div class="common-layout">
<el-container>
<el-header><Navbar /></el-header>
<el-main><router-view></router-view></el-main>
</el-container>
</div>
</template>
<script setup lang="ts">
import Navbar from "../components/Navbar.vue";
</script>
<style scoped>
.el-header{
padding: 0;
}
</style>

28
src/views/Register.vue Normal file
View File

@ -0,0 +1,28 @@
<template>
<div class="register">
<el-row>
<el-col :span="12" :offset="6" class="">
<h2 class="title">能源管理系統 Energy Management System</h2>
</el-col>
</el-row>
</div>
</template>
<script></script>
<style scoped>
.register {
position: relative;
width: 100%;
height: 100%;
background: url(../assets/bg.jpg) no-repeat center center;
background-size: 100% 100%;
}
.title {
font-family: "Microsoft YaHei";
font-weight: bold;
font-size: 26px;
color: #fff;
}
</style>

15
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
/// <reference types="vite/client" />
// 聲明 .vue 檔案可以被導入為 Vue 元件
declare module "*.vue" {
import type { DefineComponent } from "vue";
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>;
export default component;
}
// 聲明環境變數 ( .env 檔案)
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string;
readonly VITE_API_URL: string;
}

14
tsconfig.app.json Normal file
View File

@ -0,0 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

7
tsconfig.json Normal file
View File

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

24
tsconfig.node.json Normal file
View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

22
vite.config.ts Normal file
View File

@ -0,0 +1,22 @@
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
// https://vite.dev/config/
export default defineConfig({
base: 'https://192.168.0.206:8500/file/ibms_ems_front/',
build: {
emptyOutDir: true,
},
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
});