|
|
@@ -0,0 +1,495 @@
|
|
|
+<!--
|
|
|
+ * @Author: your name
|
|
|
+ * @Date: 2025-07-23 10:53:25
|
|
|
+ * @LastEditTime: 2025-07-24 10:01:15
|
|
|
+ * @LastEditors: bogon
|
|
|
+ * @Description: In User Settings Edit
|
|
|
+ * @FilePath: /performance-test/src/views/overview/components/production_indicator2/index.vue
|
|
|
+-->
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="type-variable">
|
|
|
+ <!-- production_indicator2 整体状态评估 -->
|
|
|
+ <div class="left scroller">
|
|
|
+ <FilterChart
|
|
|
+ :setUpimg="[]"
|
|
|
+ :isShowEngList="false"
|
|
|
+ :windList="windEngineGroupList"
|
|
|
+ @getEnfineList="getEnfineList"
|
|
|
+ @handlePrevious="handlePrevious"
|
|
|
+ @handleNext="handleNext"
|
|
|
+ ></FilterChart>
|
|
|
+ <el-alert type="info" :closable="false">
|
|
|
+ <template v-slot:title>
|
|
|
+ <div style="display: flex; align-items: center">
|
|
|
+ <i
|
|
|
+ class="el-icon-info"
|
|
|
+ style="font-size: 20px; margin-right: 5px"
|
|
|
+ ></i>
|
|
|
+ <h3>分析说明:</h3>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div style="font-size: 12px; margin-top: 10px">
|
|
|
+ 对各个机组整体状态评估的发电量和故障时长进行统计
|
|
|
+ </div>
|
|
|
+ </el-alert>
|
|
|
+ <div class="chartsBox" v-if="fenFaultCsvData.length > 0">
|
|
|
+ <FaultUnit
|
|
|
+ :faultTitledata="[
|
|
|
+ '机组发电量VS故障停机时长',
|
|
|
+ '故障时长(小时)',
|
|
|
+ '发电量(MWH)',
|
|
|
+ '故障次数',
|
|
|
+ ]"
|
|
|
+ :faultTypes="
|
|
|
+ fenFaultCsvData &&
|
|
|
+ fenFaultCsvData[0] &&
|
|
|
+ fenFaultCsvData[0].data.map((item) => item.wind_turbine_name)
|
|
|
+ "
|
|
|
+ :faultCounts="
|
|
|
+ fenFaultCsvData &&
|
|
|
+ fenFaultCsvData[0] &&
|
|
|
+ fenFaultCsvData[0].data.map((item) => Number(item.count))
|
|
|
+ "
|
|
|
+ :faultDurations="
|
|
|
+ fenFaultCsvData &&
|
|
|
+ fenFaultCsvData[0] &&
|
|
|
+ fenFaultCsvData[0].data.map((item) => Number(item.fault_time))
|
|
|
+ "
|
|
|
+ :fenFaultCsvData="fenFaultCsvData"
|
|
|
+ ></FaultUnit>
|
|
|
+ <!-- <template v-for="itemCsv in fenFaultCsvData">
|
|
|
+ <el-table
|
|
|
+ max-height="500"
|
|
|
+ :data="filteredFenData(itemCsv)"
|
|
|
+ :default-sort="{ prop: 'fault_time', order: 'descending' }"
|
|
|
+ border
|
|
|
+ style="width: 100%"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
+ <el-table-column prop="wind_turbine_name" label="机组" sortable>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="count" sortable label="故障次数(次)">
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="fault_time"
|
|
|
+ sortable
|
|
|
+ label="故障时长(小时)"
|
|
|
+ >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ {{ Number(scope.row.fault_time).toFixed(2) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="right">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <el-input
|
|
|
+ v-model="searchFen"
|
|
|
+ size="mini"
|
|
|
+ placeholder="输入风机名称关键字搜索"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </template> -->
|
|
|
+ </div>
|
|
|
+ <el-empty description="暂无分析记录" v-else></el-empty>
|
|
|
+ <el-dialog
|
|
|
+ v-if="isShowDescription"
|
|
|
+ title="添加评论"
|
|
|
+ :visible="isShow"
|
|
|
+ width="30%"
|
|
|
+ v-dialogDrag
|
|
|
+ :modal="false"
|
|
|
+ :lock-scroll="false"
|
|
|
+ :modal-append-to-body="false"
|
|
|
+ @close="handleClose"
|
|
|
+ >
|
|
|
+ <el-tabs value="first">
|
|
|
+ <el-tab-pane label="意见描述" name="first">
|
|
|
+ <TinymceEditor
|
|
|
+ ref="editor"
|
|
|
+ v-model="comment"
|
|
|
+ @input="handleEditorInput($event)"
|
|
|
+ @onClick="onClick"
|
|
|
+ >
|
|
|
+ </TinymceEditor>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ <el-row
|
|
|
+ type="flex"
|
|
|
+ class="row-bg"
|
|
|
+ justify="end"
|
|
|
+ style="margin: 20px 60px 0 0"
|
|
|
+ >
|
|
|
+ <el-col :span="2">
|
|
|
+ <el-button type="primary" size="small" @click="handleComment"
|
|
|
+ >提交评论</el-button
|
|
|
+ >
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+ <div class="right" v-if="isShowTinymceEditorCom">
|
|
|
+ <DicCard
|
|
|
+ :batchCode="initBatchCode"
|
|
|
+ :analysisTypeCode="'fault'"
|
|
|
+ :commentDescriptionVos="commentDescriptionVos"
|
|
|
+ >
|
|
|
+ </DicCard>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import DicCard from "@/views/overview/components/dicCard/index.vue";
|
|
|
+import FilterChart from "@/views/overview/components/filterChart/index.vue";
|
|
|
+import FaultUnit from "@/views/performance/components/chartsCom/FaultUnit.vue";
|
|
|
+import TinymceEditor from "@/components/Tinymce.vue";
|
|
|
+import {
|
|
|
+ analysisDetail,
|
|
|
+ queryAnalysisedEngine,
|
|
|
+ analysisCommentEdit,
|
|
|
+} from "@/api/performance";
|
|
|
+import Papa from "papaparse";
|
|
|
+import axios from "axios";
|
|
|
+export default {
|
|
|
+ name: "fault_unit",
|
|
|
+ components: {
|
|
|
+ DicCard,
|
|
|
+ FilterChart,
|
|
|
+ FaultUnit,
|
|
|
+ TinymceEditor,
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ initBatchCode: {
|
|
|
+ default: "",
|
|
|
+ type: String,
|
|
|
+ },
|
|
|
+ isShowTinymceEditorCom: {
|
|
|
+ default: true,
|
|
|
+ type: Boolean,
|
|
|
+ },
|
|
|
+ analysisTypeCode: {
|
|
|
+ default: "",
|
|
|
+ type: String,
|
|
|
+ },
|
|
|
+ batchCodeList: {
|
|
|
+ default: "",
|
|
|
+ type: Array,
|
|
|
+ },
|
|
|
+ isShow: {
|
|
|
+ default: false,
|
|
|
+ type: Boolean,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ searchFen: "",
|
|
|
+ form: {
|
|
|
+ value2: "",
|
|
|
+ },
|
|
|
+ setUpImgData: [],
|
|
|
+ isShowDescription: false,
|
|
|
+ commentDescriptionVos: [], //评论列表
|
|
|
+ windEngineGroupList: [], //批次风机列表
|
|
|
+ fieldEngineCodes: [], //选中风机
|
|
|
+ comment: "",
|
|
|
+ options: [],
|
|
|
+ zongFaultCsvHeader: [],
|
|
|
+ zongFaultCsvData: [],
|
|
|
+ fenFaultCsvData: [],
|
|
|
+ fenFaultCsvHeader: [],
|
|
|
+ editableTabs: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 根据搜索关键字过滤数据
|
|
|
+ filteredFenData() {
|
|
|
+ return (itemCsv) => {
|
|
|
+ // 如果有搜索关键词,则过滤数据
|
|
|
+ if (this.searchFen) {
|
|
|
+ return itemCsv.data.filter((item) => {
|
|
|
+ return item.wind_turbine_name
|
|
|
+ .toLowerCase()
|
|
|
+ .includes(this.searchFen.toLowerCase());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 没有搜索关键词时返回所有数据
|
|
|
+ console.log(itemCsv.data);
|
|
|
+ return itemCsv.data;
|
|
|
+ };
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ initBatchCode(newVal) {
|
|
|
+ if (newVal) {
|
|
|
+ this.fetchData(); // 调用合并后的函数
|
|
|
+ }
|
|
|
+ },
|
|
|
+ analysisTypeCode(newVal) {
|
|
|
+ if (newVal) {
|
|
|
+ this.fetchData(); // 调用合并后的函数
|
|
|
+ }
|
|
|
+ },
|
|
|
+ isShow() {
|
|
|
+ if (this.isShow) {
|
|
|
+ if (!this.isShowDescription) {
|
|
|
+ this.$message({
|
|
|
+ message: "当前分析模型暂无分析,不能进行评论操作",
|
|
|
+ type: "warning",
|
|
|
+ });
|
|
|
+ this.$emit("setIsShow");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ if (this.initBatchCode && this.analysisTypeCode) {
|
|
|
+ this.fetchData(); // 调用合并后的函数
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleClose() {
|
|
|
+ //关闭评论弹框
|
|
|
+ this.$emit("setIsShow");
|
|
|
+ },
|
|
|
+ onSubmit() {
|
|
|
+ console.log("submit!");
|
|
|
+ },
|
|
|
+ async handleComment() {
|
|
|
+ try {
|
|
|
+ await analysisCommentEdit({
|
|
|
+ batchCode: this.initBatchCode,
|
|
|
+ analysisTypeCode: this.analysisTypeCode,
|
|
|
+ commentList: this.editableTabs.map((item) => {
|
|
|
+ return {
|
|
|
+ commentTypeCode: item.commentTypeCode,
|
|
|
+ comment: item.commentTypeName === "分析评论" ? this.comment : "",
|
|
|
+ };
|
|
|
+ }),
|
|
|
+ });
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "保存成功",
|
|
|
+ });
|
|
|
+ this.comment = "";
|
|
|
+ this.getAnalysisDetail();
|
|
|
+ this.$emit("setIsShow");
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ this.loading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 封装的获取 CSV 数据方法
|
|
|
+ fetchCsvData(analysisType, url) {
|
|
|
+ axios
|
|
|
+ .get(url, { responseType: "blob" }) // 确保数据以 blob 格式返回
|
|
|
+ .then((response) => {
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = (e) => {
|
|
|
+ const csvText = e.target.result;
|
|
|
+ Papa.parse(csvText, {
|
|
|
+ header: true, // 使用 CSV 第一行作为键
|
|
|
+ complete: (result) => {
|
|
|
+ // 根据分析模型设置不同的数据
|
|
|
+ if (analysisType === "fault") {
|
|
|
+ if (
|
|
|
+ Object.keys(result.data[0]).includes("wind_turbine_name")
|
|
|
+ ) {
|
|
|
+ //分机型故障统计处理
|
|
|
+ this.fenFaultCsvHeader.push(Object.keys(result.data[0]));
|
|
|
+
|
|
|
+ this.fenFaultCsvData.push({
|
|
|
+ data: result.data
|
|
|
+ .filter((row) => {
|
|
|
+ return Object.keys(row).length;
|
|
|
+ })
|
|
|
+ .slice(0, result.data.length - 1)
|
|
|
+ .map((item) => ({
|
|
|
+ ...item,
|
|
|
+ count: Number(item.count),
|
|
|
+ fault_time: Number(item.fault_time) / 3600,
|
|
|
+ })),
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error: (error) => {
|
|
|
+ console.error("CSV 解析错误:", error);
|
|
|
+ },
|
|
|
+ });
|
|
|
+ };
|
|
|
+ reader.readAsText(response.data); // 读取 blob 数据
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error("无法获取 CSV 文件:", error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 合并后的函数,处理数据请求
|
|
|
+ async fetchData() {
|
|
|
+ try {
|
|
|
+ // 获取分析详情
|
|
|
+ await this.getAnalysisDetail();
|
|
|
+
|
|
|
+ // 获取风机列表
|
|
|
+ await this.getWindEnfineList(this.initBatchCode, this.analysisTypeCode);
|
|
|
+ } catch (err) {
|
|
|
+ console.error("Failed to fetch data:", err);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取分析详情接口
|
|
|
+ async getAnalysisDetail() {
|
|
|
+ try {
|
|
|
+ const result = await analysisDetail({
|
|
|
+ batchCode: this.initBatchCode,
|
|
|
+ analysisTypeCode: "fault",
|
|
|
+ fieldEngineCodes:
|
|
|
+ this.fieldEngineCodes.length === 0
|
|
|
+ ? undefined
|
|
|
+ : this.fieldEngineCodes.join(","),
|
|
|
+ });
|
|
|
+ if (result.data.length > 0) {
|
|
|
+ this.isShowDescription = true;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ result.data &&
|
|
|
+ result.data[0] &&
|
|
|
+ result.data[0].commentTypeRelations
|
|
|
+ ) {
|
|
|
+ this.editableTabs = result.data[0].commentTypeRelations;
|
|
|
+ }
|
|
|
+ //当前评论展示获取
|
|
|
+ if (
|
|
|
+ result.data &&
|
|
|
+ result.data[0] &&
|
|
|
+ result.data[0].commentDescriptionVos
|
|
|
+ ) {
|
|
|
+ this.commentDescriptionVos = result.data[0].commentDescriptionVos;
|
|
|
+ }
|
|
|
+ if (result.data && result.data[0] && result.data[0].generalFiles) {
|
|
|
+ result.data[0].generalFiles.map((item) => {
|
|
|
+ if (item.fileAddr) {
|
|
|
+ this.fenFaultCsvHeader = [];
|
|
|
+ this.fenFaultCsvData = [];
|
|
|
+ this.fetchCsvData("fault", item.fileAddr);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.fenFaultCsvHeader = [];
|
|
|
+ this.fenFaultCsvData = [];
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.error("Failed to fetch analysis details:", err);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 请求风机列表
|
|
|
+ async getWindEnfineList(batchCode, analysisTypeCode) {
|
|
|
+ // console.log("请求风机列表 分钟级");
|
|
|
+ const resEngineList = await queryAnalysisedEngine({
|
|
|
+ batchCode: batchCode,
|
|
|
+ analysisTypeCode,
|
|
|
+ });
|
|
|
+ this.windEngineGroupList = resEngineList.data;
|
|
|
+ },
|
|
|
+ handleEditorInput(index, newVal) {
|
|
|
+ // 更新对应的 comment 值
|
|
|
+ // 如果该功能没有实现,可以删除这个方法
|
|
|
+ },
|
|
|
+ //获取选中风机list
|
|
|
+ getEnfineList(data, setUpImg) {
|
|
|
+ this.fieldEngineCodes = data;
|
|
|
+ this.setUpImgData = [...setUpImg];
|
|
|
+ this.getAnalysisDetail();
|
|
|
+ },
|
|
|
+ //下一条
|
|
|
+ handleNext() {
|
|
|
+ const index = this.batchCodeList.findIndex(
|
|
|
+ (item) => item === this.initBatchCode
|
|
|
+ );
|
|
|
+ if (index === this.batchCodeList.length - 1) {
|
|
|
+ this.$message.warning("已经是最后一个分析结果了");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.$emit("setInitBathCode", this.batchCodeList[index + 1]);
|
|
|
+ },
|
|
|
+ //上一条
|
|
|
+ handlePrevious() {
|
|
|
+ const index = this.batchCodeList.findIndex(
|
|
|
+ (item) => item === this.initBatchCode
|
|
|
+ );
|
|
|
+ if (index === 0) {
|
|
|
+ this.$message.warning("没有上一条了");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.$emit("setInitBathCode", this.batchCodeList[index - 1]);
|
|
|
+ },
|
|
|
+ onClick() {},
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+::v-deep .el-table::-webkit-scrollbar {
|
|
|
+ display: block !important;
|
|
|
+}
|
|
|
+::v-deep .el-table__body-wrapper::-webkit-scrollbar {
|
|
|
+ display: block !important;
|
|
|
+}
|
|
|
+::v-deep .is-scrolling-left::-webkit-scrollbar {
|
|
|
+ display: block !important;
|
|
|
+}
|
|
|
+
|
|
|
+.type-variable {
|
|
|
+ display: flex;
|
|
|
+ height: 90%;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .left {
|
|
|
+ width: 30%;
|
|
|
+ height: 100%;
|
|
|
+ overflow: auto;
|
|
|
+ padding: 20px;
|
|
|
+ flex: 1;
|
|
|
+ .chartsBox {
|
|
|
+ height: 100%;
|
|
|
+ overflow-y: scroll;
|
|
|
+ }
|
|
|
+ /* 滚动条整体样式 */
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: 6px; /* 滚动条宽度 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 滚动条轨道 */
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
+ background: #f5f7fa;
|
|
|
+ border-radius: 3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 滚动条滑块 */
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
+ background: #c0c4cc;
|
|
|
+ border-radius: 3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 滚动条滑块悬停时 */
|
|
|
+ &::-webkit-scrollbar-thumb:hover {
|
|
|
+ background: #909399;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .right {
|
|
|
+ width: 0px;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+}
|
|
|
+.el-dialog__wrapper {
|
|
|
+ position: relative !important;
|
|
|
+}
|
|
|
+::v-deep .el-dialog {
|
|
|
+ position: fixed !important;
|
|
|
+ z-index: 999 !important;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(0, -50%);
|
|
|
+}
|
|
|
+</style>
|