MQTT位置路徑修改 | CviBuilding存進localStorage | 樓層與部門存到狀態裡 | 首頁、電價表語言包 |能源管理新增棟別、樓層、部門參數 | 歷史資料新增日期區間 | 樓層頁面deBug | 圖資deBug | MQTT頁面 | 系統監控: 新增棟別樓層部門 以及 spriteDbId的deBug | 電表設定
This commit is contained in:
parent
f956402648
commit
8b85e2d67c
@ -1,4 +1,4 @@
|
|||||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
||||||
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||||
VITE_MQTT_BASEURL = "ws://192.168.0.217:8083/mqtt"
|
VITE_MQTT_BASEURL = "wss://mqttwss.mjm-staging.developers-homelab.net"
|
||||||
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
@ -1,4 +1,4 @@
|
|||||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
||||||
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||||
VITE_MQTT_BASEURL = "wss://192.168.0.217:8084/mqtt"
|
VITE_MQTT_BASEURL = "wss://mqttwss.mjm-staging.developers-homelab.net"
|
||||||
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
@ -20,6 +20,11 @@ export const GET_ASSET_IOT_LIST_API = `/AssetManage/GetIOTList`;
|
|||||||
export const GET_ASSET_SUB_POINT_API = `/AssetManage/GetSubPoint`;
|
export const GET_ASSET_SUB_POINT_API = `/AssetManage/GetSubPoint`;
|
||||||
|
|
||||||
export const GET_ASSET_IOT_SCHEMA_API = `/AssetManage/GetResponseSchema`;
|
export const GET_ASSET_IOT_SCHEMA_API = `/AssetManage/GetResponseSchema`;
|
||||||
|
export const POST_ASSET_IOT_SCHEMA_API = `/AssetManage/SaveResponseSchema`;
|
||||||
|
|
||||||
|
export const GET_ASSET_DEVICE_ITEM_API = `/AssetManage/GetDeviceItem`;
|
||||||
|
export const POST_ASSET_DEVICE_ITEM_API = `/AssetManage/SaveDeviceItem`;
|
||||||
|
export const DELETE_ASSET_DEVICE_ITEM_API = `/AssetManage/DeleteDeviceItem`;
|
||||||
|
|
||||||
export const GET_ASSET_DEPARTMENT_API = `/AssetManage/GetDepartment`;
|
export const GET_ASSET_DEPARTMENT_API = `/AssetManage/GetDepartment`;
|
||||||
export const POST_ASSET_DEPARTMENT_API = `/AssetManage/SaveDepartment`;
|
export const POST_ASSET_DEPARTMENT_API = `/AssetManage/SaveDepartment`;
|
||||||
@ -28,3 +33,5 @@ export const DELETE_ASSET_DEPARTMENT_API = `/AssetManage/DeleteDepartment`;
|
|||||||
export const GET_ASSET_ELECTYPE_API = `/AssetManage/GetElecType`;
|
export const GET_ASSET_ELECTYPE_API = `/AssetManage/GetElecType`;
|
||||||
export const POST_ASSET_ELECTYPE_API = `/AssetManage/SaveElecType`;
|
export const POST_ASSET_ELECTYPE_API = `/AssetManage/SaveElecType`;
|
||||||
export const DELETE_ASSET_ELECTYPE_API = `/AssetManage/DeleteElecType`;
|
export const DELETE_ASSET_ELECTYPE_API = `/AssetManage/DeleteElecType`;
|
||||||
|
|
||||||
|
export const POST_ASSET_ELEC_SETTING_API = `/AssetManage/SaveAssetSetting`;
|
@ -15,12 +15,17 @@ import {
|
|||||||
POST_ASSET_SINGLE_API,
|
POST_ASSET_SINGLE_API,
|
||||||
GET_ASSET_SUB_POINT_API,
|
GET_ASSET_SUB_POINT_API,
|
||||||
GET_ASSET_IOT_SCHEMA_API,
|
GET_ASSET_IOT_SCHEMA_API,
|
||||||
|
POST_ASSET_IOT_SCHEMA_API,
|
||||||
|
GET_ASSET_DEVICE_ITEM_API,
|
||||||
|
POST_ASSET_DEVICE_ITEM_API,
|
||||||
|
DELETE_ASSET_DEVICE_ITEM_API,
|
||||||
GET_ASSET_DEPARTMENT_API,
|
GET_ASSET_DEPARTMENT_API,
|
||||||
POST_ASSET_DEPARTMENT_API,
|
POST_ASSET_DEPARTMENT_API,
|
||||||
DELETE_ASSET_DEPARTMENT_API,
|
DELETE_ASSET_DEPARTMENT_API,
|
||||||
GET_ASSET_ELECTYPE_API,
|
GET_ASSET_ELECTYPE_API,
|
||||||
POST_ASSET_ELECTYPE_API,
|
POST_ASSET_ELECTYPE_API,
|
||||||
DELETE_ASSET_ELECTYPE_API
|
DELETE_ASSET_ELECTYPE_API,
|
||||||
|
POST_ASSET_ELEC_SETTING_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";
|
||||||
@ -156,8 +161,8 @@ export const deleteAssetItem = async (main_id) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAssetFloorList = async () => {
|
export const getAssetFloorList = async (building_guid) => {
|
||||||
const res = await instance.post(GET_ASSET_FLOOR_LIST_API);
|
const res = await instance.post(GET_ASSET_FLOOR_LIST_API, { building_guid });
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -207,7 +212,63 @@ export const getAssetSubPoint = async (sub_system_tag) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getIOTSchema = async (variable_id) => {
|
export const getIOTSchema = async (variable_id) => {
|
||||||
const res = await instance.post(GET_ASSET_IOT_SCHEMA_API, {variable_id});
|
const res = await instance.post(GET_ASSET_IOT_SCHEMA_API, { variable_id });
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const postIOTSchema = async ({ name, variable_id, points }) => {
|
||||||
|
const res = await instance.post(POST_ASSET_IOT_SCHEMA_API, {
|
||||||
|
name,
|
||||||
|
variable_id,
|
||||||
|
points,
|
||||||
|
});
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getDeviceItem = async (variable_id) => {
|
||||||
|
const res = await instance.post(GET_ASSET_DEVICE_ITEM_API, { variable_id });
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const postDeviceItem = async ({
|
||||||
|
id,
|
||||||
|
variable_id,
|
||||||
|
full_name,
|
||||||
|
points,
|
||||||
|
decimals,
|
||||||
|
is_bool,
|
||||||
|
is_link,
|
||||||
|
}) => {
|
||||||
|
const res = await instance.post(POST_ASSET_DEVICE_ITEM_API, {
|
||||||
|
id,
|
||||||
|
variable_id,
|
||||||
|
full_name,
|
||||||
|
points,
|
||||||
|
decimals,
|
||||||
|
is_bool,
|
||||||
|
is_link,
|
||||||
|
});
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteDeviceItem = async (id) => {
|
||||||
|
const res = await instance.post(DELETE_ASSET_DEVICE_ITEM_API, { id });
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -273,4 +334,13 @@ export const deleteElecTypeItem = async (id) => {
|
|||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
code: res.code,
|
code: res.code,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const postAssetElecSetting = async (formData) => {
|
||||||
|
const res = await instance.post(POST_ASSET_ELEC_SETTING_API, formData);
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -11,14 +11,22 @@ import {
|
|||||||
GET_CARBON_API,
|
GET_CARBON_API,
|
||||||
POST_EDIT_CARBON_API,
|
POST_EDIT_CARBON_API,
|
||||||
GET_TIME_ELEC_API,
|
GET_TIME_ELEC_API,
|
||||||
POST_TIME_ELEC_API
|
POST_TIME_ELEC_API,
|
||||||
} from "./api";
|
} from "./api";
|
||||||
import instance, { fileInstance } from "@/util/request";
|
import instance, { fileInstance } from "@/util/request";
|
||||||
import apihandler from "@/util/apihandler";
|
import apihandler from "@/util/apihandler";
|
||||||
import downloadExcel from "@/util/downloadExcel";
|
import downloadExcel from "@/util/downloadExcel";
|
||||||
|
|
||||||
export const getRealTimeDist = async () => {
|
export const getRealTimeDist = async ({
|
||||||
const res = await instance.post(GET_REALTIME_DIST_API);
|
building_guid,
|
||||||
|
department_id_list,
|
||||||
|
floor_guid_list,
|
||||||
|
}) => {
|
||||||
|
const res = await instance.post(GET_REALTIME_DIST_API, {
|
||||||
|
building_guid,
|
||||||
|
department_id_list,
|
||||||
|
floor_guid_list,
|
||||||
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -26,8 +34,16 @@ export const getRealTimeDist = async () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getElecUseDay = async () => {
|
export const getElecUseDay = async ({
|
||||||
const res = await instance.post(GET_ELECUSE_DAY_API);
|
building_guid,
|
||||||
|
department_id_list,
|
||||||
|
floor_guid_list,
|
||||||
|
}) => {
|
||||||
|
const res = await instance.post(GET_ELECUSE_DAY_API,{
|
||||||
|
building_guid,
|
||||||
|
department_id_list,
|
||||||
|
floor_guid_list,
|
||||||
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -35,8 +51,18 @@ export const getElecUseDay = async () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTaipower = async () => {
|
export const getTaipower = async ({
|
||||||
const res = await instance.post(GET_TAI_POWER_API);
|
coefficient,
|
||||||
|
building_guid,
|
||||||
|
department_id_list,
|
||||||
|
floor_guid_list,
|
||||||
|
}) => {
|
||||||
|
const res = await instance.post(GET_TAI_POWER_API, {
|
||||||
|
coefficient,
|
||||||
|
building_guid,
|
||||||
|
department_id_list,
|
||||||
|
floor_guid_list,
|
||||||
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -118,7 +144,7 @@ export const getExcel = async ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getDemand = async (building_guid) => {
|
export const getDemand = async (building_guid) => {
|
||||||
const res = await instance.post(GET_DEMAND_API, {building_guid});
|
const res = await instance.post(GET_DEMAND_API, { building_guid });
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -126,13 +152,19 @@ export const getDemand = async (building_guid) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const postEditDemand = async ({ id, contract, alert, reset, building_guid }) => {
|
export const postEditDemand = async ({
|
||||||
|
id,
|
||||||
|
contract,
|
||||||
|
alert,
|
||||||
|
reset,
|
||||||
|
building_guid,
|
||||||
|
}) => {
|
||||||
const res = await instance.put(POST_EDIT_DEMAND_API, {
|
const res = await instance.put(POST_EDIT_DEMAND_API, {
|
||||||
id,
|
id,
|
||||||
contract,
|
contract,
|
||||||
alert,
|
alert,
|
||||||
reset,
|
reset,
|
||||||
building_guid
|
building_guid,
|
||||||
});
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
@ -142,7 +174,7 @@ export const postEditDemand = async ({ id, contract, alert, reset, building_guid
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getCarbonValue = async (building_guid) => {
|
export const getCarbonValue = async (building_guid) => {
|
||||||
const res = await instance.post(GET_CARBON_API, {building_guid});
|
const res = await instance.post(GET_CARBON_API, { building_guid });
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -150,11 +182,15 @@ export const getCarbonValue = async (building_guid) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const postEditCarbonValue = async ({ id, coefficient, building_guid }) => {
|
export const postEditCarbonValue = async ({
|
||||||
|
id,
|
||||||
|
coefficient,
|
||||||
|
building_guid,
|
||||||
|
}) => {
|
||||||
const res = await instance.put(POST_EDIT_CARBON_API, {
|
const res = await instance.put(POST_EDIT_CARBON_API, {
|
||||||
id,
|
id,
|
||||||
coefficient,
|
coefficient,
|
||||||
building_guid
|
building_guid,
|
||||||
});
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
@ -164,7 +200,7 @@ export const postEditCarbonValue = async ({ id, coefficient, building_guid }) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getTimeElec = async (building_guid) => {
|
export const getTimeElec = async (building_guid) => {
|
||||||
const res = await instance.post(GET_TIME_ELEC_API, {building_guid});
|
const res = await instance.post(GET_TIME_ELEC_API, { building_guid });
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -174,9 +210,9 @@ export const getTimeElec = async (building_guid) => {
|
|||||||
|
|
||||||
export const postTimeElec = async ({ sheet, cost, building_guid }) => {
|
export const postTimeElec = async ({ sheet, cost, building_guid }) => {
|
||||||
const res = await instance.put(POST_TIME_ELEC_API, {
|
const res = await instance.put(POST_TIME_ELEC_API, {
|
||||||
sheet,
|
sheet,
|
||||||
cost,
|
cost,
|
||||||
building_guid
|
building_guid,
|
||||||
});
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
|
@ -16,11 +16,13 @@ export const getHistorySideBar = async ({
|
|||||||
sub_system_tag,
|
sub_system_tag,
|
||||||
department_id,
|
department_id,
|
||||||
elec_type_id,
|
elec_type_id,
|
||||||
|
building_guid,
|
||||||
}) => {
|
}) => {
|
||||||
const res = await instance.post(GET_HISTORY_SIDEBAR_API, {
|
const res = await instance.post(GET_HISTORY_SIDEBAR_API, {
|
||||||
sub_system_tag,
|
sub_system_tag,
|
||||||
department_id,
|
department_id,
|
||||||
elec_type_id,
|
elec_type_id,
|
||||||
|
building_guid,
|
||||||
});
|
});
|
||||||
|
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
|
@ -6,6 +6,7 @@ const store = useBuildingStore();
|
|||||||
|
|
||||||
const selectBuilding = (bui) => {
|
const selectBuilding = (bui) => {
|
||||||
store.selectedBuilding = bui; // 改變 selectedBuilding,watch 會自動更新資料
|
store.selectedBuilding = bui; // 改變 selectedBuilding,watch 會自動更新資料
|
||||||
|
localStorage.setItem("CviBuilding", JSON.stringify(bui));
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -27,7 +27,24 @@
|
|||||||
"lastweek_electricity_consumption": "上周用电量",
|
"lastweek_electricity_consumption": "上周用电量",
|
||||||
"one_hour": "1小时",
|
"one_hour": "1小时",
|
||||||
"four_hour": "4小时",
|
"four_hour": "4小时",
|
||||||
"eight_hour": "8小时"
|
"eight_hour": "8小时",
|
||||||
|
"energy_ranking": "能耗排行",
|
||||||
|
"last_30_days_energy_trend": "近30天能耗趋势",
|
||||||
|
"today_energy_consumption": "本日能耗",
|
||||||
|
"this_month_energy_consumption": "本月能耗",
|
||||||
|
"relative_energy_consumption": "环比能耗",
|
||||||
|
"daily_relative_change": "日环比",
|
||||||
|
"weekly_relative_change": "周环比",
|
||||||
|
"monthly_relative_change": "月环比",
|
||||||
|
"yearly_relative_change": "年环比",
|
||||||
|
"today": "今日",
|
||||||
|
"yesterday": "昨日",
|
||||||
|
"this_week": "本周",
|
||||||
|
"last_week": "上周",
|
||||||
|
"this_month": "本月",
|
||||||
|
"last_month": "上月",
|
||||||
|
"this_year": "今年",
|
||||||
|
"last_year": "去年"
|
||||||
},
|
},
|
||||||
"history": {
|
"history": {
|
||||||
"title": "历史资料",
|
"title": "历史资料",
|
||||||
@ -358,12 +375,29 @@
|
|||||||
"confirm": "确认",
|
"confirm": "确认",
|
||||||
"restore": "复原",
|
"restore": "复原",
|
||||||
"stop_edit": "停止修改",
|
"stop_edit": "停止修改",
|
||||||
"start_edit": "开始修改"
|
"start_edit": "开始修改",
|
||||||
|
"convert": "轉換"
|
||||||
},
|
},
|
||||||
"msg": {
|
"msg": {
|
||||||
"sure_to_delete": "是否确认删除该项目?",
|
"sure_to_delete": "是否确认删除该项目?",
|
||||||
"sure_to_delete_permanent": "是否确认永久删除该项目?",
|
"sure_to_delete_permanent": "是否确认永久删除该项目?",
|
||||||
"delete_success": "删除成功",
|
"delete_success": "删除成功",
|
||||||
"delete_failed": "删除失败"
|
"delete_failed": "删除失败"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"MQTT_parse": "MQTT 解析",
|
||||||
|
"schema": "架构",
|
||||||
|
"point": "点位",
|
||||||
|
"description": "描述",
|
||||||
|
"IoT_point_name": "IoT 点位名称",
|
||||||
|
"IoT_point_code": "IoT 点位代号",
|
||||||
|
"number_of_decimal_places": "小数位数",
|
||||||
|
"boolean_value": "布林值",
|
||||||
|
"hide_point": "点位显示",
|
||||||
|
"schema_name": "架构名称",
|
||||||
|
"IoT_point_structure": "IoT点位结构",
|
||||||
|
"system_point_name": "系统点位名称",
|
||||||
|
"json_format_text": "请贴上 JSON 格式数据",
|
||||||
|
"json_click_text": "请在左侧输入JSON并点选转换按钮"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,24 @@
|
|||||||
"lastweek_electricity_consumption": "上週用電量",
|
"lastweek_electricity_consumption": "上週用電量",
|
||||||
"one_hour": "1小時",
|
"one_hour": "1小時",
|
||||||
"four_hour": "4小時",
|
"four_hour": "4小時",
|
||||||
"eight_hour": "8小時"
|
"eight_hour": "8小時",
|
||||||
|
"energy_ranking": "能耗排行",
|
||||||
|
"last_30_days_energy_trend": "近30天能耗趨勢",
|
||||||
|
"today_energy_consumption": "本日能耗",
|
||||||
|
"this_month_energy_consumption": "本月能耗",
|
||||||
|
"relative_energy_consumption": "環比能耗",
|
||||||
|
"daily_relative_change": "日環比",
|
||||||
|
"weekly_relative_change": "周環比",
|
||||||
|
"monthly_relative_change": "月環比",
|
||||||
|
"yearly_relative_change": "年環比",
|
||||||
|
"today": "今日",
|
||||||
|
"yesterday": "昨日",
|
||||||
|
"this_week": "本周",
|
||||||
|
"last_week": "上周",
|
||||||
|
"this_month": "本月",
|
||||||
|
"last_month": "上月",
|
||||||
|
"this_year": "今年",
|
||||||
|
"last_year": "去年"
|
||||||
},
|
},
|
||||||
"history": {
|
"history": {
|
||||||
"title": "歷史資料",
|
"title": "歷史資料",
|
||||||
@ -102,12 +119,12 @@
|
|||||||
"elec_price_list": "電價表",
|
"elec_price_list": "電價表",
|
||||||
"residential": "住宅型",
|
"residential": "住宅型",
|
||||||
"standard": "標準型",
|
"standard": "標準型",
|
||||||
"simple_elec_price_two_stage":"簡易型時間電價二段式",
|
"simple_elec_price_two_stage": "簡易型時間電價二段式",
|
||||||
"simple_elec_price_three_stage":"簡易型時間電價三段式",
|
"simple_elec_price_three_stage": "簡易型時間電價三段式",
|
||||||
"classification":"分類",
|
"classification": "分類",
|
||||||
"summer_months":"夏月",
|
"summer_months": "夏月",
|
||||||
"non_summer_months":"非夏月",
|
"non_summer_months": "非夏月",
|
||||||
"time_outside_summer_months":"夏月以外的時間",
|
"time_outside_summer_months": "夏月以外的時間",
|
||||||
"basic_elec_charge": "基本電費",
|
"basic_elec_charge": "基本電費",
|
||||||
"charged_per_household": "按戶計收",
|
"charged_per_household": "按戶計收",
|
||||||
"per_household_month": "每戶每月",
|
"per_household_month": "每戶每月",
|
||||||
@ -358,12 +375,29 @@
|
|||||||
"confirm": "確認",
|
"confirm": "確認",
|
||||||
"restore": "復原",
|
"restore": "復原",
|
||||||
"stop_edit": "停止修改",
|
"stop_edit": "停止修改",
|
||||||
"start_edit": "開始修改"
|
"start_edit": "開始修改",
|
||||||
|
"convert":"轉換"
|
||||||
},
|
},
|
||||||
"msg": {
|
"msg": {
|
||||||
"sure_to_delete": "是否確認刪除該項目?",
|
"sure_to_delete": "是否確認刪除該項目?",
|
||||||
"sure_to_delete_permanent": "是否確認永久刪除該項目?",
|
"sure_to_delete_permanent": "是否確認永久刪除該項目?",
|
||||||
"delete_success": "刪除成功",
|
"delete_success": "刪除成功",
|
||||||
"delete_failed": "刪除失敗"
|
"delete_failed": "刪除失敗"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"MQTT_parse": "MQTT 解析",
|
||||||
|
"schema":"架構",
|
||||||
|
"point":"點位",
|
||||||
|
"description":"描述",
|
||||||
|
"IoT_point_name":"IoT 點位名稱",
|
||||||
|
"IoT_point_code":"IoT 點位代號",
|
||||||
|
"number_of_decimal_places":"小數位數",
|
||||||
|
"boolean_value":"布林值",
|
||||||
|
"hide_point":"點位顯示",
|
||||||
|
"schema_name":"架構名稱",
|
||||||
|
"IoT_point_structure" :"IoT點位結構",
|
||||||
|
"system_point_name":"系統點位名稱",
|
||||||
|
"json_format_text": "請貼上 JSON 格式數據",
|
||||||
|
"json_click_text": "請在左側輸入JSON並點選轉換按鈕"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,37 @@
|
|||||||
"description": "File size cannot exceed 10MB",
|
"description": "File size cannot exceed 10MB",
|
||||||
"formats": "File formats"
|
"formats": "File formats"
|
||||||
},
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"yesterday_today": "Yesterday / Today's",
|
||||||
|
"elec_consumption_comparison": "Electricity Consumption Comparison",
|
||||||
|
"elec_consumption_comparison_trend": "Electricity Consumption Comparison Trend",
|
||||||
|
"electricity_consumption": "electricity consumption",
|
||||||
|
"today_electricity_consumption": "Today’s electricity consumption",
|
||||||
|
"yesterday_electricity_consumption": "Yesterday’s electricity consumption",
|
||||||
|
"this_last_week": "This Week's / Last Week's",
|
||||||
|
"thisweek_electricity_consumption": "This week’s electricity consumption",
|
||||||
|
"lastweek_electricity_consumption": "Last week’s electricity consumption",
|
||||||
|
"one_hour": "1 hour",
|
||||||
|
"four_hour": "4 hour",
|
||||||
|
"eight_hour": "8 hour",
|
||||||
|
"energy_ranking": "Energy consumption ranking",
|
||||||
|
"last_30_days_energy_trend": "Energy consumption trend for the past 30 days",
|
||||||
|
"today_energy_consumption": "Today",
|
||||||
|
"this_month_energy_consumption": "This month",
|
||||||
|
"relative_energy_consumption": "Energy consumption trend",
|
||||||
|
"daily_relative_change": "Daily",
|
||||||
|
"weekly_relative_change": "Weekly",
|
||||||
|
"monthly_relative_change": "Monthly",
|
||||||
|
"yearly_relative_change": "Yearly",
|
||||||
|
"today": "Today",
|
||||||
|
"yesterday": "Yesterday",
|
||||||
|
"this_week": "This week",
|
||||||
|
"last_week": "Last week",
|
||||||
|
"this_month": "This month",
|
||||||
|
"last_month": "Last month",
|
||||||
|
"this_year": "This year",
|
||||||
|
"last_year": "Last year"
|
||||||
|
},
|
||||||
"history": {
|
"history": {
|
||||||
"title": "Historical Data",
|
"title": "Historical Data",
|
||||||
"building_name": "Building",
|
"building_name": "Building",
|
||||||
@ -33,20 +64,6 @@
|
|||||||
"end_date": "End date",
|
"end_date": "End date",
|
||||||
"end_time": "End time"
|
"end_time": "End time"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
|
||||||
"yesterday_today": "Yesterday / Today's",
|
|
||||||
"elec_consumption_comparison": "Electricity Consumption Comparison",
|
|
||||||
"elec_consumption_comparison_trend": "Electricity Consumption Comparison Trend",
|
|
||||||
"electricity_consumption": "electricity consumption",
|
|
||||||
"today_electricity_consumption": "Today’s electricity consumption",
|
|
||||||
"yesterday_electricity_consumption": "Yesterday’s electricity consumption",
|
|
||||||
"this_last_week": "This Week's / Last Week's",
|
|
||||||
"thisweek_electricity_consumption": "This week’s electricity consumption",
|
|
||||||
"lastweek_electricity_consumption": "Last week’s electricity consumption",
|
|
||||||
"one_hour": "1 hour",
|
|
||||||
"four_hour": "4 hour",
|
|
||||||
"eight_hour": "8 hour"
|
|
||||||
},
|
|
||||||
"system": {
|
"system": {
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"details": "Details",
|
"details": "Details",
|
||||||
@ -358,12 +375,29 @@
|
|||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"restore": "Restore",
|
"restore": "Restore",
|
||||||
"stop_edit": "Stop editing",
|
"stop_edit": "Stop editing",
|
||||||
"start_edit": "Start editing"
|
"start_edit": "Start editing",
|
||||||
|
"convert": "Convert"
|
||||||
},
|
},
|
||||||
"msg": {
|
"msg": {
|
||||||
"sure_to_delete": "Are you sure to delete this item?",
|
"sure_to_delete": "Are you sure to delete this item?",
|
||||||
"sure_to_delete_permanent": "Are you sure you want to permanently delete this item?",
|
"sure_to_delete_permanent": "Are you sure you want to permanently delete this item?",
|
||||||
"delete_success": "Delete successfully",
|
"delete_success": "Delete successfully",
|
||||||
"delete_failed": "Delete failed"
|
"delete_failed": "Delete failed"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"MQTT_parse": "MQTT Parse",
|
||||||
|
"schema": "Schema",
|
||||||
|
"point": "Point",
|
||||||
|
"description": "Description",
|
||||||
|
"IoT_point_name": "IoT Point Name",
|
||||||
|
"IoT_point_code": "IoT Point Code",
|
||||||
|
"number_of_decimal_places": "Number of Decimal Places",
|
||||||
|
"boolean_value": "Boolean Value",
|
||||||
|
"hide_point": "Point Display",
|
||||||
|
"schema_name": "Schema name",
|
||||||
|
"IoT_point_structure": "IoT Point Structure",
|
||||||
|
"system_point_name": "System Point Name",
|
||||||
|
"json_format_text": "Please paste JSON format data",
|
||||||
|
"json_click_text": "Please enter JSON on the left and click the conversion button"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,11 @@ import {
|
|||||||
faDownload,
|
faDownload,
|
||||||
faStream,
|
faStream,
|
||||||
faSave,
|
faSave,
|
||||||
faCrown
|
faCrown,
|
||||||
|
faClock,
|
||||||
|
faCheckCircle
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { faCircle } from "@fortawesome/free-regular-svg-icons";
|
||||||
|
|
||||||
/* add icons to the library */
|
/* add icons to the library */
|
||||||
library.add(
|
library.add(
|
||||||
@ -124,7 +127,10 @@ library.add(
|
|||||||
faDownload,
|
faDownload,
|
||||||
faStream,
|
faStream,
|
||||||
faSave,
|
faSave,
|
||||||
faCrown
|
faCrown,
|
||||||
|
faClock,
|
||||||
|
faCheckCircle,
|
||||||
|
faCircle
|
||||||
);
|
);
|
||||||
|
|
||||||
export default library;
|
export default library;
|
||||||
|
@ -48,13 +48,14 @@ const useBuildingStore = defineStore("buildingInfo", () => {
|
|||||||
const res = await getBuildings();
|
const res = await getBuildings();
|
||||||
buildings.value = res.data;
|
buildings.value = res.data;
|
||||||
if (res.data.length > 0 && !selectedBuilding.value) {
|
if (res.data.length > 0 && !selectedBuilding.value) {
|
||||||
selectedBuilding.value = res.data[0]; // 預設選第一個建築
|
const storedBuilding = JSON.parse(localStorage.getItem("CviBuilding"));
|
||||||
|
selectedBuilding.value = storedBuilding || res.data[0]; // 預設選第一個建築
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 獲取樓層資料
|
// 獲取樓層資料
|
||||||
const fetchFloorList = async () => {
|
const fetchFloorList = async (building_guid) => {
|
||||||
const res = await getAssetFloorList();
|
const res = await getAssetFloorList(building_guid);
|
||||||
floorList.value = res.data[0]?.floors.map((d) => ({
|
floorList.value = res.data[0]?.floors.map((d) => ({
|
||||||
...d,
|
...d,
|
||||||
title: d.full_name,
|
title: d.full_name,
|
||||||
@ -75,7 +76,7 @@ const useBuildingStore = defineStore("buildingInfo", () => {
|
|||||||
// 當 selectedBuilding 改變時,更新 floorList 和 deptList
|
// 當 selectedBuilding 改變時,更新 floorList 和 deptList
|
||||||
watch(selectedBuilding, async (newBuilding) => {
|
watch(selectedBuilding, async (newBuilding) => {
|
||||||
if (newBuilding) {
|
if (newBuilding) {
|
||||||
await Promise.all([fetchFloorList(), fetchDepartmentList()]);
|
await Promise.all([fetchFloorList(newBuilding.building_guid), fetchDepartmentList()]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, provide, onMounted, watch } from "vue";
|
import { ref, provide, onMounted, watch, computed } from "vue";
|
||||||
import AssetMainList from "./components/AssetMainList.vue";
|
import AssetMainList from "./components/AssetMainList.vue";
|
||||||
import AssetSubList from "./components/AssetSubList.vue";
|
import AssetSubList from "./components/AssetSubList.vue";
|
||||||
import AssetTable from "./components/AssetTable.vue";
|
import AssetTable from "./components/AssetTable.vue";
|
||||||
@ -12,8 +12,6 @@ const { searchParams, changeParams } = useSearchParam();
|
|||||||
const companyOptions = ref([]);
|
const companyOptions = ref([]);
|
||||||
const iotSchemaOptions = ref([]);
|
const iotSchemaOptions = ref([]);
|
||||||
const elecTypeOptions = ref([]);
|
const elecTypeOptions = ref([]);
|
||||||
const departmentList = ref([]);
|
|
||||||
const floors = ref([]);
|
|
||||||
const getCompany = async () => {
|
const getCompany = async () => {
|
||||||
const res = await getOperationCompanyList();
|
const res = await getOperationCompanyList();
|
||||||
companyOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
companyOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
||||||
@ -27,11 +25,12 @@ const getElecType = async () => {
|
|||||||
elecTypeOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
elecTypeOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const departmentList = computed(() => storeBuild.deptList);
|
||||||
|
const floors = computed(() => storeBuild.floorList);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getCompany();
|
getCompany();
|
||||||
getElecType();
|
getElecType();
|
||||||
floors.value = storeBuild.floorList;
|
|
||||||
departmentList.value = storeBuild.deptList;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -9,23 +9,11 @@ import dayjs from "dayjs";
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openToast, cancelToastOpen } = inject("app_toast");
|
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||||
|
const { companyOptions, departmentList, floors } = inject("asset_modal_options");
|
||||||
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
||||||
const { searchParams, changeParams } = useSearchParam();
|
const { searchParams, changeParams } = useSearchParam();
|
||||||
|
|
||||||
const companyOptions = ref([]);
|
|
||||||
const getCompany = async () => {
|
|
||||||
const res = await getOperationCompanyList();
|
|
||||||
companyOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const floors = ref([]);
|
|
||||||
const totalCoordinates = ref({});
|
const totalCoordinates = ref({});
|
||||||
const getFloors = async () => {
|
|
||||||
const res = await getAssetFloorList();
|
|
||||||
floors.value = res.data[0]?.floors.map((d) => ({ ...d, key: d.floor_guid }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const tableData = ref([]);
|
const tableData = ref([]);
|
||||||
const getAssetData = async () => {
|
const getAssetData = async () => {
|
||||||
totalCoordinates.value = {}; // 在獲取新數據之前清空 totalCoordinates
|
totalCoordinates.value = {}; // 在獲取新數據之前清空 totalCoordinates
|
||||||
@ -45,6 +33,7 @@ const getAssetData = async () => {
|
|||||||
floor: floors.value.find(({ floor_guid }) => d.floor_guid === floor_guid)
|
floor: floors.value.find(({ floor_guid }) => d.floor_guid === floor_guid)
|
||||||
?.full_name,
|
?.full_name,
|
||||||
company: companyOptions.value.find(({ id }) => d.operation_id === id),
|
company: companyOptions.value.find(({ id }) => d.operation_id === id),
|
||||||
|
department: departmentList.value.find(({ id }) => d.department_id === id)?.name,
|
||||||
buying_date: d?.buying_date
|
buying_date: d?.buying_date
|
||||||
? dayjs(d?.buying_date).format("YYYY-MM-DD")
|
? dayjs(d?.buying_date).format("YYYY-MM-DD")
|
||||||
: "",
|
: "",
|
||||||
@ -56,17 +45,15 @@ const getAssetData = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getCompany();
|
|
||||||
await getFloors();
|
|
||||||
getAssetData();
|
getAssetData();
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
// {
|
||||||
title: t("assetManagement.device_number"),
|
// title: t("assetManagement.device_number"),
|
||||||
key: "device_number",
|
// key: "device_number",
|
||||||
class: "break-all",
|
// class: "break-all",
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: t("assetManagement.device_name"),
|
title: t("assetManagement.device_name"),
|
||||||
key: "full_name",
|
key: "full_name",
|
||||||
@ -83,6 +70,11 @@ const columns = computed(() => [
|
|||||||
filter: true,
|
filter: true,
|
||||||
sort: true,
|
sort: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t("assetManagement.department"),
|
||||||
|
key: "department",
|
||||||
|
filter: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t("assetManagement.device_coordinate"),
|
title: t("assetManagement.device_coordinate"),
|
||||||
key: "device_coordinate",
|
key: "device_coordinate",
|
||||||
|
@ -2,12 +2,11 @@
|
|||||||
import { onMounted, ref, inject, watch, computed } from "vue";
|
import { onMounted, ref, inject, watch, computed } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import mqtt from "mqtt";
|
import mqtt from "mqtt";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openToast, cancelToastOpen } = inject("app_toast");
|
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||||
const { formState } = inject(
|
const { formState } = inject("asset_table_modal_form");
|
||||||
"asset_table_modal_form"
|
|
||||||
);
|
|
||||||
const BASEURL = import.meta.env.VITE_MQTT_BASEURL;
|
const BASEURL = import.meta.env.VITE_MQTT_BASEURL;
|
||||||
// MQTT相關
|
// MQTT相關
|
||||||
const mqttClient = ref(null); // MQTT客戶端
|
const mqttClient = ref(null); // MQTT客戶端
|
||||||
@ -26,10 +25,13 @@ const openModal = () => {
|
|||||||
const connectMqtt = () => {
|
const connectMqtt = () => {
|
||||||
const topic = formState.value.topic || ""; // 取得主題
|
const topic = formState.value.topic || ""; // 取得主題
|
||||||
const mqttHost = `${BASEURL}`;
|
const mqttHost = `${BASEURL}`;
|
||||||
const protocol = import.meta.env.MODE === "production" ? "wss" : "ws"; // 根據伺服器配置,需要設置為 "ws" 或 "wss"
|
const protocol = "wss"; // 根據伺服器配置,需要設置為 "ws" 或 "wss"
|
||||||
mqttClient.value = mqtt.connect(mqttHost, {
|
mqttClient.value = mqtt.connect(mqttHost, {
|
||||||
protocol,
|
protocol,
|
||||||
reconnectPeriod: 1000, // 每秒嘗試重新連線
|
reconnectPeriod: 1000, // 每秒嘗試重新連線
|
||||||
|
username: "admin", // MQTT 帳號
|
||||||
|
password: "mjmadmin@99", // MQTT 密碼
|
||||||
|
port: 443,
|
||||||
});
|
});
|
||||||
|
|
||||||
mqttClient.value.on("connect", () => {
|
mqttClient.value.on("connect", () => {
|
||||||
@ -47,7 +49,14 @@ const connectMqtt = () => {
|
|||||||
|
|
||||||
mqttClient.value.on("message", (topic, message) => {
|
mqttClient.value.on("message", (topic, message) => {
|
||||||
// 儲存接收到的訊息
|
// 儲存接收到的訊息
|
||||||
receivedMessages.value.push({ topic, message: message.toString() });
|
const now = dayjs(); // 使用 dayjs() 取得當前時間
|
||||||
|
const timestamp = now.format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
|
||||||
|
receivedMessages.value.push({
|
||||||
|
topic,
|
||||||
|
message: message.toString(),
|
||||||
|
timestamp: timestamp,
|
||||||
|
});
|
||||||
clearInterval(timer); // 收到訊息後清除倒計時
|
clearInterval(timer); // 收到訊息後清除倒計時
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -88,7 +97,7 @@ const onCancel = () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex w-72">
|
<div class="flex w-72">
|
||||||
<Input :value="formState" name="topic" >
|
<Input :value="formState" name="topic">
|
||||||
<template #topLeft>MQTT Topic</template>
|
<template #topLeft>MQTT Topic</template>
|
||||||
</Input>
|
</Input>
|
||||||
<button type="button" class="btn btn-add mt-11 ms-1" @click="openModal">
|
<button type="button" class="btn btn-add mt-11 ms-1" @click="openModal">
|
||||||
@ -107,8 +116,14 @@ const onCancel = () => {
|
|||||||
:key="index"
|
:key="index"
|
||||||
class="bg-base-200 rounded-md text-wrap shadow shadow-slate-400 p-4 my-2 me-2"
|
class="bg-base-200 rounded-md text-wrap shadow shadow-slate-400 p-4 my-2 me-2"
|
||||||
>
|
>
|
||||||
<strong class=" text-base block text-info mb-2">{{ message.topic }} :</strong>
|
<strong class="text-base block text-info mb-2"
|
||||||
<p class=" text-sm break-words">{{ message.message }}</p>
|
>{{ message.topic }} :</strong
|
||||||
|
>
|
||||||
|
<p class="text-sm break-words">{{ message.message }}</p>
|
||||||
|
<p class="text-xs text-slate-200 pt-2">
|
||||||
|
<FontAwesomeIcon :icon="['fas', 'clock']" class="me-1" />
|
||||||
|
{{ message.timestamp }}
|
||||||
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,35 +2,37 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import BarChart from "@/components/chart/BarChart.vue";
|
import BarChart from "@/components/chart/BarChart.vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
const chartData = ref([
|
const chartData = ref([
|
||||||
{
|
{
|
||||||
category: "日環比",
|
category: t("dashboard.daily_relative_change"),
|
||||||
this: 230.68,
|
this: 230.68,
|
||||||
last: 377.33,
|
last: 377.33,
|
||||||
change: -39,
|
change: -39,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
category: "周環比",
|
category: t("dashboard.weekly_relative_change"),
|
||||||
this: 608.01,
|
this: 608.01,
|
||||||
last: 2711.09,
|
last: 2711.09,
|
||||||
change: -78,
|
change: -78,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
category: "月環比",
|
category: t("dashboard.monthly_relative_change"),
|
||||||
this: 6473.8,
|
this: 6473.8,
|
||||||
last: 12701.69,
|
last: 12701.69,
|
||||||
change: -49,
|
change: -49,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
category: "年環比",
|
category: t("dashboard.yearly_relative_change"),
|
||||||
this: 46687.17,
|
this: 46687.17,
|
||||||
last: null,
|
last: null,
|
||||||
change: null,
|
change: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const labels = ["今日", "昨日", "本周", "上周", "本月", "上月", "今年", "去年"];
|
const labels = [t("dashboard.today"), t("dashboard.yesterday"), t("dashboard.this_week"), t("dashboard.last_week"), t("dashboard.this_month"), t("dashboard.last_month"), t("dashboard.this_year"), t("dashboard.last_year")];
|
||||||
const barWidth = 30; // Set barWidth
|
const barWidth = 30; // Set barWidth
|
||||||
|
|
||||||
const barChartOptions = ref({
|
const barChartOptions = ref({
|
||||||
@ -161,7 +163,7 @@ const barChartOptions = ref({
|
|||||||
<div class="flex flex-wrap">
|
<div class="flex flex-wrap">
|
||||||
<div class="w-full chart-data relative px-8 py-3">
|
<div class="w-full chart-data relative px-8 py-3">
|
||||||
<div class="flex flex-wrap items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between">
|
||||||
<h2 class="font-light">環比能耗</h2>
|
<h2 class="font-light">{{ $t("dashboard.relative_energy_consumption") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-[180px]">
|
<div class="h-[180px]">
|
||||||
<BarChart
|
<BarChart
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
// 假資料 - 設備能耗列表
|
// 假資料 - 設備能耗列表
|
||||||
const mockEnergyData = {
|
const mockEnergyData = {
|
||||||
monthly: [
|
monthly: [
|
||||||
@ -47,9 +48,9 @@ const getCurrentEnergyData = () => {
|
|||||||
<div class="state-box">
|
<div class="state-box">
|
||||||
<!-- 標題和切換按鈕 -->
|
<!-- 標題和切換按鈕 -->
|
||||||
<div class="flex justify-between items-center mb-4">
|
<div class="flex justify-between items-center mb-4">
|
||||||
<h2 class="font-light w-1/2 relative">當月能耗排行</h2>
|
<h2 class="font-light relative">{{$t("dashboard.energy_ranking")}}</h2>
|
||||||
<button @click="toggleEnergyType" class="btn btn-info btn-xs">
|
<button @click="toggleEnergyType" class="btn btn-info btn-xs">
|
||||||
{{ currentEnergyType === "monthly" ? "本日能耗" : "當月能耗" }}
|
{{ currentEnergyType === "monthly" ? t("dashboard.today_energy_consumption") : t("dashboard.this_month_energy_consumption") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted, watch } from "vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import BarChart from "@/components/chart/BarChart.vue";
|
import BarChart from "@/components/chart/BarChart.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
@ -113,24 +113,25 @@ const generateCylinderChartOption = (data) => {
|
|||||||
|
|
||||||
const weekComparisonOption = generateCylinderChartOption(energyData.value);
|
const weekComparisonOption = generateCylinderChartOption(energyData.value);
|
||||||
|
|
||||||
onMounted(() => {
|
watch(
|
||||||
if (
|
() => [storeBuild.deptList.length, storeBuild.floorList.length],
|
||||||
storeBuild.deptList.length > 0 &&
|
([deptListLength, floorListLength]) => {
|
||||||
storeBuild.floorList.length > 0
|
if (deptListLength > 0 && floorListLength > 0) {
|
||||||
) {
|
formState.value = {
|
||||||
formState.value = {
|
...formState.value,
|
||||||
...formState.value,
|
floorId: storeBuild.floorList[0].key,
|
||||||
floorId: storeBuild.floorList[0].key,
|
deptId: storeBuild.deptList[0].key,
|
||||||
deptId: storeBuild.deptList[0].key,
|
};
|
||||||
};
|
}
|
||||||
}
|
},
|
||||||
});
|
{ immediate: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full chart-data relative px-8 py-1">
|
<div class="w-full chart-data relative px-8 py-1">
|
||||||
<div class="flex flex-wrap items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between">
|
||||||
<h2 class="font-light">近30天能耗趨勢</h2>
|
<h2 class="font-light">{{$t("dashboard.last_30_days_energy_trend")}}</h2>
|
||||||
<div class="flex items-center w-52 gap-4">
|
<div class="flex items-center w-52 gap-4">
|
||||||
<Select
|
<Select
|
||||||
:value="formState"
|
:value="formState"
|
||||||
|
@ -5,121 +5,6 @@ import { twMerge } from "tailwind-merge";
|
|||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
const store = useBuildingStore();
|
const store = useBuildingStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// 假資料
|
|
||||||
const mockData = ref([
|
|
||||||
{
|
|
||||||
title: "Air Detection System",
|
|
||||||
icon: "temperature-high",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: "Dust",
|
|
||||||
sub_system_tag: "EM",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Lighting System",
|
|
||||||
icon: "lightbulb",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: "LS",
|
|
||||||
sub_system_tag: "ECLS",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Air Condition System",
|
|
||||||
icon: "fan",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: "ME",
|
|
||||||
sub_system_tag: "TH",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Electricity System",
|
|
||||||
icon: "bolt",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: "EE",
|
|
||||||
sub_system_tag: "ECP3",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Elevator System",
|
|
||||||
icon: "building",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "High Voltage Switchboard",
|
|
||||||
icon: "charging-station",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Low Voltage Switchboard",
|
|
||||||
icon: "charging-station",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Water Supply System",
|
|
||||||
icon: "tint",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Sewage And Wastewater Equipment",
|
|
||||||
icon: "water",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Emergency Generator",
|
|
||||||
icon: "car-battery",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Fire Equipment",
|
|
||||||
icon: "fire-extinguisher",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "CCTV System",
|
|
||||||
icon: "video",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Access Control System",
|
|
||||||
icon: "door-open",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Shutdown System",
|
|
||||||
icon: "car",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Emergency Rescue System",
|
|
||||||
icon: "exclamation-triangle",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Air Supply Aand Exhaust System",
|
|
||||||
icon: "wind",
|
|
||||||
isError: false,
|
|
||||||
main_system_tag: null,
|
|
||||||
sub_system_tag: null,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const navigateToSubSystem = (mainSystemId, subSystemId) => {
|
const navigateToSubSystem = (mainSystemId, subSystemId) => {
|
||||||
router.push({
|
router.push({
|
||||||
|
@ -7,7 +7,7 @@ import { getCarbonValue } from "@/apis/energy";
|
|||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
const store = useBuildingStore();
|
const store = useBuildingStore();
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const { taipower_data } = inject("energy_data");
|
const { taipower_data, carbonValue } = inject("energy_data");
|
||||||
const carbonData = ref(null);
|
const carbonData = ref(null);
|
||||||
const defaultChartOption = ref({
|
const defaultChartOption = ref({
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@ -86,6 +86,7 @@ const getData = async () => {
|
|||||||
if (store.selectedBuilding.building_guid) {
|
if (store.selectedBuilding.building_guid) {
|
||||||
const res = await getCarbonValue(store.selectedBuilding.building_guid);
|
const res = await getCarbonValue(store.selectedBuilding.building_guid);
|
||||||
carbonData.value = res.data[0];
|
carbonData.value = res.data[0];
|
||||||
|
carbonValue.value = res.data[0].coefficient;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, nextTick, computed } from "vue";
|
import { ref, onMounted, nextTick, watch, inject } from "vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import { getRealTimeDist } from "@/apis/energy";
|
import { getRealTimeDist } from "@/apis/energy";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { search_data } = inject("energy_data");
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const chartDiv = ref(null);
|
const chartDiv = ref(null);
|
||||||
@ -39,7 +39,7 @@ const chartOption = {
|
|||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
},
|
},
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: 'gradient',
|
color: "gradient",
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
curveness: 0.5,
|
curveness: 0.5,
|
||||||
},
|
},
|
||||||
@ -47,50 +47,74 @@ const chartOption = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async (value) => {
|
||||||
const res = await getRealTimeDist();
|
const res = await getRealTimeDist(value);
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess && res.data && res.data.length !== 0) {
|
||||||
const rawData = res.data;
|
const rawData = res.data;
|
||||||
const totalValue = rawData.reduce((acc, item) => acc + item.value, 0);
|
if (rawData) {
|
||||||
|
const totalValue = rawData.reduce((acc, item) => acc + item.value, 0);
|
||||||
|
|
||||||
const sortedData = [...rawData].sort((a, b) => b.value - a.value);
|
const sortedData = [...rawData].sort((a, b) => b.value - a.value);
|
||||||
// 構造 data 節點
|
// 構造 data 節點
|
||||||
const data = [
|
const data = [
|
||||||
{ name: "Total", value: totalValue, percentage: 100 },
|
{ name: "Total", value: totalValue, percentage: 100 },
|
||||||
...sortedData.map((item) => ({
|
...sortedData.map((item) => ({
|
||||||
name: item.key,
|
name: item.key,
|
||||||
|
value: item.value,
|
||||||
|
percentage: item.percentage,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
// 構造 links 連結
|
||||||
|
const links = sortedData.map((item, index) => ({
|
||||||
|
source: "Total",
|
||||||
|
target: item.key,
|
||||||
value: item.value,
|
value: item.value,
|
||||||
percentage: item.percentage,
|
percentage: item.percentage,
|
||||||
})),
|
}));
|
||||||
];
|
|
||||||
|
|
||||||
// 構造 links 連結
|
const colors = [
|
||||||
const links = sortedData.map((item, index) => ({
|
"#45f4ef",
|
||||||
source: "Total",
|
"#17CEE3",
|
||||||
target: item.key,
|
"#E4EA00",
|
||||||
value: item.value,
|
"#62E39A",
|
||||||
percentage: item.percentage,
|
"#E9971F",
|
||||||
}));
|
"#E52EFF",
|
||||||
|
];
|
||||||
const colors = ["#45f4ef", "#17CEE3", "#E4EA00", "#62E39A", "#E9971F", "#E52EFF"];
|
// 更新 chartOption
|
||||||
// 更新 chartOption
|
chartOption.series[0].data = data.map((item, index) => ({
|
||||||
chartOption.series[0].data = data.map((item, index) => ({
|
...item,
|
||||||
...item,
|
itemStyle: {
|
||||||
itemStyle: {
|
color: colors[index % colors.length], // 節點顏色
|
||||||
color: colors[index % colors.length], // 節點顏色
|
},
|
||||||
},
|
}));
|
||||||
}));
|
chartOption.series[0].links = links;
|
||||||
chartOption.series[0].links = links;
|
|
||||||
|
|
||||||
|
// 初始化圖表
|
||||||
|
const myChart = echarts.init(chartDiv.value);
|
||||||
|
myChart.setOption(chartOption);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// 初始化圖表
|
// 初始化圖表
|
||||||
const myChart = echarts.init(chartDiv.value);
|
echarts.init(chartDiv.value).clear();
|
||||||
myChart.setOption(chartOption);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
watch(
|
||||||
loadData();
|
search_data,
|
||||||
});
|
(newValue, oldValue) => {
|
||||||
|
if (
|
||||||
|
newValue.building_guid &&
|
||||||
|
JSON.stringify(newValue) !== JSON.stringify(oldValue)
|
||||||
|
) {
|
||||||
|
loadData(newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, provide } from "vue";
|
import { ref, computed, provide, watch } from "vue";
|
||||||
import ImmediateDemandChart from "./ImmediateDemandChart.vue";
|
import ImmediateDemandChart from "./ImmediateDemandChart.vue";
|
||||||
import ElecConsumption from "./ElecConsumption.vue";
|
import ElecConsumption from "./ElecConsumption.vue";
|
||||||
import UsageInformation from "./UsageInformation.vue";
|
import UsageInformation from "./UsageInformation.vue";
|
||||||
@ -28,25 +28,80 @@ const {
|
|||||||
} = useActiveBtn("multiple");
|
} = useActiveBtn("multiple");
|
||||||
|
|
||||||
const taipower_data = ref([]);
|
const taipower_data = ref([]);
|
||||||
const getData = async () => {
|
const carbonValue = ref(null);
|
||||||
const res = await getTaipower();
|
const search_data = computed(() => {
|
||||||
|
return {
|
||||||
|
coefficient: carbonValue.value,
|
||||||
|
building_guid: storeBuild.selectedBuilding?.building_guid || null,
|
||||||
|
department_id_list: selectedDeptItems.value.map((item) => item.key),
|
||||||
|
floor_guid_list: selectedFloorItems.value.map((item) => item.key),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getData = async (value) => {
|
||||||
|
const res = await getTaipower(value);
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
taipower_data.value = res.data;
|
taipower_data.value = res.data
|
||||||
|
? res.data.sort((a, b) => a.month.localeCompare(b.month))
|
||||||
|
: [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
watch(
|
||||||
getData();
|
search_data,
|
||||||
setDeptItems(storeBuild.deptList);
|
(newValue, oldValue) => {
|
||||||
setFloorItems(storeBuild.floorList);
|
if (
|
||||||
});
|
newValue.building_guid &&
|
||||||
|
newValue.coefficient &&
|
||||||
|
JSON.stringify(newValue) !== JSON.stringify(oldValue)
|
||||||
|
) {
|
||||||
|
getData(newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
provide("energy_data", { taipower_data });
|
watch(
|
||||||
|
() => storeBuild.floorList,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
const floorList = newValue.map((d) => ({
|
||||||
|
...d,
|
||||||
|
active: true,
|
||||||
|
}));
|
||||||
|
setFloorItems(floorList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => storeBuild.deptList,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
const deptList = newValue.map((d) => ({
|
||||||
|
...d,
|
||||||
|
active: true,
|
||||||
|
}));
|
||||||
|
setDeptItems(deptList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
provide("energy_data", { taipower_data, search_data, carbonValue });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-wrap items-center mb-4">
|
<div class="flex flex-wrap items-center mb-4">
|
||||||
<div class="w-full border border-info px-4 py-2 rounded my-3">
|
<div class="w-full border border-info px-4 py-2 rounded mt-3">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="text-md font-extrabold">{{ $t("energy.floor") }} :</span>
|
<span class="text-md font-extrabold">{{ $t("energy.floor") }} :</span>
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BarChart from "@/components/chart/BarChart.vue";
|
import BarChart from "@/components/chart/BarChart.vue";
|
||||||
import { ref, onMounted, computed } from "vue";
|
import { ref, watch, computed, inject } from "vue";
|
||||||
import { getElecUseDay } from "@/apis/energy";
|
import { getElecUseDay } from "@/apis/energy";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { search_data } = inject("energy_data");
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dataSource = ref([]);
|
const dataSource = ref([]);
|
||||||
const dateRange = ref({
|
const dateRange = ref({
|
||||||
@ -107,10 +107,12 @@ const chartOption = computed(() => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async (value) => {
|
||||||
const res = await getElecUseDay();
|
const res = await getElecUseDay(value);
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
dataSource.value = res.data.map((d) => ({ ...d, key: d.id }));
|
dataSource.value = res.data
|
||||||
|
.sort((a, b) => a.time.localeCompare(b.time))
|
||||||
|
.map((d) => ({ ...d, key: d.id }));
|
||||||
|
|
||||||
const dates = res.data.map((d) => d.time.split(" ")[0]);
|
const dates = res.data.map((d) => d.time.split(" ")[0]);
|
||||||
dateRange.value = {
|
dateRange.value = {
|
||||||
@ -120,9 +122,21 @@ const loadData = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
watch(
|
||||||
loadData();
|
search_data,
|
||||||
});
|
(newValue, oldValue) => {
|
||||||
|
if (
|
||||||
|
newValue.building_guid &&
|
||||||
|
JSON.stringify(newValue) !== JSON.stringify(oldValue)
|
||||||
|
) {
|
||||||
|
loadData(newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -19,7 +19,7 @@ const calculateData = () => {
|
|||||||
item.month.startsWith(currentYear)
|
item.month.startsWith(currentYear)
|
||||||
);
|
);
|
||||||
|
|
||||||
const totalElecBills = filteredData.reduce((sum, item) => sum + item.kWh, 0);
|
const totalElecBills = filteredData.reduce((sum, item) => sum + item.costTotal, 0);
|
||||||
const latestMonthData = filteredData[filteredData.length - 1];
|
const latestMonthData = filteredData[filteredData.length - 1];
|
||||||
const latestMonth = latestMonthData ? latestMonthData.month : "";
|
const latestMonth = latestMonthData ? latestMonthData.month : "";
|
||||||
const monthDays = latestMonth ? daysInMonth(latestMonth) : 0;
|
const monthDays = latestMonth ? daysInMonth(latestMonth) : 0;
|
||||||
|
@ -3,7 +3,7 @@ import { computed, defineProps, inject, ref, watch } from "vue";
|
|||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { getHistoryData, getHistoryExportData } from "@/apis/history";
|
import { getHistoryData, getHistoryExportData } from "@/apis/history";
|
||||||
import useSearchParam from "@/hooks/useSearchParam";
|
import useSearchParam from "@/hooks/useSearchParam";
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { searchParams } = useSearchParam();
|
const { searchParams } = useSearchParam();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -26,7 +26,6 @@ const cancelToastOpen = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const submit = async (e, type = "") => {
|
const submit = async (e, type = "") => {
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
e?.stopPropagation();
|
e?.stopPropagation();
|
||||||
@ -53,8 +52,13 @@ const submit = async (e, type = "") => {
|
|||||||
} else {
|
} else {
|
||||||
const res = await getHistoryData({
|
const res = await getHistoryData({
|
||||||
...searchParams.value,
|
...searchParams.value,
|
||||||
Type: 1,
|
Type:
|
||||||
table_type:route.params.type
|
route.params.type != 1
|
||||||
|
? 2
|
||||||
|
: searchParams.value.Type
|
||||||
|
? searchParams.value.Type
|
||||||
|
: 1,
|
||||||
|
table_type: route.params.type,
|
||||||
});
|
});
|
||||||
updateTableData(res.data);
|
updateTableData(res.data);
|
||||||
}
|
}
|
||||||
@ -82,7 +86,7 @@ const submitBtns = computed(() => [
|
|||||||
disabled: isSearchButtonDisabled.value,
|
disabled: isSearchButtonDisabled.value,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("button.export"),
|
title: t("button.export"),
|
||||||
key: "export",
|
key: "export",
|
||||||
icon: "download",
|
icon: "download",
|
||||||
btn: "btn-export",
|
btn: "btn-export",
|
||||||
@ -115,13 +119,18 @@ watch(
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Toast
|
<Toast
|
||||||
:content="isToastOpen.content"
|
:content="isToastOpen.content"
|
||||||
:open="isToastOpen.open"
|
:open="isToastOpen.open"
|
||||||
status="info"
|
status="info"
|
||||||
:cancel="cancelToastOpen"
|
:cancel="cancelToastOpen"
|
||||||
/>
|
/>
|
||||||
<ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" :withBtnClass="true"/>
|
<ButtonGroup
|
||||||
|
class="ml-5"
|
||||||
|
:items="submitBtns"
|
||||||
|
:withLine="false"
|
||||||
|
:withBtnClass="true"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
@ -64,7 +64,7 @@ const formatChartData = (data) => {
|
|||||||
const seriesKey = `${item.device_name || ""}_${item.item_name || ""}`;
|
const seriesKey = `${item.device_name || ""}_${item.item_name || ""}`;
|
||||||
acc[seriesKey] = {
|
acc[seriesKey] = {
|
||||||
timestamps: item.data.map((d) =>
|
timestamps: item.data.map((d) =>
|
||||||
dayjs(d.timestamp).format("YYYY-MM-DD HH:mm")
|
dayjs(d.time).format("YYYY-MM-DD HH:mm")
|
||||||
),
|
),
|
||||||
values: item.data.map((d) =>
|
values: item.data.map((d) =>
|
||||||
d.value == "無資料" ? null : parseFloat(d.value)
|
d.value == "無資料" ? null : parseFloat(d.value)
|
||||||
@ -73,7 +73,6 @@ const formatChartData = (data) => {
|
|||||||
minValue: parseFloat(item.minValue),
|
minValue: parseFloat(item.minValue),
|
||||||
averageValue: parseFloat(item.averageValue),
|
averageValue: parseFloat(item.averageValue),
|
||||||
};
|
};
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
@ -86,8 +85,7 @@ watch(
|
|||||||
const formattedData = formatChartData(newData);
|
const formattedData = formatChartData(newData);
|
||||||
|
|
||||||
const series = Object.keys(formattedData).map((seriesKey, index) => {
|
const series = Object.keys(formattedData).map((seriesKey, index) => {
|
||||||
const { maxValue, minValue, averageValue } =
|
const { maxValue, minValue, averageValue } = formattedData[seriesKey];
|
||||||
formattedData[seriesKey];
|
|
||||||
return {
|
return {
|
||||||
name: seriesKey,
|
name: seriesKey,
|
||||||
type: "line",
|
type: "line",
|
||||||
|
@ -65,7 +65,7 @@ const getElecType = async () => {
|
|||||||
...d,
|
...d,
|
||||||
title: d.name,
|
title: d.name,
|
||||||
key: d.id,
|
key: d.id,
|
||||||
active: false,
|
active: true,
|
||||||
}));
|
}));
|
||||||
setElecTypeItems(elecType);
|
setElecTypeItems(elecType);
|
||||||
};
|
};
|
||||||
@ -152,8 +152,23 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => storeBuild.deptList,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
const deptList = newValue.map((d) => ({
|
||||||
|
...d,
|
||||||
|
active: true,
|
||||||
|
}));
|
||||||
|
setDeptItems(deptList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setDeptItems(storeBuild.deptList);
|
|
||||||
getElecType();
|
getElecType();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -4,14 +4,40 @@ import useSearchParam from "@/hooks/useSearchParam";
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import useActiveBtn from "@/hooks/useActiveBtn";
|
||||||
|
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const { searchParams, changeParams } = useSearchParam();
|
const { searchParams, changeParams } = useSearchParam();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const {
|
||||||
|
items: searchTypeItems,
|
||||||
|
changeActiveBtn: changeTypeActiveBtn,
|
||||||
|
setItems: setTypeItems,
|
||||||
|
selectedBtn: selectedTypeItems,
|
||||||
|
} = useActiveBtn();
|
||||||
|
|
||||||
const itemsForStartTime = ref([]);
|
const itemsForStartTime = ref([]);
|
||||||
|
|
||||||
const itemsForEndTime = ref();
|
const itemsForEndTime = ref();
|
||||||
|
|
||||||
const initializeItems = () => {
|
const initializeItems = () => {
|
||||||
|
setTypeItems([
|
||||||
|
{
|
||||||
|
title: t("history.date_range"),
|
||||||
|
key: 1,
|
||||||
|
active: searchParams.value.Type
|
||||||
|
? parseInt(searchParams.value.Type) === 1
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("history.time_range"),
|
||||||
|
key: 2,
|
||||||
|
active: searchParams.value.Type
|
||||||
|
? parseInt(searchParams.value.Type) === 2
|
||||||
|
: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
itemsForStartTime.value = [
|
itemsForStartTime.value = [
|
||||||
{
|
{
|
||||||
key: "Start_date",
|
key: "Start_date",
|
||||||
@ -56,10 +82,10 @@ const initializeItems = () => {
|
|||||||
watch(
|
watch(
|
||||||
() => route.params.type,
|
() => route.params.type,
|
||||||
() => {
|
() => {
|
||||||
initializeItems();
|
initializeItems();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -101,6 +127,13 @@ watch(
|
|||||||
deep: true,
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(selectedTypeItems, (newValue) => {
|
||||||
|
changeParams({
|
||||||
|
...searchParams.value,
|
||||||
|
Type: newValue.key,
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -108,6 +141,16 @@ watch(
|
|||||||
<h2 class="text-lg font-bold ps-2 whitespace-nowrap">
|
<h2 class="text-lg font-bold ps-2 whitespace-nowrap">
|
||||||
{{ $t("history.date_range") }} :
|
{{ $t("history.date_range") }} :
|
||||||
</h2>
|
</h2>
|
||||||
|
<ButtonGroup
|
||||||
|
v-if="route.params.type == 1"
|
||||||
|
:items="searchTypeItems"
|
||||||
|
:withLine="true"
|
||||||
|
:onclick="
|
||||||
|
(e, item) => {
|
||||||
|
changeTypeActiveBtn(item);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
<DateGroup class="mr-3" :items="itemsForStartTime" :withLine="true" />
|
<DateGroup class="mr-3" :items="itemsForStartTime" :withLine="true" />
|
||||||
<DateGroup :items="itemsForEndTime" :withLine="true" />
|
<DateGroup :items="itemsForEndTime" :withLine="true" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,13 +6,14 @@ import useSearchParam from "@/hooks/useSearchParam";
|
|||||||
import { getHistorySideBar } from "@/apis/history";
|
import { getHistorySideBar } from "@/apis/history";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const storeBuild = useBuildingStore();
|
||||||
|
const buildingGuid = computed(() => storeBuild.selectedBuilding?.building_guid);
|
||||||
const { searchParams, changeParams } = useSearchParam();
|
const { searchParams, changeParams } = useSearchParam();
|
||||||
const { deptData, elecType, subSystem } = inject("energy_table_data");
|
const { deptData, elecType, subSystem } = inject("energy_table_data");
|
||||||
const selectedBuilding = ref([]);
|
const selectedBuilding = ref([]);
|
||||||
const deviceData = ref([]);
|
const deviceData = ref([]);
|
||||||
const searchTerm = ref(""); //搜尋文字
|
const searchTerm = ref(""); //搜尋文字
|
||||||
const activeSearchTerm = ref("");
|
const activeSearchTerm = ref("");
|
||||||
|
|
||||||
const getDeviceData = async ({
|
const getDeviceData = async ({
|
||||||
sub_system_tag,
|
sub_system_tag,
|
||||||
department_id,
|
department_id,
|
||||||
@ -22,6 +23,7 @@ const getDeviceData = async ({
|
|||||||
sub_system_tag,
|
sub_system_tag,
|
||||||
department_id,
|
department_id,
|
||||||
elec_type_id,
|
elec_type_id,
|
||||||
|
building_guid: buildingGuid.value,
|
||||||
});
|
});
|
||||||
deviceData.value = (res.data || []).map((building) => ({
|
deviceData.value = (res.data || []).map((building) => ({
|
||||||
building_tag: building.building_tag,
|
building_tag: building.building_tag,
|
||||||
|
@ -47,7 +47,8 @@ const getElecType = async () => {
|
|||||||
const elecType = res.data.map((d, index) => ({
|
const elecType = res.data.map((d, index) => ({
|
||||||
...d,
|
...d,
|
||||||
title: d.name,
|
title: d.name,
|
||||||
key: d.id
|
key: d.id,
|
||||||
|
active: true,
|
||||||
}));
|
}));
|
||||||
setElecItems(elecType);
|
setElecItems(elecType);
|
||||||
};
|
};
|
||||||
@ -99,9 +100,39 @@ watch(
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => storeBuild.deptList,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
const deptList = newValue.map((d) => ({
|
||||||
|
...d,
|
||||||
|
active: true,
|
||||||
|
}));
|
||||||
|
setDeptItems(deptList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => storeBuild.floorList,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
const floorList = newValue.map((d) => ({
|
||||||
|
...d,
|
||||||
|
active: true,
|
||||||
|
}));
|
||||||
|
setFloorItems(floorList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setDeptItems(storeBuild.deptList);
|
|
||||||
setFloorItems(storeBuild.floorList);
|
|
||||||
getElecType();
|
getElecType();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -65,7 +65,7 @@ const updateFileList = (files) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
onSubSysClick(options.value[0].key);
|
// onSubSysClick(options.value[0].key);
|
||||||
updateFileList([]);
|
updateFileList([]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -122,29 +122,15 @@ const getPoint = async (deviceList) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
selectedPoints,
|
[selectedPoints, selectedDeptItems],
|
||||||
(newVal, oldVal) => {
|
([newPoints, newDeptItems], [oldPoints, oldDeptItems]) => {
|
||||||
changeParams({
|
changeParams({
|
||||||
...searchParams.value,
|
...searchParams.value,
|
||||||
Points: newVal.map((d) => d.points),
|
Points: newPoints.map((d) => d.points),
|
||||||
|
Dept: newDeptItems.map((d) => d.id),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
{
|
{ immediate: true }
|
||||||
immediate: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
selectedDeptItems,
|
|
||||||
(newVal, oldVal) => {
|
|
||||||
changeParams({
|
|
||||||
...searchParams.value,
|
|
||||||
Dept: newVal.map((d) => d.id),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const form = ref(null);
|
const form = ref(null);
|
||||||
@ -154,14 +140,32 @@ watch(searchParams, (newVal, oldValue) => {
|
|||||||
(newVal?.Device_list?.length && typeof oldValue.Device_list === "string") ||
|
(newVal?.Device_list?.length && typeof oldValue.Device_list === "string") ||
|
||||||
(newVal?.Device_list?.length && !oldValue?.Device_list?.length)
|
(newVal?.Device_list?.length && !oldValue?.Device_list?.length)
|
||||||
) {
|
) {
|
||||||
getPoint(
|
if (newVal?.Device_list[0]!==null){
|
||||||
typeof newVal.Device_list == "string"
|
getPoint(
|
||||||
? [newVal.Device_list]
|
typeof newVal.Device_list == "string"
|
||||||
: newVal.Device_list
|
? [newVal.Device_list]
|
||||||
);
|
: newVal.Device_list
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.deptList,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
const deptList = newValue.map((d) => ({
|
||||||
|
...d,
|
||||||
|
active: true,
|
||||||
|
}));
|
||||||
|
setDeptItems(deptList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setMainSysItems(
|
setMainSysItems(
|
||||||
store.mainSubSys.map(({ full_name, main_system_tag }, index) => ({
|
store.mainSubSys.map(({ full_name, main_system_tag }, index) => ({
|
||||||
@ -170,13 +174,6 @@ onMounted(() => {
|
|||||||
active: index === 0,
|
active: index === 0,
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
setDeptItems(
|
|
||||||
store.deptList.map((d, index) => ({
|
|
||||||
...d,
|
|
||||||
title: d.name,
|
|
||||||
key: d.id,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
|
@ -5,17 +5,23 @@ import useBuildingStore from "@/stores/useBuildingStore";
|
|||||||
import useSearchParam from "@/hooks/useSearchParam";
|
import useSearchParam from "@/hooks/useSearchParam";
|
||||||
import { getHistorySideBar } from "@/apis/history";
|
import { getHistorySideBar } from "@/apis/history";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { searchParams, changeParams } = useSearchParam();
|
const { searchParams, changeParams } = useSearchParam();
|
||||||
|
const storeBuild = useBuildingStore();
|
||||||
const selectedBuilding = ref([]);
|
const selectedBuilding = ref([]);
|
||||||
const deviceData = ref([]);
|
const deviceData = ref([]);
|
||||||
const searchTerm = ref(""); //搜尋文字
|
const searchTerm = ref(""); //搜尋文字
|
||||||
const activeSearchTerm = ref("");
|
const activeSearchTerm = ref("");
|
||||||
|
|
||||||
const getDeviceData = async (sub_system_tag,department_id) => {
|
const getDeviceData = async (sub_system_tag, department_id) => {
|
||||||
const deptArray = department_id? department_id.map(Number):null;
|
const deptArray = department_id ? department_id.map(Number) : [];
|
||||||
const res = await getHistorySideBar({sub_system_tag: sub_system_tag,department_id:deptArray});
|
const res = await getHistorySideBar({
|
||||||
|
sub_system_tag: sub_system_tag,
|
||||||
|
department_id: deptArray,
|
||||||
|
elec_type_id: [],
|
||||||
|
building_guid: storeBuild.selectedBuilding?.building_guid || null,
|
||||||
|
});
|
||||||
deviceData.value = res.data.map((building) => ({
|
deviceData.value = res.data.map((building) => ({
|
||||||
building_tag: building.building_tag,
|
building_tag: building.building_tag,
|
||||||
building_name: building.building_name,
|
building_name: building.building_name,
|
||||||
@ -30,9 +36,7 @@ const getDeviceData = async (sub_system_tag,department_id) => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
selectedBuilding.value = res.data.map((d) => d.building_tag);
|
selectedBuilding.value = res.data.map((d) => d.building_tag);
|
||||||
changeSelected(
|
changeSelected([res.data[0]?.floor_list[0]?.device_list[0]?.device_number]);
|
||||||
[res.data[0]?.floor_list[0]?.device_list[0]?.device_number]
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const sysIsExisted = (building_tag) => {
|
const sysIsExisted = (building_tag) => {
|
||||||
@ -57,7 +61,7 @@ watch(
|
|||||||
newVal.sub_system_tag &&
|
newVal.sub_system_tag &&
|
||||||
newVal.sub_system_tag != oldVal?.sub_system_tag
|
newVal.sub_system_tag != oldVal?.sub_system_tag
|
||||||
) {
|
) {
|
||||||
getDeviceData(newVal.sub_system_tag,searchParams.value.Dept);
|
getDeviceData(newVal.sub_system_tag, searchParams.value.Dept);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -69,11 +73,8 @@ watch(
|
|||||||
watch(
|
watch(
|
||||||
searchParams,
|
searchParams,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
if (
|
if (newVal.Dept && newVal.Dept?.length != oldVal?.Dept?.length) {
|
||||||
newVal.Dept &&
|
getDeviceData(searchParams.value.sub_system_tag, newVal.Dept);
|
||||||
newVal.Dept?.length != oldVal?.Dept?.length
|
|
||||||
) {
|
|
||||||
getDeviceData(searchParams.value.sub_system_tag,newVal.Dept);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -182,15 +183,19 @@ const changeSelected = (Device_list, renew = false) => {
|
|||||||
|
|
||||||
const filteredDeviceData = computed(() => {
|
const filteredDeviceData = computed(() => {
|
||||||
if (!activeSearchTerm.value) return deviceData.value;
|
if (!activeSearchTerm.value) return deviceData.value;
|
||||||
return deviceData.value.map((building) => ({
|
return deviceData.value
|
||||||
...building,
|
.map((building) => ({
|
||||||
floors: building.floors.map((floor) => ({
|
...building,
|
||||||
...floor,
|
floors: building.floors
|
||||||
devices: floor.devices.filter((device) =>
|
.map((floor) => ({
|
||||||
device.device_name.includes(activeSearchTerm.value)
|
...floor,
|
||||||
),
|
devices: floor.devices.filter((device) =>
|
||||||
})).filter(floor => floor.devices.length > 0)
|
device.device_name.includes(activeSearchTerm.value)
|
||||||
})).filter(building => building.floors.length > 0);
|
),
|
||||||
|
}))
|
||||||
|
.filter((floor) => floor.devices.length > 0),
|
||||||
|
}))
|
||||||
|
.filter((building) => building.floors.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSearch = (e) => {
|
const handleSearch = (e) => {
|
||||||
@ -222,7 +227,10 @@ const handleInput = (e) => {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<ul class="menu text-lg">
|
<ul class="menu text-lg">
|
||||||
<template v-for="building in filteredDeviceData" :key="building.building_tag">
|
<template
|
||||||
|
v-for="building in filteredDeviceData"
|
||||||
|
:key="building.building_tag"
|
||||||
|
>
|
||||||
<li>
|
<li>
|
||||||
<details :open="selectedBuilding.includes(building.building_tag)">
|
<details :open="selectedBuilding.includes(building.building_tag)">
|
||||||
<summary>
|
<summary>
|
||||||
|
@ -9,6 +9,7 @@ import Floors from "./components/Floors.vue";
|
|||||||
import Building from "./components/Building.vue";
|
import Building from "./components/Building.vue";
|
||||||
import ElecPriceManagement from "./components/ElecPriceManagement.vue";
|
import ElecPriceManagement from "./components/ElecPriceManagement.vue";
|
||||||
import MQTTList from "./components/MQTTList.vue";
|
import MQTTList from "./components/MQTTList.vue";
|
||||||
|
import Demand from "./components/Demand.vue";
|
||||||
// import PointList from "./components/PointList.vue";
|
// import PointList from "./components/PointList.vue";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -31,6 +32,8 @@ const updateComponent = () => {
|
|||||||
currentComponent.value = ElecPriceManagement;
|
currentComponent.value = ElecPriceManagement;
|
||||||
} else if (sub_system_id === "MQTT_Result") {
|
} else if (sub_system_id === "MQTT_Result") {
|
||||||
currentComponent.value = MQTTList;
|
currentComponent.value = MQTTList;
|
||||||
|
} else if (sub_system_id === "Demand") {
|
||||||
|
currentComponent.value = Demand;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
169
src/views/setting/components/Demand.vue
Normal file
169
src/views/setting/components/Demand.vue
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, inject, computed, watch } from "vue";
|
||||||
|
import { getAssetList, postAssetElecSetting } from "@/apis/asset";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
|
import { getElecTypeList } from "@/apis/asset";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||||
|
const storeBuild = useBuildingStore();
|
||||||
|
const departmentList = computed(() => storeBuild.deptList);
|
||||||
|
const floors = computed(() => storeBuild.floorList);
|
||||||
|
const elecType = ref([]);
|
||||||
|
const isEditing = ref(false);
|
||||||
|
const tableData = ref([]);
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
title: t("assetManagement.operation"),
|
||||||
|
key: "operation",
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("assetManagement.device_number"),
|
||||||
|
key: "device_number",
|
||||||
|
class: "break-all",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("assetManagement.device_name"),
|
||||||
|
key: "full_name",
|
||||||
|
filter: true,
|
||||||
|
class: "break-all",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("assetManagement.floor"),
|
||||||
|
key: "floor",
|
||||||
|
filter: true,
|
||||||
|
sort: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("assetManagement.department"),
|
||||||
|
key: "department",
|
||||||
|
filter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("energy.electricity_classification"),
|
||||||
|
key: "elecType",
|
||||||
|
filter: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const getElecType = async () => {
|
||||||
|
const res = await getElecTypeList();
|
||||||
|
elecType.value = res.data.map((d, index) => ({
|
||||||
|
...d,
|
||||||
|
key: d.id,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAssetData = async () => {
|
||||||
|
// Electricity Meter P3
|
||||||
|
const res = await getAssetList(465);
|
||||||
|
if (res.isSuccess) {
|
||||||
|
tableData.value = res.data.map((d) => ({
|
||||||
|
...d,
|
||||||
|
key: d.id,
|
||||||
|
floor: floors.value.find(({ floor_guid }) => d.floor_guid === floor_guid)
|
||||||
|
?.full_name,
|
||||||
|
department: departmentList.value.find(({ id }) => d.department_id === id)
|
||||||
|
?.name,
|
||||||
|
elecType: elecType.value.find(({ id }) => d.elec_type_id === id)?.name,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onOk = async () => {
|
||||||
|
const formData = tableData.value.map((item) => ({
|
||||||
|
main_id: item.main_id,
|
||||||
|
is_demand: item.is_demand,
|
||||||
|
}));
|
||||||
|
const res = await postAssetElecSetting(formData);
|
||||||
|
if (res.isSuccess) {
|
||||||
|
onCancel();
|
||||||
|
} else {
|
||||||
|
openToast("error", res.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCancel = async () => {
|
||||||
|
isEditing.value = false;
|
||||||
|
await getAssetData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const Check = (id) => {
|
||||||
|
const items = tableData.value.find((d) => d.main_id === id);
|
||||||
|
items.is_demand = items.is_demand ? 0 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getElecType();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[floors, departmentList],
|
||||||
|
() => {
|
||||||
|
if (floors.value.length > 0 && departmentList.value.length > 0) {
|
||||||
|
getAssetData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-start items-center mt-10 mb-5">
|
||||||
|
<h3 class="text-xl mr-5">電表</h3>
|
||||||
|
<button
|
||||||
|
v-if="!isEditing"
|
||||||
|
class="btn btn-sm btn-add mr-3"
|
||||||
|
@click.stop.prevent="isEditing = true"
|
||||||
|
>
|
||||||
|
<font-awesome-icon :icon="['fas', 'pencil-alt']" />{{
|
||||||
|
$t("button.start_edit")
|
||||||
|
}}
|
||||||
|
</button>
|
||||||
|
<template v-else>
|
||||||
|
<button class="btn btn-sm btn-add mr-3" @click.prevent="onOk()">
|
||||||
|
<font-awesome-icon :icon="['fas', 'save']" />{{ $t("button.confirm") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-sm btn-outline-info mr-3"
|
||||||
|
@click.stop.prevent="onCancel()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon :icon="['fas', 'times']" />{{ $t("button.cancel") }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<Table :columns="columns" :dataSource="tableData" class="mt-3">
|
||||||
|
<template #bodyCell="{ record, column, index }">
|
||||||
|
<template v-if="column.key === 'operation'">
|
||||||
|
<template v-if="!isEditing">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
v-if="record.is_demand"
|
||||||
|
:icon="['fas', 'check-circle']"
|
||||||
|
size="lg"
|
||||||
|
class="text-gray-300"
|
||||||
|
/>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
v-else
|
||||||
|
:icon="['far', 'circle']"
|
||||||
|
size="lg"
|
||||||
|
class="text-gray-300"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<Checkbox
|
||||||
|
:checked="record.is_demand"
|
||||||
|
@click="() => Check(record.main_id)"
|
||||||
|
></Checkbox>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ record[column.key] }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped></style>
|
@ -20,7 +20,7 @@ const onOk = async (sheet, data) => {
|
|||||||
getData();
|
getData();
|
||||||
onCancel(sheet);
|
onCancel(sheet);
|
||||||
} else {
|
} else {
|
||||||
openToast("error", res.msg, "#immediate_demand_add_item");
|
openToast("error", res.msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ watch(
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex justify-start items-center my-5">
|
<div class="flex justify-start items-center my-5">
|
||||||
<h3 class="text-xl mr-5">簡易型時間電價二段式</h3>
|
<h3 class="text-xl mr-5">{{ $t("energy.simple_elec_price_two_stage") }}</h3>
|
||||||
<button
|
<button
|
||||||
v-if="!sim2isEditing"
|
v-if="!sim2isEditing"
|
||||||
class="btn btn-sm btn-add mr-3"
|
class="btn btn-sm btn-add mr-3"
|
||||||
@ -81,16 +81,16 @@ watch(
|
|||||||
<table class="">
|
<table class="">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="6" class="bg-teal-800 bg-opacity-20">分類</th>
|
<th colspan="6" class="bg-teal-800 bg-opacity-20">{{ $t("energy.classification") }}</th>
|
||||||
<th class="bg-teal-800 bg-opacity-20">夏月<br />(6/1~9/30)</th>
|
<th class="bg-teal-800 bg-opacity-20">{{ $t("energy.summer_months") }}<br />(6/1~9/30)</th>
|
||||||
<th class="bg-teal-800 bg-opacity-20">非夏月<br />(夏月以外的時間)</th>
|
<th class="bg-teal-800 bg-opacity-20">{{ $t("energy.non_summer_months") }}<br />({{ $t("energy.time_outside_summer_months") }})</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-teal-800 bg-opacity-40">基本電費</td>
|
<td class="bg-teal-800 bg-opacity-40">{{$t("energy.fixed_elec_cost")}}</td>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">按戶計收</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">{{$t("energy.charged_per_household")}}</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">每戶每月</td>
|
<td class="bg-teal-800 bg-opacity-40">{{$t("energy.per_household_month")}}</td>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -100,12 +100,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="6">流動電費</td>
|
<td rowspan="6">{{$t("energy.var_elec_cost")}}</td>
|
||||||
<td rowspan="4">週一~週五</td>
|
<td rowspan="4">{{$t("energy.mon_to_friday")}}</td>
|
||||||
<td rowspan="2" class="bg-rose-600 bg-opacity-70">尖峰時間</td>
|
<td rowspan="2" class="bg-rose-600 bg-opacity-70">{{$t("energy.peak_hours")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">夏月</td>
|
<td class="bg-rose-600 bg-opacity-20">{{$t("energy.summer_months")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">09:00 ~ 24:00</td>
|
<td class="bg-rose-600 bg-opacity-20">09:00 ~ 24:00</td>
|
||||||
<td rowspan="5">每度</td>
|
<td rowspan="5">{{$t("energy.price_per_kwh")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -116,7 +116,7 @@ watch(
|
|||||||
<td class="bg-rose-600 bg-opacity-20">-</td>
|
<td class="bg-rose-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-rose-600 bg-opacity-20">非夏月</td>
|
<td class="bg-rose-600 bg-opacity-20">{{$t("energy.non_summer_months")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
06:00 ~ 11:00<br />14:00 ~ 24:00
|
06:00 ~ 11:00<br />14:00 ~ 24:00
|
||||||
</td>
|
</td>
|
||||||
@ -130,8 +130,8 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td rowspan="2" class="bg-green-600 bg-opacity-60">{{$t("energy.off_peak_hours")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">夏月</td>
|
<td class="bg-green-600 bg-opacity-20">{{$t("energy.summer_months")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -143,7 +143,7 @@ watch(
|
|||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-green-600 bg-opacity-20">非夏月</td>
|
<td class="bg-green-600 bg-opacity-20">{{$t("energy.non_summer_months")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
00:00 ~ 06:00<br />11:00 ~ 14:00
|
00:00 ~ 06:00<br />11:00 ~ 14:00
|
||||||
</td>
|
</td>
|
||||||
@ -157,9 +157,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>週六、週日<br />及離峰日</td>
|
<td>{{$t("energy.sat_sun_off_peak_days")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td class="bg-green-600 bg-opacity-60">{{$t("energy.off_peak_hours")}}</td>
|
||||||
<td colspan="2" class="bg-green-600 bg-opacity-20">全日</td>
|
<td colspan="2" class="bg-green-600 bg-opacity-20">{{$t("energy.all_day")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -176,11 +176,11 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4">每月總度數超過2000度之部分</td>
|
<td colspan="4">{{$t("energy.usage_over_2000kwh")}}</td>
|
||||||
<td>每度</td>
|
<td>{{$t("energy.price_per_kwh")}}</td>
|
||||||
<td colspan="2" class="!text-start">
|
<td colspan="2" class="!text-start">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
加
|
{{$t("energy.add")}}
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
v-model.number="sim2NewValue[7]"
|
v-model.number="sim2NewValue[7]"
|
||||||
@ -193,7 +193,7 @@ watch(
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="flex justify-start items-center mt-16">
|
<div class="flex justify-start items-center mt-16">
|
||||||
<h3 class="text-xl mr-5">簡易型時間電價三段式</h3>
|
<h3 class="text-xl mr-5"> {{$t("energy.simple_elec_price_three_stage")}}</h3>
|
||||||
<button
|
<button
|
||||||
v-if="!sim3isEditing"
|
v-if="!sim3isEditing"
|
||||||
class="btn btn-sm btn-add mr-3"
|
class="btn btn-sm btn-add mr-3"
|
||||||
@ -221,16 +221,16 @@ watch(
|
|||||||
<table class="my-5">
|
<table class="my-5">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="6" class="bg-teal-800 bg-opacity-20">分類</th>
|
<th colspan="6" class="bg-teal-800 bg-opacity-20">{{$t("energy.classification")}}</th>
|
||||||
<th class="bg-teal-800 bg-opacity-20">夏月<br />(6/1~9/30)</th>
|
<th class="bg-teal-800 bg-opacity-20">{{$t("energy.summer_months")}}<br />(6/1~9/30)</th>
|
||||||
<th class="bg-teal-800 bg-opacity-20">非夏月<br />(夏月以外的時間)</th>
|
<th class="bg-teal-800 bg-opacity-20">{{$t("energy.non_summer_months")}}<br />({{$t("energy.time_outside_summer_months")}})</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-teal-800 bg-opacity-40">基本電費</td>
|
<td class="bg-teal-800 bg-opacity-40">{{$t("energy.fixed_elec_cost")}}</td>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">按戶計收</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">{{$t("energy.charged_per_household")}}</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">每戶每月</td>
|
<td class="bg-teal-800 bg-opacity-40">{{$t("energy.per_household_month")}}</td>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -240,12 +240,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="7">流動電費</td>
|
<td rowspan="7">{{$t("energy.var_elec_cost")}}</td>
|
||||||
<td rowspan="5">週一~週五</td>
|
<td rowspan="5">{{$t("energy.mon_to_friday")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-70">尖峰時間</td>
|
<td class="bg-rose-600 bg-opacity-70">{{$t("energy.peak_hours")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">夏月</td>
|
<td class="bg-rose-600 bg-opacity-20">{{$t("energy.summer_months")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">16:00 ~ 22:00</td>
|
<td class="bg-rose-600 bg-opacity-20">16:00 ~ 22:00</td>
|
||||||
<td rowspan="6">每度</td>
|
<td rowspan="6">{{$t("energy.price_per_kwh")}}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -256,8 +256,8 @@ watch(
|
|||||||
<td class="bg-rose-600 bg-opacity-20">-</td>
|
<td class="bg-rose-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">半尖峰時間</td>
|
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">{{$t("energy.semi_peak_hours")}}</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">夏月</td>
|
<td class="bg-yellow-500 bg-opacity-20">{{$t("energy.summer_months")}}</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
09:00 ~ 16:00<br />22:00~24:00
|
09:00 ~ 16:00<br />22:00~24:00
|
||||||
</td>
|
</td>
|
||||||
@ -271,7 +271,7 @@ watch(
|
|||||||
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">非夏月</td>
|
<td class="bg-yellow-500 bg-opacity-20">{{$t("energy.non_summer_months")}}</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
06:00 ~ 11:00<br />14:00 ~ 24:00
|
06:00 ~ 11:00<br />14:00 ~ 24:00
|
||||||
</td>
|
</td>
|
||||||
@ -285,8 +285,8 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td rowspan="2" class="bg-green-600 bg-opacity-60">{{$t("energy.off_peak_hours")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">夏月</td>
|
<td class="bg-green-600 bg-opacity-20">{{$t("energy.summer_months")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -298,7 +298,7 @@ watch(
|
|||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-green-600 bg-opacity-20">非夏月</td>
|
<td class="bg-green-600 bg-opacity-20">{{$t("energy.non_summer_months")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
00:00 ~ 06:00<br />11:00 ~ 14:00
|
00:00 ~ 06:00<br />11:00 ~ 14:00
|
||||||
</td>
|
</td>
|
||||||
@ -312,9 +312,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>週六、週日<br />及離峰日</td>
|
<td>{{$t("energy.sat_sun_off_peak_days")}}</td>
|
||||||
<td colspan="2" class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td colspan="2" class="bg-green-600 bg-opacity-60">{{$t("energy.off_peak_hours")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">全日</td>
|
<td class="bg-green-600 bg-opacity-20">{{$t("energy.all_day")}}</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -331,11 +331,11 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4">每月總度數超過2000度之部分</td>
|
<td colspan="4">{{$t("energy.usage_over_2000kwh")}}</td>
|
||||||
<td>每度</td>
|
<td>{{$t("energy.price_per_kwh")}}</td>
|
||||||
<td colspan="2" class="!text-start">
|
<td colspan="2" class="!text-start">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
加
|
{{$t("energy.add")}}
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
v-model.number="sim3NewValue[8]"
|
v-model.number="sim3NewValue[8]"
|
||||||
|
@ -53,7 +53,9 @@ watch(
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex justify-start items-center my-5">
|
<div class="flex justify-start items-center my-5">
|
||||||
<h3 class="text-xl mr-5">標準型時間電價二段式</h3>
|
<h3 class="text-xl mr-5">
|
||||||
|
{{ $t("energy.standard_time_of_use_tariff_2_stage") }}
|
||||||
|
</h3>
|
||||||
<button
|
<button
|
||||||
v-if="!stand2isEditing"
|
v-if="!stand2isEditing"
|
||||||
class="btn btn-sm btn-add mr-3"
|
class="btn btn-sm btn-add mr-3"
|
||||||
@ -81,19 +83,33 @@ watch(
|
|||||||
<table class="">
|
<table class="">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="6" class="bg-teal-800 bg-opacity-20">分類</th>
|
<th colspan="6" class="bg-teal-800 bg-opacity-20">
|
||||||
<th class="bg-teal-800 bg-opacity-20">夏月<br />(6/1~9/30)</th>
|
{{ $t("energy.classification") }}
|
||||||
<th class="bg-teal-800 bg-opacity-20">非夏月<br />(夏月以外的時間)</th>
|
</th>
|
||||||
|
<th class="bg-teal-800 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}<br />(6/1~9/30)
|
||||||
|
</th>
|
||||||
|
<th class="bg-teal-800 bg-opacity-20">
|
||||||
|
{{ $t("energy.non_summer_months") }}<br />({{
|
||||||
|
$t("energy.time_outside_summer_months")
|
||||||
|
}})
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="6" class="bg-teal-800 bg-opacity-40">基本電費</td>
|
<td rowspan="6" class="bg-teal-800 bg-opacity-40">
|
||||||
<td colspan="2" rowspan="2" class="bg-teal-800 bg-opacity-40">
|
{{ $t("energy.fixed_elec_cost") }}
|
||||||
按戶計收
|
</td>
|
||||||
|
<td colspan="2" rowspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.charged_per_household") }}
|
||||||
|
</td>
|
||||||
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.single_phase") }}
|
||||||
|
</td>
|
||||||
|
<td rowspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.per_household_month") }}
|
||||||
</td>
|
</td>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">單相</td>
|
|
||||||
<td rowspan="2" class="bg-teal-800 bg-opacity-40">每戶每月</td>
|
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -103,7 +119,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">三相</td>
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.three_phase") }}
|
||||||
|
</td>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -113,8 +131,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">經常契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
<td rowspan="4" class="bg-teal-800 bg-opacity-40">每瓩每月</td>
|
{{ $t("energy.frequent_contract") }}
|
||||||
|
</td>
|
||||||
|
<td rowspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.per_kw_per_month") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -131,7 +153,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">非夏日契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.non_summer_contract") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">-</td>
|
<td class="bg-teal-800 bg-opacity-40">-</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
@ -142,7 +166,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">週六半尖峰契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.saturday_semi_peak_contract") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -159,7 +185,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">離峰契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.off_peak_contract") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -176,12 +204,16 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="9">流動電費</td>
|
<td rowspan="9">{{ $t("energy.var_elec_cost") }}</td>
|
||||||
<td rowspan="4">週一~週五</td>
|
<td rowspan="4">{{ $t("energy.mon_to_friday") }}</td>
|
||||||
<td rowspan="2" class="bg-rose-600 bg-opacity-70">尖峰時間</td>
|
<td rowspan="2" class="bg-rose-600 bg-opacity-70">
|
||||||
<td class="bg-rose-600 bg-opacity-20">夏月</td>
|
{{ $t("energy.peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">09:00 ~ 24:00</td>
|
<td class="bg-rose-600 bg-opacity-20">09:00 ~ 24:00</td>
|
||||||
<td rowspan="9">每度</td>
|
<td rowspan="9">{{ $t("energy.price_per_kwh") }}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -192,8 +224,12 @@ watch(
|
|||||||
<td class="bg-rose-600 bg-opacity-20">-</td>
|
<td class="bg-rose-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-rose-600 bg-opacity-20">非夏月</td>
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
<td class="bg-rose-600 bg-opacity-20">06:00 ~ 11:00<br />14:00~24:00</td>
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
|
06:00 ~ 11:00<br />14:00~24:00
|
||||||
|
</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">-</td>
|
<td class="bg-rose-600 bg-opacity-20">-</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -204,8 +240,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td rowspan="2" class="bg-green-600 bg-opacity-60">
|
||||||
<td class="bg-green-600 bg-opacity-20">夏月</td>
|
{{ $t("energy.off_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -217,7 +257,9 @@ watch(
|
|||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-green-600 bg-opacity-20">非夏月</td>
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
00:00 ~ 06:00<br />
|
00:00 ~ 06:00<br />
|
||||||
11:00 ~ 14:00
|
11:00 ~ 14:00
|
||||||
@ -232,9 +274,13 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="4">週六</td>
|
<td rowspan="4">{{ $t("energy.saturday") }}</td>
|
||||||
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">半尖峰時間</td>
|
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">
|
||||||
<td class="bg-yellow-400 bg-opacity-20">夏日</td>
|
{{ $t("energy.semi_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-yellow-400 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-yellow-400 bg-opacity-20">09:00 ~ 24:00</td>
|
<td class="bg-yellow-400 bg-opacity-20">09:00 ~ 24:00</td>
|
||||||
<td class="bg-yellow-400 bg-opacity-20">
|
<td class="bg-yellow-400 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -246,7 +292,9 @@ watch(
|
|||||||
<td class="bg-yellow-400 bg-opacity-20">-</td>
|
<td class="bg-yellow-400 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-yellow-400 bg-opacity-20">非夏日</td>
|
<td class="bg-yellow-400 bg-opacity-20">
|
||||||
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-yellow-400 bg-opacity-20">
|
<td class="bg-yellow-400 bg-opacity-20">
|
||||||
06:00 ~ 11:00<br />
|
06:00 ~ 11:00<br />
|
||||||
14:00 ~ 24:00
|
14:00 ~ 24:00
|
||||||
@ -261,8 +309,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td rowspan="2" class="bg-green-600 bg-opacity-60">
|
||||||
<td class="bg-green-600 bg-opacity-20">夏月</td>
|
{{ $t("energy.off_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -274,8 +326,12 @@ watch(
|
|||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-green-600 bg-opacity-20">非夏月</td>
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 06:00<br />11:00 ~ 14:00</td>
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
00:00 ~ 06:00<br />11:00 ~ 14:00
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -286,9 +342,13 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>週六、週日<br />及離峰日</td>
|
<td>{{ $t("energy.sat_sun_off_peak_days") }}</td>
|
||||||
<td class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td class="bg-green-600 bg-opacity-60">
|
||||||
<td colspan="2" class="bg-green-600 bg-opacity-20">全日</td>
|
{{ $t("energy.off_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td colspan="2" class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.all_day") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -308,7 +368,9 @@ watch(
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="flex justify-start items-center mt-14">
|
<div class="flex justify-start items-center mt-14">
|
||||||
<h3 class="text-xl mr-5">標準型時間電價三段式</h3>
|
<h3 class="text-xl mr-5">
|
||||||
|
{{ $t("energy.standard_time_of_use_tariff_3_stage") }}
|
||||||
|
</h3>
|
||||||
<button
|
<button
|
||||||
v-if="!stand3isEditing"
|
v-if="!stand3isEditing"
|
||||||
class="btn btn-sm btn-add mr-3"
|
class="btn btn-sm btn-add mr-3"
|
||||||
@ -336,17 +398,33 @@ watch(
|
|||||||
<table class="my-5">
|
<table class="my-5">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="6" class="bg-teal-800 bg-opacity-20">分類</th>
|
<th colspan="6" class="bg-teal-800 bg-opacity-20">
|
||||||
<th class="bg-teal-800 bg-opacity-20">夏月<br />(6/1~9/30)</th>
|
{{ $t("energy.classification") }}
|
||||||
<th class="bg-teal-800 bg-opacity-20">非夏月<br />(夏月以外的時間)</th>
|
</th>
|
||||||
|
<th class="bg-teal-800 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}<br />(6/1~9/30)
|
||||||
|
</th>
|
||||||
|
<th class="bg-teal-800 bg-opacity-20">
|
||||||
|
{{ $t("energy.non_summer_months") }}<br />({{
|
||||||
|
$t("energy.time_outside_summer_months")
|
||||||
|
}})
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="6" class="bg-teal-800 bg-opacity-40">基本電費</td>
|
<td rowspan="6" class="bg-teal-800 bg-opacity-40">
|
||||||
<td colspan="2" rowspan="2" class="bg-teal-800 bg-opacity-40">按戶計收</td>
|
{{ $t("energy.fixed_elec_cost") }}
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">單相</td>
|
</td>
|
||||||
<td rowspan="2" class="bg-teal-800 bg-opacity-40">每戶每月</td>
|
<td colspan="2" rowspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.charged_per_household") }}
|
||||||
|
</td>
|
||||||
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.single_phase") }}
|
||||||
|
</td>
|
||||||
|
<td rowspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.per_household_month") }}
|
||||||
|
</td>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -356,7 +434,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">三相</td>
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.three_phase") }}
|
||||||
|
</td>
|
||||||
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
<td colspan="2" class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -366,8 +446,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">經常契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
<td rowspan="4" class="bg-teal-800 bg-opacity-40">每瓩每月</td>
|
{{ $t("energy.frequent_contract") }}
|
||||||
|
</td>
|
||||||
|
<td rowspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.per_kw_per_month") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -384,7 +468,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">非夏日契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.non_summer_contract") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -401,7 +487,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">週六半尖峰契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.saturday_semi_peak_contract") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -418,7 +506,9 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="bg-teal-800 bg-opacity-40">離峰契約</td>
|
<td colspan="4" class="bg-teal-800 bg-opacity-40">
|
||||||
|
{{ $t("energy.off_peak_contract") }}
|
||||||
|
</td>
|
||||||
<td class="bg-teal-800 bg-opacity-40">
|
<td class="bg-teal-800 bg-opacity-40">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -435,12 +525,14 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="10">流動電費</td>
|
<td rowspan="10">{{ $t("energy.var_elec_cost") }}</td>
|
||||||
<td rowspan="5">週一~週五</td>
|
<td rowspan="5">{{ $t("energy.mon_to_friday") }}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-70">尖峰時間</td>
|
<td class="bg-rose-600 bg-opacity-70">{{ $t("energy.peak_hours") }}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">夏月</td>
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">16:00 ~ 22:00</td>
|
<td class="bg-rose-600 bg-opacity-20">16:00 ~ 22:00</td>
|
||||||
<td rowspan="10">每度</td>
|
<td rowspan="10">{{ $t("energy.price_per_kwh") }}</td>
|
||||||
<td class="bg-rose-600 bg-opacity-20">
|
<td class="bg-rose-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -451,9 +543,15 @@ watch(
|
|||||||
<td class="bg-rose-600 bg-opacity-20">-</td>
|
<td class="bg-rose-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">半尖峰時間</td>
|
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">
|
||||||
<td class="bg-yellow-500 bg-opacity-20">夏月</td>
|
{{ $t("energy.semi_peak_hours") }}
|
||||||
<td class="bg-yellow-500 bg-opacity-20">09:00 ~ 16:00<br />22:00 ~ 24:00</td>
|
</td>
|
||||||
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
|
09:00 ~ 16:00<br />22:00 ~ 24:00
|
||||||
|
</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -464,8 +562,12 @@ watch(
|
|||||||
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">非夏月</td>
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
<td class="bg-yellow-500 bg-opacity-20">06:00 ~ 11:00<br />14:00 ~ 24:00</td>
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
|
06:00 ~ 11:00<br />14:00 ~ 24:00
|
||||||
|
</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -476,8 +578,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td rowspan="2" class="bg-green-600 bg-opacity-60">
|
||||||
<td class="bg-green-600 bg-opacity-20">夏月</td>
|
{{ $t("energy.off_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -489,7 +595,9 @@ watch(
|
|||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-green-600 bg-opacity-20">非夏月</td>
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
00:00 ~ 06:00<br />
|
00:00 ~ 06:00<br />
|
||||||
11:00 ~ 14:00
|
11:00 ~ 14:00
|
||||||
@ -504,9 +612,13 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="4">週六</td>
|
<td rowspan="4">{{ $t("energy.saturday") }}</td>
|
||||||
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">半尖峰時間</td>
|
<td rowspan="2" class="bg-yellow-400 bg-opacity-80">
|
||||||
<td class="bg-yellow-500 bg-opacity-20">夏日</td>
|
{{ $t("energy.semi_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">09:00 ~ 24:00</td>
|
<td class="bg-yellow-500 bg-opacity-20">09:00 ~ 24:00</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -518,7 +630,9 @@ watch(
|
|||||||
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
<td class="bg-yellow-500 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">非夏日</td>
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-yellow-500 bg-opacity-20">
|
<td class="bg-yellow-500 bg-opacity-20">
|
||||||
06:00 ~ 11:00<br />
|
06:00 ~ 11:00<br />
|
||||||
14:00 ~ 24:00
|
14:00 ~ 24:00
|
||||||
@ -533,8 +647,12 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td rowspan="2" class="bg-green-600 bg-opacity-60">
|
||||||
<td class="bg-green-600 bg-opacity-20">夏月</td>
|
{{ $t("energy.off_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.summer_months") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
<td class="bg-green-600 bg-opacity-20">00:00 ~ 09:00</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -546,8 +664,12 @@ watch(
|
|||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bg-green-600 bg-opacity-20">非夏月</td>
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<td class="bg-green-600 bg-opacity-20">00:00 ~ 06:00<br />11:00 ~ 14:00</td>
|
{{ $t("energy.non_summer_months") }}
|
||||||
|
</td>
|
||||||
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
|
00:00 ~ 06:00<br />11:00 ~ 14:00
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">-</td>
|
<td class="bg-green-600 bg-opacity-20">-</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
@ -558,9 +680,13 @@ watch(
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>週日及離峰日</td>
|
<td>{{ $t("energy.sunday_and_off_peak_days") }}</td>
|
||||||
<td class="bg-green-600 bg-opacity-60">離峰時間</td>
|
<td class="bg-green-600 bg-opacity-60">
|
||||||
<td colspan="2" class="bg-green-600 bg-opacity-20">全日</td>
|
{{ $t("energy.off_peak_hours") }}
|
||||||
|
</td>
|
||||||
|
<td colspan="2" class="bg-green-600 bg-opacity-20">
|
||||||
|
{{ $t("energy.all_day") }}
|
||||||
|
</td>
|
||||||
<td class="bg-green-600 bg-opacity-20">
|
<td class="bg-green-600 bg-opacity-20">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import Table from "@/components/customUI/Table.vue";
|
import Table from "@/components/customUI/Table.vue";
|
||||||
import FloorsModal from "./FloorsModal.vue";
|
import FloorsModal from "./FloorsModal.vue";
|
||||||
import { getAssetFloorList, deleteAssetFloor } from "@/apis/asset";
|
import { deleteAssetFloor } from "@/apis/asset";
|
||||||
import { onMounted, ref, inject, computed } from "vue";
|
import { onMounted, ref, inject, computed } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
|
|
||||||
|
const storeBuild = useBuildingStore();
|
||||||
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openToast, cancelToastOpen } = inject("app_toast");
|
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||||
@ -28,18 +31,10 @@ const columns = computed(() => [
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const dataSource = ref([]);
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
const getDataSource = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
const res = await getAssetFloorList();
|
|
||||||
dataSource.value = res.data[0]?.floors.map((d) => ({ ...d, key: d.floor_guid }));
|
|
||||||
loading.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getDataSource();
|
storeBuild.fetchFloorList(storeBuild.selectedBuilding?.building_guid);
|
||||||
});
|
});
|
||||||
|
|
||||||
const formState = ref({
|
const formState = ref({
|
||||||
@ -47,9 +42,22 @@ const formState = ref({
|
|||||||
floorFile: [],
|
floorFile: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const openModal = (record) => {
|
const openModal = (record) => {
|
||||||
if (record.floor_guid) {
|
if (record.floor_guid) {
|
||||||
formState.value = { ...record };
|
console.log('record',record);
|
||||||
|
formState.value.floor_guid = record.floor_guid;
|
||||||
|
formState.value.full_name = record.full_name;
|
||||||
|
if(record.floor_map_url){
|
||||||
|
const floorFile = record
|
||||||
|
? {
|
||||||
|
// size: record.oriSize,
|
||||||
|
name: record.floor_map_name,
|
||||||
|
src: `${record.floor_map_url}.svg`,
|
||||||
|
ext: 'svg',
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
formState.value.floorFile = [floorFile];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
formState.value = {
|
formState.value = {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
@ -59,14 +67,14 @@ const openModal = (record) => {
|
|||||||
floor_modal.showModal();
|
floor_modal.showModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const remove = async () => {
|
const remove = async (id) => {
|
||||||
openToast("warning", t("msg.sure_to_delete"), "body", async () => {
|
openToast("warning", t("msg.sure_to_delete"), "body", async () => {
|
||||||
await cancelToastOpen();
|
await cancelToastOpen();
|
||||||
const res = await deleteAssetFloor({
|
const res = await deleteAssetFloor({
|
||||||
floor_guid: formState.value.floor_guid,
|
floor_guid: id,
|
||||||
});
|
});
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
getDataSource();
|
storeBuild.fetchFloorList(storeBuild.selectedBuilding?.building_guid);
|
||||||
openToast("success", t("msg.delete_success"));
|
openToast("success", t("msg.delete_success"));
|
||||||
} else {
|
} else {
|
||||||
openToast("error", res.msg);
|
openToast("error", res.msg);
|
||||||
@ -78,13 +86,13 @@ const remove = async () => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex justify-start items-center mt-10 mb-5">
|
<div class="flex justify-start items-center mt-10 mb-5">
|
||||||
<h3 class="text-xl mr-5">{{ $t("energy.floor") }}</h3>
|
<h3 class="text-xl mr-5">{{ $t("energy.floor") }}</h3>
|
||||||
<FloorsModal
|
<FloorsModal :formState="formState" :openModal="openModal" />
|
||||||
:formState="formState"
|
|
||||||
:getData="getDataSource"
|
|
||||||
:openModal="openModal"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<Table :columns="columns" :dataSource="dataSource" :loading="loading">
|
<Table
|
||||||
|
:columns="columns"
|
||||||
|
:dataSource="storeBuild.floorList"
|
||||||
|
:loading="loading"
|
||||||
|
>
|
||||||
<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-else-if="column.key === 'operation'">
|
<template v-else-if="column.key === 'operation'">
|
||||||
@ -96,13 +104,17 @@ const remove = async () => {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-error text-white"
|
class="btn btn-sm btn-error text-white"
|
||||||
@click.stop.prevent="() => remove()"
|
@click.stop.prevent="() => remove(record.floor_guid)"
|
||||||
>
|
>
|
||||||
{{ $t("button.delete") }}
|
{{ $t("button.delete") }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'floor_plan'">
|
<template v-else-if="column.key === 'floor_plan'">
|
||||||
<img :src="`${FILE_BASEURL}/${record.floor_map_url}.svg`" class="w-[200px] bg-white mx-auto" />
|
<img
|
||||||
|
v-if="record.floor_map_url"
|
||||||
|
:src="`${FILE_BASEURL}/${record.floor_map_url}.svg`"
|
||||||
|
class="w-[200px] bg-white mx-auto"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ record[column.key] }}
|
{{ record[column.key] }}
|
||||||
|
@ -5,16 +5,17 @@ import "yup-phone-lite";
|
|||||||
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
|
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
|
||||||
import { postAssetFloor } from "@/apis/asset";
|
import { postAssetFloor } from "@/apis/asset";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
|
|
||||||
|
const storeBuild = useBuildingStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openToast } = inject("app_toast");
|
const { openToast } = inject("app_toast");
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
formState: Object,
|
formState: Object,
|
||||||
getData: Function,
|
|
||||||
openModal: Function,
|
openModal: Function,
|
||||||
});
|
});
|
||||||
const form = ref(null);
|
const form = ref(null);
|
||||||
|
|
||||||
const floorScheme = yup.object({
|
const floorScheme = yup.object({
|
||||||
full_name: yup.string().required(t("button.required")),
|
full_name: yup.string().required(t("button.required")),
|
||||||
floorFile: yup.array(),
|
floorFile: yup.array(),
|
||||||
@ -22,7 +23,7 @@ const floorScheme = yup.object({
|
|||||||
|
|
||||||
const updateFileList = (files) => {
|
const updateFileList = (files) => {
|
||||||
console.log("file", files);
|
console.log("file", files);
|
||||||
FloorFormState.value.floorFile = files;
|
props.formState.floorFile = files;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } =
|
const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } =
|
||||||
@ -30,23 +31,26 @@ const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } =
|
|||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
handleErrorReset();
|
handleErrorReset();
|
||||||
|
updateFileList([]);
|
||||||
floor_modal.close();
|
floor_modal.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onOk = async () => {
|
const onOk = async () => {
|
||||||
const value = await handleSubmit(floorScheme, props.formState);
|
const value = await handleSubmit(floorScheme, props.formState);
|
||||||
const formData = new FormData(form.value);
|
const formData = new FormData(form.value);
|
||||||
formData.append(
|
if (props.formState.floor_guid) {
|
||||||
"floor_guid",
|
formData.append("floor_guid", props.formState.floor_guid);
|
||||||
selectedOption.value === "add" ? null : currentFloor.value.floor_guid
|
}
|
||||||
);
|
if (props.formState.floorFile[0]) {
|
||||||
formData.append("building_tag", store.selectedBuilding.building_tag);
|
formData.append("initMapName", props.formState.floorFile[0]?.name);
|
||||||
formData.append("initMapName", FloorFormState.value.floorFile[0]?.name);
|
formData.append("mapFile", props.formState.floorFile[0]);
|
||||||
formData.append("mapFile", FloorFormState.value.floorFile[0]);
|
}
|
||||||
|
formData.append("building_guid", storeBuild.selectedBuilding.building_guid);
|
||||||
|
|
||||||
formData.delete("floorFile");
|
formData.delete("floorFile");
|
||||||
const res = await postAssetFloor(formData);
|
const res = await postAssetFloor(formData);
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
props.getData();
|
storeBuild.fetchFloorList(storeBuild.selectedBuilding?.building_guid);
|
||||||
onCancel();
|
onCancel();
|
||||||
} else {
|
} else {
|
||||||
openToast("error", res.msg, "#floor_modal");
|
openToast("error", res.msg, "#floor_modal");
|
||||||
|
@ -79,7 +79,7 @@ const toggleNode = (node, checked) => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MITTCheckboxTree
|
<MQTTCheckboxTree
|
||||||
v-if="node.children?.length && node.expanded"
|
v-if="node.children?.length && node.expanded"
|
||||||
:data="node.children"
|
:data="node.children"
|
||||||
:checked-nodes="checkedNodes"
|
:checked-nodes="checkedNodes"
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch, computed } from "vue";
|
import { ref, onMounted, watch, computed, inject } from "vue";
|
||||||
import { getAssetMainList, getAssetSubList, getIOTSchema } from "@/apis/asset";
|
import {
|
||||||
|
getAssetMainList,
|
||||||
|
getAssetSubList,
|
||||||
|
getIOTSchema,
|
||||||
|
getDeviceItem,
|
||||||
|
deleteDeviceItem,
|
||||||
|
} from "@/apis/asset";
|
||||||
import useActiveBtn from "@/hooks/useActiveBtn";
|
import useActiveBtn from "@/hooks/useActiveBtn";
|
||||||
import MQTTListAddModal from "./MQTTListAddModal.vue";
|
import MQTTListAddModal from "./MQTTListAddModal.vue";
|
||||||
import PointListAddModal from "./PointListAddModal.vue";
|
import PointListAddModal from "./PointListAddModal.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const formState = ref({});
|
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||||
const MQTTDataSource = ref([]);
|
const MQTTDataSource = ref([]);
|
||||||
const MQTTloading = ref(false);
|
const MQTTloading = ref(false);
|
||||||
const PointsDataSource = ref([]);
|
const PointsDataSource = ref([]);
|
||||||
const Pointsloading = ref(false);
|
const Pointsloading = ref(false);
|
||||||
|
const variable_id = ref(null);
|
||||||
|
const editRecord = ref(null);
|
||||||
// 系統類別
|
// 系統類別
|
||||||
const {
|
const {
|
||||||
items: mainSysItems,
|
items: mainSysItems,
|
||||||
@ -50,36 +58,44 @@ const getSubSystems = async (id) => {
|
|||||||
|
|
||||||
const MQTTColumns = computed(() => [
|
const MQTTColumns = computed(() => [
|
||||||
{
|
{
|
||||||
title: "schema",
|
title: t("setting.schema"),
|
||||||
key: "schema_name",
|
key: "schema_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "point",
|
title: t("setting.point"),
|
||||||
key: "pointOrg",
|
key: "pointOrg",
|
||||||
filter: true,
|
filter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Description",
|
title: t("setting.description"),
|
||||||
key: "description",
|
key: "description",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const PointsColumns = computed(() => [
|
const PointsColumns = computed(() => [
|
||||||
{
|
{
|
||||||
title: "IoT 點位名稱",
|
title: t("setting.IoT_point_name"),
|
||||||
key: "IoT_point_name",
|
key: "full_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "小數點個數",
|
title: t("setting.IoT_point_code"),
|
||||||
key: "decimal",
|
key: "points",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "bool 值",
|
title: t("setting.number_of_decimal_places"),
|
||||||
|
key: "decimals",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("setting.boolean_value"),
|
||||||
key: "is_bool",
|
key: "is_bool",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "點位隱藏",
|
title: t("setting.hide_point"),
|
||||||
key: "is_open",
|
key: "is_link",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("assetManagement.operation"),
|
||||||
|
key: "operation",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -97,6 +113,46 @@ const getDataSource = async (id) => {
|
|||||||
MQTTloading.value = false;
|
MQTTloading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPointsData = async (id) => {
|
||||||
|
Pointsloading.value = true;
|
||||||
|
const res = await getDeviceItem(id);
|
||||||
|
PointsDataSource.value = res.data.map((d) => ({
|
||||||
|
...d,
|
||||||
|
key: d.id,
|
||||||
|
}));
|
||||||
|
Pointsloading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const remove = async (id) => {
|
||||||
|
openToast("warning", t("msg.sure_to_delete"), "body", async () => {
|
||||||
|
await cancelToastOpen();
|
||||||
|
const res = await deleteDeviceItem(id);
|
||||||
|
if (res.isSuccess) {
|
||||||
|
getPointsData(variable_id.value);
|
||||||
|
openToast("success", t("msg.delete_success"));
|
||||||
|
} else {
|
||||||
|
openToast("error", res.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const openModal = (record) => {
|
||||||
|
if (record?.id) {
|
||||||
|
editRecord.value = record;
|
||||||
|
} else {
|
||||||
|
editRecord.value = {
|
||||||
|
id: 0,
|
||||||
|
variable_id: variable_id.value,
|
||||||
|
full_name: "",
|
||||||
|
points: "",
|
||||||
|
decimals: 0,
|
||||||
|
is_bool: 0,
|
||||||
|
is_link: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
point_list_item.showModal();
|
||||||
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
selectedMainSysItems,
|
selectedMainSysItems,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
@ -114,6 +170,8 @@ watch(
|
|||||||
(newValue) => {
|
(newValue) => {
|
||||||
if (newValue && newValue.key) {
|
if (newValue && newValue.key) {
|
||||||
getDataSource(parseInt(newValue.key));
|
getDataSource(parseInt(newValue.key));
|
||||||
|
getPointsData(parseInt(newValue.key));
|
||||||
|
variable_id.value = parseInt(newValue.key);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -157,23 +215,55 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-start items-center mt-5 mb-2">
|
<div class="flex justify-start items-center mt-5 mb-2">
|
||||||
<h3 class="text-xl mr-5">MQTT_Parse : </h3>
|
<h3 class="text-xl mr-5">{{ $t("setting.MQTT_parse") }} :</h3>
|
||||||
<MQTTListAddModal />
|
<MQTTListAddModal
|
||||||
|
:getData="getDataSource"
|
||||||
|
:pointsData="PointsDataSource"
|
||||||
|
:variable_id="variable_id"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
:columns="MQTTColumns"
|
:columns="MQTTColumns"
|
||||||
:dataSource="MQTTDataSource"
|
:dataSource="MQTTDataSource"
|
||||||
:loading="MQTTloading"
|
:loading="MQTTloading"
|
||||||
></Table>
|
>
|
||||||
|
</Table>
|
||||||
<div class="flex justify-start items-center mt-5 mb-2">
|
<div class="flex justify-start items-center mt-5 mb-2">
|
||||||
<h3 class="text-xl mr-5">Points : </h3>
|
<h3 class="text-xl mr-5">{{ $t("setting.point") }} :</h3>
|
||||||
<PointListAddModal />
|
<PointListAddModal
|
||||||
|
:getData="getPointsData"
|
||||||
|
:variable_id="variable_id"
|
||||||
|
:editRecord="editRecord"
|
||||||
|
:openModal="openModal"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
:columns="PointsColumns"
|
:columns="PointsColumns"
|
||||||
:dataSource="PointsDataSource"
|
:dataSource="PointsDataSource"
|
||||||
:loading="Pointsloading"
|
:loading="Pointsloading"
|
||||||
></Table>
|
><template #bodyCell="{ record, column, index }">
|
||||||
|
<template v-if="column.key === 'is_bool'">
|
||||||
|
{{ record.is_bool === 1 ? t("alert.yes") : t("alert.no") }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'is_link'">
|
||||||
|
{{ record.is_link === 1 ? t("alert.yes") : t("alert.no") }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'operation'">
|
||||||
|
<button
|
||||||
|
class="btn btn-sm btn-success text-white mr-2"
|
||||||
|
@click.stop.prevent="() => openModal(record)"
|
||||||
|
>
|
||||||
|
{{ $t("button.edit") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-sm btn-error text-white"
|
||||||
|
@click.stop.prevent="() => remove(record.id)"
|
||||||
|
>
|
||||||
|
{{ $t("button.delete") }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch, defineProps } from "vue";
|
import { ref, onMounted, watch, defineProps, inject } from "vue";
|
||||||
import { getAssetMainList, getAssetSubList, getIOTSchema } from "@/apis/asset";
|
import { postIOTSchema } from "@/apis/asset";
|
||||||
import useActiveBtn from "@/hooks/useActiveBtn";
|
|
||||||
import MQTTCheckboxTree from "./MQTTCheckboxTree.vue";
|
import MQTTCheckboxTree from "./MQTTCheckboxTree.vue";
|
||||||
import generateSchema from "json-schema-generator";
|
import generateSchema from "json-schema-generator";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { openToast } = inject("app_toast");
|
||||||
|
const props = defineProps({
|
||||||
|
getData: Function,
|
||||||
|
pointsData: Object,
|
||||||
|
variable_id: Number,
|
||||||
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// 新增:將 jsonInput 與結構資料初始化
|
// 新增:將 jsonInput 與結構資料初始化
|
||||||
const jsonInput = ref("");
|
const jsonInput = ref("");
|
||||||
@ -14,10 +19,6 @@ const checkedNodes = ref([]);
|
|||||||
const form = ref(null);
|
const form = ref(null);
|
||||||
const schemaName = ref("");
|
const schemaName = ref("");
|
||||||
const formStates = ref([]);
|
const formStates = ref([]);
|
||||||
const optionData = ref([
|
|
||||||
{ key: 0, full_name: "否" },
|
|
||||||
{ key: 1, full_name: "是" },
|
|
||||||
]);
|
|
||||||
|
|
||||||
// JSON Schema 轉換
|
// JSON Schema 轉換
|
||||||
const customGenerateSchema = (json) => {
|
const customGenerateSchema = (json) => {
|
||||||
@ -92,22 +93,42 @@ watch(
|
|||||||
(newCheckedNodes) => {
|
(newCheckedNodes) => {
|
||||||
// 為每個 node 創建一個 formState
|
// 為每個 node 創建一個 formState
|
||||||
formStates.value = newCheckedNodes.map((node) => ({
|
formStates.value = newCheckedNodes.map((node) => ({
|
||||||
IoT_point_schema: node,
|
PointOrg: node,
|
||||||
sys_point_name: null,
|
PointSys: "",
|
||||||
is_bool: 1,
|
item_id: null,
|
||||||
decimal: 0,
|
|
||||||
is_open: 1,
|
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onOk = async () => {
|
||||||
|
const points = formStates.value.map((state) => ({
|
||||||
|
PointOrg: state.PointOrg,
|
||||||
|
PointSys: props.pointsData.find((point) => point.id === state.item_id)
|
||||||
|
.points,
|
||||||
|
item_id: state.item_id,
|
||||||
|
}));
|
||||||
|
const apiData = {
|
||||||
|
name: schemaName.value,
|
||||||
|
variable_id: props.variable_id,
|
||||||
|
points: points,
|
||||||
|
};
|
||||||
|
const res = await postIOTSchema(apiData);
|
||||||
|
if (res.isSuccess) {
|
||||||
|
props.getData(props.variable_id);
|
||||||
|
onCancel();
|
||||||
|
} else {
|
||||||
|
openToast("error", res.msg, "#MQTT_Parse_item");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const openModal = () => {
|
const openModal = () => {
|
||||||
MQTT_Parse_item.showModal();
|
MQTT_Parse_item.showModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
MQTT_Parse_item.close();
|
MQTT_Parse_item.close();
|
||||||
|
clearAll();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -117,7 +138,7 @@ const onCancel = () => {
|
|||||||
</button>
|
</button>
|
||||||
<Modal
|
<Modal
|
||||||
id="MQTT_Parse_item"
|
id="MQTT_Parse_item"
|
||||||
title="MQTT_Parse"
|
:title="t('setting.MQTT_parse')"
|
||||||
:onCancel="onCancel"
|
:onCancel="onCancel"
|
||||||
:width="1600"
|
:width="1600"
|
||||||
>
|
>
|
||||||
@ -126,21 +147,18 @@ const onCancel = () => {
|
|||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<textarea
|
<textarea
|
||||||
v-model="jsonInput"
|
v-model="jsonInput"
|
||||||
placeholder="請貼上 JSON 格式數據"
|
:placeholder="t('setting.json_format_text')"
|
||||||
class="w-full h-[500px] p-4 border rounded-lg font-mono text-white"
|
class="w-full h-[500px] p-4 border rounded-lg font-mono text-white"
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="my-auto">
|
<div class="my-auto">
|
||||||
<button @click="parseJson" class="btn-success btn w-24 mb-4">
|
<button @click="parseJson" class="btn-success btn w-28 mb-4">
|
||||||
轉換
|
{{ $t("button.convert")
|
||||||
<font-awesome-icon
|
}}<font-awesome-icon :icon="['fas', 'chevron-right']" />
|
||||||
:icon="['fas', 'chevron-right']"
|
|
||||||
size="lg"
|
|
||||||
class="block"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
<button @click="clearAll" class="bg-error btn w-24">
|
<button @click="clearAll" class="bg-error btn w-28">
|
||||||
刪除<font-awesome-icon :icon="['fas', 'trash-alt']" />
|
{{ $t("button.delete")
|
||||||
|
}}<font-awesome-icon :icon="['fas', 'trash-alt']" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full p-4 rounded-lg border overflow-y-scroll h-[500px]">
|
<div class="w-full p-4 rounded-lg border overflow-y-scroll h-[500px]">
|
||||||
@ -149,81 +167,71 @@ const onCancel = () => {
|
|||||||
:data="treeData"
|
:data="treeData"
|
||||||
v-model:checked-nodes="checkedNodes"
|
v-model:checked-nodes="checkedNodes"
|
||||||
/>
|
/>
|
||||||
<div v-else class="text-white">請在左側輸入 JSON 並點擊轉換按鈕</div>
|
<div v-else class="text-white">
|
||||||
|
{{ $t("setting.json_click_text") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form ref="form" class="" v-if="checkedNodes.length">
|
<form ref="form" class="" v-if="checkedNodes.length">
|
||||||
<div class="flex items-center mt-5">
|
<div class="flex items-center mt-5">
|
||||||
<h2 class="text-lg font-bold whitespace-nowrap me-2">結構名稱 :</h2>
|
<h2 class="text-lg font-bold whitespace-nowrap me-2">
|
||||||
<Input v-model="schemaName" />
|
{{ $t("setting.schema_name") }}:
|
||||||
|
</h2>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model.text="schemaName"
|
||||||
|
class="input border-info focus-within:border-info"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<table class="table">
|
<table class="table w-1/2 mt-2">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<!-- <th>IoT 點位名稱</th> -->
|
<th>{{$t("setting.IoT_point_structure")}}</th>
|
||||||
<th>IoT 點位結構</th>
|
<th>{{$t("setting.system_point_name")}}</th>
|
||||||
<th>系統點位名稱</th>
|
|
||||||
<!-- <th>bool 值</th>
|
|
||||||
<th>小數點個數</th>
|
|
||||||
<th>點位隱藏</th> -->
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(node, index) in checkedNodes" :key="node">
|
<tr v-for="(node, index) in checkedNodes" :key="node">
|
||||||
<!-- <td>
|
<td>
|
||||||
<Input :value="formStates[index]" name="IoT_point_name" />
|
|
||||||
</td> -->
|
|
||||||
<td class="w-1/2">
|
|
||||||
<Input
|
<Input
|
||||||
:value="formStates[index]"
|
:value="formStates[index]"
|
||||||
name="IoT_point_schema"
|
name="PointOrg"
|
||||||
:readonly="true"
|
:readonly="true"
|
||||||
|
class="mx-auto"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select>
|
<Select
|
||||||
<option value="option1">選項 1</option>
|
|
||||||
<option value="option2">選項 2</option>
|
|
||||||
<option value="option3">選項 3</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<!-- <td>
|
|
||||||
<div class="flex w-36">
|
|
||||||
<Select
|
|
||||||
:value="formStates[index]"
|
|
||||||
selectClass="w-20 mx-auto border-info focus-within:border-info"
|
|
||||||
name="is_bool"
|
|
||||||
Attribute="full_name"
|
|
||||||
:options="optionData"
|
|
||||||
>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<InputNumber
|
|
||||||
:value="formStates[index]"
|
:value="formStates[index]"
|
||||||
class="mx-auto"
|
class="my-2 mx-auto"
|
||||||
name="decimal"
|
selectClass="border-info focus-within:border-info "
|
||||||
|
name="item_id"
|
||||||
|
Attribute="full_name"
|
||||||
|
:options="props.pointsData"
|
||||||
>
|
>
|
||||||
</InputNumber>
|
</Select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
<div class="flex w-36">
|
|
||||||
<Select
|
|
||||||
:value="formStates[index]"
|
|
||||||
selectClass="w-20 mx-auto border-info focus-within:border-info"
|
|
||||||
name="is_open"
|
|
||||||
Attribute="full_name"
|
|
||||||
:options="optionData"
|
|
||||||
>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</td> -->
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
<template #modalAction>
|
||||||
|
<button
|
||||||
|
type="reset"
|
||||||
|
class="btn btn-outline-success mr-2"
|
||||||
|
@click.prevent="onCancel"
|
||||||
|
>
|
||||||
|
{{ $t("button.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-outline-success"
|
||||||
|
@click.stop.prevent="onOk"
|
||||||
|
>
|
||||||
|
{{ $t("button.submit") }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,56 +1,114 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch, defineProps } from "vue";
|
import { ref, onMounted, watch, defineProps, inject, readonly } from "vue";
|
||||||
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
|
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
|
||||||
|
import { postDeviceItem } from "@/apis/asset";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
|
const { openToast } = inject("app_toast");
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const props = defineProps({
|
||||||
|
getData: Function,
|
||||||
|
openModal: Function,
|
||||||
|
editRecord: Object,
|
||||||
|
variable_id: Number,
|
||||||
|
});
|
||||||
const form = ref(null);
|
const form = ref(null);
|
||||||
const formState = ref({
|
const formState = ref({
|
||||||
id: 0,
|
id: 0,
|
||||||
IoT_point_name: "",
|
variable_id: props.variable_id,
|
||||||
|
full_name: "",
|
||||||
|
points: "",
|
||||||
|
decimals: 0,
|
||||||
is_bool: 0,
|
is_bool: 0,
|
||||||
decimal: 2,
|
is_link: 0,
|
||||||
is_open: 0,
|
|
||||||
});
|
});
|
||||||
let schema = ref(
|
let schema = ref(
|
||||||
yup.object({
|
yup.object({
|
||||||
IoT_point_name: yup.string().required(t("button.required")),
|
full_name: yup.string().required(t("button.required")),
|
||||||
is_bool: yup.string().required(t("button.required")),
|
decimals: yup.number().required(t("button.required")),
|
||||||
decimal: yup.string().required(t("button.required")),
|
is_bool: yup.number().required(t("button.required")),
|
||||||
is_open: yup.string().required(t("button.required")),
|
is_link: yup.number().required(t("button.required")),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } =
|
const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } =
|
||||||
useFormErrorMessage(schema.value);
|
useFormErrorMessage(schema.value);
|
||||||
|
|
||||||
const openModal = () => {
|
const onOk = async () => {
|
||||||
point_list_item.showModal();
|
const values = await handleSubmit(schema.value, formState.value);
|
||||||
|
console.log("value", values);
|
||||||
|
const res = await postDeviceItem({
|
||||||
|
...values,
|
||||||
|
decimals: Number(values.decimals),
|
||||||
|
is_bool: Number(values.is_bool),
|
||||||
|
is_link: Number(values.is_link),
|
||||||
|
});
|
||||||
|
if (res.isSuccess) {
|
||||||
|
props.getData(props.variable_id);
|
||||||
|
onCancel();
|
||||||
|
} else {
|
||||||
|
openToast("error", res.msg, "#point_list_item");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
point_list_item.close();
|
point_list_item.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.editRecord,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
formState.value = {
|
||||||
|
...newValue,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
formState.value = {
|
||||||
|
id: 0,
|
||||||
|
variable_id: props.variable_id,
|
||||||
|
full_name: "",
|
||||||
|
points: "",
|
||||||
|
decimals: 0,
|
||||||
|
is_bool: 0,
|
||||||
|
is_link: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="openModal">
|
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="props.openModal">
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
<Modal id="point_list_item" title="Points" :onCancel="onCancel" :width="710">
|
<Modal id="point_list_item" title="Points" :onCancel="onCancel" :width="710">
|
||||||
<template #modalContent>
|
<template #modalContent>
|
||||||
<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="IoT_point_name">
|
<Input :value="formState" class="my-2" name="full_name">
|
||||||
<template #topLeft>IoT 點位名稱</template>
|
<template #topLeft>{{ $t("setting.IoT_point_name") }}</template>
|
||||||
<template #bottomLeft
|
<template #bottomLeft
|
||||||
><span class="text-error text-base">
|
><span class="text-error text-base">
|
||||||
{{ formErrorMsg.IoT_point_name }}
|
{{ formErrorMsg.full_name }}
|
||||||
</span></template
|
</span></template
|
||||||
></Input
|
></Input
|
||||||
>
|
>
|
||||||
<InputNumber :value="formState" class="my-2" name="decimal">
|
<Input
|
||||||
<template #topLeft>小數點個數</template>
|
:value="formState"
|
||||||
|
class="my-2"
|
||||||
|
name="points"
|
||||||
|
:disabled="props.editRecord?.id"
|
||||||
|
>
|
||||||
|
<template #topLeft>{{ $t("setting.IoT_point_code") }}</template>
|
||||||
|
<template #bottomLeft
|
||||||
|
><span class="text-error text-base">
|
||||||
|
{{ formErrorMsg.points }}
|
||||||
|
</span></template
|
||||||
|
></Input
|
||||||
|
>
|
||||||
|
<InputNumber :value="formState" class="my-2" name="decimals">
|
||||||
|
<template #topLeft>{{
|
||||||
|
$t("setting.number_of_decimal_places")
|
||||||
|
}}</template>
|
||||||
</InputNumber>
|
</InputNumber>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
class="my-2"
|
class="my-2"
|
||||||
@ -70,12 +128,12 @@ const onCancel = () => {
|
|||||||
]"
|
]"
|
||||||
:required="true"
|
:required="true"
|
||||||
>
|
>
|
||||||
<template #topLeft>bool 值</template>
|
<template #topLeft>{{ $t("setting.boolean_value") }}</template>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
class="my-2"
|
class="my-2"
|
||||||
name="is_open"
|
name="is_link"
|
||||||
:value="formState"
|
:value="formState"
|
||||||
:items="[
|
:items="[
|
||||||
{
|
{
|
||||||
@ -91,10 +149,26 @@ const onCancel = () => {
|
|||||||
]"
|
]"
|
||||||
:required="true"
|
:required="true"
|
||||||
>
|
>
|
||||||
<template #topLeft>點位隱藏</template>
|
<template #topLeft>{{ $t("setting.hide_point") }}</template>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
<template #modalAction>
|
||||||
|
<button
|
||||||
|
type="reset"
|
||||||
|
class="btn btn-outline-success mr-2"
|
||||||
|
@click.prevent="onCancel"
|
||||||
|
>
|
||||||
|
{{ $t("button.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-outline-success"
|
||||||
|
@click.stop.prevent="onOk"
|
||||||
|
>
|
||||||
|
{{ $t("button.submit") }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ watch(
|
|||||||
},
|
},
|
||||||
params.data[2]
|
params.data[2]
|
||||||
);
|
);
|
||||||
selected_dbid.value[0] = params.data[2].forge_dbid;
|
selected_dbid.value[1] = params.data[2].spriteDbId;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -146,7 +146,7 @@ watch(
|
|||||||
allData.value
|
allData.value
|
||||||
) {
|
) {
|
||||||
selectedData.value = selectedData.value.map((item) => {
|
selectedData.value = selectedData.value.map((item) => {
|
||||||
if (item[2].forge_dbid === newSelectedDbid[0]) {
|
if (item[2].spriteDbId === newSelectedDbid[1]) {
|
||||||
return [...item.slice(0, 2), { ...item[2], is2DActive: true }];
|
return [...item.slice(0, 2), { ...item[2], is2DActive: true }];
|
||||||
}
|
}
|
||||||
return [...item.slice(0, 2), { ...item[2], is2DActive: false }];
|
return [...item.slice(0, 2), { ...item[2], is2DActive: false }];
|
||||||
|
@ -1,51 +1,118 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, inject, watch } from "vue"
|
import { computed, inject, watch } from "vue";
|
||||||
import useSystemShowData from "@/hooks/useSystemShowData"
|
import useSystemShowData from "@/hooks/useSystemShowData";
|
||||||
|
|
||||||
const { getCurrentInfoModalData, selected_dbid } = inject("system_selectedDevice")
|
const { getCurrentInfoModalData, selected_dbid } = inject(
|
||||||
|
"system_selectedDevice"
|
||||||
|
);
|
||||||
const { subscribeData } = inject("system_deviceList");
|
const { subscribeData } = inject("system_deviceList");
|
||||||
|
|
||||||
const { showData } = useSystemShowData()
|
const { showData } = useSystemShowData();
|
||||||
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
||||||
|
|
||||||
const fitToView = (forge_dbid, spriteDbId) => {
|
const fitToView = (forge_dbid, spriteDbId) => {
|
||||||
selected_dbid.value = [forge_dbid, spriteDbId];
|
selected_dbid.value = [forge_dbid, spriteDbId];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openDialog = () => {
|
||||||
|
document.getElementById("iframe_modal").showModal();
|
||||||
|
};
|
||||||
|
const cancelDialog = () => {
|
||||||
|
document.getElementById("iframe_modal").close();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- <InfoModal :data="currentInfoModalData" /> -->
|
<dialog
|
||||||
|
id="iframe_modal"
|
||||||
|
className="modal w-[590px] h-[490px] my-auto rounded-lg mx-auto"
|
||||||
|
>
|
||||||
|
<iframe
|
||||||
|
src="https://app.mockplus.cn/p/zNB4y8k5L"
|
||||||
|
frameborder="0"
|
||||||
|
class="w-full h-full"
|
||||||
|
></iframe>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
class="btn-link btn-text-without-border z-20 absolute right-[2.3rem] top-[2.2rem]"
|
||||||
|
@click="cancelDialog"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
:icon="['fas', 'times']"
|
||||||
|
class="text-[#a5abb1] text-2xl"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
<template v-if="showData.length > 0">
|
<template v-if="showData.length > 0">
|
||||||
<div class="equipment-show" v-for="d in showData" :key="d.full_name">
|
<div class="equipment-show" v-for="d in showData" :key="d.full_name">
|
||||||
<template v-if="d.device_list.length > 0">
|
<template v-if="d.device_list.length > 0">
|
||||||
<p class="title">{{ d.full_name }}</p>
|
<p class="title">{{ d.full_name }}</p>
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
||||||
<div class="col-auto relative" v-for="device in d.device_list" :key="device.device_guid">
|
<div
|
||||||
<div class="item h-full cursor-pointer" @click="() => fitToView(device.forge_dbid, device.spriteDbId)">
|
class="col-auto relative"
|
||||||
|
v-for="device in d.device_list"
|
||||||
|
:key="device.device_guid"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="item h-full cursor-pointer"
|
||||||
|
@click="() => fitToView(device.forge_dbid, device.spriteDbId)"
|
||||||
|
>
|
||||||
<div class="left h-full flex flex-wrap justify-center">
|
<div class="left h-full flex flex-wrap justify-center">
|
||||||
<div class="sec02 w-full">
|
<div class="sec02 w-full">
|
||||||
<img v-if="device.device_image_url" :src="`${FILE_BASEURL}/upload/device_icon/${device.device_image}`"
|
<img
|
||||||
:alt="device.device_image">
|
v-if="device.device_image_url"
|
||||||
|
:src="`${FILE_BASEURL}/upload/device_icon/${device.device_image}`"
|
||||||
|
:alt="device.device_image"
|
||||||
|
/>
|
||||||
<span v-else></span>
|
<span v-else></span>
|
||||||
<span>{{ device.full_name }}</span>
|
<span>{{ device.full_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between w-full self-end">
|
<div class="flex justify-between w-full self-end">
|
||||||
<div class="sec03">
|
<div class="sec03">
|
||||||
<span class="w-5 h-5 rounded-full" :style="{ backgroundColor: device.device_normal_color }"></span>
|
<span
|
||||||
|
class="w-5 h-5 rounded-full"
|
||||||
|
:style="{
|
||||||
|
backgroundColor:
|
||||||
|
device.full_name === 'SmartSocket-AA001'
|
||||||
|
? 'red'
|
||||||
|
: device.full_name === 'SmartSocket-AA003' ||
|
||||||
|
device.full_name === 'SmartSocket-AA004'
|
||||||
|
? 'gray'
|
||||||
|
: device.device_normal_color,
|
||||||
|
}"
|
||||||
|
></span>
|
||||||
<span class="mx-2">{{ $t("system.status") }}:</span>
|
<span class="mx-2">{{ $t("system.status") }}:</span>
|
||||||
<span>{{ device.device_status }}</span>
|
<span>{{
|
||||||
|
device.full_name === "SmartSocket-AA001"
|
||||||
|
? "Error"
|
||||||
|
: device.full_name === "SmartSocket-AA003" ||
|
||||||
|
device.full_name === "SmartSocket-AA004"
|
||||||
|
? "Offline"
|
||||||
|
: device.device_status || 'Online'
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn-text border-0 "
|
<button
|
||||||
@click.prevent="(e) => getCurrentInfoModalData(e, { left: e.clientX, top: e.clientY }, device)">{{
|
class="btn-text border-0"
|
||||||
$t("system.details") }}</button>
|
@click.prevent="
|
||||||
|
(e) => {
|
||||||
|
if (device.full_name === 'SmartSocket-AA001') {
|
||||||
|
openDialog();
|
||||||
|
} else {
|
||||||
|
getCurrentInfoModalData(
|
||||||
|
e,
|
||||||
|
{ left: e.clientX, top: e.clientY },
|
||||||
|
device
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ $t("system.details") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -53,7 +120,7 @@ const fitToView = (forge_dbid, spriteDbId) => {
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='css' scoped>
|
<style lang="css" scoped>
|
||||||
/*設備顯示*/
|
/*設備顯示*/
|
||||||
.title {
|
.title {
|
||||||
@apply text-lg text-white relative inline-block mb-5 after:absolute after:-bottom-2 after:left-1/4 after:w-4/5 after:h-[1px] after:bg-info;
|
@apply text-lg text-white relative inline-block mb-5 after:absolute after:-bottom-2 after:left-1/4 after:w-4/5 after:h-[1px] after:bg-info;
|
||||||
@ -88,7 +155,7 @@ const fitToView = (forge_dbid, spriteDbId) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.equipment-show .item .sec01 span:nth-child(2) {
|
.equipment-show .item .sec01 span:nth-child(2) {
|
||||||
font-size: .6rem;
|
font-size: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.equipment-show .item .sec02 {
|
.equipment-show .item .sec02 {
|
||||||
@ -144,4 +211,4 @@ const fitToView = (forge_dbid, spriteDbId) => {
|
|||||||
display: block;
|
display: block;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
} */
|
} */
|
||||||
</style>
|
</style>
|
||||||
|
@ -12,18 +12,24 @@ const {
|
|||||||
changeActiveBtn: changeDeptActiveBtn,
|
changeActiveBtn: changeDeptActiveBtn,
|
||||||
setItems: setDeptItems,
|
setItems: setDeptItems,
|
||||||
selectedBtn: selectedDeptItems,
|
selectedBtn: selectedDeptItems,
|
||||||
} = useActiveBtn();
|
} = useActiveBtn("multiple");
|
||||||
|
|
||||||
onMounted(() => {
|
watch(
|
||||||
const deptList = [
|
() => storeBuild.deptList,
|
||||||
{
|
(newValue) => {
|
||||||
title: "All",
|
if (newValue) {
|
||||||
key: "main",
|
const deptList = newValue.map((d) => ({
|
||||||
},
|
...d,
|
||||||
...storeBuild.deptList,
|
active: true,
|
||||||
];
|
}));
|
||||||
setDeptItems(deptList);
|
setDeptItems(deptList);
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -34,6 +40,7 @@ onMounted(() => {
|
|||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
:items="sysDeptItems"
|
:items="sysDeptItems"
|
||||||
className="btn-xs rounded-md"
|
className="btn-xs rounded-md"
|
||||||
|
:withLine="true"
|
||||||
:onclick="
|
:onclick="
|
||||||
(e, item) => {
|
(e, item) => {
|
||||||
changeDeptActiveBtn(item);
|
changeDeptActiveBtn(item);
|
||||||
|
@ -1,74 +1,88 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { getAssetFloorList } from "@/apis/asset";
|
import { onMounted, ref, watch, inject } from "vue";
|
||||||
import { onMounted, ref, watch, inject } from 'vue';
|
|
||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
import useActiveBtn from "@/hooks/useActiveBtn"
|
import useActiveBtn from "@/hooks/useActiveBtn";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const store = useBuildingStore();
|
const store = useBuildingStore();
|
||||||
|
|
||||||
const { updateCurrentFloor } = inject("system_deviceList")
|
const { updateCurrentFloor } = inject("system_deviceList");
|
||||||
|
|
||||||
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
|
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
|
||||||
const getFloors = async () => {
|
|
||||||
const res = await getAssetFloorList()
|
|
||||||
let data = res.data.find(d => d.building_tag === store.selectedBuilding?.building_tag)
|
|
||||||
data = [
|
|
||||||
{
|
|
||||||
title: "All",
|
|
||||||
key: "main",
|
|
||||||
active: route.params.floor_id === "main",
|
|
||||||
},
|
|
||||||
...data.floors.map((d, idx) => ({
|
|
||||||
title: d.full_name,
|
|
||||||
key: d.floor_guid,
|
|
||||||
active: route.params.floor_id === d.floor_guid,
|
|
||||||
map_url: d.floor_map_url ? d.floor_map_url + ".svg" : null
|
|
||||||
}))
|
|
||||||
]
|
|
||||||
setItems(data);
|
|
||||||
|
|
||||||
updateCurrentFloor(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onClick = (item) => {
|
const onClick = (item) => {
|
||||||
changeActiveBtn(item)
|
changeActiveBtn(item);
|
||||||
|
|
||||||
router.push({
|
router.push({
|
||||||
name: 'sub_system', params: {
|
name: "sub_system",
|
||||||
...route.params, floor_id: item.key
|
params: {
|
||||||
}, query: { ...route.query, gas: route.query.gas, mode: item.key === "main" ? "3D" : route.query.mode }
|
...route.params,
|
||||||
})
|
floor_id: item.key,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
gas: route.query.gas,
|
||||||
|
mode: item.key === "main" ? "3D" : route.query.mode,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
watch(
|
||||||
|
() => route.params.sub_system_id,
|
||||||
watch(() => route.params.sub_system_id, (newValue, oldValue) => {
|
(newValue, oldValue) => {
|
||||||
if (newValue !== oldValue) {
|
if (newValue !== oldValue) {
|
||||||
setItems(items.value.map((item, index) => ({ ...item, active: index === 0 })));
|
setItems(
|
||||||
|
items.value.map((item, index) => ({ ...item, active: index === 0 }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}, {
|
watch(
|
||||||
deep: true
|
() => store.floorList,
|
||||||
})
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
watch(() => store.selectedBuilding, (newValue) => {
|
console.log('newValue',newValue);
|
||||||
newValue && getFloors()
|
|
||||||
}, {
|
const floorList = [
|
||||||
deep: true,
|
{
|
||||||
immediate: true
|
title: "All",
|
||||||
})
|
key: "main",
|
||||||
|
active: route.params.floor_id === "main",
|
||||||
|
},
|
||||||
|
...store.floorList.map((d, idx) => ({
|
||||||
|
title: d.full_name,
|
||||||
|
key: d.floor_guid,
|
||||||
|
active: route.params.floor_id === d.floor_guid,
|
||||||
|
map_url: d.floor_map_url ? d.floor_map_url + ".svg" : null,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
setItems(floorList);
|
||||||
|
updateCurrentFloor(floorList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="text-md font-extrabold">{{ $t("energy.floor") }} :</span>
|
<span class="text-md font-extrabold">{{ $t("energy.floor") }} :</span>
|
||||||
<ButtonGroup :items="items" :withLine="false" className="btn-xs rounded-md" :onclick="(e, item) => onClick(item)" />
|
<ButtonGroup
|
||||||
|
:items="items"
|
||||||
|
:withLine="true"
|
||||||
|
className="btn-xs rounded-md"
|
||||||
|
:onclick="(e, item) => onClick(item)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
Loading…
Reference in New Issue
Block a user