設備管理點位新增 | 密碼欄位可視 | 能源管理英文版
This commit is contained in:
parent
d2a9027869
commit
68f0af6229
@ -13,3 +13,4 @@ export const GET_ASSET_FLOOR_LIST_API = `/AssetManage/GetFloorList`;
|
|||||||
export const POST_ASSET_FLOOR_API = `/AssetManage/SaveFloor`;
|
export const POST_ASSET_FLOOR_API = `/AssetManage/SaveFloor`;
|
||||||
|
|
||||||
export const GET_ASSET_IOT_LIST_API = `/AssetManage/GetIOTList`;
|
export const GET_ASSET_IOT_LIST_API = `/AssetManage/GetIOTList`;
|
||||||
|
export const GET_ASSET_SUB_POINT_API = `/AssetManage/GetSubPoint`;
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
GET_ASSET_IOT_LIST_API,
|
GET_ASSET_IOT_LIST_API,
|
||||||
DELETE_ASSET_ITEM_API,
|
DELETE_ASSET_ITEM_API,
|
||||||
POST_ASSET_SINGLE_API,
|
POST_ASSET_SINGLE_API,
|
||||||
|
GET_ASSET_SUB_POINT_API,
|
||||||
} from "./api";
|
} from "./api";
|
||||||
import instance from "@/util/request";
|
import instance from "@/util/request";
|
||||||
import apihandler from "@/util/apihandler";
|
import apihandler from "@/util/apihandler";
|
||||||
@ -98,7 +99,8 @@ export const postAssetSingle = async (data) => {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
value.forEach((element, index) => {
|
value.forEach((element, index) => {
|
||||||
formData.append(`${key}[${index}].device_guid`, element);
|
formData.append(`sub_device[${index}].device_number`, element.device_number);
|
||||||
|
formData.append(`sub_device[${index}].points`, element.points);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -141,8 +143,22 @@ export const postAssetFloor = async (formData) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAssetIOTList = async () => {
|
export const getAssetIOTList = async (sub_system_tag, points) => {
|
||||||
const res = await instance.post(GET_ASSET_IOT_LIST_API);
|
const res = await instance.post(GET_ASSET_IOT_LIST_API, {
|
||||||
|
sub_system_tag,
|
||||||
|
points,
|
||||||
|
});
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAssetSubPoint = async (sub_system_tag) => {
|
||||||
|
const res = await instance.post(GET_ASSET_SUB_POINT_API, {
|
||||||
|
sub_system_tag,
|
||||||
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.btn{
|
.btn{
|
||||||
@apply px-6 py-1;
|
@apply px-4 py-1;
|
||||||
text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.9);
|
text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.9);
|
||||||
box-shadow: 0px 0px 5px rgba(255, 255, 255, 0.8);
|
box-shadow: 0px 0px 5px rgba(255, 255, 255, 0.8);
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@ import { defineProps, computed } from "vue";
|
|||||||
import VueDatePicker from "@vuepic/vue-datepicker";
|
import VueDatePicker from "@vuepic/vue-datepicker";
|
||||||
import "@vuepic/vue-datepicker/dist/main.css";
|
import "@vuepic/vue-datepicker/dist/main.css";
|
||||||
import { zhTW } from "date-fns/locale";
|
import { zhTW } from "date-fns/locale";
|
||||||
|
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
items: Array,
|
items: Array,
|
||||||
withLine: Boolean,
|
withLine: Boolean,
|
||||||
@ -62,13 +62,12 @@ const curWidth = computed(() => {
|
|||||||
showPreview: false,
|
showPreview: false,
|
||||||
}"
|
}"
|
||||||
v-model="item.value"
|
v-model="item.value"
|
||||||
locale="zh-TW"
|
locale='en-US'
|
||||||
:day-names="['一', '二', '三', '四', '五', '六', '日']"
|
|
||||||
:format="item.dateFormat"
|
:format="item.dateFormat"
|
||||||
:enable-time-picker="false"
|
:enable-time-picker="false"
|
||||||
:time-picker="Boolean(item.timePicker)"
|
:time-picker="Boolean(item.timePicker)"
|
||||||
:placeholder="item.placeholder"
|
:placeholder="item.placeholder"
|
||||||
selectText="確定"
|
:selectText="t('button.submit')"
|
||||||
:input-class-name="
|
:input-class-name="
|
||||||
twMerge('dp-custom-input', 'btn border', inputClass)
|
twMerge('dp-custom-input', 'btn border', inputClass)
|
||||||
"
|
"
|
||||||
|
@ -52,13 +52,19 @@ const changePageData = (currentPage) => {
|
|||||||
watch(
|
watch(
|
||||||
() => [props.dataSource, props.sort],
|
() => [props.dataSource, props.sort],
|
||||||
([newVal, newVal2]) => {
|
([newVal, newVal2]) => {
|
||||||
// console.log(props.dataSource, newVal);
|
const totalPageNumber =
|
||||||
currentPage.value = 1;
|
|
||||||
totalPage.value =
|
|
||||||
props.totalPages || Math.ceil(props.dataSource.length / props.pageSize);
|
props.totalPages || Math.ceil(props.dataSource.length / props.pageSize);
|
||||||
|
if (currentPage.value > totalPageNumber) {
|
||||||
|
currentPage.value = 1;
|
||||||
|
} else {
|
||||||
|
// 若頁數在範圍內,則保持當前頁面
|
||||||
|
currentPage.value = currentPage.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalPage.value = totalPageNumber;
|
||||||
props.onPageChange
|
props.onPageChange
|
||||||
? current_table_data.updateDataSource(props.dataSource)
|
? current_table_data.updateDataSource(props.dataSource)
|
||||||
: changePageData(1);
|
: changePageData(currentPage.value || 1);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true,
|
deep: true,
|
||||||
@ -99,7 +105,7 @@ const pageInput = computed(() => {
|
|||||||
:key="`page${page}`"
|
:key="`page${page}`"
|
||||||
:class="
|
:class="
|
||||||
twMerge(
|
twMerge(
|
||||||
'w-10 h-10 mx-1 border-2 border-sub-success rounded-full flex items-center justify-center',
|
'w-10 h-10 mx-1 border-2 border-sub-success rounded-full flex items-center justify-center cursor-pointer',
|
||||||
currentPage === page ? 'bg-sub-success' : 'bg-transparent'
|
currentPage === page ? 'bg-sub-success' : 'bg-transparent'
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
@ -145,7 +151,7 @@ const pageInput = computed(() => {
|
|||||||
<span
|
<span
|
||||||
class="w-full text-center absolute -bottom-8 left-1/2 -translate-x-1/2 text-base"
|
class="w-full text-center absolute -bottom-8 left-1/2 -translate-x-1/2 text-base"
|
||||||
>
|
>
|
||||||
{{ totalItems || dataSource.length }} {{ $t("table.in_otal") }}</span
|
{{ totalItems || dataSource.length }} {{ $t("table.in_otal") }}</span
|
||||||
>
|
>
|
||||||
</label>
|
</label>
|
||||||
<ul
|
<ul
|
||||||
|
@ -163,14 +163,33 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .ant-menu-submenu-title:active {
|
::v-deep .ant-menu-submenu-title:active {
|
||||||
background-color: #35759d !important;
|
color: #35759d !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
::v-deep .ant-menu-item:not(.ant-menu-item-selected) {
|
||||||
|
&::before {
|
||||||
|
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10 grayscale;
|
||||||
|
content: "";
|
||||||
|
background: url(@ASSET/img/chart-data-background03.svg) center center;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .ant-menu-item-selected {
|
::v-deep .ant-menu-item-selected {
|
||||||
background-color: #35759d !important;
|
@apply bg-transparent relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10;
|
||||||
|
content: "";
|
||||||
|
background: url(@ASSET/img/chart-data-background03.svg) center center;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
a {
|
a {
|
||||||
color: #fff !important;
|
color: #89d2ff !important;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -204,6 +204,7 @@
|
|||||||
"operate_text": "显示名称",
|
"operate_text": "显示名称",
|
||||||
"fill_text": "请由系统人员填写",
|
"fill_text": "请由系统人员填写",
|
||||||
"equipment_point": "设备点位",
|
"equipment_point": "设备点位",
|
||||||
|
"point": "点位",
|
||||||
"add_sensor": "新增感测器",
|
"add_sensor": "新增感测器",
|
||||||
"associated_device": "关联设备",
|
"associated_device": "关联设备",
|
||||||
"choose": "选择",
|
"choose": "选择",
|
||||||
|
@ -204,6 +204,7 @@
|
|||||||
"operate_text": "顯示名稱",
|
"operate_text": "顯示名稱",
|
||||||
"fill_text": "請由系統人員填寫",
|
"fill_text": "請由系統人員填寫",
|
||||||
"equipment_point": "設備點位",
|
"equipment_point": "設備點位",
|
||||||
|
"point": "點位",
|
||||||
"add_sensor": "新增感測器",
|
"add_sensor": "新增感測器",
|
||||||
"associated_device": "關聯設備",
|
"associated_device": "關聯設備",
|
||||||
"choose": "選擇",
|
"choose": "選擇",
|
||||||
|
@ -204,6 +204,7 @@
|
|||||||
"operate_text": "Display name",
|
"operate_text": "Display name",
|
||||||
"fill_text": "Please fill it in by system personnel",
|
"fill_text": "Please fill it in by system personnel",
|
||||||
"equipment_point": "Equipment point",
|
"equipment_point": "Equipment point",
|
||||||
|
"point": "Point",
|
||||||
"add_sensor": "Add new sensor",
|
"add_sensor": "Add new sensor",
|
||||||
"associated_device": "Associated devices",
|
"associated_device": "Associated devices",
|
||||||
"choose": "Choose",
|
"choose": "Choose",
|
||||||
|
@ -53,7 +53,9 @@ import {
|
|||||||
faFireExtinguisher,
|
faFireExtinguisher,
|
||||||
faDoorOpen,
|
faDoorOpen,
|
||||||
faCar,
|
faCar,
|
||||||
faWind
|
faWind,
|
||||||
|
faEye,
|
||||||
|
faEyeSlash,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
/* add icons to the library */
|
/* add icons to the library */
|
||||||
@ -108,7 +110,9 @@ library.add(
|
|||||||
faFireExtinguisher,
|
faFireExtinguisher,
|
||||||
faDoorOpen,
|
faDoorOpen,
|
||||||
faCar,
|
faCar,
|
||||||
faWind
|
faWind,
|
||||||
|
faEye,
|
||||||
|
faEyeSlash
|
||||||
);
|
);
|
||||||
|
|
||||||
export default library;
|
export default library;
|
||||||
|
@ -71,7 +71,7 @@ const deleteItem = async (id) => {
|
|||||||
>
|
>
|
||||||
<template #buttonContent="{ item }">
|
<template #buttonContent="{ item }">
|
||||||
<span class="text-base">{{ item.title }}</span>
|
<span class="text-base">{{ item.title }}</span>
|
||||||
<template v-if="!item.is_IOT">
|
<!-- <template v-if="!item.is_IOT">
|
||||||
<span
|
<span
|
||||||
class="ml-2 text-base text-warning"
|
class="ml-2 text-base text-warning"
|
||||||
@click.stop.prevent="() => edit(item)"
|
@click.stop.prevent="() => edit(item)"
|
||||||
@ -84,7 +84,7 @@ const deleteItem = async (id) => {
|
|||||||
>
|
>
|
||||||
<FontAwesomeIcon :icon="['fas', 'trash-alt']" />
|
<FontAwesomeIcon :icon="['fas', 'trash-alt']" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template> -->
|
||||||
</template>
|
</template>
|
||||||
</ButtonConnectedGroup>
|
</ButtonConnectedGroup>
|
||||||
</div>
|
</div>
|
||||||
|
@ -140,7 +140,10 @@ const edit = async (id) => {
|
|||||||
ext: file.saveName.split(".")[file.saveName.split(".").length - 1],
|
ext: file.saveName.split(".")[file.saveName.split(".").length - 1],
|
||||||
}));
|
}));
|
||||||
res.data.sub_device = res.data.sub_device?.map(
|
res.data.sub_device = res.data.sub_device?.map(
|
||||||
({ device_guid }) => device_guid
|
({ device_number, points }) => ({
|
||||||
|
device_number,
|
||||||
|
points,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
editRecord.value = res.data;
|
editRecord.value = res.data;
|
||||||
openModal();
|
openModal();
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { getAssetIOTList } from "@/apis/asset";
|
import { getAssetIOTList } from "@/apis/asset";
|
||||||
import { ref, computed, inject, watch } from "vue";
|
import { ref, computed, inject, watch, onMounted } from "vue";
|
||||||
|
import ButtonGroup from "@/components/customUI/ButtonGroup.vue";
|
||||||
|
import useActiveBtn from "@/hooks/useActiveBtn";
|
||||||
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
|
import { getAssetSubPoint } from "@/apis/asset";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { formState } = inject("asset_table_modal_form");
|
const { formState } = inject("asset_table_modal_form");
|
||||||
@ -11,65 +15,98 @@ const tableColumns = computed(() => [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "tag",
|
title: "tag",
|
||||||
key: "tag",
|
key: "device_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("assetManagement.system_name"),
|
title: t("assetManagement.point"),
|
||||||
key: "full_name",
|
key: "point_name",
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// title: "狀態",
|
|
||||||
// key: "status",
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
title: t("assetManagement.operation"),
|
title: t("assetManagement.operation"),
|
||||||
key: "operation",
|
key: "operation",
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
// 選小類
|
||||||
|
const store = useBuildingStore();
|
||||||
|
const {
|
||||||
|
items: sysTagItems,
|
||||||
|
changeActiveBtn: changeSysActiveBtn,
|
||||||
|
setItems: setSysItems,
|
||||||
|
selectedBtn: selectedSysItems,
|
||||||
|
} = useActiveBtn();
|
||||||
const modalColumns = computed(() => [
|
const modalColumns = computed(() => [
|
||||||
{
|
{
|
||||||
title: t("assetManagement.choose"),
|
title: t("assetManagement.choose"),
|
||||||
key: "check",
|
key: "check",
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "tag",
|
title: "tag",
|
||||||
key: "tag",
|
key: "device_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("assetManagement.system_name"),
|
title: t("assetManagement.point"),
|
||||||
key: "full_name",
|
key: "point_name",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 設定點位
|
||||||
|
const {
|
||||||
|
items: points,
|
||||||
|
changeActiveBtn: changeActivePoint,
|
||||||
|
setItems: setPoints,
|
||||||
|
selectedBtn: selectedPoints,
|
||||||
|
} = useActiveBtn();
|
||||||
|
|
||||||
|
const getPoint = async (sub_system_tag) => {
|
||||||
|
const res = await getAssetSubPoint(sub_system_tag);
|
||||||
|
setPoints(
|
||||||
|
res.data.map((d, index) => ({
|
||||||
|
...d,
|
||||||
|
title: d.points,
|
||||||
|
key: d.points,
|
||||||
|
active: false,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: 抓取IOT
|
// TODO: 抓取IOT
|
||||||
const iotData = ref([]);
|
const iotData = ref([]);
|
||||||
|
const iotCheckedList = ref([]); // 初始選中的項目
|
||||||
|
const currentCheckedList = ref([]); // 當前勾選的項目
|
||||||
|
|
||||||
const getIOTData = async () => {
|
const getIOTData = async (sub_system_tag = null, points = null) => {
|
||||||
const res = await getAssetIOTList();
|
const res = await getAssetIOTList(sub_system_tag, points);
|
||||||
let data = res.data.map((d) => ({
|
let data = res.data.map((d) => ({
|
||||||
...d,
|
...d,
|
||||||
title: d.full_name,
|
title: d.full_name,
|
||||||
key: d.device_guid,
|
key: d.device_number + d.points,
|
||||||
tag: d.device_number,
|
checked: formState.value.sub_device?.some(
|
||||||
checked: formState.value.sub_device?.includes(d.device_guid),
|
({ device_number, points }) =>
|
||||||
|
device_number + points === `${d.device_number}${d.points}`
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
iotData.value = data;
|
iotData.value = data;
|
||||||
iotCheckedList.value = data.filter(({ checked }) => checked);
|
if (!sub_system_tag && !points) {
|
||||||
|
iotCheckedList.value = data.filter(({ checked }) => checked);
|
||||||
|
currentCheckedList.value = [...iotCheckedList.value];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const iotCheckedList = ref([]);
|
|
||||||
const onChange = (value, checked) => {
|
const onChange = (value, checked) => {
|
||||||
const d = iotData.value.find(({ device_guid }) => device_guid === value);
|
const d = iotData.value.find(
|
||||||
|
({ device_number, points }) => `${device_number}${points}` === value
|
||||||
|
);
|
||||||
let newList = [];
|
let newList = [];
|
||||||
if (checked) {
|
if (checked) {
|
||||||
newList = [...iotCheckedList.value, d];
|
newList = [...currentCheckedList.value, d];
|
||||||
} else {
|
} else {
|
||||||
newList = iotCheckedList.value.filter(
|
newList = currentCheckedList.value.filter(
|
||||||
(checked) => checked.device_guid !== d.device_guid
|
(item) => item.device_number + item.points !== value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
iotCheckedList.value = newList;
|
currentCheckedList.value = newList;
|
||||||
return newList;
|
return newList;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,8 +115,12 @@ const openModal = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onOk = () => {
|
const onOk = () => {
|
||||||
formState.value.sub_device = iotCheckedList.value.map(
|
iotCheckedList.value = currentCheckedList.value;
|
||||||
({ device_guid }) => device_guid
|
formState.value.sub_device = currentCheckedList.value.map(
|
||||||
|
({ device_number, points }) => ({
|
||||||
|
device_number,
|
||||||
|
points,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
onCancel();
|
onCancel();
|
||||||
};
|
};
|
||||||
@ -88,23 +129,57 @@ const onCancel = () => {
|
|||||||
asset_add_IoT_item.close();
|
asset_add_IoT_item.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[selectedSysItems, selectedPoints],
|
||||||
|
([newSys, newPoint]) => {
|
||||||
|
if (newSys || newPoint) {
|
||||||
|
getIOTData(newSys?.key, newPoint?.key);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
watch(selectedSysItems, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
getPoint(newVal.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
watch(
|
watch(
|
||||||
formState,
|
formState,
|
||||||
() => {
|
() => {
|
||||||
getIOTData();
|
getIOTData();
|
||||||
|
setSysItems(
|
||||||
|
store.subSys.map(({ full_name, sub_system_tag }, index) => ({
|
||||||
|
title: full_name,
|
||||||
|
key: sub_system_tag,
|
||||||
|
active: 0,
|
||||||
|
}))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true,
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteItem = (id) => {
|
const deleteItem = (value) => {
|
||||||
console.log(formState.value.sub_device, id);
|
const itemToDelete = iotCheckedList.value.find(
|
||||||
// formState.value.device_guid = formState.value.device_guid.filter(
|
({ device_number, points }) => `${device_number}${points}` === value
|
||||||
// (d) => d !== id
|
);
|
||||||
// );
|
|
||||||
const newList = onChange(id, false);
|
if (itemToDelete) {
|
||||||
formState.value.sub_device = newList.map(({ device_guid }) => device_guid);
|
iotCheckedList.value = iotCheckedList.value.filter(
|
||||||
|
(item) => item.device_number + item.points !== value
|
||||||
|
);
|
||||||
|
currentCheckedList.value = iotCheckedList.value;
|
||||||
|
|
||||||
|
formState.value.sub_device = iotCheckedList.value.map(
|
||||||
|
({ device_number, points }) => ({
|
||||||
|
device_number,
|
||||||
|
points,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -131,15 +206,11 @@ const deleteItem = (id) => {
|
|||||||
<template #bodyCell="{ record, column, index }">
|
<template #bodyCell="{ record, column, index }">
|
||||||
<template v-if="column.key === 'index'">{{ index + 1 }}</template
|
<template v-if="column.key === 'index'">{{ index + 1 }}</template
|
||||||
><template v-if="column.key === 'operation'">
|
><template v-if="column.key === 'operation'">
|
||||||
<!-- <span
|
|
||||||
class="mr-5 text-base text-warning cursor-pointer"
|
|
||||||
@click.stop.prevent="() => edit(record)"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon :icon="['fas', 'pencil-alt']"></FontAwesomeIcon>
|
|
||||||
</span> -->
|
|
||||||
<span
|
<span
|
||||||
class="text-base text-error cursor-pointer"
|
class="text-base text-error cursor-pointer"
|
||||||
@click.stop.prevent="() => deleteItem(record.device_guid)"
|
@click.stop.prevent="
|
||||||
|
() => deleteItem(record.device_number + record.points)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
:icon="['fas', 'trash-alt']"
|
:icon="['fas', 'trash-alt']"
|
||||||
@ -155,16 +226,39 @@ const deleteItem = (id) => {
|
|||||||
width="900"
|
width="900"
|
||||||
>
|
>
|
||||||
<template #modalContent>
|
<template #modalContent>
|
||||||
|
<ButtonGroup
|
||||||
|
:items="sysTagItems"
|
||||||
|
:withLine="true"
|
||||||
|
:onclick="
|
||||||
|
(e, item) => {
|
||||||
|
changeSysActiveBtn(item);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="my-3"
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
v-if="selectedSysItems"
|
||||||
|
:items="points"
|
||||||
|
:withLine="true"
|
||||||
|
:onclick="
|
||||||
|
(e, item) => {
|
||||||
|
changeActivePoint(item);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="my-3"
|
||||||
|
/>
|
||||||
<Table :columns="modalColumns" :dataSource="iotData" :withStyle="false">
|
<Table :columns="modalColumns" :dataSource="iotData" :withStyle="false">
|
||||||
<template #bodyCell="{ record, column, index }">
|
<template #bodyCell="{ record, column, index }">
|
||||||
<template v-if="column.key === 'check'">
|
<template v-if="column.key === 'check'">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="device_guid"
|
name="device_number"
|
||||||
:value="record.device_guid"
|
:value="record.device_number + record.points"
|
||||||
:onChange="onChange"
|
:onChange="onChange"
|
||||||
:checked="
|
:checked="
|
||||||
iotCheckedList?.some(
|
currentCheckedList?.some(
|
||||||
({ device_guid }) => device_guid === record.device_guid
|
({ device_number, points }) =>
|
||||||
|
`${device_number}${points}` ===
|
||||||
|
`${record.device_number}${record.points}`
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
></Checkbox>
|
></Checkbox>
|
||||||
|
@ -13,6 +13,10 @@ const props = defineProps({
|
|||||||
reset: Function,
|
reset: Function,
|
||||||
getData: Function,
|
getData: Function,
|
||||||
});
|
});
|
||||||
|
const showPassword = ref(false);
|
||||||
|
const togglePasswordVisibility = () => {
|
||||||
|
showPassword.value = !showPassword.value;
|
||||||
|
};
|
||||||
|
|
||||||
let userSchema = ref(
|
let userSchema = ref(
|
||||||
yup.object({
|
yup.object({
|
||||||
@ -143,17 +147,24 @@ const onOk = async () => {
|
|||||||
<Input
|
<Input
|
||||||
v-if="!Boolean(formState?.Id)"
|
v-if="!Boolean(formState?.Id)"
|
||||||
:value="formState"
|
:value="formState"
|
||||||
class="my-2"
|
class="relative my-2"
|
||||||
name="Password"
|
name="Password"
|
||||||
type="password"
|
:type="showPassword ? 'text' : 'password'"
|
||||||
>
|
>
|
||||||
<template #topLeft>{{ $t("accountManagement.password") }}</template>
|
<template #topLeft>{{ $t("accountManagement.password") }}</template>
|
||||||
<template #bottomLeft
|
<template #bottomLeft
|
||||||
><span class="text-error text-base">
|
><span class="text-error text-base">
|
||||||
{{ formErrorMsg.Password }}
|
{{ formErrorMsg.Password }}
|
||||||
</span></template
|
</span></template
|
||||||
></Input
|
>
|
||||||
>
|
<template #bottomRight>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
:icon="['fas', showPassword ? 'eye-slash' : 'eye']"
|
||||||
|
class="fa-2x absolute top-14 right-0 transform -translate-x-1/2 cursor-pointer"
|
||||||
|
@click="togglePasswordVisibility"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Input>
|
||||||
<Input :value="formState" class="my-2" name="Name">
|
<Input :value="formState" class="my-2" name="Name">
|
||||||
<template #topLeft>{{ $t("accountManagement.name") }}</template>
|
<template #topLeft>{{ $t("accountManagement.name") }}</template>
|
||||||
<template #bottomLeft
|
<template #bottomLeft
|
||||||
|
@ -15,6 +15,10 @@ const props = defineProps({
|
|||||||
const formState = ref({
|
const formState = ref({
|
||||||
Password: "",
|
Password: "",
|
||||||
});
|
});
|
||||||
|
const showPassword = ref(false);
|
||||||
|
const togglePasswordVisibility = () => {
|
||||||
|
showPassword.value = !showPassword.value;
|
||||||
|
};
|
||||||
|
|
||||||
let userSchema = yup.object({
|
let userSchema = yup.object({
|
||||||
Password: yup.string().required(t("button.required")),
|
Password: yup.string().required(t("button.required")),
|
||||||
@ -49,7 +53,12 @@ const onOk = async () => {
|
|||||||
<template #modalContent>
|
<template #modalContent>
|
||||||
<p class="mt-10 text-3xl">{{ account.Name }}</p>
|
<p class="mt-10 text-3xl">{{ account.Name }}</p>
|
||||||
<form ref="form" class="mt-5 w-full flex flex-wrap justify-between">
|
<form ref="form" class="mt-5 w-full flex flex-wrap justify-between">
|
||||||
<Input :value="formState" class="my-2" name="Password" type="password">
|
<Input
|
||||||
|
:value="formState"
|
||||||
|
class="relative my-2"
|
||||||
|
name="Password"
|
||||||
|
:type="showPassword ? 'text' : 'password'"
|
||||||
|
>
|
||||||
<template #topLeft>{{
|
<template #topLeft>{{
|
||||||
$t("accountManagement.change_password")
|
$t("accountManagement.change_password")
|
||||||
}}</template>
|
}}</template>
|
||||||
@ -57,8 +66,15 @@ const onOk = async () => {
|
|||||||
><span class="text-error text-base">
|
><span class="text-error text-base">
|
||||||
{{ formErrorMsg.Password }}
|
{{ formErrorMsg.Password }}
|
||||||
</span></template
|
</span></template
|
||||||
></Input
|
>
|
||||||
>
|
<template #bottomRight>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
:icon="['fas', showPassword ? 'eye-slash' : 'eye']"
|
||||||
|
class="fa-2x absolute top-14 right-0 transform -translate-x-1/2 cursor-pointer"
|
||||||
|
@click="togglePasswordVisibility"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Input>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
<template #modalAction>
|
<template #modalAction>
|
||||||
|
@ -20,7 +20,7 @@ const yesterdayTodayData = {
|
|||||||
|
|
||||||
// 本週與上週用電比較資料
|
// 本週與上週用電比較資料
|
||||||
const weekComparisonData = {
|
const weekComparisonData = {
|
||||||
categories: ["週五", "週六", "週日", "週一", "週二", "週三", "週四"],
|
categories: ["Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu"],
|
||||||
values: [
|
values: [
|
||||||
{
|
{
|
||||||
name: "This week's electricity consumption",
|
name: "This week's electricity consumption",
|
||||||
@ -131,6 +131,31 @@ const generateCylinderChartOption = (categories, values) => {
|
|||||||
},
|
},
|
||||||
z: 12,
|
z: 12,
|
||||||
},
|
},
|
||||||
|
// 圓柱底部
|
||||||
|
{
|
||||||
|
name: null,
|
||||||
|
type: "pictorialBar",
|
||||||
|
symbolSize: [barWidth, 5],
|
||||||
|
symbolOffset: [-9, 4],
|
||||||
|
symbolPosition: "start",
|
||||||
|
data: values[0].value,
|
||||||
|
z: 12,
|
||||||
|
itemStyle: {
|
||||||
|
color: "#0ca9d4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: null,
|
||||||
|
type: "pictorialBar",
|
||||||
|
symbolSize: [barWidth, 5],
|
||||||
|
symbolOffset: [9, 4],
|
||||||
|
symbolPosition: "start",
|
||||||
|
data: values[1].value,
|
||||||
|
itemStyle: {
|
||||||
|
color: "#ffe000",
|
||||||
|
},
|
||||||
|
z: 12,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
grid: {
|
grid: {
|
||||||
left: "3%",
|
left: "3%",
|
||||||
@ -180,14 +205,14 @@ const weekComparisonOption = generateCylinderChartOption(
|
|||||||
(kWH)
|
(kWH)
|
||||||
</h2>
|
</h2>
|
||||||
<div class="w-[48%]">
|
<div class="w-[48%]">
|
||||||
<a href="#" class="text-con">
|
<div class="text-con">
|
||||||
<img src="@ASSET/img/chart-title01.svg" />
|
<img src="@ASSET/img/chart-title01.svg" />
|
||||||
<span>{{ $t("dashboard.today_electricity_consumption") }}</span>
|
<span>{{ $t("dashboard.today_electricity_consumption") }}</span>
|
||||||
</a>
|
</div>
|
||||||
<a href="#" class="text-con">
|
<div class="text-con">
|
||||||
<img src="@ASSET/img/chart-title02.svg" />
|
<img src="@ASSET/img/chart-title02.svg" />
|
||||||
<span>{{ $t("dashboard.yesterday_electricity_consumption") }}</span>
|
<span>{{ $t("dashboard.yesterday_electricity_consumption") }}</span>
|
||||||
</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-[250px]">
|
<div class="h-[250px]">
|
||||||
@ -208,14 +233,14 @@ const weekComparisonOption = generateCylinderChartOption(
|
|||||||
(kWH)
|
(kWH)
|
||||||
</h2>
|
</h2>
|
||||||
<div class="w-[48%]">
|
<div class="w-[48%]">
|
||||||
<a href="#" class="text-con">
|
<div class="text-con">
|
||||||
<img src="@ASSET/img/chart-title01.svg" />
|
<img src="@ASSET/img/chart-title01.svg" />
|
||||||
<span>{{ $t("dashboard.thisweek_electricity_consumption") }}</span>
|
<span>{{ $t("dashboard.thisweek_electricity_consumption") }}</span>
|
||||||
</a>
|
</div>
|
||||||
<a href="#" class="text-con">
|
<div class="text-con">
|
||||||
<img src="@ASSET/img/chart-title02.svg" />
|
<img src="@ASSET/img/chart-title02.svg" />
|
||||||
<span>{{ $t("dashboard.lastweek_electricity_consumption") }}</span>
|
<span>{{ $t("dashboard.lastweek_electricity_consumption") }}</span>
|
||||||
</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-[250px]">
|
<div class="h-[250px]">
|
||||||
|
@ -10,10 +10,10 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
data: ["尖峰", "半尖峰", "離峰度數"],
|
data: ["Peak", "Semi-Peak", "Off-Peak"],
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
orient: "horizontal",
|
orient: "horizontal",
|
||||||
bottom: "0%",
|
bottom: "0%",
|
||||||
@ -28,18 +28,18 @@ const defaultChartOption = ref({
|
|||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
data: [
|
data: [
|
||||||
"1月",
|
"Jan",
|
||||||
"2月",
|
"Feb",
|
||||||
"3月",
|
"Mar",
|
||||||
"4月",
|
"Apr",
|
||||||
"5月",
|
"May",
|
||||||
"6月",
|
"Jun",
|
||||||
"7月",
|
"Jul",
|
||||||
"8月",
|
"Aug",
|
||||||
"9月",
|
"Sep",
|
||||||
"10月",
|
"Oct",
|
||||||
"11月",
|
"Nov",
|
||||||
"12月",
|
"Dec",
|
||||||
],
|
],
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
@ -53,7 +53,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "尖峰",
|
name: "Peak",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
@ -65,7 +65,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "半尖峰",
|
name: "Semi-Peak",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
@ -76,7 +76,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "離峰度數",
|
name: "Off-Peak",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
|
@ -10,10 +10,10 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
data: ["碳排當量", "減量目標"],
|
data: ["Carbon Equivalent", "Reduction Target"],
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
orient: "horizontal",
|
orient: "horizontal",
|
||||||
bottom: "0%",
|
bottom: "0%",
|
||||||
@ -28,18 +28,18 @@ const defaultChartOption = ref({
|
|||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
data: [
|
data: [
|
||||||
"1月",
|
"Jan",
|
||||||
"2月",
|
"Feb",
|
||||||
"3月",
|
"Mar",
|
||||||
"4月",
|
"Apr",
|
||||||
"5月",
|
"May",
|
||||||
"6月",
|
"Jun",
|
||||||
"7月",
|
"Jul",
|
||||||
"8月",
|
"Aug",
|
||||||
"9月",
|
"Sep",
|
||||||
"10月",
|
"Oct",
|
||||||
"11月",
|
"Nov",
|
||||||
"12月",
|
"Dec",
|
||||||
],
|
],
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
@ -53,7 +53,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "碳排當量",
|
name: "Carbon Equivalent",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
data: [
|
data: [
|
||||||
5400, 6500, 7200, 7500, 9800, 9500, 11200, 11500, 11800, 7500, 6500,
|
5400, 6500, 7200, 7500, 9800, 9500, 11200, 11500, 11800, 7500, 6500,
|
||||||
@ -64,7 +64,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "減量目標",
|
name: "Reduction Target",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
data: [
|
data: [
|
||||||
5000, 6000, 6000, 7000, 9500, 9000, 10000, 11000, 10000, 7200, 6000,
|
5000, 6000, 6000, 7000, 9500, 9000, 10000, 11000, 10000, 7200, 6000,
|
||||||
|
@ -14,7 +14,7 @@ const data = {
|
|||||||
],
|
],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "即時趨勢",
|
name: "Real-Time Trend", // 即時趨勢
|
||||||
type: "line",
|
type: "line",
|
||||||
data: [320, 310, 300, 305, 310, 300],
|
data: [320, 310, 300, 305, 310, 300],
|
||||||
smooth: true,
|
smooth: true,
|
||||||
@ -26,7 +26,7 @@ const data = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "契約容量",
|
name: "Contract Capacity", // 契約容量
|
||||||
type: "line",
|
type: "line",
|
||||||
data: [400, 400, 400, 400, 400, 400],
|
data: [400, 400, 400, 400, 400, 400],
|
||||||
smooth: true,
|
smooth: true,
|
||||||
@ -38,7 +38,7 @@ const data = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "警戒容量",
|
name: "Alert Capacity", // 警戒容量
|
||||||
type: "line",
|
type: "line",
|
||||||
data: [350, 350, 350, 350, 350, 350],
|
data: [350, 350, 350, 350, 350, 350],
|
||||||
smooth: true,
|
smooth: true,
|
||||||
@ -50,7 +50,7 @@ const data = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "偵測值",
|
name: "Measured Value", // 偵測值
|
||||||
type: "line",
|
type: "line",
|
||||||
data: [280, 300, 290, 295, 300, 290],
|
data: [280, 300, 290, 295, 300, 290],
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
@ -19,10 +19,10 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
data: ["尖峰", "半尖峰", "離峰度數"],
|
data: ["Peak", "Semi-Peak", "Off-Peak"],
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
orient: "horizontal",
|
orient: "horizontal",
|
||||||
bottom: "0%",
|
bottom: "0%",
|
||||||
@ -31,7 +31,7 @@ const defaultChartOption = ref({
|
|||||||
top: "5%",
|
top: "5%",
|
||||||
left: "0%",
|
left: "0%",
|
||||||
right: "0%",
|
right: "0%",
|
||||||
bottom: "10%",
|
bottom: "15%",
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
@ -49,7 +49,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "尖峰",
|
name: "Peak",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
@ -61,7 +61,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "半尖峰",
|
name: "Semi-Peak",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
@ -73,7 +73,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "離峰度數",
|
name: "Off-Peak",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
|
@ -10,10 +10,10 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
data: [ "流動電費","基本電費", "電費總額"],
|
data: ["Var. Elec. Cost", "Fixed Elec. Cost", "Total Elec. Cost"],
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
orient: "horizontal",
|
orient: "horizontal",
|
||||||
bottom: "0%",
|
bottom: "0%",
|
||||||
@ -28,18 +28,18 @@ const defaultChartOption = ref({
|
|||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
data: [
|
data: [
|
||||||
"1月",
|
"Jan",
|
||||||
"2月",
|
"Feb",
|
||||||
"3月",
|
"Mar",
|
||||||
"4月",
|
"Apr",
|
||||||
"5月",
|
"May",
|
||||||
"6月",
|
"Jun",
|
||||||
"7月",
|
"Jul",
|
||||||
"8月",
|
"Aug",
|
||||||
"9月",
|
"Sep",
|
||||||
"10月",
|
"Oct",
|
||||||
"11月",
|
"Nov",
|
||||||
"12月",
|
"Dec",
|
||||||
],
|
],
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
@ -53,7 +53,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "流動電費",
|
name: "Var. Elec. Cost",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
@ -65,7 +65,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "基本電費",
|
name: "Fixed Elec. Cost",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
@ -78,7 +78,7 @@ const defaultChartOption = ref({
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "電費總額",
|
name: "Total Elec. Cost",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "total",
|
stack: "total",
|
||||||
data: [
|
data: [
|
||||||
@ -99,7 +99,9 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-slate-800 p-3">
|
<div class="bg-slate-800 p-3">
|
||||||
<div class="text-white mb-3 text-base">{{$t("energy.monthly_elec_consumption")}}</div>
|
<div class="text-white mb-3 text-base">
|
||||||
|
{{ $t("energy.monthly_elec_consumption") }}
|
||||||
|
</div>
|
||||||
<div class="bar-box">
|
<div class="bar-box">
|
||||||
<BarChart
|
<BarChart
|
||||||
id="electricity_bill_chart"
|
id="electricity_bill_chart"
|
||||||
|
@ -22,6 +22,10 @@ const formState = ref({
|
|||||||
account: "",
|
account: "",
|
||||||
password: "",
|
password: "",
|
||||||
});
|
});
|
||||||
|
const showPassword = ref(false);
|
||||||
|
const togglePasswordVisibility = () => {
|
||||||
|
showPassword.value = !showPassword.value;
|
||||||
|
};
|
||||||
|
|
||||||
const imageSrc = import.meta.env.MODE === "production" ? "./logo.svg" : Image;
|
const imageSrc = import.meta.env.MODE === "production" ? "./logo.svg" : Image;
|
||||||
|
|
||||||
@ -63,17 +67,22 @@ const doLogin = async () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex flex-col items-end my-2">
|
<div class="w-full flex flex-col items-end my-2">
|
||||||
<div class="w-full flex justify-between">
|
<div class="w-full flex justify-between relative">
|
||||||
<label class="mr-2 text-2xl text-black" for="password">{{
|
<label class="mr-2 text-2xl text-black" for="password">{{
|
||||||
$t("password")
|
$t("password")
|
||||||
}}</label>
|
}}</label>
|
||||||
<input
|
<input
|
||||||
name="password"
|
name="password"
|
||||||
class="w-5/6 border-2 rounded-full bg-white text-black px-4 py-1"
|
class="w-5/6 border-2 rounded-full bg-white text-black px-4 py-1"
|
||||||
type="password"
|
:type="showPassword ? 'text' : 'password'"
|
||||||
v-model="formState.password"
|
v-model="formState.password"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
/>
|
/>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
:icon="['fas', showPassword ? 'eye-slash' : 'eye']"
|
||||||
|
class="text-gray-400 text-2xl absolute top-1/2 right-4 transform -translate-y-1/2 cursor-pointer"
|
||||||
|
@click="togglePasswordVisibility"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-error text-base">
|
<span class="text-error text-base">
|
||||||
{{ formErrorMsg.password }}
|
{{ formErrorMsg.password }}
|
||||||
|
Loading…
Reference in New Issue
Block a user