tangjunhao 2 mesi fa
parent
commit
2614b61941

+ 1 - 0
src/style/index.css

@@ -282,6 +282,7 @@ img{
 /* 确保输入框高度和单元格一致 */
 .el-table td {
   padding: 0 !important;
+  height: 32px;
 }
 
 /* 让输入框文本居中 */

+ 26 - 6
src/views/model/dialog/RunDialog.vue

@@ -23,12 +23,14 @@
         </el-button>
       </div>
       <div class="echarts-container">
-        <EchartLine />
+        <EchartLine
+          :key="ChartKey"
+          :chart-data="runData"
+          :x-label="runxLabel"
+          :y-label="runyLabel"
+        />
       </div>
     </div>
-    
-
-    
   </el-dialog>
 </template>
 
@@ -41,12 +43,23 @@ import stop from "@/assets/img/stop.png"
 
 import EchartLine from "../echarts/EchartLine.vue"
 
+const props = defineProps({
+  runData: {
+    type: Array,
+    default: () => []
+  }
+})
+
 const visible = ref(false)
 let spacesize = ref(10)
 
 const projectStore = useProjectStore()
 let pid = computed(() => projectStore.pid || "")
 
+const ChartKey = ref(0)
+const runxLabel = ref("Time")
+const runyLabel = ref("Residual")
+
 function openDialog() {
   visible.value = true
 }
@@ -69,7 +82,15 @@ const runProject = () => {
     })
 }
 
-
+// 监听 runData 变化
+watch(
+  () => props.runData,
+  (newVal) => {
+    // console.log('runData changed:', newVal);
+    ChartKey.value++; // 修改 key 强制组件重新渲染
+  },
+  { deep: true } // 深度监听数组内容变化
+);
 
 // 暴露给父组件
 defineExpose({ openDialog, closeDialog })
@@ -85,5 +106,4 @@ defineExpose({ openDialog, closeDialog })
   width: 100%;
   height: 400px;
 }
-
 </style>

+ 44 - 12
src/views/model/echarts/EchartLine.vue

@@ -7,11 +7,30 @@
 <script setup>
 import * as echarts from "echarts"
 
+const props = defineProps({
+  chartData: {
+    type: Array,
+    required: true
+  },
+  xLabel: {
+    type: String,
+    default: "Time"
+  },
+  yLabel: {
+    type: String,
+    default: "Value"
+  }
+})
+
 const chartContainer = ref(null)
 let chartInstance = null
 
-// 使用 dataset:二维数组,第一行为表头
-const datasetSource = ref([["Time", "value"]])
+// 用 props 传进来的 chartData 构建 datasetSource
+const datasetSource = computed(() => {
+  const header = [props.xLabel, props.yLabel]
+  const rows = props.chartData.map((item) => [item.step, item.value])
+  return [header, ...rows]
+})
 
 const initChart = () => {
   if (!chartContainer.value) return
@@ -22,19 +41,28 @@ const initChart = () => {
     tooltip: { trigger: "axis" },
     legend: {},
     dataset: { source: datasetSource.value },
-
+    grid: {
+      top: "30px",
+      right: "40px",
+      bottom: "50px",
+      left: "30px",
+      containLabel: true 
+    },
     xAxis:
       datasetSource.value.length <= 1
         ? {
             type: "category",
+            nameLocation: "middle",
+            nameGap: 30,
             name: "Time",
             data: ["1", "2", "3", "4", "5"],
             splitNumber: 5
           }
         : {
             type: "category",
-            name: "Time"
-            // 自动使用 dataset 的第一列作为类目轴
+            name: props.xLabel,
+            nameLocation: "middle",
+            nameGap: 30,
           },
 
     yAxis:
@@ -42,22 +70,26 @@ const initChart = () => {
         ? {
             type: "value",
             name: "Value",
+            nameLocation: "middle",
+            nameGap: 30,
             min: 0,
             max: 100,
             splitNumber: 5
           }
         : {
             type: "value",
-            name: "Value",
+            name: props.yLabel,
+            nameLocation: "middle",
+            nameGap: 30,
           },
 
-    series: datasetSource.value[0]
-      .slice(1) // 跳过第一列(x轴列名)
-      .map((name) => ({
+    series: [
+      {
         type: "line",
-        name, // 设置图例名称
-        smooth: true // 平滑曲线
-      }))
+        name: props.yLabel,
+        smooth: true
+      }
+    ]
   }
 
   chartInstance.setOption(option)

+ 17 - 27
src/views/model/index.vue

@@ -194,7 +194,7 @@
     <!-- 模拟数据弹窗 -->
     <SLDataDialog ref="SLdatadialogref" @selectRunType="handleSelectRunType" />
     <!-- 运行弹窗 -->
-    <RunDialog ref="RunDialogRef" />
+    <RunDialog ref="RunDialogRef" :runData="arrobj"/>
 
   </el-container>
 </template>
@@ -421,7 +421,7 @@ const getresultlist = () => {
       // 处理结果列表数据
       activities.value = res.rows.map((item) => ({
         jobId: item.jobId,
-        content: item.ser,
+        content: "结果"+item.ser,
         timestamp: item.startTime
       }))
     })
@@ -466,35 +466,14 @@ const websocketonopen = (res) => {
 // Websoket接收消息事件
 const websocketonmessage = (res) => {
   console.log('websocket接受消息:',res.data)
-  arrobj.value = []
   if (res.data.indexOf("{") !== -1) {
-    // console.log("websocket接受消息:", res.data)
-    // 解析 WebSocket 接收到的消息数据
     
-
-    // 新增:记录结构化 JSON 数据到日志(仅打印 step, vars, vals)
-    const lines = res.data.split("\n")
-    const filteredLogs = lines
-      .filter((line) => line.trim() !== "")
-      .map((line) => {
-        try {
-          const json = JSON.parse(line)
-          const { step, vars, vals } = json
-          return JSON.stringify({ step, vars, vals })
-        } catch (e) {
-          // 如果不是合法 JSON,就原样返回
-          return line
-        }
-      })
-      .join("\n")
-
-    logContent.value = logContent.value + "\n" + filteredLogs
-
-    // 自动滚动日志到底部
-    let textarea = document.getElementById("textarea_id")
-    textarea.scrollTop = textarea.scrollHeight
   } else {
+    if (res.data.indexOf("——开始") !== -1) {
+      arrobj.value = [] // 清空数据点数组
+    }
     if (res.data.indexOf("——成功") !== -1) {
+      getresultlist();//刷新结果列表
       const timer = setTimeout(function () {
         console.log("关闭定时器")
       }, 10000)
@@ -509,6 +488,17 @@ const websocketonmessage = (res) => {
       let textarea = document.getElementById("textarea_id")
       textarea.scrollTop = textarea.scrollHeight
     }
+    // 提取数据点
+    const lines = res.data.split("\n")
+    for (const line of lines) {
+      const match = line.match(/value:\s*([\d.]+);\s*([\d.]+);/)
+      if (match) {
+        const step = parseFloat(match[1])
+        const value = parseFloat(match[2])
+        arrobj.value.push({ step, value })
+      }
+    }
+    // console.log('arrobjvalue',arrobj.value)
   }
 
   reset()

+ 178 - 107
src/views/model/vueflow/aside/asideData.vue

@@ -70,32 +70,28 @@
             </Pane>
             <Pane min-size="20" size="50" max-size="80">
               <!-- <div>xia</div> -->
-               <el-table :data="resultData" border class="datatable">
+              <el-table :data="resultData" border class="datatable">
                 <el-table-column type="index" width="40" label="" />
                 <el-table-column prop="name" label="属性"> </el-table-column>
                 <el-table-column prop="value" label="值">
                   <template #default="{ row }">
                     <el-button
                       v-if="row.coms.length > 1"
+                      @click="openresultline(row.name, row.unit, row.coms)"
                     ></el-button>
                     <div v-else>{{ row.value }}</div>
                   </template>
                 </el-table-column>
-                <el-table-column prop="unit" label="单位"> </el-table-column>
+                <el-table-column
+                  v-if="resultData.some((item) => item.coms.length <= 1)"
+                  prop="unit"
+                  label="单位"
+                >
+                </el-table-column>
               </el-table>
             </Pane>
           </Splitpanes>
         </el-tab-pane>
-        <!-- <el-tab-pane label="模拟数据" name="simulatedata" style="height: 100%">
-          <Splitpanes horizontal>
-            <Pane min-size="20" size="50" max-size="80">
-              <div>shang</div>
-            </Pane>
-            <Pane min-size="20" size="50" max-size="80">
-              <div>xia</div>
-            </Pane>
-          </Splitpanes>
-        </el-tab-pane> -->
       </el-tabs>
     </el-main>
 
@@ -131,7 +127,7 @@
           >
         </el-col>
       </el-row>
-      
+
       <el-table
         :data="tableData"
         border
@@ -242,6 +238,48 @@
         </span>
       </template>
     </el-dialog>
+
+    <!-- 结果曲线弹窗 -->
+    <el-dialog
+      v-model="resultlinedialog"
+      align-center
+      :append-to-body="true"
+      width="770"
+      class="dialog_class"
+      draggable
+    >
+      <template #header="{ titleId, titleClass }">
+        <div class="my-header">
+          <!-- <el-image :src="icon" fit="contain"></el-image> -->
+          <h4 :id="titleId" :class="titleClass">结果曲线</h4>
+        </div>
+      </template>
+      <el-space>
+        <el-table
+          :data="tableResultData"
+          border
+          height="300"
+          style="width: 100%"
+        >
+          <el-table-column type="index" label="" width="60"></el-table-column>
+          <el-table-column
+            prop="step"
+            :label="resultxLabel"
+            width="100"
+          ></el-table-column>
+          <el-table-column prop="value" :label="resultyLabel" width="150">
+          </el-table-column>
+        </el-table>
+        <div class="resultecharts">
+          <EchartLine
+            :key="resultChartKey"
+            :chart-data="tableResultData"
+            :x-label="resultxLabel"
+            :y-label="resultyLabel"
+          />
+        </div>
+      </el-space>
+    </el-dialog>
   </el-container>
 </template>
 <script setup>
@@ -256,7 +294,9 @@ import {
   ElSelect,
   ElMessageBox
 } from "element-plus"
-import { Loading } from '@element-plus/icons-vue'
+import { Loading } from "@element-plus/icons-vue"
+
+import EchartLine from "../../echarts/EchartLine.vue"
 
 const activename = ref("data")
 
@@ -266,6 +306,7 @@ const titlename = ref()
 const comdata = ref()
 const paneTabledialog = ref(false)
 const paneKVdialog = ref(false)
+const resultlinedialog = ref(false)
 const dialogname = ref("")
 // 用于侧栏按钮打开弹窗加载
 const loadingStates = ref({})
@@ -278,6 +319,11 @@ let pcaId = ref("") //项目组件的属性id
 
 const tableKVData = ref([])
 
+const tableResultData = ref([])
+const resultChartKey = ref(0) // 用于强制刷新图表
+const resultxLabel = ref("时间(s)")
+const resultyLabel = ref("")
+
 const closePanel = () => {
   emit("close")
 }
@@ -370,7 +416,7 @@ const getcomdata = async (onpcId) => {
 
       if (item.valueType === 1) {
         promises.push(getlistopt(item, "value"))
-      }else if( item.valueType === 0 ){
+      } else if (item.valueType === 0) {
         item.value = item.valueDef
       }
 
@@ -387,7 +433,9 @@ const getcomdata = async (onpcId) => {
     console.log("所有数据初始化完成")
 
     // 查找截面形状行并触发初始处理
-    const shapeRow = comdata.value.find(item => item.code === "CrossSectionalShape")
+    const shapeRow = comdata.value.find(
+      (item) => item.code === "CrossSectionalShape"
+    )
     if (shapeRow && shapeRow.value !== undefined) {
       console.log("形状")
       handleShapeChange(shapeRow, shapeRow.value)
@@ -409,19 +457,21 @@ const getbtnvalue = async (pcaId, dataType) => {
 
     if (dataType === 1) {
       // 处理 headers - 使用 Promise.all 确保所有异步操作完成
-      await Promise.all(res.headers?.map(async (header) => {
-        if (header?.unitType !== "无") {
-          await getlistopt(header, "unit")
-        } else {
-          header.unit = "无"
-          header.unitoptions = []
-        }
-        if(header?.valueType === 1){
-          await getlistopt(header, "value")
-        }else {
-          header.options = []
-        }
-      }))
+      await Promise.all(
+        res.headers?.map(async (header) => {
+          if (header?.unitType !== "无") {
+            await getlistopt(header, "unit")
+          } else {
+            header.unit = "无"
+            header.unitoptions = []
+          }
+          if (header?.valueType === 1) {
+            await getlistopt(header, "value")
+          } else {
+            header.options = []
+          }
+        })
+      )
 
       // 设置表格列
       tableColumns.value = res.headers || []
@@ -430,54 +480,57 @@ const getbtnvalue = async (pcaId, dataType) => {
       const rowMap = new Map()
 
       // 使用 Promise.all 确保所有数据项处理完成
-      await Promise.all(res.datas?.map(async (item) => {
-        if (!item?.pcadgId) return
-        
-        const rowId = item.pcadgId
-        // 为行加pcadgId
-        if (!rowMap.has(rowId)) {
-          rowMap.set(rowId, { pcadgId: rowId })
-        }
+      await Promise.all(
+        res.datas?.map(async (item) => {
+          if (!item?.pcadgId) return
+
+          const rowId = item.pcadgId
+          // 为行加pcadgId
+          if (!rowMap.has(rowId)) {
+            rowMap.set(rowId, { pcadgId: rowId })
+          }
 
-        const header = res.headers?.find((h) => h?.cdvId === item?.cdvId)
-        if (!header) return
+          const header = res.headers?.find((h) => h?.cdvId === item?.cdvId)
+          if (!header) return
 
-        const row = rowMap.get(rowId)
+          const row = rowMap.get(rowId)
 
-        // 为表头的下拉框赋值
-        if(header.unitType !== "无"){
-          header.unit = item.unit;
-        }
-        
-        // 处理下拉类型
-        if (header?.valueType === 1) {
-          await getlistopt(header, "value")
-          row[header.code] = {
-            value: item?.value || header?.value || '',
-            unit: item?.unit || '无',
-            options: header?.options || [],
-            pcadgId: item.pcadgId,
-            pcadId: item.pcadId,
-            cdvId: item.cdvId
+          // 为表头的下拉框赋值
+          if (header.unitType !== "无") {
+            header.unit = item.unit
           }
-        } else {
-          // 非下拉类型
-          row[header.code] = {
-            value: item?.value || '',
-            unit: item?.unit || '无',
-            pcadgId: item.pcadgId,
-            pcadId: item.pcadId,
-            cdvId: item.cdvId
+
+          // 处理下拉类型
+          if (header?.valueType === 1) {
+            await getlistopt(header, "value")
+            row[header.code] = {
+              value: item?.value || header?.value || "",
+              unit: item?.unit || "无",
+              options: header?.options || [],
+              pcadgId: item.pcadgId,
+              pcadId: item.pcadId,
+              cdvId: item.cdvId
+            }
+          } else {
+            // 非下拉类型
+            row[header.code] = {
+              value: item?.value || "",
+              unit: item?.unit || "无",
+              pcadgId: item.pcadgId,
+              pcadId: item.pcadId,
+              cdvId: item.cdvId
+            }
           }
-        }
-      }))
+        })
+      )
 
       // 确保所有数据处理完成后再设置 tableData
       // tableData.value = Array.from(rowMap.values())
       // 排序
-      tableData.value = Array.from(rowMap.values()).sort((a, b) => a.pcadgId - b.pcadgId)
-      console.log("tableData赋值:",tableData.value)
-
+      tableData.value = Array.from(rowMap.values()).sort(
+        (a, b) => a.pcadgId - b.pcadgId
+      )
+      console.log("tableData赋值:", tableData.value)
     } else if (dataType === 2) {
       // 处理属性-值对形式
       const kvData = []
@@ -485,10 +538,8 @@ const getbtnvalue = async (pcaId, dataType) => {
 
       res.headers?.forEach((header) => {
         if (!header?.cdvId) return
-        
-        const dataItem = res.datas?.find(
-          (item) => item?.cdvId === header.cdvId
-        )
+
+        const dataItem = res.datas?.find((item) => item?.cdvId === header.cdvId)
         rowCount++
 
         kvData.push({
@@ -550,31 +601,31 @@ const getlistopt = async (item, gettype) => {
 
 const handleClick = async (row) => {
   try {
-    loadingStates.value = { ...loadingStates.value, [row.pcaId]: true };  // 开始加载
-    dialogname.value = row.name;
-    pcaId = row.pcaId;
-    const dataType = row.dataType;
+    loadingStates.value = { ...loadingStates.value, [row.pcaId]: true } // 开始加载
+    dialogname.value = row.name
+    pcaId = row.pcaId
+    const dataType = row.dataType
 
     // 因为公用table,清除上次数据
     tableColumns.value = []
     tableData.value = []
     tableKVData.value = []
-    
+
     // 等待异步操作完成
-    await getbtnvalue(pcaId, dataType);
-    
+    await getbtnvalue(pcaId, dataType)
+
     // 确保数据准备好后再打开弹窗
     if (dataType === 1) {
-      paneTabledialog.value = true;
-      console.log('数据:',tableColumns.value)
-      console.log('数据2:',tableData.value)
+      paneTabledialog.value = true
+      console.log("数据:", tableColumns.value)
+      console.log("数据2:", tableData.value)
     } else if (dataType === 2) {
-      paneKVdialog.value = true;
+      paneKVdialog.value = true
     }
   } catch (error) {
-    console.error("处理点击时出错:", error);
+    console.error("处理点击时出错:", error)
   } finally {
-    loadingStates.value = { ...loadingStates.value, [row.pcaId]: false };   // 无论成功失败都结束加载
+    loadingStates.value = { ...loadingStates.value, [row.pcaId]: false } // 无论成功失败都结束加载
   }
 }
 
@@ -655,7 +706,7 @@ const handleDeleteSelected = async () => {
 
   // 检查是否有pcadgId(非空字符串)
   const pcadgId = currentRow.value.pcadgId
-  
+
   console.log("获取到的pcadgId:", pcadgId) // 调试用
 
   try {
@@ -663,11 +714,10 @@ const handleDeleteSelected = async () => {
       // 使用await等待删除完成
       await deleterow(pcadgId)
     }
-    
+
     // 无论是否有pcadgId,最终都要从本地删除
     tableData.value.splice(index, 1)
     updateSelectionAfterDelete(index)
-    
   } catch (error) {
     ElMessage.error("删除失败,请重试")
     console.error("删除过程中出错:", error)
@@ -695,7 +745,7 @@ const deleterow = async (pcadgId) => {
     pcaId: pcaId,
     pcadgId: pcadgId
   }
-  
+
   try {
     const res = await request(params)
     return res // 返回成功结果
@@ -727,7 +777,6 @@ const handleInsertSelected = () => {
 }
 
 const handleUnitChange = (column, newUnit) => {
-
   // 更新该列所有行的单位值
   tableData.value.forEach((row) => {
     if (row[column.code]) {
@@ -744,10 +793,10 @@ const saveTabelDialog = () => {
     ElMessage.warning("请设置正确的数据")
     return
   }
-  
+
   // 深拷贝原始数据
   const originalData = JSON.parse(JSON.stringify(tableData.value))
-  
+
   // 在拷贝的数据上更新pcadgId
   const dataToSave = originalData.map((row, rowIndex) => {
     const newRow = { ...row }
@@ -763,7 +812,7 @@ const saveTabelDialog = () => {
   })
 
   console.log("准备保存的表格数据:", dataToSave)
-  
+
   // 收集所有行数据
   const formattedData = dataToSave.map((row) => {
     // 收集当前行的所有字段数据
@@ -792,7 +841,7 @@ const saveTabelDialog = () => {
     pcaId: pcaId,
     pcadvals: result
   }
-  
+
   request(params)
     .then((res) => {
       paneTabledialog.value = false
@@ -844,16 +893,16 @@ const saveKVTabelDialog = () => {
 }
 
 function parseKey(key, type) {
-  if (typeof key !== 'string') {
-    return type === 'name' || type === 'unit' ? '' : { name: '', unit: '' }
+  if (typeof key !== "string") {
+    return type === "name" || type === "unit" ? "" : { name: "", unit: "" }
   }
 
   const match = key.match(/^(.+?)\((.+?)\)$/)
   const name = match ? match[1] : key
-  const unit = match ? match[2] : ''
+  const unit = match ? match[2] : ""
 
-  if (type === 'name') return name
-  if (type === 'unit') return unit
+  if (type === "name") return name
+  if (type === "unit") return unit
   return { name, unit }
 }
 
@@ -865,20 +914,37 @@ const getresultData = (jobId) => {
   }
   request(params)
     .then((res) => {
-      console.log("jieguo:",res);
-      resultData.value = res.rows.map((item) => ({
-        name: parseKey(item.keyZh, 'name'),
-        unit: parseKey(item.keyZh, 'unit'),
-        value: item.coms[0]?.value,
-        coms: item.coms
-      }))
-      
+      console.log("jieguo:", res)
+      resultData.value = res.rows
+        .filter((item) => item.keyEn !== "Time(Time-s)")
+        .map((item) => ({
+          name: parseKey(item.keyZh, "name"),
+          unit: parseKey(item.keyEn, "unit"),
+          value: item.coms[0]?.value,
+          coms: item.coms
+        }))
     })
     .catch((err) => {
       console.error("err", err)
     })
 }
 
+const openresultline = (name, unit, coms) => {
+  if (!coms || coms.length === 0) {
+    ElMessage.warning("没有可用的结果数据")
+    return
+  }
+  resultyLabel.value = name + "(" + unit + ")" || ""
+
+  tableResultData.value = coms.map((item, index) => ({
+    step: item.step,
+    value: item.value
+  }))
+
+  resultChartKey.value = Date.now() //刷新图表
+  resultlinedialog.value = true
+}
+
 defineExpose({
   getcomdata,
   getresultData
@@ -917,4 +983,9 @@ defineExpose({
 .btnwidth100 {
   width: 100%;
 }
+
+.resultecharts {
+  width: 420px;
+  height: 400px;
+}
 </style>