asideData.vue 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. <template>
  2. <el-container style="height: 100%">
  3. <el-header class="panel-header">
  4. <p>{{ titlename }}</p>
  5. <el-button style="border: none" @click="closePanel">
  6. <el-icon><Close /></el-icon>
  7. </el-button>
  8. </el-header>
  9. <el-main>
  10. <el-tabs v-model="activename" style="height: 100%">
  11. <el-tab-pane label="数据" name="data" style="height: 100%">
  12. <Splitpanes horizontal>
  13. <Pane min-size="20" size="50" max-size="80">
  14. <el-table :data="filteredData" border class="datatable">
  15. <el-table-column type="index" width="40" label="" />
  16. <el-table-column prop="name" label="属性"> </el-table-column>
  17. <el-table-column prop="value" label="值">
  18. <template #default="{ row }">
  19. <!-- 如果是1 :下拉选择 -->
  20. <el-select
  21. v-if="row.valueType === 1"
  22. v-model="row.value"
  23. placeholder="请选择"
  24. class="full-width-select"
  25. @change="(val) => handleShapeChange(row, val)"
  26. >
  27. <el-option
  28. v-for="option in row.options"
  29. :key="option.val"
  30. :label="option.tag"
  31. :value="option.val"
  32. >
  33. </el-option>
  34. </el-select>
  35. <!-- 如果是2: 输入框 -->
  36. <el-input
  37. v-else-if="row.valueType === 2"
  38. v-model="row.value"
  39. class="full-width-input"
  40. />
  41. <!-- 如果是3: 弹窗 -->
  42. <el-button
  43. v-else-if="row.valueType === 3"
  44. :loading="loadingStates[row.pcaId] || false"
  45. @click="handleClick(row)"
  46. ></el-button>
  47. <div v-else>{{ row.valueDef }}</div>
  48. </template>
  49. </el-table-column>
  50. <el-table-column prop="unit" label="单位" width="100">
  51. <template #default="{ row }">
  52. <el-select
  53. v-if="row.unitType !== '无'"
  54. v-model="row.unitDef"
  55. placeholder="请选择"
  56. @focus="fetchUnitsForRow(row)"
  57. :loading="moreOptionsLoading"
  58. class="full-width-select"
  59. >
  60. <el-option
  61. v-for="option in row.unitoptions"
  62. :key="option.utId"
  63. :label="option.value"
  64. :value="option.value"
  65. >
  66. </el-option>
  67. </el-select>
  68. <div v-else>{{ row.unitType }}</div>
  69. </template>
  70. </el-table-column>
  71. </el-table>
  72. <div class="footbtn">
  73. <el-button @click="savecomvalue">保存</el-button>
  74. </div>
  75. </Pane>
  76. <Pane min-size="20" size="50" max-size="80">
  77. <!-- <div>xia</div> -->
  78. <el-table :data="resultData" border class="datatable">
  79. <el-table-column type="index" width="40" label="" />
  80. <el-table-column prop="name" label="属性"> </el-table-column>
  81. <el-table-column prop="value" label="值">
  82. <template #default="{ row }">
  83. <el-button
  84. v-if="row.coms.length > 1"
  85. @click="openresultline(row.name, row.unit, row.coms)"
  86. ></el-button>
  87. <div v-else>{{ row.value }}</div>
  88. </template>
  89. </el-table-column>
  90. <el-table-column
  91. v-if="resultData.some((item) => item.coms.length <= 1)"
  92. prop="unit"
  93. label="单位"
  94. >
  95. </el-table-column>
  96. </el-table>
  97. </Pane>
  98. </Splitpanes>
  99. </el-tab-pane>
  100. </el-tabs>
  101. </el-main>
  102. <!-- 用于数据按钮table -->
  103. <el-dialog
  104. v-model="paneTabledialog"
  105. align-center
  106. :append-to-body="true"
  107. width="700"
  108. class="dialog_class"
  109. draggable
  110. >
  111. <template #header="{ titleId, titleClass }">
  112. <div class="my-header">
  113. <!-- <el-image :src="icon" fit="contain"></el-image> -->
  114. <h4 :id="titleId" :class="titleClass">{{ dialogname }}</h4>
  115. </div>
  116. </template>
  117. <el-row :gutter="10" style="margin-bottom: 10px">
  118. <el-col :span="4"> </el-col>
  119. <el-col :span="5"> </el-col>
  120. <el-col :span="5">
  121. <el-button class="btnwidth100" @click="handleAddRow">添加</el-button>
  122. </el-col>
  123. <el-col :span="5">
  124. <el-button class="btnwidth100" @click="handleDeleteSelected"
  125. >删除</el-button
  126. >
  127. </el-col>
  128. <el-col :span="5">
  129. <el-button class="btnwidth100" @click="handleInsertSelected"
  130. >插入</el-button
  131. >
  132. </el-col>
  133. </el-row>
  134. <el-table
  135. :data="tableData"
  136. border
  137. height="300"
  138. style="width: 100%"
  139. @row-click="handleRowClick"
  140. highlight-current-row
  141. ref="tableRef"
  142. >
  143. <el-table-column type="index" width="40"></el-table-column>
  144. <el-table-column
  145. v-for="col in tableColumns"
  146. :key="col.code"
  147. :label="col.name"
  148. :min-width="200"
  149. >
  150. <template #header>
  151. <div class="unitheader">
  152. <div>{{ col.name }}</div>
  153. <div style="width: 50%; min-width: 100px">
  154. <el-select
  155. v-if="col.unit !== '无'"
  156. v-model="col.unit"
  157. size="small"
  158. @change="(val) => handleUnitChange(col, val)"
  159. >
  160. <el-option
  161. v-for="opt in col.unitoptions"
  162. :key="opt.val"
  163. :label="opt.tag"
  164. :value="opt.val"
  165. />
  166. </el-select>
  167. </div>
  168. </div>
  169. </template>
  170. <template #default="{ row }">
  171. <el-select
  172. v-if="col.valueType === 1"
  173. v-model="row[col.code].value"
  174. class="full-width-select"
  175. >
  176. <el-option
  177. v-for="option in row[col.code].options"
  178. :key="option.val"
  179. :label="option.tag"
  180. :value="option.val"
  181. >
  182. </el-option>
  183. </el-select>
  184. <el-input
  185. v-else-if="col.valueType === 2"
  186. v-model="row[col.code].value"
  187. class="full-width-input"
  188. />
  189. <el-button v-else-if="col.valueType === 3"></el-button>
  190. <div v-else>{{ col.valueDef }}</div>
  191. </template>
  192. </el-table-column>
  193. </el-table>
  194. <template #footer>
  195. <span class="lastbtn">
  196. <el-button @click="paneTabledialog = false">{{
  197. $t("dialog.cancel")
  198. }}</el-button>
  199. <el-button type="primary" @click="saveTabelDialog()">
  200. {{ $t("dialog.ok") }}
  201. </el-button>
  202. </span>
  203. </template>
  204. </el-dialog>
  205. <!-- 用于数据按钮键值对 -->
  206. <el-dialog
  207. v-model="paneKVdialog"
  208. align-center
  209. :append-to-body="true"
  210. width="500"
  211. class="dialog_class"
  212. draggable
  213. >
  214. <template #header="{ titleId, titleClass }">
  215. <div class="my-header">
  216. <!-- <el-image :src="icon" fit="contain"></el-image> -->
  217. <h4 :id="titleId" :class="titleClass">{{ dialogname }}</h4>
  218. </div>
  219. </template>
  220. <el-table :data="tableKVData" border height="300" style="width: 100%">
  221. <el-table-column type="index" label="编号" width="60"></el-table-column>
  222. <el-table-column prop="property" label="属性"></el-table-column>
  223. <el-table-column prop="value" label="值">
  224. <template #default="{ row }">
  225. <el-input v-model="row.value" class="full-width-input"></el-input>
  226. </template>
  227. </el-table-column>
  228. </el-table>
  229. <template #footer>
  230. <span class="lastbtn">
  231. <el-button @click="paneKVdialog = false">{{
  232. $t("dialog.cancel")
  233. }}</el-button>
  234. <el-button type="primary" @click="saveKVTabelDialog">
  235. {{ $t("dialog.ok") }}
  236. </el-button>
  237. </span>
  238. </template>
  239. </el-dialog>
  240. <!-- 结果曲线弹窗 -->
  241. <el-dialog
  242. v-model="resultlinedialog"
  243. align-center
  244. :append-to-body="true"
  245. width="770"
  246. class="dialog_class"
  247. draggable
  248. >
  249. <template #header="{ titleId, titleClass }">
  250. <div class="my-header">
  251. <!-- <el-image :src="icon" fit="contain"></el-image> -->
  252. <h4 :id="titleId" :class="titleClass">结果曲线</h4>
  253. </div>
  254. </template>
  255. <el-space>
  256. <el-table
  257. :data="tableResultData"
  258. border
  259. height="300"
  260. style="width: 100%"
  261. >
  262. <el-table-column type="index" label="" width="60"></el-table-column>
  263. <el-table-column
  264. prop="step"
  265. :label="resultxLabel"
  266. width="100"
  267. ></el-table-column>
  268. <el-table-column prop="value" :label="resultyLabel" width="150">
  269. </el-table-column>
  270. </el-table>
  271. <div class="resultecharts">
  272. <EchartLine
  273. :key="resultChartKey"
  274. :chart-data="tableResultData"
  275. :x-label="resultxLabel"
  276. :y-label="resultyLabel"
  277. />
  278. </div>
  279. </el-space>
  280. </el-dialog>
  281. </el-container>
  282. </template>
  283. <script setup>
  284. import { Splitpanes, Pane } from "splitpanes"
  285. import "splitpanes/dist/splitpanes.css"
  286. import { Close } from "@element-plus/icons-vue"
  287. import { request } from "@/utils/request"
  288. import {
  289. ElMessage,
  290. ElButton,
  291. ElDialog,
  292. ElSelect,
  293. ElMessageBox
  294. } from "element-plus"
  295. import { Loading } from "@element-plus/icons-vue"
  296. import EchartLine from "../../echarts/EchartLine.vue"
  297. const activename = ref("data")
  298. const emit = defineEmits(["close"])
  299. const titlename = ref()
  300. const comdata = ref()
  301. const paneTabledialog = ref(false)
  302. const paneKVdialog = ref(false)
  303. const resultlinedialog = ref(false)
  304. const dialogname = ref("")
  305. // 用于侧栏按钮打开弹窗加载
  306. const loadingStates = ref({})
  307. // data表格按钮点击弹窗表格
  308. const tableColumns = ref([])
  309. const tableData = ref([])
  310. let pcId = ref("") // 项目组件id
  311. let pcaId = ref("") //项目组件的属性id
  312. const tableKVData = ref([])
  313. const tableResultData = ref([])
  314. const resultChartKey = ref(0) // 用于强制刷新图表
  315. const resultxLabel = ref("时间(s)")
  316. const resultyLabel = ref("")
  317. // 单位选项缓存
  318. const unitOptionsCache = ref({});
  319. // 更多选项加载状态
  320. const moreOptionsLoading = ref(false);
  321. const closePanel = () => {
  322. emit("close")
  323. }
  324. const filteredData = computed(() => {
  325. return comdata.value ? comdata.value.filter((item) => item.isVisible) : []
  326. })
  327. const resultData = ref([])
  328. // 定义形状与隐藏字段的映射
  329. const SHAPE_HIDDEN_FIELDS = {
  330. 0: [
  331. "SideLength",
  332. "Width",
  333. "Height",
  334. "InnerWallThickness",
  335. "OuterWallThickness",
  336. "Inside",
  337. "Outside"
  338. ],
  339. 1: [
  340. "Diameter",
  341. "Width",
  342. "Height",
  343. "InnerWallThickness",
  344. "OuterWallThickness",
  345. "Inside",
  346. "Outside"
  347. ],
  348. 2: [
  349. "Diameter",
  350. "SideLength",
  351. "InnerWallThickness",
  352. "OuterWallThickness",
  353. "Inside",
  354. "Outside"
  355. ],
  356. 3: [
  357. "Diameter",
  358. "Width",
  359. "Height",
  360. "InnerWallThickness",
  361. "OuterWallThickness",
  362. "Inside",
  363. "Outside"
  364. ],
  365. 4: ["Diameter", "SideLength", "Width", "Height", "PipeThickness"]
  366. }
  367. const handleShapeChange = (row, val) => {
  368. if (row.code === "CrossSectionalShape") {
  369. // 先重置所有行可见
  370. comdata.value.forEach((item) => {
  371. item.isVisible = true
  372. })
  373. // 隐藏对应形状不需要的字段
  374. const fieldsToHide = SHAPE_HIDDEN_FIELDS[val] || []
  375. comdata.value.forEach((item) => {
  376. if (fieldsToHide.includes(item.code)) {
  377. item.isVisible = false
  378. }
  379. })
  380. }
  381. }
  382. const getcomdata = async (onpcId) => {
  383. pcId.value = onpcId // 将传入的pcId赋值给响应式变量
  384. const params = {
  385. transCode: "ES0009",
  386. pcId: onpcId
  387. }
  388. try {
  389. const res = await request(params) // 使用 await 等待请求完成
  390. titlename.value = `${res.name}${res.idCode}${res.ser}`
  391. comdata.value = res.rows.map((item) => ({
  392. ...item,
  393. isVisible: true // 默认所有行都可见
  394. }))
  395. console.log("comdata.value", comdata.value)
  396. // 使用 for...of 循环以便使用 await
  397. for (const item of comdata.value) {
  398. if (!item.pcaId) continue
  399. // 并行处理 value 和 unit 的初始化
  400. const promises = []
  401. if (item.valueType === 1) {
  402. promises.push(getlistopt(item, "value"))
  403. } else if (item.valueType === 0) {
  404. item.value = item.valueDef
  405. }
  406. if (item.unitType !== "无") {
  407. promises.push(getlistopt(item, "unit"))
  408. } else {
  409. item.unit = "无"
  410. }
  411. // 等待当前 item 的所有初始化完成
  412. await Promise.all(promises)
  413. }
  414. console.log("所有数据初始化完成")
  415. // 查找截面形状行并触发初始处理
  416. const shapeRow = comdata.value.find(
  417. (item) => item.code === "CrossSectionalShape"
  418. )
  419. if (shapeRow && shapeRow.value !== undefined) {
  420. console.log("形状")
  421. handleShapeChange(shapeRow, shapeRow.value)
  422. }
  423. } catch (err) {
  424. console.error("初始化失败:", err)
  425. ElMessage.error("初始化失败")
  426. }
  427. }
  428. const getbtnvalue = async (pcaId, dataType) => {
  429. const params = {
  430. transCode: "ES0010",
  431. pcaId: pcaId
  432. }
  433. try {
  434. const res = await request(params)
  435. if (dataType === 1) {
  436. // 处理 headers - 使用 Promise.all 确保所有异步操作完成
  437. await Promise.all(
  438. res.headers?.map(async (header) => {
  439. if (header?.unitType !== "无") {
  440. await getlistopt(header, "unit")
  441. } else {
  442. header.unit = "无"
  443. header.unitoptions = []
  444. }
  445. if (header?.valueType === 1) {
  446. await getlistopt(header, "value")
  447. } else {
  448. header.options = []
  449. }
  450. })
  451. )
  452. // 设置表格列
  453. tableColumns.value = res.headers || []
  454. // 将 datas 按行号分组
  455. const rowMap = new Map()
  456. // 使用 Promise.all 确保所有数据项处理完成
  457. await Promise.all(
  458. res.datas?.map(async (item) => {
  459. if (!item?.pcadgId) return
  460. const rowId = item.pcadgId
  461. // 为行加pcadgId
  462. if (!rowMap.has(rowId)) {
  463. rowMap.set(rowId, { pcadgId: rowId })
  464. }
  465. const header = res.headers?.find((h) => h?.cdvId === item?.cdvId)
  466. if (!header) return
  467. const row = rowMap.get(rowId)
  468. // 为表头的下拉框赋值
  469. if (header.unitType !== "无") {
  470. header.unit = item.unit
  471. }
  472. // 处理下拉类型
  473. if (header?.valueType === 1) {
  474. await getlistopt(header, "value")
  475. row[header.code] = {
  476. value: item?.value || header?.value || "",
  477. unit: item?.unit || "无",
  478. options: header?.options || [],
  479. pcadgId: item.pcadgId,
  480. pcadId: item.pcadId,
  481. cdvId: item.cdvId
  482. }
  483. } else {
  484. // 非下拉类型
  485. row[header.code] = {
  486. value: item?.value || "",
  487. unit: item?.unit || "无",
  488. pcadgId: item.pcadgId,
  489. pcadId: item.pcadId,
  490. cdvId: item.cdvId
  491. }
  492. }
  493. })
  494. )
  495. // 确保所有数据处理完成后再设置 tableData
  496. // tableData.value = Array.from(rowMap.values())
  497. // 排序
  498. tableData.value = Array.from(rowMap.values()).sort(
  499. (a, b) => a.pcadgId - b.pcadgId
  500. )
  501. console.log("tableData赋值:", tableData.value)
  502. } else if (dataType === 2) {
  503. // 处理属性-值对形式
  504. const kvData = []
  505. let rowCount = 0
  506. res.headers?.forEach((header) => {
  507. if (!header?.cdvId) return
  508. const dataItem = res.datas?.find((item) => item?.cdvId === header.cdvId)
  509. rowCount++
  510. kvData.push({
  511. cdvId: header.cdvId,
  512. property: header?.name || "",
  513. value: dataItem?.value || "",
  514. pcadId: dataItem?.pcadId || "",
  515. pcadgId: rowCount,
  516. unit: dataItem?.unit || "无"
  517. })
  518. })
  519. tableKVData.value = kvData
  520. }
  521. } catch (err) {
  522. console.error("值初始化失败:", err)
  523. ElMessage.error("值初始化失败")
  524. }
  525. }
  526. const getlistopt = async (item, gettype) => {
  527. let params = {}
  528. if (gettype === "value") {
  529. params = {
  530. transCode: "BES001",
  531. type: item.valueDef
  532. }
  533. } else {
  534. params = {
  535. transCode: "BES001",
  536. type: item.unitType
  537. }
  538. }
  539. try {
  540. const res = await request(params)
  541. // console.log("选项获取成功", res)
  542. if (gettype === "value") {
  543. if (
  544. item.value === undefined ||
  545. item.value === null ||
  546. item.value === ""
  547. ) {
  548. item.value = res.rows?.[0]?.val ?? ""
  549. }
  550. item.options = res.rows || []
  551. } else if (gettype === "unit") {
  552. if (item.unit === undefined || item.unit === null || item.unit === "") {
  553. item.unit = res.rows?.[0]?.val ?? ""
  554. }
  555. item.unitoptions = res.rows || []
  556. }
  557. } catch (err) {
  558. console.error("err", err)
  559. ElMessage.error("选项初始化失败")
  560. }
  561. }
  562. const handleClick = async (row) => {
  563. try {
  564. loadingStates.value = { ...loadingStates.value, [row.pcaId]: true } // 开始加载
  565. dialogname.value = row.name
  566. pcaId = row.pcaId
  567. const dataType = row.dataType
  568. // 因为公用table,清除上次数据
  569. tableColumns.value = []
  570. tableData.value = []
  571. tableKVData.value = []
  572. // 等待异步操作完成
  573. await getbtnvalue(pcaId, dataType)
  574. // 确保数据准备好后再打开弹窗
  575. if (dataType === 1) {
  576. paneTabledialog.value = true
  577. console.log("数据:", tableColumns.value)
  578. console.log("数据2:", tableData.value)
  579. } else if (dataType === 2) {
  580. paneKVdialog.value = true
  581. }
  582. } catch (error) {
  583. console.error("处理点击时出错:", error)
  584. } finally {
  585. loadingStates.value = { ...loadingStates.value, [row.pcaId]: false } // 无论成功失败都结束加载
  586. }
  587. }
  588. const savecomvalue = () => {
  589. console.log("comdata:", comdata.value)
  590. // dataType 为 -1 的数据
  591. const validItems = comdata.value.filter((item) => item.dataType === -1)
  592. console.log("validItemsddddddddddddd:", validItems);
  593. const pcavals = validItems
  594. .map((item) => {
  595. const pcaId = item.pcaId ?? ""
  596. const value = item.value ?? ""
  597. const unit = item.unitDef ?? ""
  598. return `${pcaId},${value},${unit}`
  599. })
  600. .join(";");
  601. console.log("pcavals:ssssssssssss", pcavals);
  602. const params = {
  603. transCode: "ES0008",
  604. pcavals: pcavals
  605. }
  606. request(params)
  607. .then((res) => {
  608. ElMessage.success("保存成功")
  609. })
  610. .catch((err) => {
  611. console.error("err", err)
  612. ElMessage.error("保存失败")
  613. })
  614. }
  615. //
  616. // 关于表格弹窗的操作
  617. //
  618. const tableRef = ref(null) // 表格引用
  619. const currentRow = ref(null) // 当前选中行
  620. // 创建新行的辅助函数
  621. const createNewRow = () => {
  622. const newRow = {}
  623. tableColumns.value.forEach((col) => {
  624. newRow[col.code] = {
  625. value: col.valueType === 1 ? col.options?.[0]?.val || "" : "",
  626. unit: col.unit || "无",
  627. options: col.valueType === 1 ? col.options : [],
  628. pcadgId: "", // 初始化为空字符串
  629. pcadId: "",
  630. cdvId: col.cdvId
  631. }
  632. })
  633. return newRow
  634. }
  635. const handleAddRow = () => {
  636. const newRow = createNewRow()
  637. tableData.value.push(newRow)
  638. // 选中新添加的行
  639. nextTick(() => {
  640. currentRow.value = newRow
  641. tableRef.value?.setCurrentRow(newRow)
  642. })
  643. }
  644. // 处理行点击
  645. const handleRowClick = (row) => {
  646. currentRow.value = row
  647. // 高亮显示选中行
  648. tableRef.value?.setCurrentRow(row)
  649. }
  650. // 删除选中行 - 如果pcadgId不为空则调用API删除
  651. const handleDeleteSelected = async () => {
  652. if (!currentRow.value) {
  653. ElMessage.warning("请先点击选择要删除的行")
  654. return
  655. }
  656. const index = tableData.value.findIndex((row) => row === currentRow.value)
  657. if (index === -1) return
  658. // 检查是否有pcadgId(非空字符串)
  659. const pcadgId = currentRow.value.pcadgId
  660. console.log("获取到的pcadgId:", pcadgId) // 调试用
  661. try {
  662. if (pcadgId && pcadgId !== "") {
  663. // 使用await等待删除完成
  664. await deleterow(pcadgId)
  665. }
  666. // 无论是否有pcadgId,最终都要从本地删除
  667. tableData.value.splice(index, 1)
  668. updateSelectionAfterDelete(index)
  669. } catch (error) {
  670. ElMessage.error("删除失败,请重试")
  671. console.error("删除过程中出错:", error)
  672. }
  673. }
  674. // 删除后更新选中行的辅助函数
  675. const updateSelectionAfterDelete = (deletedIndex) => {
  676. if (tableData.value.length > 0) {
  677. const newIndex = Math.min(deletedIndex, tableData.value.length - 1)
  678. currentRow.value = tableData.value[newIndex]
  679. nextTick(() => {
  680. tableRef.value?.setCurrentRow(currentRow.value)
  681. })
  682. } else {
  683. currentRow.value = null
  684. }
  685. ElMessage.success("删除成功")
  686. }
  687. // 后端删除API调用
  688. const deleterow = async (pcadgId) => {
  689. const params = {
  690. transCode: "ES0016",
  691. pcaId: pcaId,
  692. pcadgId: pcadgId
  693. }
  694. try {
  695. const res = await request(params)
  696. return res // 返回成功结果
  697. } catch (err) {
  698. console.error("删除请求失败:", err)
  699. throw err // 重新抛出错误以便外部捕获
  700. }
  701. }
  702. // 在选中行下方插入新行 - 简化版,不再更新pcadgId
  703. const handleInsertSelected = () => {
  704. if (!currentRow.value && tableData.value.length > 0) {
  705. ElMessage.warning("请先点击选择要插入的位置")
  706. return
  707. }
  708. const index = currentRow.value
  709. ? tableData.value.findIndex((row) => row === currentRow.value)
  710. : -1
  711. const newRow = createNewRow()
  712. tableData.value.splice(index + 1, 0, newRow)
  713. // 选中新插入的行
  714. nextTick(() => {
  715. currentRow.value = newRow
  716. tableRef.value?.setCurrentRow(newRow)
  717. })
  718. }
  719. const handleUnitChange = (column, newUnit) => {
  720. // 更新该列所有行的单位值
  721. tableData.value.forEach((row) => {
  722. if (row[column.code]) {
  723. row[column.code].unit = newUnit
  724. }
  725. })
  726. }
  727. // 保存
  728. // 保存 - 在保存时统一更新pcadgId
  729. const saveTabelDialog = () => {
  730. // 检查表格数据是否为空
  731. if (!tableData.value || tableData.value.length === 0) {
  732. ElMessage.warning("请设置正确的数据")
  733. return
  734. }
  735. // 深拷贝原始数据
  736. const originalData = JSON.parse(JSON.stringify(tableData.value))
  737. // 在拷贝的数据上更新pcadgId
  738. const dataToSave = originalData.map((row, rowIndex) => {
  739. const newRow = { ...row }
  740. tableColumns.value.forEach((col) => {
  741. if (newRow[col.code] && typeof newRow[col.code] === "object") {
  742. newRow[col.code] = {
  743. ...newRow[col.code],
  744. pcadgId: rowIndex + 1 // 行号从1开始
  745. }
  746. }
  747. })
  748. return newRow
  749. })
  750. console.log("准备保存的表格数据:", dataToSave)
  751. // 收集所有行数据
  752. const formattedData = dataToSave.map((row) => {
  753. // 收集当前行的所有字段数据
  754. const rowFields = tableColumns.value.map((col) => {
  755. const cellData = row[col.code]
  756. if (!cellData) return ""
  757. // 组装 cdvId-pcadgId-pcadId-value-unit 格式
  758. return [
  759. cellData.cdvId || "", // cdvId
  760. cellData.pcadgId || "", // pcadgId (行号)
  761. cellData.pcadId || "", // pcadId
  762. cellData.value || "", // value
  763. cellData.unit || "" // unit
  764. ].join(",") // 字段间用逗号分隔
  765. })
  766. return rowFields.join(";") // 行内字段用分号分隔
  767. })
  768. // 最终数据用分号分隔各行
  769. const result = formattedData.join(";")
  770. const params = {
  771. transCode: "ES0011",
  772. pcaId: pcaId,
  773. pcadvals: result
  774. }
  775. request(params)
  776. .then((res) => {
  777. paneTabledialog.value = false
  778. ElMessage.success("保存成功")
  779. })
  780. .catch((err) => {
  781. console.error("err", err)
  782. // 保存失败,保持原始数据不变
  783. ElMessage.error("保存失败")
  784. })
  785. }
  786. //
  787. // 关于KV表格弹窗的操作
  788. //
  789. const saveKVTabelDialog = () => {
  790. // 检查表格数据是否为空
  791. if (!tableKVData.value || tableKVData.value.length === 0) {
  792. ElMessage.warning("请设置正确的数据")
  793. return
  794. }
  795. console.log("表格数据:", tableKVData.value)
  796. const result = tableKVData.value
  797. .map((item) => {
  798. return [
  799. item.cdvId,
  800. item.pcadgId,
  801. item.pcadId,
  802. item.value,
  803. item.unit
  804. ].join(",")
  805. })
  806. .join(";")
  807. // console.log('格式化后的字符串:', result);
  808. const params = {
  809. transCode: "ES0011",
  810. pcaId: pcaId,
  811. pcadvals: result
  812. }
  813. request(params)
  814. .then((res) => {
  815. paneKVdialog.value = false
  816. ElMessage.success("保存成功")
  817. })
  818. .catch((err) => {
  819. console.error("err", err)
  820. ElMessage.error("保存失败")
  821. })
  822. }
  823. function parseKey(key, type) {
  824. if (typeof key !== "string") {
  825. return type === "name" || type === "unit" ? "" : { name: "", unit: "" }
  826. }
  827. const match = key.match(/^(.+?)\((.+?)\)$/)
  828. const name = match ? match[1] : key
  829. const unit = match ? match[2] : ""
  830. if (type === "name") return name
  831. if (type === "unit") return unit
  832. return { name, unit }
  833. }
  834. const getresultData = (jobId) => {
  835. const params = {
  836. transCode: "ES0015",
  837. pcId: pcId.value,
  838. jobId: jobId
  839. }
  840. request(params)
  841. .then((res) => {
  842. console.log("jieguo:", res)
  843. resultData.value = res.rows
  844. .filter((item) => item.keyEn !== "Time(Time-s)")
  845. .map((item) => ({
  846. name: parseKey(item.keyZh, "name"),
  847. unit: parseKey(item.keyEn, "unit"),
  848. value: item.coms[0]?.value,
  849. coms: item.coms
  850. }))
  851. })
  852. .catch((err) => {
  853. console.error("err", err)
  854. })
  855. }
  856. const openresultline = (name, unit, coms) => {
  857. if (!coms || coms.length === 0) {
  858. ElMessage.warning("没有可用的结果数据")
  859. return
  860. }
  861. resultyLabel.value = name + "(" + unit + ")" || ""
  862. tableResultData.value = coms.map((item, index) => ({
  863. step: item.step,
  864. value: item.value
  865. }))
  866. resultChartKey.value = Date.now() //刷新图表
  867. resultlinedialog.value = true
  868. }
  869. // 组件参数点击下拉框调用接口获取单位
  870. const fetchUnitsForRow = async (row) => {
  871. if (unitOptionsCache.value[row.unitType]) {
  872. row.unitoptions = unitOptionsCache.value[row.gutId]
  873. if (!row.unitDef && row.unitOptions.length > 0) {
  874. row.unitDef = row.unitOptions[0].value
  875. }
  876. return
  877. }
  878. moreOptionsLoading.value = true;
  879. const params = {
  880. transCode: "ES0019",
  881. gutId: row.unitType
  882. }
  883. try {
  884. const res = await request(params)
  885. row.unitoptions = res.rows || []
  886. console.log("单位选项获取成功", row.unitoptions );
  887. unitOptionsCache.value[row.unitType] = row.unitoptions
  888. if (!row.unitType && row.unitoptions .length > 0) {
  889. row.unitDef = row.unitoptions [0].value
  890. }
  891. moreOptionsLoading.value = false;
  892. } catch (err) {
  893. moreOptionsLoading.value = false;
  894. ElMessage.error(err.returnMsg || t("error.fetchFailed"))
  895. row.unitoptions = []
  896. unitOptionsCache.value[row.unitType] = []
  897. } finally {
  898. moreOptionsLoading.value = false;
  899. }
  900. }
  901. defineExpose({
  902. getcomdata,
  903. getresultData
  904. })
  905. </script>
  906. <style scoped>
  907. .panel-header {
  908. display: flex;
  909. justify-content: space-between;
  910. align-items: center;
  911. }
  912. .datatable {
  913. width: 100%;
  914. max-height: 290px;
  915. overflow: auto;
  916. }
  917. .footbtn {
  918. display: flex;
  919. justify-content: end;
  920. align-items: center;
  921. padding: 10px 20px;
  922. }
  923. .unitheader {
  924. width: 100%;
  925. display: flex;
  926. gap: 10px;
  927. }
  928. .unitheader :deep(.el-select__wrapper) {
  929. width: 100%;
  930. }
  931. .btnwidth100 {
  932. width: 100%;
  933. }
  934. .resultecharts {
  935. width: 420px;
  936. height: 400px;
  937. }
  938. </style>