asideData.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  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="comdata" 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. <el-select
  20. v-if="row.valueType === 1"
  21. v-model="row.value"
  22. placeholder="请选择"
  23. class="full-width-select"
  24. >
  25. <el-option
  26. v-for="option in row.options"
  27. :key="option.val"
  28. :label="option.tag"
  29. :value="option.val"
  30. >
  31. </el-option>
  32. </el-select>
  33. <el-input
  34. v-else-if="row.valueType === 2"
  35. v-model="row.value"
  36. class="full-width-input"
  37. />
  38. <el-button
  39. v-else-if="row.valueType === 3"
  40. @click="handleClick(row)"
  41. ></el-button>
  42. <div v-else>{{ row.valueDef }}</div>
  43. </template>
  44. </el-table-column>
  45. <el-table-column prop="unit" label="单位" width="100">
  46. <template #default="{ row }">
  47. <el-select
  48. v-if="row.unitType !== '无'"
  49. v-model="row.unit"
  50. placeholder="请选择"
  51. class="full-width-select"
  52. >
  53. <el-option
  54. v-for="option in row.unitoptions"
  55. :key="option.val"
  56. :label="option.tag"
  57. :value="option.val"
  58. >
  59. </el-option>
  60. </el-select>
  61. <div v-else>{{ row.unitType }}</div>
  62. </template>
  63. </el-table-column>
  64. </el-table>
  65. <div class="footbtn">
  66. <el-button @click="savecomvalue">保存</el-button>
  67. </div>
  68. </Pane>
  69. <Pane min-size="20" size="50" max-size="80">
  70. <!-- <div>xia</div> -->
  71. </Pane>
  72. </Splitpanes>
  73. </el-tab-pane>
  74. <!-- <el-tab-pane label="模拟数据" name="simulatedata" style="height: 100%">
  75. <Splitpanes horizontal>
  76. <Pane min-size="20" size="50" max-size="80">
  77. <div>shang</div>
  78. </Pane>
  79. <Pane min-size="20" size="50" max-size="80">
  80. <div>xia</div>
  81. </Pane>
  82. </Splitpanes>
  83. </el-tab-pane> -->
  84. </el-tabs>
  85. </el-main>
  86. <!-- 用于数据按钮table -->
  87. <el-dialog
  88. v-model="paneTabledialog"
  89. align-center
  90. :append-to-body="true"
  91. width="700"
  92. class="dialog_class"
  93. draggable
  94. >
  95. <template #header="{ titleId, titleClass }">
  96. <div class="my-header">
  97. <!-- <el-image :src="icon" fit="contain"></el-image> -->
  98. <h4 :id="titleId" :class="titleClass">{{ dialogname }}</h4>
  99. </div>
  100. </template>
  101. <el-row :gutter="10" style="margin-bottom: 10px">
  102. <el-col :span="4"> </el-col>
  103. <el-col :span="5"> </el-col>
  104. <el-col :span="5">
  105. <el-button class="btnwidth100" @click="handleAddRow">添加</el-button>
  106. </el-col>
  107. <el-col :span="5">
  108. <el-button class="btnwidth100" @click="handleDeleteSelected"
  109. >删除</el-button
  110. >
  111. </el-col>
  112. <el-col :span="5">
  113. <el-button class="btnwidth100" @click="handleInsertSelected"
  114. >插入</el-button
  115. >
  116. </el-col>
  117. </el-row>
  118. <!-- <el-row :gutter="10" style="margin-bottom: 10px">
  119. <el-col :span="4"> </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-col :span="5">
  134. <el-button class="btnwidth100">修正</el-button>
  135. </el-col>
  136. </el-row> -->
  137. <el-table
  138. :data="tableData"
  139. border
  140. height="300"
  141. style="width: 100%"
  142. @row-click="handleRowClick"
  143. highlight-current-row
  144. ref="tableRef"
  145. >
  146. <el-table-column type="index" width="40"></el-table-column>
  147. <el-table-column
  148. v-for="col in tableColumns"
  149. :key="col.code"
  150. :label="col.name"
  151. :min-width="200"
  152. >
  153. <template #header>
  154. <div class="unitheader">
  155. <div>{{ col.name }}</div>
  156. <div style="width: 50%; min-width: 100px">
  157. <el-select
  158. v-if="col.unit !== '无'"
  159. v-model="col.unit"
  160. size="small"
  161. @change="(val) => handleUnitChange(col, val)"
  162. >
  163. <el-option
  164. v-for="opt in col.unitoptions"
  165. :key="opt.val"
  166. :label="opt.tag"
  167. :value="opt.val"
  168. />
  169. </el-select>
  170. </div>
  171. </div>
  172. </template>
  173. <template #default="{ row }">
  174. <el-select
  175. v-if="col.valueType === 1"
  176. v-model="row[col.code].value"
  177. class="full-width-select"
  178. >
  179. <el-option
  180. v-for="option in row[col.code].options"
  181. :key="option.val"
  182. :label="option.tag"
  183. :value="option.val"
  184. >
  185. </el-option>
  186. </el-select>
  187. <el-input
  188. v-else-if="col.valueType === 2"
  189. v-model="row[col.code].value"
  190. class="full-width-input"
  191. />
  192. <el-button v-else-if="col.valueType === 3"></el-button>
  193. <div v-else>{{ col.valueDef }}</div>
  194. </template>
  195. </el-table-column>
  196. </el-table>
  197. <template #footer>
  198. <span class="lastbtn">
  199. <el-button @click="paneTabledialog = false">{{
  200. $t("dialog.cancel")
  201. }}</el-button>
  202. <el-button type="primary" @click="saveTabelDialog()">
  203. {{ $t("dialog.ok") }}
  204. </el-button>
  205. </span>
  206. </template>
  207. </el-dialog>
  208. <!-- 用于数据按钮键值对 -->
  209. <el-dialog
  210. v-model="paneKVdialog"
  211. align-center
  212. :append-to-body="true"
  213. width="500"
  214. class="dialog_class"
  215. draggable
  216. >
  217. <template #header="{ titleId, titleClass }">
  218. <div class="my-header">
  219. <!-- <el-image :src="icon" fit="contain"></el-image> -->
  220. <h4 :id="titleId" :class="titleClass">{{ dialogname }}</h4>
  221. </div>
  222. </template>
  223. <el-table
  224. :data="tableKVData"
  225. border
  226. height="300"
  227. style="width: 100%"
  228. >
  229. <el-table-column type="index" label="编号" width="60"></el-table-column>
  230. <el-table-column prop="property" label="属性"></el-table-column>
  231. <el-table-column prop="value" label="值">
  232. <template #default="{ row }">
  233. <el-input v-model="row.value" class="full-width-input"></el-input>
  234. </template>
  235. </el-table-column>
  236. </el-table>
  237. <template #footer>
  238. <span class="lastbtn">
  239. <el-button @click="paneKVdialog = false">{{
  240. $t("dialog.cancel")
  241. }}</el-button>
  242. <el-button type="primary" @click="saveKVTabelDialog">
  243. {{ $t("dialog.ok") }}
  244. </el-button>
  245. </span>
  246. </template>
  247. </el-dialog>
  248. </el-container>
  249. </template>
  250. <script setup>
  251. import { Splitpanes, Pane } from "splitpanes"
  252. import "splitpanes/dist/splitpanes.css"
  253. import { Close } from "@element-plus/icons-vue"
  254. import { request } from "@/utils/request"
  255. import {
  256. ElMessage,
  257. ElButton,
  258. ElDialog,
  259. ElSelect,
  260. ElMessageBox
  261. } from "element-plus"
  262. const activename = ref("data")
  263. const emit = defineEmits(["close"])
  264. const titlename = ref()
  265. const comdata = ref()
  266. const paneTabledialog = ref(false)
  267. const paneKVdialog = ref(false)
  268. const dialogname = ref("")
  269. // data表格按钮点击弹窗表格
  270. const tableColumns = ref([])
  271. const tableData = ref([])
  272. let pcaId = ref("") //项目组件的属性id
  273. const tableKVData = ref([])
  274. const closePanel = () => {
  275. emit("close")
  276. }
  277. const getcomdata = async (pcId) => {
  278. // 改为 async 函数
  279. const params = {
  280. transCode: "ES0009",
  281. pcId: pcId
  282. }
  283. try {
  284. const res = await request(params) // 使用 await 等待请求完成
  285. titlename.value = `${res.name}${res.idCode}${res.ser}`
  286. comdata.value = res.rows
  287. console.log("comdata.value", comdata.value)
  288. // 使用 for...of 循环以便使用 await
  289. for (const item of comdata.value) {
  290. if (!item.pcaId) continue
  291. // 并行处理 value 和 unit 的初始化
  292. const promises = []
  293. if (item.valueType === 1) {
  294. promises.push(getlistopt(item, "value"))
  295. }
  296. if (item.unitType !== "无") {
  297. promises.push(getlistopt(item, "unit"))
  298. } else {
  299. item.unit = "无"
  300. }
  301. // 等待当前 item 的所有初始化完成
  302. await Promise.all(promises)
  303. }
  304. console.log("所有数据初始化完成")
  305. } catch (err) {
  306. console.error("初始化失败:", err)
  307. ElMessage.error("初始化失败")
  308. }
  309. }
  310. const getbtnvalue = (pcaId, dataType) => {
  311. const params = {
  312. transCode: "ES0010",
  313. pcaId: pcaId
  314. }
  315. request(params)
  316. .then(async (res) => {
  317. if (dataType === 1) {
  318. // 遍历 headers,初始化单位值
  319. for (const header of res.headers) {
  320. if (header.unitType !== "无") {
  321. // 调用 getlistopt 获取单位选项并设置默认值
  322. await getlistopt(header, "unit")
  323. } else {
  324. // 如果不需要单位,直接设置为"无"
  325. header.unit = "无"
  326. header.unitoptions = [] // 保持选项列表为空
  327. }
  328. }
  329. // 设置表格列
  330. tableColumns.value = res.headers || []
  331. // 将 datas 按行号(pcadgId)分组,每行是一个对象
  332. const rowMap = new Map()
  333. res.datas?.forEach(async (item) => {
  334. // 添加 async
  335. const rowId = item.pcadgId
  336. if (!rowMap.has(rowId)) {
  337. rowMap.set(rowId, { pcadgId: rowId })
  338. }
  339. const header = res.headers.find((h) => h.cdvId === item.cdvId)
  340. if (header) {
  341. const row = rowMap.get(rowId)
  342. // 如果是下拉类型,调用 getlistopt 获取选项
  343. if (header.valueType === 1) {
  344. await getlistopt(header, "value") // 获取选项并设置默认值
  345. // 使用从 getlistopt 获取的 value(如果 item.value 为空)
  346. row[header.code] = {
  347. value: item.value || header.value, // 优先使用 item.value
  348. unit: item.unit,
  349. options: header.options, // 添加 options 到行数据
  350. pcadgId: item.pcadgId,
  351. pcadId: item.pcadId,
  352. cdvId: item.cdvId
  353. }
  354. } else {
  355. // 非下拉类型保持原样
  356. row[header.code] = {
  357. value: item.value,
  358. unit: item.unit,
  359. pcadgId: item.pcadgId,
  360. pcadId: item.pcadId,
  361. cdvId: item.cdvId
  362. }
  363. }
  364. }
  365. })
  366. tableData.value = Array.from(rowMap.values())
  367. console.log("tableData.value", tableData.value)
  368. } else if (dataType === 2) {
  369. // 处理属性-值对形式
  370. const kvData = []
  371. // 记录行号
  372. let rowCount = 0;
  373. res.headers?.forEach((header) => {
  374. // 找到对应的数据项
  375. const dataItem = res.datas?.find(
  376. (item) => item.cdvId === header.cdvId
  377. )
  378. rowCount++;
  379. kvData.push({
  380. cdvId: header.cdvId,
  381. property: header.name, // 属性名称
  382. value: dataItem ? dataItem.value : "",
  383. pcadgId: dataItem ? dataItem.pcadgId : "",
  384. pcadId: rowCount,
  385. unit: dataItem ? dataItem.unit : "无"
  386. })
  387. })
  388. tableKVData.value = kvData
  389. // console.log("tableKVData.value", tableKVData.value)
  390. }
  391. })
  392. .catch((err) => {
  393. console.error('err',err)
  394. ElMessage.error("值初始化失败")
  395. })
  396. }
  397. const getlistopt = async (item, gettype) => {
  398. let params = {}
  399. if (gettype === "value") {
  400. params = {
  401. transCode: "BES001",
  402. type: item.valueDef
  403. }
  404. } else {
  405. params = {
  406. transCode: "BES001",
  407. type: item.unitType
  408. }
  409. }
  410. try {
  411. const res = await request(params)
  412. // console.log("选项获取成功", res)
  413. if (gettype === "value") {
  414. if (
  415. item.value === undefined ||
  416. item.value === null ||
  417. item.value === ""
  418. ) {
  419. item.value = res.rows?.[0]?.val ?? ""
  420. }
  421. item.options = res.rows || []
  422. } else if (gettype === "unit") {
  423. if (item.unit === undefined || item.unit === null || item.unit === "") {
  424. item.unit = res.rows?.[0]?.val ?? ""
  425. }
  426. item.unitoptions = res.rows || []
  427. }
  428. } catch (err) {
  429. console.error("err", err)
  430. ElMessage.error("选项初始化失败")
  431. }
  432. }
  433. const handleClick = (row) => {
  434. dialogname.value = row.name
  435. pcaId = row.pcaId
  436. const dataType = row.dataType
  437. getbtnvalue(pcaId, dataType)
  438. if (dataType === 1) {
  439. paneTabledialog.value = true
  440. // console.log("tableColumns:", tableColumns.value)
  441. } else if (dataType === 2) {
  442. paneKVdialog.value = true
  443. }
  444. }
  445. const savecomvalue = () => {
  446. console.log("comdata:", comdata.value)
  447. // dataType 为 -1 的数据
  448. const validItems = comdata.value.filter((item) => item.dataType === -1)
  449. const pcavals = validItems
  450. .map((item) => {
  451. const pcaId = item.pcaId ?? ""
  452. const value = item.value ?? ""
  453. const unit = item.unit ?? ""
  454. return `${pcaId},${value},${unit}`
  455. })
  456. .join(";")
  457. const params = {
  458. transCode: "ES0008",
  459. pcavals: pcavals
  460. }
  461. request(params)
  462. .then((res) => {
  463. ElMessage.success("保存成功")
  464. })
  465. .catch((err) => {
  466. console.error("err", err)
  467. ElMessage.error("保存失败")
  468. })
  469. }
  470. //
  471. // 关于表格弹窗的操作
  472. //
  473. const tableRef = ref(null) // 表格引用
  474. const currentRow = ref(null) // 当前选中行
  475. // 创建新行的辅助函数
  476. const createNewRow = () => {
  477. const rowIndex = tableData.value.length + 1
  478. const newRow = {}
  479. tableColumns.value.forEach((col) => {
  480. newRow[col.code] = {
  481. value: col.valueType === 1 ? col.options?.[0]?.val || "" : "",
  482. unit: col.unit || "无",
  483. options: col.valueType === 1 ? col.options : [],
  484. pcadgId: rowIndex,
  485. pcadId: "",
  486. cdvId: col.cdvId
  487. }
  488. })
  489. return newRow
  490. }
  491. const handleAddRow = () => {
  492. const newRow = createNewRow()
  493. tableData.value.push(newRow)
  494. // 选中新添加的行
  495. nextTick(() => {
  496. currentRow.value = newRow
  497. tableRef.value?.setCurrentRow(newRow)
  498. })
  499. }
  500. // 处理行点击
  501. const handleRowClick = (row) => {
  502. currentRow.value = row
  503. // 高亮显示选中行
  504. tableRef.value?.setCurrentRow(row)
  505. }
  506. // 删除选中行
  507. const handleDeleteSelected = () => {
  508. if (!currentRow.value) {
  509. ElMessage.warning("请先点击选择要删除的行")
  510. return
  511. }
  512. const index = tableData.value.findIndex((row) => row === currentRow.value)
  513. if (index !== -1) {
  514. tableData.value.splice(index, 1)
  515. // 更新后续行的 pcadgId
  516. for (let i = index; i < tableData.value.length; i++) {
  517. const newPcadgId = i + 1 // 行号从1开始
  518. // 更新行中每个列的 pcadgId
  519. tableColumns.value.forEach((col) => {
  520. if (
  521. tableData.value[i][col.code] &&
  522. typeof tableData.value[i][col.code] === "object"
  523. ) {
  524. tableData.value[i][col.code].pcadgId = newPcadgId
  525. }
  526. })
  527. }
  528. // 删除后自动选中上一行或下一行(如果还有行)
  529. if (tableData.value.length > 0) {
  530. const newIndex = Math.min(index, tableData.value.length - 1)
  531. currentRow.value = tableData.value[newIndex]
  532. nextTick(() => {
  533. tableRef.value?.setCurrentRow(currentRow.value)
  534. })
  535. } else {
  536. currentRow.value = null
  537. }
  538. }
  539. }
  540. // 在选中行下方插入新行
  541. const handleInsertSelected = () => {
  542. if (!currentRow.value && tableData.value.length > 0) {
  543. ElMessage.warning("请先点击选择要插入的位置")
  544. return
  545. }
  546. const index = currentRow.value
  547. ? tableData.value.findIndex((row) => row === currentRow.value)
  548. : -1
  549. // 创建新行时使用正确的行号(插入位置+1)
  550. const newRow = createNewRow()
  551. // 插入新行
  552. tableData.value.splice(index + 1, 0, newRow)
  553. // 更新所有后续行的行号,包括该行
  554. for (let i = index + 1; i < tableData.value.length; i++) {
  555. const currentRowPcadgId = i + 1
  556. // 更新行中每个列的 pcadgId
  557. tableColumns.value.forEach((col) => {
  558. if (tableData.value[i][col.code]) {
  559. tableData.value[i][col.code].pcadgId = currentRowPcadgId
  560. }
  561. })
  562. }
  563. // 选中新插入的行
  564. nextTick(() => {
  565. currentRow.value = newRow
  566. tableRef.value?.setCurrentRow(newRow)
  567. })
  568. }
  569. const handleUnitChange = (column, newUnit) => {
  570. // 更新表头的单位值
  571. column.unit = newUnit
  572. // 更新该列所有行的单位值
  573. tableData.value.forEach((row) => {
  574. if (row[column.code]) {
  575. row[column.code].unit = newUnit
  576. }
  577. })
  578. }
  579. // 保存
  580. const saveTabelDialog = () => {
  581. // 检查表格数据是否为空
  582. if (!tableData.value || tableData.value.length === 0) {
  583. ElMessage.warning("请设置正确的数据");
  584. return;
  585. }
  586. console.log("表格数据:", tableData.value)
  587. // 收集所有行数据
  588. const formattedData = tableData.value.map((row) => {
  589. // 收集当前行的所有字段数据
  590. const rowFields = tableColumns.value.map((col) => {
  591. const cellData = row[col.code]
  592. if (!cellData) return ""
  593. // 组装 cdvId-pcadgId-pcadId-value-unit 格式
  594. return [
  595. cellData.cdvId || "", // cdvId
  596. cellData.pcadgId || "", // pcadgId (行号)
  597. cellData.pcadId || "", // pcadId
  598. cellData.value || "", // value
  599. cellData.unit || "" // unit
  600. ].join(",") // 字段间用逗号分隔
  601. })
  602. return rowFields.join(";") // 行内字段用分号分隔
  603. })
  604. // 最终数据用分号分隔各行
  605. const result = formattedData.join(";")
  606. // console.log("格式化后的表格数据:", result);
  607. const params = {
  608. transCode: "ES0011",
  609. pcaId: pcaId,
  610. pcadvals: result
  611. }
  612. request(params)
  613. .then((res) => {
  614. paneTabledialog.value = false
  615. ElMessage.success("保存成功")
  616. })
  617. .catch((err) => {
  618. console.error("err", err)
  619. ElMessage.error("保存失败")
  620. })
  621. }
  622. //
  623. // 关于KV表格弹窗的操作
  624. //
  625. const saveKVTabelDialog = () => {
  626. // 检查表格数据是否为空
  627. if (!tableKVData.value || tableKVData.value.length === 0) {
  628. ElMessage.warning("请设置正确的数据");
  629. return;
  630. }
  631. console.log('表格数据:',tableKVData.value)
  632. const result = tableKVData.value.map((item)=>{
  633. return [item.cdvId, item.pcadgId, item.pcadId, item.value, item.unit].join(',')
  634. }).join(";");
  635. // console.log('格式化后的字符串:', result);
  636. const params = {
  637. transCode: "ES0011",
  638. pcaId: pcaId,
  639. pcadvals: result
  640. }
  641. request(params)
  642. .then((res) => {
  643. paneKVdialog.value = false
  644. ElMessage.success("保存成功")
  645. })
  646. .catch((err) => {
  647. console.error("err", err)
  648. ElMessage.error("保存失败")
  649. })
  650. }
  651. defineExpose({
  652. getcomdata
  653. })
  654. </script>
  655. <style scoped>
  656. .panel-header {
  657. display: flex;
  658. justify-content: space-between;
  659. align-items: center;
  660. }
  661. .datatable {
  662. width: 100%;
  663. max-height: 300px;
  664. overflow: auto;
  665. }
  666. .footbtn {
  667. display: flex;
  668. justify-content: end;
  669. align-items: center;
  670. padding: 10px 20px;
  671. }
  672. .unitheader {
  673. width: 100%;
  674. display: flex;
  675. gap: 10px;
  676. }
  677. .unitheader :deep(.el-select__wrapper) {
  678. width: 100%;
  679. }
  680. .btnwidth100 {
  681. width: 100%;
  682. }
  683. </style>