能源管理色系改變 | 圖資家暫存區與路徑欄位 | 系統小卡fitToView退後一點 | 上傳組件新增格式說明

This commit is contained in:
koko 2024-11-15 18:12:28 +08:00
parent 8c3e6b18f8
commit 01954e3f6e
25 changed files with 510 additions and 100 deletions

View File

@ -3,7 +3,7 @@
<html lang="en" data-theme="dracula">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.png" />
<link rel="icon" href="/favicon.ico" />
<link
rel="stylesheet"
href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.css"

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -85,8 +85,8 @@ export const addGraphTableData = async (formData) => {
});
};
export const delGraphData = async (id) => {
const res = await instance.post(DELETE_GRAPH_TABLE_API, { id });
export const delGraphData = async (id, hard_delete = false, recover_delete = false) => {
const res = await instance.post(DELETE_GRAPH_TABLE_API, { id, hard_delete, recover_delete });
return apihandler(res.code, res.data, {
msg: res.msg,

View File

@ -1 +1,12 @@
<svg id="圖層_1" data-name="圖層 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124.4 12.01"><defs><style>.cls-1,.cls-3{fill:#ffe422;}.cls-2{fill:#969696;opacity:0.3;}.cls-3{opacity:0.8;}</style></defs><polygon class="cls-1" points="92.68 2.87 31.5 2.87 28.8 0 95.59 0 92.68 2.87"/><path class="cls-2" d="M124.4.14V11.86c0,.08-.3.15-.66.15H97.84a2.27,2.27,0,0,1-.5,0l-1.76-.45a2.34,2.34,0,0,0-.5,0H29.76a2.2,2.2,0,0,0-.5,0L27.5,12a2.34,2.34,0,0,1-.5,0H.66C.3,12,0,11.94,0,11.86V.14C0,.06.3,0,.66,0L26.87.11a1.79,1.79,0,0,1,.5.05L29,2.25a2.27,2.27,0,0,0,.5,0H94.86a2.34,2.34,0,0,0,.5,0L97.25.16a1.83,1.83,0,0,1,.5,0l26-.11C124.1,0,124.4.06,124.4.14Z"/><path class="cls-3" d="M122.92,12V2.12a.89.89,0,0,0-.89-.89H96.41a.9.9,0,0,0-.67.31l-1.83,1.6a.36.36,0,0,1-.29.13H30.73a.36.36,0,0,1-.29-.13l-1.6-1.6a.9.9,0,0,0-.67-.31H2.37a.89.89,0,0,0-.89.89V12m.25,0V2.12a.64.64,0,0,1,.64-.64h25.8a.65.65,0,0,1,.48.23l1.6,1.59a.64.64,0,0,0,.48.22H93.62a.62.62,0,0,0,.48-.22l1.83-1.59a.65.65,0,0,1,.48-.23H122a.64.64,0,0,1,.64.64V12"/></svg>
<svg id="圖層_1" data-name="圖層 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124.4 12.01">
<defs>
<style>
.cls-1,.cls-3 { fill: #05AA9A; }
.cls-2 { fill: #969696; opacity: 0.3; }
.cls-3 { opacity: 0.8; }
</style>
</defs>
<polygon class="cls-1" points="92.68 2.87 31.5 2.87 28.8 0 95.59 0 92.68 2.87"/>
<path class="cls-2" d="M124.4.14V11.86c0,.08-.3.15-.66.15H97.84a2.27,2.27,0,0,1-.5,0l-1.76-.45a2.34,2.34,0,0,0-.5,0H29.76a2.2,2.2,0,0,0-.5,0L27.5,12a2.34,2.34,0,0,1-.5,0H.66C.3,12,0,11.94,0,11.86V.14C0,.06.3,0,.66,0L26.87.11a1.79,1.79,0,0,1,.5.05L29,2.25a2.27,2.27,0,0,0,.5,0H94.86a2.34,2.34,0,0,0,.5,0L97.25.16a1.83,1.83,0,0,1,.5,0l26-.11C124.1,0,124.4.06,124.4.14Z"/>
<path class="cls-3" d="M122.92,12V2.12a.89.89,0,0,0-.89-.89H96.41a.9.9,0,0,0-.67.31l-1.83,1.6a.36.36,0,0,1-.29.13H30.73a.36.36,0,0,1-.29-.13l-1.6-1.6a.9.9,0,0,0-.67-.31H2.37a.89.89,0,0,0-.89.89V12m.25,0V2.12a.64.64,0,0,1,.64-.64h25.8a.65.65,0,0,1,.48.23l1.6,1.59a.64.64,0,0,0,.48.22H93.62a.62.62,0,0,0,.48-.22l1.83-1.59a.65.65,0,0,1,.48-.23H122a.64.64,0,0,1,.64.64V12"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -60,7 +60,7 @@ onMounted(() => {
{{ title }}
</slot>
</div>
<div class="min-h-[400px]">
<div class="min-h-[200px]">
<slot name="modalContent"></slot>
</div>

View File

@ -9,6 +9,7 @@ const props = defineProps({
getFileList: Function,
multiple: Boolean,
baseUrl: String,
formats: { type: String, default: "txt、doc、xls、pdf、png、jpg" }
});
const acceptFileType = [
@ -265,6 +266,7 @@ const revokeURL = (src) => {
</div>
<p class="text-2xl my-2">{{ $t("upload.title") }}</p>
<p class="mb-0 col-grey">{{ $t("upload.description") }}</p>
<p class="mb-0 col-grey">{{ $t("upload.formats") }} : {{props.formats}}</p>
</div>
</div>

View File

@ -12,7 +12,8 @@
},
"upload": {
"title": "选择一个文件或拖放到这里",
"description": "档案不超过 10MB"
"description": "档案不超过 10MB",
"formats": "档案格式"
},
"dashboard": {
"yesterday_today": "昨天/今天",
@ -55,6 +56,11 @@
"green_elec": "绿电",
"immediate_demand": "即时需量",
"average_demand": "平均需量",
"real_time_Trend": "即时趋势",
"contract_capacity": "契约容量",
"alert_capacity": "警戒容量",
"reset_value": "复归值",
"edit_automatic_demand": "编辑自动需量",
"elec_bills": "今年电费累计(元)",
"interval_elec_charges": "区间电费(元)",
"year_carbon_emission": "今年碳排当量累计(公斤)",
@ -71,7 +77,9 @@
"var_elec_cost": "流动电费",
"fixed_elec_cost": "基本电费",
"total_elec_cost": "总电费",
"carbon_equivalent": "碳排当量"
"carbon_equivalent": "碳排当量",
"edit_carbon_emission": "编辑碳排放系数",
"carbon_emission_coefficient":"碳排放系数"
},
"alarm": {
"title": "显示警告",
@ -191,7 +199,10 @@
"index": "编号",
"oriOrgName": "档案",
"operation": "功能",
"upload": "图资上传"
"folder_path": "资料夹路径",
"upload": "图资上传",
"staging_area": "删除暂存区",
"no_path": "无资料夹路径"
},
"assetManagement": {
"title": "资产管理",
@ -272,10 +283,12 @@
"start_time_placeholder": "请输入预计开始日期",
"rename": "重新命名",
"download": "下载",
"confirm": "确认"
"confirm": "确认",
"restore": "复原"
},
"msg":{
"sure_to_delete": "是否确认删除该项目?",
"sure_to_delete_permanent": "是否确认永久删除该项目?",
"delete_success": "删除成功",
"delete_failed": "删除失败"
}

View File

@ -12,7 +12,8 @@
},
"upload": {
"title": "選擇一個文件或拖放到這裡",
"description": "檔案不超過 10MB"
"description": "檔案不超過 10MB",
"formats": "檔案格式"
},
"dashboard": {
"yesterday_today": "昨天/今天",
@ -55,6 +56,11 @@
"green_elec": "綠電",
"immediate_demand": "即時需量",
"average_demand": "平均需量",
"real_time_Trend": "即時趨勢",
"contract_capacity": "契約容量",
"alert_capacity": "警戒容量",
"reset_value": "復歸值",
"edit_automatic_demand": "編輯自動需量",
"elec_bills": "今年電費累計(元)",
"interval_elec_charges": "區間電費(元)",
"year_carbon_emission": "今年碳排當量累計(公斤)",
@ -71,7 +77,9 @@
"var_elec_cost": "流動電費",
"fixed_elec_cost": "基本電費",
"total_elec_cost": "總電費",
"carbon_equivalent": "碳排當量"
"carbon_equivalent": "碳排當量",
"edit_carbon_emission": "編輯碳排放係數",
"carbon_emission_coefficient":"碳排放係數"
},
"alarm": {
"title": "顯示警告",
@ -191,7 +199,10 @@
"index": "編號",
"oriOrgName": "檔案",
"operation": "功能",
"upload": "圖資上傳"
"folder_path": "資料夾路徑",
"upload": "圖資上傳",
"staging_area": "刪除暫存區",
"no_path": "無資料夾路徑"
},
"assetManagement": {
"title": "資產管理",
@ -272,10 +283,12 @@
"start_time_placeholder": "請輸入預計開始日期",
"rename": "重新命名",
"download": "下載",
"confirm": "確認"
"confirm": "確認",
"restore": "復原"
},
"msg":{
"sure_to_delete": "是否確認刪除該項目?",
"sure_to_delete_permanent": "是否確認永久刪除該項目?",
"delete_success": "刪除成功",
"delete_failed": "刪除失敗"
}

View File

@ -12,7 +12,8 @@
},
"upload": {
"title": "Select a file or drag and drop here",
"description": "File size cannot exceed 10MB"
"description": "File size cannot exceed 10MB",
"formats": "File formats"
},
"history": {
"title": "Historical Data",
@ -53,8 +54,13 @@
"elec_consumption": "Real-time distribution of electricity consumption",
"total_elec": "Total electricity consumption",
"green_elec": "Green electricity",
"immediate_demand": "immediate demand",
"average_demand": "average demand",
"immediate_demand": "Immediate demand",
"average_demand": "Average demand",
"real_time_Trend": "Real-time Trend",
"contract_capacity": "Contract Capacity",
"alert_capacity": "Alert Capacity",
"reset_value": "Reset Value",
"edit_automatic_demand": "Edit automatic demand",
"elec_bills": "Total electricity bills this year (yuan)",
"interval_elec_charges": "Interval electricity charges (yuan)",
"year_carbon_emission": "Cumulative carbon emission equivalent this year (kg)",
@ -71,7 +77,9 @@
"var_elec_cost": "Var. Elec. Cost",
"fixed_elec_cost": "Fixed Elec. Cost",
"total_elec_cost": "Total Elec. Cost",
"carbon_equivalent": "Carbon Equivalent"
"carbon_equivalent": "Carbon Equivalent",
"edit_carbon_emission": "Edit carbon emission coefficient",
"carbon_emission_coefficient":"Carbon emission coefficient"
},
"alarm": {
"title": "Warning",
@ -191,7 +199,10 @@
"index": "Serial Number",
"oriOrgName": "File",
"operation": "Function",
"upload": "Upload"
"folder_path": "Folder Path",
"upload": "Upload",
"staging_area": "Staging Area",
"no_path": "No path"
},
"assetManagement": {
"title": "Asset Management",
@ -272,10 +283,12 @@
"start_time_placeholder": "Please enter expected start date",
"rename": "Rename",
"download": "Download",
"confirm": "Confirm"
"confirm": "Confirm",
"restore": "Restore"
},
"msg":{
"msg": {
"sure_to_delete": "Are you sure to delete this item?",
"sure_to_delete_permanent": "Are you sure you want to permanently delete this item?",
"delete_success": "Delete successfully",
"delete_failed": "Delete failed"
}

View File

@ -280,6 +280,7 @@ const onCancel = () => {
:getFileList="updateFileList"
:multiple="false"
class="col-span-2"
formats="svg"
>
<template #topLeft>{{ $t("assetManagement.oriFile") }}</template>
</Upload>

View File

@ -9,11 +9,11 @@ const yesterdayTodayData = {
categories: ["00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00", "07:00", "08:00", "09:00", "10:00", "11:00"],
values: [
{
name: `2024.10.21 ${t("dashboard.electricity_consumption")}`,
name: `2024.11.8 ${t("dashboard.electricity_consumption")}`,
value: [8, 8, 8, 8, 8, 15, 25, 65, 75, 60, 70, 65],
},
{
name: `2024.10.20 ${t("dashboard.electricity_consumption")}`,
name: `2024.11.7 ${t("dashboard.electricity_consumption")}`,
value: [10, 10, 10, 10, 10, 20, 30, 80, 90, 70, 80, 85],
},
],
@ -74,9 +74,9 @@ const generateCylinderChartOption = (categories, values) => {
x2: 1, //
y2: 0, //
colorStops: [
{ offset: 0, color: "#acd7e4" }, //
{ offset: 0.5, color: "#0ca9d4" }, //
{ offset: 1, color: "#acd7e4" }, //
{ offset: 0, color: "#17CEE3" }, //
{ offset: 0.5, color: "#398ECA" }, //
{ offset: 1, color: "#17CEE3" }, //
],
},
},
@ -94,9 +94,9 @@ const generateCylinderChartOption = (categories, values) => {
x2: 1, //
y2: 0, //
colorStops: [
{ offset: 0, color: "#fff6b3" }, //
{ offset: 0.5, color: "#ffe000" }, //
{ offset: 1, color: "#fff6b3" }, //
{ offset: 0, color: "#62E39A" }, //
{ offset: 0.5, color: "#05AA9A" }, //
{ offset: 1, color: "#62E39A" }, //
],
},
},
@ -125,7 +125,7 @@ const generateCylinderChartOption = (categories, values) => {
symbolPosition: "end",
data: values[1].value,
itemStyle: {
color: "#c3ae1a",
color: "#05AA9A",
borderWidth: 10,
borderColor: "#fff",
borderType: "solid",
@ -153,7 +153,7 @@ const generateCylinderChartOption = (categories, values) => {
symbolPosition: "start",
data: values[1].value,
itemStyle: {
color: "#ffe000",
color: "#05AA9A",
},
z: 12,
},
@ -201,18 +201,17 @@ const weekComparisonOption = generateCylinderChartOption(
<div class="lg:w-1/2 w-full chart-data relative px-8 py-3">
<div class="flex flex-wrap items-center">
<h2 class="text-xs font-light w-1/2 relative">
{{ $t("dashboard.yesterday_today") }}<br />
{{ $t("dashboard.elec_consumption_comparison_trend") }}
(kWH)
</h2>
<div class="w-[48%]">
<div class="text-con">
<img src="@ASSET/img/chart-title01.svg" />
<span>2024.10.20 {{ $t("dashboard.electricity_consumption") }}</span>
<span>2024.11.8 {{ $t("dashboard.electricity_consumption") }}</span>
</div>
<div class="text-con">
<img src="@ASSET/img/chart-title02.svg" />
<span>2024.10.21 {{ $t("dashboard.electricity_consumption") }}</span>
<span>2024.11.7 {{ $t("dashboard.electricity_consumption") }}</span>
</div>
</div>
</div>

View File

@ -49,7 +49,7 @@ const defaultChartOption = ref({
stack: "total",
data: [],
itemStyle: {
color: "#45f4ef",
color: "#398ECA",
},
},
{
@ -58,7 +58,7 @@ const defaultChartOption = ref({
stack: "total",
data: [],
itemStyle: {
color: "#ffd345",
color: "#05AA9A",
},
},
{
@ -67,7 +67,7 @@ const defaultChartOption = ref({
stack: "total",
data: [],
itemStyle: {
color: "#64ed81",
color: "#62E39A",
},
},
],

View File

@ -1,11 +1,11 @@
<script setup>
import BarChart from "@/components/chart/BarChart.vue";
import { ref, onMounted, inject, watch } from "vue";
import CarbonEmissionModal from "./CarbonEmissionModal.vue";
import { useI18n } from "vue-i18n";
const { t, locale } = useI18n();
const { taipower_data } = inject("energy_data");
const editRecord = ref(null);
const defaultChartOption = ref({
tooltip: {
trigger: "axis",
@ -48,16 +48,14 @@ const defaultChartOption = ref({
type: "bar",
data: [],
itemStyle: {
color: "#45f4ef",
color: "#398ECA",
},
},
],
});
const updateChartNames = () => {
defaultChartOption.value.legend.data = [
t("energy.carbon_equivalent"),
];
defaultChartOption.value.legend.data = [t("energy.carbon_equivalent")];
defaultChartOption.value.series[0].name = t("energy.carbon_equivalent");
};
@ -66,8 +64,8 @@ watch(
taipower_data,
() => {
//
const months = taipower_data.value.map(item => item.month);
const carbonTotal = taipower_data.value.map(item => item.carbon);
const months = taipower_data.value.map((item) => item.month);
const carbonTotal = taipower_data.value.map((item) => item.carbon);
// xAxis series
defaultChartOption.value.xAxis.data = months;
@ -81,6 +79,24 @@ watch(locale, () => {
updateChartNames();
});
const openModal = (record) => {
if (record) {
editRecord.value = record;
} else {
editRecord.value = null;
}
carbon_emission_item.showModal();
};
const onCancel = () => {
editRecord.value = null;
carbon_emission_item.close();
};
const fetchData = async () => {
console.log("ok");
};
onMounted(() => {
updateChartNames();
});
@ -88,8 +104,16 @@ onMounted(() => {
<template>
<div class="bg-slate-800 p-3">
<div class="text-white mb-3 text-base">
{{ $t("energy.monthly_carbon_emission_and_reduction") }}
<div class="flex items-center">
<div class="text-white mb-3 text-base">
{{ $t("energy.monthly_carbon_emission_and_reduction") }}
</div>
<CarbonEmissionModal
:openModal="openModal"
:onCancel="onCancel"
:editRecord="editRecord"
:fetchData="fetchData"
/>
</div>
<div class="bar-box">
<BarChart

View File

@ -0,0 +1,105 @@
<script setup>
import { inject, defineProps, watch, ref } from "vue";
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
import { postAlertMember } from "@/apis/alert";
import * as yup from "yup";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { openToast } = inject("app_toast");
const props = defineProps({
openModal: Function,
onCancel: Function,
editRecord: Object,
fetchData: Function,
});
let scheme = yup.object({
factor: yup.number().required(t("button.required")),
});
const form = ref(null);
const formState = ref({
factor: null,
});
const SaveCheckAuth = ref([]);
const { formErrorMsg, handleSubmit, handleErrorReset } = useFormErrorMessage(
scheme.value
);
watch(
() => props.editRecord,
(newValue) => {
if (newValue) {
formState.value = {
...newValue,
};
}
}
);
const onOk = async () => {
const values = await handleSubmit(scheme, formState.value);
const res = await postAlertMember({
...values,
});
if (res.isSuccess) {
props.fetchData();
closeModal();
} else {
openToast("error", res.msg, "#carbon_emission_item");
}
};
const closeModal = () => {
SaveCheckAuth.value = [];
handleErrorReset();
props.onCancel();
};
</script>
<template>
<button class="btn btn-sm btn-success ms-auto me-3" @click.stop.prevent="openModal">
{{ $t("button.edit") }}
</button>
<Modal
id="carbon_emission_item"
:title="t('energy.edit_carbon_emission')"
:open="open"
:onCancel="closeModal"
width="300"
>
<template #modalContent>
<form ref="form" class="mt-5 flex flex-col items-center">
<Input :value="formState" class="w-full" name="factor">
<template #topLeft>{{$t('energy.carbon_emission_coefficient')}}</template>
<template #bottomLeft>
<span class="text-error text-base">
{{ formErrorMsg.factor }}
</span>
</template>
</Input>
</form>
</template>
<template #modalAction>
<button
type="reset"
class="btn btn-outline-success mr-2"
@click.prevent="closeModal"
>
{{ $t("button.cancel") }}
</button>
<button
type="submit"
class="btn btn-outline-success"
@click.prevent="onOk"
>
{{ $t("button.submit") }}
</button>
</template>
</Modal>
</template>
<style lang="scss" scoped></style>

View File

@ -53,10 +53,11 @@ const loadData = async () => {
const rawData = res.data;
const totalValue = rawData.reduce((acc, item) => acc + item.value, 0);
const sortedData = [...rawData].sort((a, b) => b.value - a.value);
// data
const data = [
{ name: "Total", value: totalValue, percentage: 100 },
...rawData.map((item) => ({
...sortedData.map((item) => ({
name: item.key,
value: item.value,
percentage: item.percentage,
@ -64,14 +65,14 @@ const loadData = async () => {
];
// links
const links = rawData.map((item, index) => ({
const links = sortedData.map((item, index) => ({
source: "Total",
target: item.key,
value: item.value,
percentage: item.percentage,
}));
const colors = ["#45f4ef", "#f5d54e", "#63ed84", "#5a5cac", "#ff5e5e", "#e266fe"];
const colors = ["#45f4ef", "#398ECA", "#05AA9A", "#62E39A", "#17CEE3", "#E9971F"];
// chartOption
chartOption.series[0].data = data.map((item, index) => ({
...item,

View File

@ -1,7 +1,11 @@
<script setup>
import LineChart from "@/components/chart/LineChart.vue";
import { ref, onMounted } from "vue";
import ImmediateDemandModal from "./ImmediateDemandModal.vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const editRecord = ref(null);
//
const data = {
categories: [
@ -14,7 +18,7 @@ const data = {
],
series: [
{
name: "Real-Time Trend", //
name: t("energy.real_time_Trend"), //
type: "line",
data: [320, 310, 300, 305, 310, 300],
smooth: true,
@ -22,11 +26,11 @@ const data = {
width: 3,
},
itemStyle: {
color: "#34b7f1",
color: "#398ECA",
},
},
{
name: "Contract Capacity", //
name: t("energy.contract_capacity"), //
type: "line",
data: [400, 400, 400, 400, 400, 400],
smooth: true,
@ -34,11 +38,11 @@ const data = {
width: 3,
},
itemStyle: {
color: "#A259FF",
color: "#05AA9A",
},
},
{
name: "Alert Capacity", //
name: t("energy.alert_capacity"), //
type: "line",
data: [350, 350, 350, 350, 350, 350],
smooth: true,
@ -46,11 +50,11 @@ const data = {
width: 3,
},
itemStyle: {
color: "#FFCE56",
color: "#62E39A",
},
},
{
name: "Measured Value", //
name: t("energy.reset_value"), //
type: "line",
data: [280, 300, 290, 295, 300, 290],
smooth: true,
@ -58,7 +62,7 @@ const data = {
width: 3,
},
itemStyle: {
color: "#4CAF50",
color: "#17CEE3",
},
},
],
@ -107,6 +111,24 @@ const defaultChartOption = ref({
series: data.series,
});
const openModal = (record) => {
if (record) {
editRecord.value = record;
} else {
editRecord.value = null;
}
immediate_demand_add_item.showModal();
};
const onCancel = () => {
editRecord.value = null;
immediate_demand_add_item.close();
};
const fetchData = async () => {
console.log("ok");
};
onMounted(() => {
//
});
@ -114,7 +136,7 @@ onMounted(() => {
<template>
<div class="p-3">
<div class="flex text-white mb-5">
<div class="flex items-center text-white mb-5">
<div class="flex items-end text-base relative text mr-32">
{{ $t("energy.immediate_demand") }}
<span class="text-2xl px-2.5">245.48 kw</span>
@ -123,6 +145,12 @@ onMounted(() => {
{{ $t("energy.average_demand") }}
<span class="text-2xl px-2.5">230.8 kw</span>
</div>
<ImmediateDemandModal
:openModal="openModal"
:onCancel="onCancel"
:editRecord="editRecord"
:fetchData="fetchData"
/>
</div>
<LineChart
id="immediate_demand_chart"

View File

@ -0,0 +1,125 @@
<script setup>
import { inject, defineProps, watch, ref } from "vue";
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
import { postAlertMember } from "@/apis/alert";
import * as yup from "yup";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { openToast } = inject("app_toast");
const props = defineProps({
openModal: Function,
onCancel: Function,
editRecord: Object,
fetchData: Function,
});
let scheme = yup.object({
contract: yup.number().required(t("button.required")),
alert:yup.number().required(t("button.required")),
reset:yup.number().required(t("button.required")),
});
const form = ref(null);
const formState = ref({
contract: null,
alert: null,
reset: null,
});
const SaveCheckAuth = ref([]);
const { formErrorMsg, handleSubmit, handleErrorReset } = useFormErrorMessage(
scheme.value
);
watch(
() => props.editRecord,
(newValue) => {
if (newValue) {
formState.value = {
...newValue,
};
}
}
);
const onOk = async () => {
const values = await handleSubmit(scheme, formState.value);
const res = await postAlertMember({
...values,
});
if (res.isSuccess) {
props.fetchData();
closeModal();
} else {
openToast("error", res.msg, "#immediate_demand_add_item");
}
};
const closeModal = () => {
SaveCheckAuth.value = [];
handleErrorReset();
props.onCancel();
};
</script>
<template>
<button class="btn btn-sm btn-success ms-auto me-6 my-3" @click.stop.prevent="openModal">
{{ $t("button.edit") }}
</button>
<Modal
id="immediate_demand_add_item"
:title="t('energy.edit_automatic_demand')"
:open="open"
:onCancel="closeModal"
width="300"
>
<template #modalContent>
<form ref="form" class="mt-5 flex flex-col items-center">
<Input :value="formState" class="w-full" name="contract">
<template #topLeft>{{$t("energy.contract_capacity")}}</template>
<template #bottomLeft>
<span class="text-error text-base">
{{ formErrorMsg.contract }}
</span>
</template>
</Input>
<Input class="w-full" :value="formState" name="alert">
<template #topLeft>{{$t("energy.alert_capacity")}}</template>
<template #bottomLeft>
<span class="text-error text-base">
{{ formErrorMsg.alert }}
</span>
</template>
</Input>
<Input class="w-full" :value="formState" name="reset">
<template #topLeft>{{$t("energy.reset_value")}}</template>
<template #bottomLeft>
<span class="text-error text-base">
{{ formErrorMsg.reset }}
</span>
</template>
</Input>
</form>
</template>
<template #modalAction>
<button
type="reset"
class="btn btn-outline-success mr-2"
@click.prevent="closeModal"
>
{{ $t("button.cancel") }}
</button>
<button
type="submit"
class="btn btn-outline-success"
@click.prevent="onOk"
>
{{ $t("button.submit") }}
</button>
</template>
</Modal>
</template>
<style lang="scss" scoped></style>

View File

@ -14,9 +14,9 @@ const dateRange = ref({
//
const chartConfig = {
colors: {
peak: "#3c50e0",
semiPeak: "#6577f3",
offPeak: "#8fd0ef",
peak: "#398ECA",
semiPeak: "#05AA9A",
offPeak: "#62E39A",
},
textColor: "#ffffff",
fontSize: 14,

View File

@ -50,7 +50,7 @@ const defaultChartOption = ref({
stack: "total",
data: [],
itemStyle: {
color: "#ffd345",
color: "#398ECA",
},
},
{
@ -59,7 +59,7 @@ const defaultChartOption = ref({
stack: "total",
data: [],
itemStyle: {
color: "#45f4ef",
color: "#05AA9A",
},
},
{
@ -68,7 +68,7 @@ const defaultChartOption = ref({
stack: "total",
data: [],
itemStyle: {
color: "#64ed81",
color: "#62E39A",
},
},
],

View File

@ -4,10 +4,11 @@ import GraphTable from "./components/GraphTable.vue";
import { provide, ref } from "vue";
const current_dir = ref(null);
const sidebar_data = ref([]);
const updateCurrentDir = (d) => {
current_dir.value = d;
};
provide("current_dir", { current_dir, updateCurrentDir });
provide("current_dir", { current_dir, updateCurrentDir, sidebar_data });
</script>
<template>
@ -15,7 +16,7 @@ provide("current_dir", { current_dir, updateCurrentDir });
<h1 class="text-2xl font-extrabold mb-2">
{{ $t("graphManagement.title") }}
</h1>
<div class="grid grid-cols-9 gap-8">
<div class="grid grid-cols-9 gap-6">
<GraphSidebar class="col-span-2" />
<GraphTable class="col-span-7" />
</div>

View File

@ -11,11 +11,12 @@ import { ref, onMounted, onUnmounted, provide, computed, inject } from "vue";
import useSearchParams from "@/hooks/useSearchParam";
import { useI18n } from "vue-i18n";
const { t, locale } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast");
const { changeParams, searchParams } = useSearchParams();
let raw_data = ref([]);
const { updateCurrentDir } = inject("current_dir");
const { updateCurrentDir, sidebar_data } = inject("current_dir");
// data
const graphData = computed(() => {
@ -40,6 +41,7 @@ const graphData = computed(() => {
updateCurrentDir(
data.find((d) => d.id === parseInt(searchParams.value.id)) || formatD[0]
);
sidebar_data.value = formatD;
return formatD;
});
@ -181,13 +183,20 @@ const addFilename = (root = false) => {
// filename
const deleteFilename = async () => {
const res = await removeSideBarTreeName(selectedItem.value.id);
if (res.isSuccess) {
raw_data.value = raw_data.value.filter(
({ id }) => id !== selectedItem.value.id
);
cancelOpen();
}
openToast("warning", t("msg.sure_to_delete"), "body", async () => {
await cancelToastOpen();
const res = await removeSideBarTreeName(selectedItem.value.id);
if (res.isSuccess) {
raw_data.value = raw_data.value.filter(
({ id }) => id !== selectedItem.value.id
);
cancelOpen();
openToast("success", t("msg.delete_success"));
getData();
} else {
openToast("error", res.msg);
}
});
};
const onClickout = (e) => {
@ -233,8 +242,13 @@ onUnmounted(() => {
:add="addFilename"
:remove="deleteFilename"
/>
<p class="text-xl py-1 ml-7 cursor-pointer" @click.stop.prevent="onLeftClick(-1,null)">
<font-awesome-icon
:icon="['fas', 'trash-alt']"
class="text-rose-500 text-2xl me-3 "
/>{{$t("graphManagement.staging_area")}}
</p>
</div>
</template>
<style lang="scss" scoped></style>
./GraphSidebarDropdown.vue

View File

@ -7,6 +7,7 @@ import { downloadExcelByHref } from "@/util/downloadExcel";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast");
const { sidebar_data } = inject("current_dir");
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const columns = computed(() => [
@ -15,14 +16,18 @@ const columns = computed(() => [
key: "index",
width: 100,
},
{
title: t("graphManagement.folder_path"),
key: "folderPath",
},
{
title: t("graphManagement.oriOrgName"),
key: "oriOrgName",
width: "60%",
},
{
title: t("graphManagement.operation"),
key: "operation",
width: "25%",
},
]);
@ -32,7 +37,7 @@ const { searchParams } = useSearchParams();
const getData = async (id) => {
const res = await getGraphData(id);
if (res.isSuccess) {
dataSource.value = res.data.map((d) => ({ ...d, key: d.id }));
dataSource.value = res.data.map((d) => ({ ...d, key: d.id, parentId: d.layer_id }));
}
};
@ -43,17 +48,29 @@ const updateEditRecord = (data) => {
editRecord.value = data;
};
const delRecord = async (id) => {
openToast("warning", t("msg.sure_to_delete"), "body", async () => {
await cancelToastOpen();
const res = await delGraphData(id);
const delRecord = async (id, hard_delete = false, recover_delete = false) => {
if (recover_delete) {
const res = await delGraphData(id, false, recover_delete);
if (res.isSuccess) {
getData(parseInt(searchParams.value.id));
openToast("success", t("msg.delete_success"));
getData(0);
} else {
openToast("error", res.msg);
}
});
}else{
const confirmMessage = hard_delete
? t("msg.sure_to_delete_permanent")
: t("msg.sure_to_delete");
openToast("warning", confirmMessage, "body", async () => {
await cancelToastOpen();
const res = await delGraphData(id,hard_delete,false);
if (res.isSuccess) {
getData(parseInt(searchParams.value.id > 0 ? parseInt(searchParams.value.id) : 0));
openToast("success", t("msg.delete_success"));
} else {
openToast("error", res.msg);
}
});
}
};
watch(
@ -61,7 +78,7 @@ watch(
(newVal) => {
if (newVal.value.id) {
updateEditRecord(null);
getData(parseInt(newVal.value.id));
getData(newVal.value.id > 0 ? parseInt(newVal.value.id) : 0);
}
},
{
@ -70,6 +87,17 @@ watch(
}
);
const getFolderPath = (id, nodes = sidebar_data.value) => {
for (const node of nodes) {
if (node.id === id) return node.remark;
if (node.children && node.children.length > 0) {
const childPath = getFolderPath(id, node.children);
if (childPath) return `${childPath}`;
}
}
return null;
};
const downloadFile = async (record) => {
console.log(record);
downloadExcelByHref(
@ -82,12 +110,20 @@ const downloadFile = async (record) => {
<template>
<div>
<div class="flex items-center mb-3">
<font-awesome-icon
:icon="['fas', 'trash-alt']"
class="text-rose-600 text-3xl me-4 my-2"
v-if="searchParams.id < 0"
/>
<GraphModal
:editRecord="editRecord"
:updateEditRecord="updateEditRecord"
:getTableData="getData"
v-else
/>
<h1 class="text-xl">{{ current_dir?.remark }}</h1>
<h1 class="text-xl">
{{ searchParams.id < 0 ? $t("graphManagement.staging_area") : current_dir?.remark }}
</h1>
</div>
<Table :columns="columns" :dataSource="dataSource">
<template #bodyCell="{ record, column, index }">
@ -101,10 +137,14 @@ const downloadFile = async (record) => {
{{ record.oriOrgName }}
</a>
</template>
<template v-else-if="column.key == 'folderPath'" >
{{ getFolderPath(record.parentId) || $t("graphManagement.no_path") }}
</template>
<template v-else-if="column.key === 'operation'">
<button
class="btn btn-sm btn-success text-white mr-2"
@click.stop.prevent="() => downloadFile(record)"
v-if="searchParams.id > 0"
>
{{ $t("button.download") }}
</button>
@ -115,16 +155,24 @@ const downloadFile = async (record) => {
updateEditRecord(record);
}
"
v-if="searchParams.id > 0"
>
{{ $t("button.edit") }}
</button>
<button
class="btn btn-sm btn-error text-white"
class="btn btn-sm btn-info text-white mr-2"
@click.stop.prevent="
() => {
delRecord(record.id);
delRecord(record.id, false, true);
}
"
v-else
>
{{ $t("button.restore") }}
</button>
<button
class="btn btn-sm btn-error text-white"
@click.stop.prevent="() => delRecord(record.id, searchParams.id > 0 ? false : true)"
>
{{ $t("button.delete") }}
</button>

View File

@ -8,10 +8,12 @@ import { ref, provide } from "vue";
const tableData = ref([]);
const loading = ref(false);
const updateTableData = (data) => {
tableData.value = data.items.map((d) => ({
...d,
key: `${d.device_number}_${d.points}_${dayjs(d.timestamp).format("x")}`,
}));
tableData.value = data
? data.items.map((d) => ({
...d,
key: `${d.device_number}_${d.points}_${dayjs(d.timestamp).format("x")}`,
}))
: [];
};
const updateLoading = () => {

View File

@ -7,13 +7,23 @@ const { getCurrentInfoModalData } = inject("system_selectedDevice")
const { showData } = useSystemShowData()
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const fitToView = (forge_dbid) => {
// console.log(forge_dbid)
// window.NOP_VIEWER.hide(forge_dbid + 3);
// window.NOP_VIEWER.impl.invalidate(true);
window.NOP_VIEWER.fitToView([forge_dbid])
}
const viewer = window.NOP_VIEWER;
if (!viewer) return;
const nav = viewer.navigation;
const camera = nav.getCamera();
viewer.fitToView([forge_dbid], null, true);
const direction = new THREE.Vector3();
camera.getWorldDirection(direction);
// 退
const distanceBack = 30; // 退
camera.position.add(direction.multiplyScalar(-distanceBack));
const target = nav.getTarget();
const fov = nav.getVerticalFov();
nav.setRequestTransition(true, camera.position, target, fov);
};
</script>
<template>