StoredProcedureEditForm.vue 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. <!-- eslint-disable vue/no-parsing-error -->
  2. <template>
  3. <div
  4. v-loading="saveLoading"
  5. class="inner-container"
  6. :element-loading-text="saveText"
  7. >
  8. <el-scrollbar class="data-set-scrollbar">
  9. <div class="header">
  10. <el-page-header class="bs-el-page-header">
  11. <template slot="content">
  12. <div class="page-header">
  13. <div class="page-header-left">
  14. {{ !isEdit ? '存储过程数据集详情' : dataForm.id ? '存储过程数据集编辑' : '存储过程数据集新增' }}
  15. </div>
  16. <div class="page-header-right">
  17. <el-button
  18. class="bs-el-button-default"
  19. @click="openNewWindow('https://www.yuque.com/chuinixiongkou/bigscreen/procedure_dataset')"
  20. >
  21. 帮助
  22. </el-button>
  23. <el-button
  24. v-if="isEdit"
  25. type="primary"
  26. @click="save('form')"
  27. >
  28. 保存
  29. </el-button>
  30. <el-button
  31. class="bs-el-button-default"
  32. @click="goBack"
  33. >
  34. 返回
  35. </el-button>
  36. </div>
  37. </div>
  38. </template>
  39. </el-page-header>
  40. </div>
  41. <el-row style="margin: 16px 16px 0;">
  42. <el-col :span="isEdit ? 16 : 24">
  43. <el-form
  44. ref="form"
  45. :model="dataForm"
  46. :rules="rules"
  47. label-width="120px"
  48. style="padding: 16px 16px 0;"
  49. class="bs-el-form"
  50. >
  51. <el-row :gutter="20">
  52. <el-col :span="12">
  53. <el-form-item
  54. label="数据集名称"
  55. prop="name"
  56. >
  57. <el-input
  58. v-model="dataForm.name"
  59. class="bs-el-input"
  60. clearable
  61. :disabled="!isEdit"
  62. />
  63. </el-form-item>
  64. </el-col>
  65. <el-col :span="12">
  66. <el-form-item
  67. label="分组"
  68. prop="typeId"
  69. >
  70. <el-select
  71. ref="selectParentName"
  72. v-model="dataForm.typeId"
  73. class="bs-el-select"
  74. popper-class="bs-el-select"
  75. placeholder="请选择分组"
  76. clearable
  77. :disabled="!isEdit"
  78. filterable
  79. :filter-method="selectorFilter"
  80. @clear="clearType"
  81. @visible-change="setCurrentNode"
  82. >
  83. <el-option
  84. style="height: auto;padding: 0;"
  85. :label="typeName"
  86. :value="dataForm.typeId"
  87. >
  88. <div>
  89. <el-tree
  90. ref="categorySelectTree"
  91. :data="categoryData"
  92. node-key="id"
  93. :indent="0"
  94. :props="{ label: 'name', children: 'children' }"
  95. :default-expand-all="true"
  96. :highlight-current="true"
  97. :expand-on-click-node="false"
  98. class="bs-el-tree"
  99. :filter-node-method="treeFilter"
  100. @node-click="selectParentCategory"
  101. >
  102. <span
  103. slot-scope="{ data }"
  104. class="custom-tree-node"
  105. >
  106. <span>
  107. <i
  108. :class="data.children && data.children.length ? 'el-icon el-icon-folder' : 'el-icon el-icon-document'"
  109. />
  110. {{ data.name }}
  111. </span>
  112. </span>
  113. </el-tree>
  114. </div>
  115. </el-option>
  116. </el-select>
  117. </el-form-item>
  118. </el-col>
  119. </el-row>
  120. <el-row :gutter="20">
  121. <el-col :span="12">
  122. <el-form-item
  123. label="描述"
  124. prop="remark"
  125. >
  126. <el-input
  127. v-model="dataForm.remark"
  128. class="bs-el-input"
  129. :disabled="!isEdit"
  130. />
  131. </el-form-item>
  132. </el-col>
  133. <el-col :span="12">
  134. <el-form-item
  135. label="数据源"
  136. prop="sourceId"
  137. >
  138. <el-select
  139. v-model="dataForm.sourceId"
  140. clearable
  141. class="bs-el-select"
  142. popper-class="bs-el-select"
  143. filterable
  144. placeholder="请选择数据源"
  145. :disabled="!isEdit"
  146. @change="setSqlProcess($event)"
  147. >
  148. <el-option
  149. v-for="source in sourceList"
  150. :key="source.id"
  151. :label="source.sourceName"
  152. :value="source.id"
  153. />
  154. </el-select>
  155. </el-form-item>
  156. </el-col>
  157. </el-row>
  158. <el-row :gutter="20">
  159. <el-col :span="12">
  160. <el-form-item
  161. label="数据缓存"
  162. prop="cache"
  163. >
  164. <el-radio-group
  165. v-model="dataForm.cache"
  166. class="bs-el-radio-group"
  167. >
  168. <el-radio :label="1">
  169. 开启
  170. </el-radio>
  171. <el-radio :label="0">
  172. 关闭
  173. </el-radio>
  174. </el-radio-group>
  175. <el-tooltip
  176. class="item"
  177. effect="light"
  178. content="开启缓存:会在首次调用该数据集时,将结果缓存,在接下来的十分钟内,若再次被调用则直接返回缓存中的数据,注意:在当前数据集编辑页面缓存不生效"
  179. placement="top"
  180. >
  181. <i
  182. class="el-icon-warning-outline"
  183. style="color: #E3C98C;margin-left: 16px;font-size:14px"
  184. />
  185. </el-tooltip>
  186. </el-form-item>
  187. </el-col>
  188. <el-col :span="12">
  189. <el-form-item
  190. label="标签"
  191. prop="labelIds"
  192. >
  193. <LabelSelect
  194. :dataset-id="datasetId"
  195. :id-list="dataForm.labelIds"
  196. @commit="(ids) => { dataForm.labelIds = ids }"
  197. />
  198. </el-form-item>
  199. </el-col>
  200. </el-row>
  201. </el-form>
  202. <div
  203. v-if="isEdit"
  204. class="sql-config"
  205. >
  206. <div>
  207. <codemirror
  208. ref="targetInSql"
  209. v-model="dataForm.sqlProcess"
  210. :options="cOptions"
  211. style="margin-top: 2px"
  212. />
  213. <div class="bs-codemirror-bottom-text">
  214. 示例:
  215. <strong>call 存储过程名称(<span style="color: red;">${参数名称}</span>,?),SqlServer数据源使用:exec 存储过程名称 <span style="color: red;">@参数名称</span>=?</strong>
  216. </div>
  217. </div>
  218. <div style="text-align: center; padding: 16px 0;">
  219. <el-button
  220. type="primary"
  221. @click="buildParamsAndRun"
  222. >
  223. 解析并运行
  224. </el-button>
  225. </div>
  226. </div>
  227. </el-col>
  228. <el-col
  229. v-if="isEdit"
  230. :span="8"
  231. >
  232. <div class="right-setting">
  233. <div class="paramConfig">
  234. <div class="title-style bs-title-style">
  235. 存储过程参数
  236. <el-button
  237. type="text"
  238. style="float: right;border: none;margin-top: -4px;"
  239. @click="openParamsConfig"
  240. >
  241. 配置
  242. </el-button>
  243. </div>
  244. <div class="field-wrap bs-field-wrap bs-scrollbar">
  245. <div
  246. v-for="param in dataForm.paramsList"
  247. :key="param.name"
  248. class="field-item"
  249. @click="openParamsConfig"
  250. >
  251. <span>{{ param.name }}</span>&nbsp;<span
  252. v-show="param.remark"
  253. style="color: #909399;"
  254. >
  255. ({{ param.remark }})
  256. </span>
  257. <el-button
  258. class="edit_field"
  259. type="text"
  260. style="float: right;border: none;margin-top: 2px;"
  261. @click="openParamsConfig"
  262. >
  263. 配置
  264. </el-button>
  265. </div>
  266. </div>
  267. </div>
  268. <div class="structure">
  269. <div class="title-style bs-title-style">
  270. 输出字段
  271. <el-button
  272. type="text"
  273. style="float: right;border: none;margin-top: -4px;"
  274. @click="fieldsetVisible = true"
  275. >
  276. 配置
  277. </el-button>
  278. </div>
  279. <div class="field-wrap bs-field-wrap bs-scrollbar">
  280. <div
  281. v-for="field in structurePreviewList"
  282. :key="field.fieldName"
  283. class="field-item"
  284. @click="fieldsetVisible = true"
  285. >
  286. <span>{{ field.fieldName }}</span>&nbsp;<span
  287. v-show="field.fieldDesc"
  288. style="color: #909399;"
  289. >({{
  290. field.fieldDesc }})</span>
  291. <el-button
  292. class="edit_field"
  293. type="text"
  294. style="float: right;border: none;margin-top: 2px;"
  295. @click="fieldsetVisible = true"
  296. >
  297. 配置
  298. </el-button>
  299. </div>
  300. </div>
  301. <!-- </divclass="field-wrap> -->
  302. </div>
  303. </div>
  304. </el-col>
  305. </el-row>
  306. <div
  307. v-if="isEdit"
  308. style="margin-top: 12px;"
  309. >
  310. <div class="result-view">
  311. 数据预览
  312. </div>
  313. <div class="bs-table-box is-Edit bs-scrollbar">
  314. <el-table
  315. align="center"
  316. :data="dataPreviewList"
  317. max-height="400"
  318. class="bs-el-table bs-scrollbar"
  319. >
  320. <el-table-column
  321. v-for="(value, key) in dataPreviewList[0] ? dataPreviewList[0] : noDataTableDisplayFields"
  322. :key="key"
  323. :label="key"
  324. align="center"
  325. show-overflow-tooltip
  326. :render-header="renderHeader"
  327. >
  328. <template slot-scope="scope">
  329. <span>{{ scope.row[key] }}</span>
  330. </template>
  331. </el-table-column>
  332. </el-table>
  333. <div style="padding: 12px 0 0;color:var(--bs-el-text)">
  334. <span v-show="dataPreviewList.length">数据预览中,存储过程仅展示20条数据</span>
  335. </div>
  336. </div>
  337. </div>
  338. <!-- 字段填充方式 -->
  339. <el-dialog
  340. title="提示"
  341. :visible.sync="fieldDescVisible"
  342. width="420px"
  343. append-to-body
  344. :close-on-click-modal="false"
  345. custom-class="fieldDescCheck"
  346. class="bs-dialog-wrap bs-el-dialog"
  347. >
  348. <p style="color:var(--bs-el-text);line-height: 24px;padding-left: 10px;display: flex;">
  349. <i
  350. class="el-icon-warning"
  351. style="color: #E6A23C;font-size: 24px;margin-right: 5px;"
  352. />
  353. 存在字段描述信息为空,请确认
  354. </p>
  355. <span
  356. slot="footer"
  357. class="dialog-footer"
  358. >
  359. <el-button
  360. class="bs-el-button-default"
  361. @click="fieldDescFill"
  362. >
  363. 使用字段名填充
  364. </el-button>
  365. <el-button
  366. class="bs-el-button-default"
  367. @click="fieldDescEdit"
  368. >
  369. 进入编辑
  370. </el-button>
  371. <el-button
  372. type="primary"
  373. @click="toSave"
  374. >继续保存</el-button>
  375. </span>
  376. </el-dialog>
  377. <!-- 字段填充 -->
  378. <el-dialog
  379. title="输出字段配置"
  380. :visible.sync="fieldsetVisible"
  381. width="1000px"
  382. append-to-body
  383. :close-on-click-modal="false"
  384. :before-close="cancelField"
  385. class="bs-dialog-wrap bs-el-dialog"
  386. >
  387. <div class="bs-table-box">
  388. <el-table
  389. :data="structurePreviewListCopy"
  390. :border="true"
  391. align="center"
  392. class="bs-el-table"
  393. >
  394. <el-empty slot="empty" />
  395. <el-table-column
  396. align="left"
  397. show-overflow-tooltip
  398. prop="fieldName"
  399. label="字段值"
  400. />
  401. <el-table-column
  402. align="center"
  403. show-overflow-tooltip
  404. prop="fieldType"
  405. label="字段类型"
  406. />
  407. <el-table-column
  408. align="center"
  409. prop="fieldDesc"
  410. label="字段描述"
  411. >
  412. <template slot-scope="scope">
  413. <el-input
  414. v-if="isEdit"
  415. v-model="scope.row.fieldDesc"
  416. size="small"
  417. class="labeldsc bs-el-input"
  418. />
  419. <span v-else>{{ scope.row.fieldDesc }}</span>
  420. </template>
  421. </el-table-column>
  422. <el-table-column
  423. align="center"
  424. prop="orderNum"
  425. label="字段排序"
  426. sortable
  427. >
  428. <template slot-scope="scope">
  429. <el-input
  430. v-if="isEdit"
  431. v-model="scope.row.orderNum"
  432. size="small"
  433. class="labeldsc bs-el-input"
  434. />
  435. <span v-else>{{ scope.row.orderNum }}</span>
  436. </template>
  437. </el-table-column>
  438. <!-- 添加一个插槽,供其他人可扩展表格列,并把表格列的数据返回出去 -->
  439. <slot name="output-field-table-column" />
  440. </el-table>
  441. </div>
  442. <span
  443. slot="footer"
  444. class="dialog-footer"
  445. >
  446. <el-button @click="cancelField">取消</el-button>
  447. <el-button
  448. type="primary"
  449. @click="setField"
  450. >确定</el-button>
  451. </span>
  452. </el-dialog>
  453. <!-- 参数配置 -->
  454. <el-dialog
  455. title="存储过程参数配置"
  456. :visible.sync="paramsVisible"
  457. width="1000px"
  458. append-to-body
  459. :close-on-click-modal="false"
  460. :before-close="cancelParam"
  461. class="bs-dialog-wrap bs-el-dialog"
  462. >
  463. <div class="bs-table-box">
  464. <el-table
  465. ref="singleTable"
  466. :data="paramsListCopy"
  467. :border="true"
  468. align="center"
  469. class="bs-el-table"
  470. >
  471. <el-empty slot="empty" />
  472. <el-table-column
  473. prop="name"
  474. label="参数名称"
  475. align="center"
  476. />
  477. <el-table-column
  478. prop="type"
  479. label="参数类型"
  480. align="center"
  481. width="200"
  482. filterable
  483. >
  484. <template slot-scope="scope">
  485. <el-select
  486. v-model="scope.row.type"
  487. popper-class="bs-el-select"
  488. class="bs-el-select"
  489. placeholder="请选择"
  490. >
  491. <el-option
  492. v-for="item in typeSelect"
  493. :key="item.value"
  494. :label="item.value"
  495. :value="item.value"
  496. />
  497. </el-select>
  498. </template>
  499. </el-table-column>
  500. <el-table-column
  501. prop="require"
  502. label="是否必填"
  503. align="center"
  504. width="200"
  505. filterable
  506. >
  507. <template slot-scope="scope">
  508. <el-radio-group
  509. v-model="scope.row.require"
  510. class="bs-el-radio-group"
  511. >
  512. <el-radio :label="1">
  513. </el-radio>
  514. <el-radio :label="0">
  515. </el-radio>
  516. </el-radio-group>
  517. </template>
  518. </el-table-column>
  519. <el-table-column
  520. prop="value"
  521. label="参数值"
  522. align="center"
  523. >
  524. <template slot-scope="scope">
  525. <el-date-picker
  526. v-if="scope.row.type === 'Date'"
  527. v-model="scope.row.value"
  528. type="datetime"
  529. value-format="yyyy-MM-dd HH:mm:ss"
  530. placeholder="选择日期时间"
  531. />
  532. <el-input
  533. v-else
  534. v-model="scope.row.value"
  535. class="bs-el-input"
  536. clearable
  537. placeholder="请输入值"
  538. />
  539. </template>
  540. </el-table-column>
  541. <el-table-column
  542. prop="remark"
  543. label="备注"
  544. align="center"
  545. >
  546. <template slot-scope="scope">
  547. <el-input
  548. v-model="scope.row.remark"
  549. clearable
  550. class="bs-el-input"
  551. placeholder="请输入备注"
  552. rows="2"
  553. maxlength="200"
  554. />
  555. </template>
  556. </el-table-column>
  557. <el-table-column
  558. label="操作"
  559. width="105"
  560. align="center"
  561. >
  562. <template slot="header">
  563. <el-button
  564. icon="el-icon-plus"
  565. type="text"
  566. class="no-border"
  567. @click="addParam"
  568. >
  569. 添加
  570. </el-button>
  571. </template>
  572. <template slot-scope="scope">
  573. <el-button
  574. type="text"
  575. style="color: #e47470;"
  576. class="no-border"
  577. @click="delRow(scope.$index)"
  578. >
  579. 删除
  580. </el-button>
  581. </template>
  582. </el-table-column>
  583. </el-table>
  584. </div>
  585. <span
  586. slot="footer"
  587. class="dialog-footer"
  588. >
  589. <el-button
  590. class="bs-el-button-default"
  591. @click="cancelParam"
  592. >
  593. 取消
  594. </el-button>
  595. <el-button
  596. type="primary"
  597. @click="setParam"
  598. >
  599. 确定
  600. </el-button>
  601. </span>
  602. </el-dialog>
  603. </el-scrollbar>
  604. </div>
  605. </template>
  606. <script>
  607. import LabelSelect from 'data-room-ui/DataSetLabelManagement/src/LabelSelect.vue'
  608. import {
  609. nameCheckRepeat,
  610. datasetAdd,
  611. datasetUpdate,
  612. getCategoryTree,
  613. datasetExecuteTest,
  614. getDataset
  615. } from 'data-room-ui/js/utils/datasetConfigService'
  616. import { datasourceList } from 'data-room-ui/js/utils/dataSourceService'
  617. import { codemirror } from 'vue-codemirror'
  618. import 'codemirror/lib/codemirror.css'
  619. import 'codemirror/theme/nord.css'
  620. import 'codemirror/mode/sql/sql.js'
  621. // import _ from 'lodash'
  622. import cloneDeep from 'lodash/cloneDeep'
  623. import { datasetMixins } from 'data-room-ui/js/mixins/datasetMixin'
  624. export default {
  625. name: 'StoredProcedureEditForm',
  626. components: {
  627. codemirror,
  628. LabelSelect
  629. },
  630. mixins: [datasetMixins],
  631. data () {
  632. const validateName = (rule, value, callback) => {
  633. nameCheckRepeat({
  634. id: this.datasetId,
  635. name: value,
  636. moduleCode: this.appCode
  637. }).then((r) => {
  638. if (r) {
  639. callback(new Error('数据集名称已存在'))
  640. } else {
  641. callback()
  642. }
  643. })
  644. }
  645. return {
  646. dataForm: {
  647. id: '',
  648. name: '',
  649. typeId: '',
  650. datasetType: 'storedProcedure',
  651. remark: '',
  652. labelIds: [],
  653. // 以下为config配置
  654. sourceId: '',
  655. cache: 0,
  656. sqlProcess: 'call ',
  657. paramsList: [],
  658. fieldDesc: {},
  659. fieldList: [],
  660. code: '',
  661. script: '',
  662. cacheCoherence: null
  663. },
  664. rules: {
  665. name: [
  666. { required: true, message: '请输入数据集名称', trigger: 'blur' },
  667. { validator: validateName, trigger: 'blur' }
  668. ],
  669. sourceId: [
  670. { required: true, message: '请选择数据源', trigger: 'blur' }
  671. ],
  672. typeId: [
  673. { required: true, message: '请选择分组', trigger: 'blur' }
  674. ]
  675. },
  676. cOptions: {
  677. mode: 'text/x-mysql',
  678. lineNumbers: true,
  679. lineWrapping: true,
  680. theme: 'nord',
  681. extraKey: { Ctrl: 'autocomplete' },
  682. hintOptions: {
  683. completeSingle: true
  684. }
  685. },
  686. sourceList: [],
  687. msg: '',
  688. exception: '',
  689. passTest: false, // 通过测试
  690. paramsVisible: false,
  691. tableNameList: [],
  692. paramsListCopy: [],
  693. isTest: false // 是否执行测试
  694. }
  695. },
  696. computed: {
  697. checkPass () {
  698. return {
  699. sqlProcess: this.dataForm.sqlProcess,
  700. script: this.dataForm.script,
  701. paramsList: this.dataForm.paramsList
  702. }
  703. },
  704. noDataTableDisplayFields () {
  705. // 表格列对象
  706. const tableColumnObject = {}
  707. this.structurePreviewList.forEach(item => {
  708. tableColumnObject[item.fieldName] = ''
  709. })
  710. return tableColumnObject
  711. }
  712. },
  713. watch: {
  714. checkPass: {
  715. handler (value) {
  716. this.passTest = false
  717. },
  718. deep: true
  719. }
  720. },
  721. mounted () {
  722. this.init()
  723. },
  724. methods: {
  725. /**
  726. * 初始化
  727. * 1. 获取分类树
  728. * 2. 获取数据源列表
  729. * 3. 获取数据集详情
  730. */
  731. async init () {
  732. this.categoryData = await getCategoryTree({ type: 'dataset', moduleCode: this.appCode })
  733. if (this.typeId) {
  734. this.dataForm.typeId = this.typeId
  735. this.$nextTick(() => {
  736. try {
  737. this.typeName = this.$refs.categorySelectTree.getNode(this.dataForm.typeId).data.name
  738. } catch (error) {
  739. console.error(error)
  740. }
  741. })
  742. }
  743. this.getDataSource()
  744. if (!this.datasetId) {
  745. return
  746. }
  747. // 获取详情
  748. getDataset(this.datasetId).then(res => {
  749. this.dataForm.id = res.id
  750. this.dataForm.name = res.name
  751. this.dataForm.typeId = res.typeId
  752. this.dataForm.remark = res.remark
  753. this.dataForm.datasetType = res.datasetType
  754. this.dataForm.moduleCode = res.moduleCode
  755. this.dataForm.editable = res.editable
  756. this.dataForm.sourceId = res.sourceId
  757. this.dataForm.cache = res.cache
  758. // config 配置
  759. this.dataForm.sqlProcess = res.config.sqlProcess
  760. this.dataForm.paramsList = res.config.paramsList ? res.config.paramsList : []
  761. this.dataForm.fieldDesc = res.config.fieldDesc
  762. this.dataForm.fieldList = res.config.fieldList
  763. this.dataForm.cacheCoherence = res.config.cacheCoherence
  764. // 使用传入的数据集名称 ?
  765. this.dataForm.name = this.datasetName
  766. this.paramsListCopy = cloneDeep(this.dataForm.paramsList)
  767. if (this.dataForm.typeId) {
  768. this.$nextTick(() => {
  769. try {
  770. this.typeName = this.$refs.categorySelectTree.getNode(this.dataForm.typeId).data.name
  771. } catch (error) {
  772. console.error(error)
  773. }
  774. })
  775. }
  776. this.datasetTest(false)
  777. })
  778. },
  779. /**
  780. * 获取数据源列表
  781. */
  782. getDataSource () {
  783. const params = {
  784. sourceName: '',
  785. sourceType: '',
  786. moduleCode: this.appCode
  787. }
  788. datasourceList(params).then(data => {
  789. this.sourceList = data
  790. })
  791. },
  792. setSqlProcess (v, e) {
  793. for (let i = 0; i < this.sourceList.length; i++) {
  794. if (this.sourceList[i].id === v) {
  795. if (this.sourceList[i].sourceType === 'sqlserver') {
  796. this.dataForm.sqlProcess = 'exec '
  797. } else {
  798. this.dataForm.sqlProcess = 'call '
  799. }
  800. }
  801. }
  802. },
  803. /**
  804. * 打开参数配置弹窗
  805. */
  806. openParamsConfig () {
  807. this.isTest = false
  808. this.paramsVisible = true
  809. },
  810. /**
  811. * 删除参数配置
  812. * @param {*} index
  813. */
  814. delRow (index) {
  815. this.paramsListCopy.splice(index, 1)
  816. },
  817. /**
  818. * 新增参数配置
  819. */
  820. addParam () {
  821. this.paramsListCopy.push({
  822. name: '',
  823. type: '',
  824. value: '',
  825. status: 1,
  826. require: 0,
  827. remark: ''
  828. })
  829. },
  830. /**
  831. * 取消编辑参数
  832. */
  833. cancelParam () {
  834. this.paramsListCopy = cloneDeep(this.dataForm.paramsList)
  835. this.paramsVisible = false
  836. },
  837. /**
  838. * 保存参数设置
  839. */
  840. setParam () {
  841. this.dataForm.paramsList = cloneDeep(this.paramsListCopy)
  842. if (this.isTest) {
  843. this.datasetTest()
  844. }
  845. this.paramsVisible = false
  846. },
  847. /**
  848. * 保存
  849. * @param formName
  850. * @param noCheckToSave 是否跳过检查直接保存
  851. */
  852. save (formName, noCheckToSave = false) {
  853. if (this.passTest === false) {
  854. this.$message.error('请确保数据集SQL加工脚本不为空且运行通过')
  855. return
  856. }
  857. if (!this.structurePreviewList.length) {
  858. this.$message.warning('该存储过程未生成输出字段,请重新检查')
  859. return
  860. }
  861. if (!noCheckToSave) {
  862. const temp = this.structurePreviewList.some(item => {
  863. return item.fieldDesc === '' || !item.hasOwnProperty('fieldDesc')
  864. }) // true-存在为空
  865. if (temp) {
  866. this.fieldDescVisible = true
  867. return
  868. }
  869. }
  870. this.$refs[formName].validate((valid) => {
  871. if (!valid) {
  872. return false
  873. }
  874. // 检查参数名称是否重复
  875. if (this.dataForm.paramsList.length > 0) {
  876. const names = this.dataForm.paramsList.map(value => value.name)
  877. const namesSet = new Set(names)
  878. if (namesSet.size !== names.length) {
  879. this.$message.error('参数名称不能重复,请重新输入')
  880. return
  881. }
  882. }
  883. // 组装输出字段描述
  884. const columnMap = {}
  885. if (this.structurePreviewList.length > 0) {
  886. this.structurePreviewList.forEach(r => {
  887. columnMap[r.fieldName] = r.fieldDesc
  888. })
  889. this.dataForm.fieldDesc = columnMap
  890. }
  891. this.dataForm.fieldList = this.structurePreviewList.length ? this.structurePreviewList : []
  892. this.saveLoading = true
  893. this.saveText = '正在保存...'
  894. const dataSave = this.dataForm.id ? datasetUpdate : datasetAdd
  895. const datasetParams = {
  896. id: this.dataForm.id,
  897. name: this.dataForm.name,
  898. typeId: this.dataForm.typeId,
  899. datasetType: 'storedProcedure',
  900. remark: this.dataForm.remark,
  901. sourceId: this.dataForm.sourceId,
  902. cache: this.dataForm.cache,
  903. moduleCode: this.appCode,
  904. editable: this.appCode ? 1 : 0,
  905. labelIds: this.dataForm.labelIds,
  906. config: {
  907. className: 'com.gccloud.dataset.entity.config.StoredProcedureDataSetConfig',
  908. sourceId: this.dataForm.sourceId,
  909. sqlProcess: this.dataForm.sqlProcess,
  910. paramsList: this.dataForm.paramsList,
  911. fieldList: this.dataForm.fieldList,
  912. fieldDesc: this.dataForm.fieldDesc
  913. }
  914. }
  915. dataSave(datasetParams).then(res => {
  916. this.$message.success('保存成功')
  917. this.$parent.init(false)
  918. this.$parent.setType = null
  919. this.saveLoading = false
  920. this.saveText = ''
  921. this.goBack()
  922. }).catch(() => {
  923. this.saveLoading = false
  924. this.saveText = ''
  925. })
  926. this.saveLoading = false
  927. this.saveText = ''
  928. })
  929. },
  930. /**
  931. * 解析参数配置,并且执行测试
  932. */
  933. buildParamsAndRun () {
  934. this.isTest = true
  935. const reg = /\${(.*?)}/g
  936. const paramNames = [...new Set([...this.dataForm.sqlProcess.matchAll(reg)].map(item => item[1]))]
  937. const names = this.dataForm.paramsList.map(item => item.name)
  938. const params = []
  939. paramNames.forEach(name => {
  940. if (names.includes(name)) {
  941. const param = this.dataForm.paramsList.find(item => item.name === name)
  942. params.push(param)
  943. } else {
  944. params.push({
  945. name: name,
  946. type: 'String',
  947. value: '',
  948. status: 1,
  949. require: 0,
  950. remark: ''
  951. })
  952. }
  953. })
  954. this.dataForm.paramsList = cloneDeep(params)
  955. this.paramsListCopy = cloneDeep(this.dataForm.paramsList)
  956. if (this.dataForm.paramsList.length) {
  957. this.paramsVisible = true
  958. } else {
  959. this.datasetTest()
  960. }
  961. },
  962. goBack () {
  963. this.$emit('back')
  964. },
  965. /**
  966. * 执行测试
  967. * @param val
  968. */
  969. datasetTest (val = true) {
  970. if (this.dataForm.sourceId === '') {
  971. this.$message.error('请选择数据源')
  972. return
  973. }
  974. if (this.dataForm.sqlProcess === '') {
  975. this.$message.error('请输入数据集SQL加工脚本')
  976. return
  977. }
  978. if (this.dataForm.paramsList.length > 0) {
  979. const names = this.dataForm.paramsList.map(value => value.name)
  980. const namesSet = new Set(names)
  981. if (namesSet.size !== names.length) {
  982. this.$message.error('参数名称不能重复,请重新输入')
  983. return
  984. }
  985. }
  986. // 点击测试初始化分页当前页为1
  987. if (val === true) {
  988. this.current = 1
  989. }
  990. this.saveLoading = true
  991. // 组装数据集执行参数
  992. const executeParams = {
  993. dataSourceId: this.dataForm.sourceId,
  994. script: this.dataForm.sqlProcess,
  995. params: this.dataForm.paramsList,
  996. dataSetType: 'storedProcedure',
  997. // 存储过程数据集默认查询20条数据
  998. size: 20,
  999. current: 1
  1000. }
  1001. datasetExecuteTest(executeParams).then(res => {
  1002. this.dataPreviewList = res.data.list
  1003. this.structurePreviewList = res.structure
  1004. // 输出字段描述合并
  1005. this.structurePreviewList.forEach(field => {
  1006. const fieldInfo = this.dataForm.fieldList.find(item => item.fieldName === field.fieldName)
  1007. if (fieldInfo) {
  1008. field.fieldDesc = fieldInfo.fieldDesc
  1009. field.orderNum = fieldInfo.orderNum
  1010. field.sourceTable = fieldInfo.sourceTable
  1011. }
  1012. })
  1013. this.structurePreviewList.forEach(item => {
  1014. if (!item.hasOwnProperty('orderNum')) {
  1015. this.$set(item, 'orderNum', 0)
  1016. }
  1017. if (!item.hasOwnProperty('sourceTable')) {
  1018. this.$set(item, 'sourceTable', '')
  1019. }
  1020. if (!item.hasOwnProperty('fieldDesc')) {
  1021. this.$set(item, 'fieldDesc', '')
  1022. }
  1023. })
  1024. this.totalCount = res.data.totalCount
  1025. this.tableNameList = res.tableNameList
  1026. // 如果只有一个表,自动填充字段表名
  1027. if (this.tableNameList && this.tableNameList.length === 1) {
  1028. this.structurePreviewList.forEach(item => {
  1029. item.sourceTable = this.tableNameList[0]
  1030. })
  1031. }
  1032. this.structurePreviewListCopy = cloneDeep(this.structurePreviewList)
  1033. let paramsNameCheck = false
  1034. this.dataForm.paramsList.forEach(param => {
  1035. const checkList = this.structurePreviewList.filter(item => item.fieldName === param.name)
  1036. if (checkList.length) {
  1037. paramsNameCheck = true
  1038. param.name = ''
  1039. }
  1040. })
  1041. if (paramsNameCheck) {
  1042. this.$message.warning('参数名称不可以与字段名相同!')
  1043. this.passTest = false
  1044. } else {
  1045. if (val) this.$message.success('运行成功')
  1046. this.exception = ''
  1047. this.msg = ''
  1048. this.passTest = true
  1049. }
  1050. this.saveLoading = false
  1051. }).catch((e) => {
  1052. this.passTest = false
  1053. this.saveLoading = false
  1054. })
  1055. },
  1056. selectorFilter (value) {
  1057. this.$refs.categorySelectTree.filter(value)
  1058. },
  1059. treeFilter (value, data) {
  1060. if (!value) return true
  1061. return data.name.indexOf(value) !== -1
  1062. }
  1063. }
  1064. }
  1065. </script>
  1066. <style lang="scss" scoped>
  1067. @import '../../assets/style/bsTheme.scss';
  1068. .data-set-scrollbar {
  1069. height: 100%;
  1070. overflow-y: auto;
  1071. overflow-x: none;
  1072. }
  1073. // .tree-box {
  1074. // padding: 0;
  1075. // max-height: 270px;
  1076. // }
  1077. ::v-deep .el-input__inner {
  1078. width: 100% !important;
  1079. }
  1080. .page-header {
  1081. display: flex;
  1082. position: relative;
  1083. .page-header-right {
  1084. position: absolute;
  1085. right: 16px;
  1086. }
  1087. }
  1088. .sql-config {
  1089. padding: 0 16px;
  1090. }
  1091. .operation {
  1092. ::v-deep .el-select {
  1093. width: 200px !important;
  1094. margin-right: 16px;
  1095. }
  1096. display: flex;
  1097. }
  1098. // .codeStyle {
  1099. // border: 1px solid #EBEEF5;
  1100. // }
  1101. ::v-deep .CodeMirror {
  1102. height: 180px !important;
  1103. font-family: Helvetica, Tahoma;
  1104. // .CodeMirror-scroll {
  1105. // background: #fff;
  1106. // .CodeMirror-gutters {
  1107. // background-color: #f6f7fb;
  1108. // }
  1109. // }
  1110. }
  1111. .no-border {
  1112. border: 0;
  1113. }
  1114. ::v-deep .fieldDescCheck {
  1115. .el-dialog__body {
  1116. height: fit-content !important;
  1117. min-height: unset !important;
  1118. }
  1119. }
  1120. .title-style {
  1121. padding: 8px 12px;
  1122. background-color: #f6f7fb;
  1123. border-left: 5px solid var(--bs-el-color-primary);
  1124. margin: 16px 16px 0 0;
  1125. }
  1126. .field-wrap {
  1127. overflow: auto;
  1128. margin-right: 16px;
  1129. .field-item {
  1130. line-height: 32px;
  1131. padding: 0 12px 0 16px;
  1132. cursor: pointer;
  1133. .edit_field {
  1134. display: none;
  1135. }
  1136. &:hover {
  1137. background-color: #f2f7fe;
  1138. .edit_field {
  1139. display: block;
  1140. }
  1141. }
  1142. }
  1143. }
  1144. .right-setting {
  1145. height: 390px;
  1146. overflow: hidden;
  1147. display: flex;
  1148. flex-direction: column;
  1149. .paramConfig {
  1150. max-height: 195px;
  1151. .field-wrap {
  1152. max-height: 143px;
  1153. }
  1154. }
  1155. .structure {
  1156. flex: 1;
  1157. overflow: hidden;
  1158. .field-wrap {
  1159. height: calc(100% - 40px);
  1160. }
  1161. }
  1162. }
  1163. .result-view {
  1164. font-size: 14px;
  1165. font-weight: 600;
  1166. color: var(--bs-el-text);
  1167. position: relative;
  1168. padding: 16px 0;
  1169. padding-left: 12px;
  1170. border-bottom: 1px solid var(--bs-background-1);
  1171. &::before {
  1172. content: "";
  1173. height: 14px;
  1174. position: absolute;
  1175. left: 0;
  1176. top: 50%;
  1177. transform: translateY(-50%);
  1178. border-left: 4px solid var(--bs-el-color-primary);
  1179. }
  1180. }
  1181. ::v-deep .bs-table-box.is-Edit .el-table {
  1182. max-height: unset !important;
  1183. .el-table__body-wrapper {
  1184. max-height: unset !important;
  1185. }
  1186. }
  1187. .bs-table-box {
  1188. height: 100% !important;
  1189. margin-bottom: 0 !important;
  1190. }
  1191. </style>