|
@@ -0,0 +1,422 @@
|
|
|
+<template>
|
|
|
+ <div class="card-all">
|
|
|
+ <div class="card-title">
|
|
|
+ <div class="card-t">{{ data.name }}</div>
|
|
|
+ <div class="card-c" @click="handleClick">修改</div>
|
|
|
+ </div>
|
|
|
+ <div class="paramsRunRcharts">
|
|
|
+ <div class="paramsRunBtn" @click="showParamsModel">选择显示参数</div>
|
|
|
+ <LineChart
|
|
|
+ :showYAxisLabels="showYAxisLabels"
|
|
|
+ :xAxisData="xAxisParamsData"
|
|
|
+ :seriesData="seriesParamsData"
|
|
|
+ :legendData="legendPramsData"
|
|
|
+ :gridTop="gridParamsTop"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 参数运行曲线model -->
|
|
|
+ <ModalComponent
|
|
|
+ v-model:visible="showModal"
|
|
|
+ customClass="custom-modal"
|
|
|
+ title="选择显示曲线图的参数"
|
|
|
+ >
|
|
|
+ <div class="hra">
|
|
|
+ <div class="hra-left">
|
|
|
+ <div>选择设备</div>
|
|
|
+ <div class="custom-time-select">
|
|
|
+ <el-select
|
|
|
+ class="hra-sel"
|
|
|
+ v-model="btnBigIndex"
|
|
|
+ @change="setCateData"
|
|
|
+ placeholder="选择设备"
|
|
|
+ >
|
|
|
+ <template v-slot:prefix>
|
|
|
+ <!-- <el-icon color="rgba(255, 255, 255, 0.75)">
|
|
|
+ <Filter />
|
|
|
+ </el-icon> -->
|
|
|
+ </template>
|
|
|
+ <el-option v-for="item in cateBigRef" :key="item" :value="item">{{
|
|
|
+ item
|
|
|
+ }}</el-option>
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="hra-right">
|
|
|
+ <div>选择大类(仅可选择一类)</div>
|
|
|
+ <div
|
|
|
+ :class="['btn', btnIndex == index ? 'btnCurrent' : '']"
|
|
|
+ @click="btnTab(index, item)"
|
|
|
+ v-for="(item, index) in cateSmallRef"
|
|
|
+ :key="item"
|
|
|
+ >
|
|
|
+ {{ item }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 模态框内容插槽 -->
|
|
|
+ <div class="custom-box box-height">
|
|
|
+ <el-checkbox-group @change="changeAttr" v-model="checkedParams">
|
|
|
+ <el-checkbox
|
|
|
+ v-for="item in setParams"
|
|
|
+ :key="item"
|
|
|
+ :label="item"
|
|
|
+ :value="item"
|
|
|
+ ></el-checkbox>
|
|
|
+ <!-- 其他选项 -->
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ </ModalComponent>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import moment from "moment";
|
|
|
+import { Warning } from "@element-plus/icons-vue";
|
|
|
+
|
|
|
+import {
|
|
|
+ ref,
|
|
|
+ onMounted,
|
|
|
+ onUnmounted,
|
|
|
+ nextTick,
|
|
|
+ computed,
|
|
|
+ watch,
|
|
|
+ Ref,
|
|
|
+ getCurrentInstance,
|
|
|
+ defineProps,
|
|
|
+ defineEmits,
|
|
|
+} from "vue";
|
|
|
+import { useRoute, useRouter } from "vue-router";
|
|
|
+import { ElTimeSelect, ElMessage } from "element-plus";
|
|
|
+import CalendarHeatmap from "@/components/CalendarHeatmap/index.vue";
|
|
|
+import LineChart from "@/components/LineChart/index.vue";
|
|
|
+import { COLUMN_MAP } from "@/utils/engine";
|
|
|
+import sTitle from "@/components/StructTitle/index.vue";
|
|
|
+import ModalComponent from "@/components/ModalComponent/index.vue";
|
|
|
+import WebSocketClient from "@/utils/webSocketClient";
|
|
|
+import { Interface } from "readline";
|
|
|
+import { time } from "console";
|
|
|
+import {
|
|
|
+ recordAssessmentResult,
|
|
|
+ healthStatusTip,
|
|
|
+ healthySetList,
|
|
|
+ measurementPoints,
|
|
|
+ devicesAndCategories,
|
|
|
+} from "@/api/index";
|
|
|
+const props = defineProps({
|
|
|
+ data: {
|
|
|
+ type: Object,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+});
|
|
|
+watch(
|
|
|
+ () => props.data,
|
|
|
+ (newData, oldData) => {
|
|
|
+ lineParamsAllRef.value = newData;
|
|
|
+ },
|
|
|
+ { deep: true }
|
|
|
+);
|
|
|
+const emit = defineEmits(["viewDetails"]);
|
|
|
+
|
|
|
+const handleClick = () => {
|
|
|
+ emit("viewDetails", props.data);
|
|
|
+};
|
|
|
+onMounted(() => {
|
|
|
+ getcateData();
|
|
|
+ getPointData(btnBigIndex.value, "温度");
|
|
|
+});
|
|
|
+let cateBigRef = ref([]);
|
|
|
+let cateSmallRef = ref([]);
|
|
|
+let setParams = ref([]);
|
|
|
+let btnIndex = ref(0);
|
|
|
+let btnBigIndex = ref("右DE");
|
|
|
+const btnTab = (index, val) => {
|
|
|
+ btnIndex.value = index;
|
|
|
+ getPointData(btnBigIndex.value, val);
|
|
|
+};
|
|
|
+const setCateData = () => {
|
|
|
+ getPointData(btnBigIndex.value, cateSmallRef.value[btnIndex.value]);
|
|
|
+};
|
|
|
+
|
|
|
+const getcateData = async () => {
|
|
|
+ let data = await devicesAndCategories({});
|
|
|
+ cateBigRef = data.data.devices;
|
|
|
+ cateSmallRef.value = data.data.categories;
|
|
|
+};
|
|
|
+const getPointData = async (deviceName, categoryName) => {
|
|
|
+ let data = await measurementPoints({ deviceName, categoryName });
|
|
|
+ setParams.value = data.data.map((its) => its.pointName);
|
|
|
+};
|
|
|
+// 获取所有显示参数
|
|
|
+let lineParamsAllRef = ref([]);
|
|
|
+watch(
|
|
|
+ () => lineParamsAllRef.value,
|
|
|
+ (newdata: any) => {
|
|
|
+ if (lineParamsAllRef.value.length == 0) {
|
|
|
+ const result: Array<AnyObject> = convertToChartData(
|
|
|
+ newdata,
|
|
|
+ checkedParams.value
|
|
|
+ );
|
|
|
+ setLineparames(newdata, result);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const result: Array<AnyObject> = convertToChartData(
|
|
|
+ newdata,
|
|
|
+ checkedParams.value
|
|
|
+ );
|
|
|
+
|
|
|
+ setLineparames(newdata, result);
|
|
|
+ },
|
|
|
+ { deep: true }
|
|
|
+);
|
|
|
+// const setParams = ref(convertObjectToArray(COLUMN_MAP));
|
|
|
+const changeAttr = (valArr: string[]) => {
|
|
|
+ btnIndex.value == 5
|
|
|
+ ? (showYAxisLabels.value = false)
|
|
|
+ : (showYAxisLabels.value = true);
|
|
|
+ let val = setParams.value.filter((element) => valArr.includes(element));
|
|
|
+ if (val.length > 5) {
|
|
|
+ ElMessage({
|
|
|
+ message: `最多选择5个参数`,
|
|
|
+ type: "error",
|
|
|
+ });
|
|
|
+ checkedParams.value = val.slice(0, 5);
|
|
|
+ } else {
|
|
|
+ checkedParams.value = val;
|
|
|
+ }
|
|
|
+ // localStorage.setItem(
|
|
|
+ // "OE_checked_params",
|
|
|
+ // JSON.stringify(checkedParams.value)
|
|
|
+ // );
|
|
|
+ // localStorage.setItem("btnIndex", btnIndex.value);
|
|
|
+ // localStorage.setItem("btnBigIndex", btnBigIndex.value);
|
|
|
+};
|
|
|
+// 显示参数相关(模态框)
|
|
|
+const showModal = ref(false);
|
|
|
+let openFailIndex = 0;
|
|
|
+const showParamsModel = () => {
|
|
|
+ // 判断要是数据没请求过来的情况下 延迟500毫秒在调用下,最多三次
|
|
|
+ if (cateSmallRef.value.length == 0 && openFailIndex < 3) {
|
|
|
+ openFailIndex++;
|
|
|
+ setTimeout(() => {
|
|
|
+ showParamsModel();
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ // let btn = localStorage.getItem("btnIndex");
|
|
|
+ // let btnBig = localStorage.getItem("btnBigIndex");
|
|
|
+ // if (!!btn && !!btnBig) {
|
|
|
+ // btnIndex.value = btn;
|
|
|
+ // btnBigIndex.value = btnBig;
|
|
|
+ // getPointData(btnBigIndex.value, cateSmallRef.value[btnIndex.value]);
|
|
|
+ // }
|
|
|
+
|
|
|
+ showModal.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+const checkedParams = ref([]);
|
|
|
+// 设备参数全
|
|
|
+// 参数运行示例数据
|
|
|
+// 横坐标轴时间点
|
|
|
+let xAxisParamsData = ref([]);
|
|
|
+let seriesParamsData = ref([]);
|
|
|
+let showParamsLegend = ref(true);
|
|
|
+let showYAxisLabels = ref(true);
|
|
|
+let legendPramsData = ref([]);
|
|
|
+let gridParamsTop = ref(40); // 根据是否显示图例动态调整
|
|
|
+const invertObjectKeysAndValues = (
|
|
|
+ obj: Record<string, string>
|
|
|
+): Record<string, string> => {
|
|
|
+ return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
|
+ acc[value] = key;
|
|
|
+ return acc;
|
|
|
+ }, {} as Record<string, string>);
|
|
|
+};
|
|
|
+// const inverParams = invertObjectKeysAndValues(COLUMN_MAP);
|
|
|
+const inverParams = COLUMN_MAP;
|
|
|
+// 设置默认5个数值
|
|
|
+// checkedParams.value = Object.values(COLUMN_MAP).slice(0, 5);
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param dataAll 全部数据,获取数据中的time
|
|
|
+ * @param selectData 折线图数据,符合格式返回
|
|
|
+ * @description xAxisParamsData 横坐标时间点 [时间]
|
|
|
+ * @description seriesParamsData 折线图数据[{
|
|
|
+ name: "温度",
|
|
|
+ data: [3020, 2010, 2005, 2030, 2040, 2025, 2015, 2020, 2005, 2010],
|
|
|
+ }]
|
|
|
+ * @description legendPramsData 图例数据["温度", "压力", "流量"]
|
|
|
+ */
|
|
|
+const setLineparames = (
|
|
|
+ dataAll: Array<AnyObject>,
|
|
|
+ selectData: Array<AnyObject>
|
|
|
+) => {
|
|
|
+ // 横坐标时间点
|
|
|
+ xAxisParamsData.value = dataAll.map((its) =>
|
|
|
+ moment(its.data._ts).format("HH:mm:ss")
|
|
|
+ );
|
|
|
+ // .slice(-30);
|
|
|
+ // 折线图数据
|
|
|
+ seriesParamsData.value = selectData.map((its) => {
|
|
|
+ return {
|
|
|
+ ...its,
|
|
|
+ data: its.data.slice(-30),
|
|
|
+ };
|
|
|
+ });
|
|
|
+ // 图例
|
|
|
+ legendPramsData.value = selectData.map((its) => its.name);
|
|
|
+};
|
|
|
+// 参数转化
|
|
|
+const convertObjectToArray = (
|
|
|
+ obj: Record<string, string>
|
|
|
+): { name: string; value: string }[] => {
|
|
|
+ return Object.entries(obj).map(([key, value]) => ({
|
|
|
+ name: key,
|
|
|
+ value,
|
|
|
+ }));
|
|
|
+};
|
|
|
+
|
|
|
+interface AnyObject {
|
|
|
+ [key: string]: any;
|
|
|
+}
|
|
|
+const convertToChartData = (
|
|
|
+ selectedData: AnyObject[],
|
|
|
+ properties: string[]
|
|
|
+): { name: string; data: any[] }[] => {
|
|
|
+ // properties.forEach(its=>{
|
|
|
+ // console.log(selectedData.map((item) => item.data['right_de_rpm_sensor_fault']),its,inverParams[its]);
|
|
|
+
|
|
|
+ // })
|
|
|
+ // // console.log(selectedData);
|
|
|
+
|
|
|
+ // debugger
|
|
|
+ return properties.map((propertyName) => ({
|
|
|
+ name: propertyName,
|
|
|
+ // name: propertyName,
|
|
|
+ data: selectedData.map((item) => item.data[inverParams[propertyName]]),
|
|
|
+ }));
|
|
|
+};
|
|
|
+const formatPressure = (value: number | string) => {
|
|
|
+ // console.log(typeof value,'------');
|
|
|
+
|
|
|
+ // if (typeof value == 'string') {
|
|
|
+ // return Number(value).toFixed(2);
|
|
|
+ // }
|
|
|
+ return value;
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.card-all {
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ height: 380px;
|
|
|
+ border: 1px solid rgba(56, 151, 255, 0.6);
|
|
|
+ background: rgba(22, 93, 255, 0.1);
|
|
|
+ /* padding: 10px; */
|
|
|
+}
|
|
|
+.card-title {
|
|
|
+ box-sizing: border-box;
|
|
|
+ width: 100%;
|
|
|
+ height: 44px;
|
|
|
+ line-height: 44px;
|
|
|
+ /* padding: 10px; */
|
|
|
+ display: flex;
|
|
|
+ padding-left: 20px;
|
|
|
+ padding-right: 20px;
|
|
|
+ justify-content: space-between;
|
|
|
+ border-bottom: 1px solid rgba(56, 151, 255, 0.6);
|
|
|
+
|
|
|
+ color: rgba(255, 255, 255, 0.85);
|
|
|
+}
|
|
|
+.card-c {
|
|
|
+ color: #3897ff;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.paramsRunRcharts {
|
|
|
+ margin-top: 10px;
|
|
|
+ width: 100%;
|
|
|
+ height: 320px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ position: relative;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+.paramsRunBtn {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 6;
|
|
|
+ right: 20px;
|
|
|
+ top: 15px;
|
|
|
+ width: 130px;
|
|
|
+ height: 30px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #ffffffbf;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 30px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border: 1px solid rgb(0, 122, 255);
|
|
|
+ border-radius: 4px;
|
|
|
+
|
|
|
+ background: rgba(0, 122, 255, 0.1);
|
|
|
+}
|
|
|
+.hra {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-start;
|
|
|
+ align-items: center;
|
|
|
+ color: #fff;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+.hra-left {
|
|
|
+ display: flex;
|
|
|
+ width: 190px;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 80px;
|
|
|
+}
|
|
|
+.hra-right {
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ white-space: pre-wrap; /* Allows wrapping */
|
|
|
+ /* min-width: 200px; */
|
|
|
+
|
|
|
+ justify-content: flex-start;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.hra-sel {
|
|
|
+ width: 120px;
|
|
|
+}
|
|
|
+.warnIcon {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #999;
|
|
|
+ margin-left: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.btn {
|
|
|
+ /* width: 22%; */
|
|
|
+ margin: 5px 5px;
|
|
|
+ padding: 8px 15px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: rgba(0, 122, 255, 0.25);
|
|
|
+ color: rgba(255, 255, 255, 0.45);
|
|
|
+ text-align: center;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid rgb(0, 122, 255);
|
|
|
+}
|
|
|
+.btn:hover {
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+.btnCurrent {
|
|
|
+ color: #fff;
|
|
|
+ background: #165dff;
|
|
|
+}
|
|
|
+.btn-big {
|
|
|
+ width: 40%;
|
|
|
+}
|
|
|
+.btn-big:hover {
|
|
|
+ background-color: rgb(0, 122, 255);
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+</style>
|