HttpEditForm.vue 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. <template>
  2. <div
  3. class="inner-container"
  4. :element-loading-text="saveText"
  5. >
  6. <el-scrollbar class="data-set-scrollbar">
  7. <div class="header">
  8. <el-page-header class="bs-el-page-header">
  9. <template slot="content">
  10. <div class="page-header">
  11. <div class="page-header-left">
  12. {{ !isEdit ? 'HTTP数据集详情' : dataForm.id ? 'HTTP数据集编辑' : 'HTTP数据集新增' }}
  13. </div>
  14. <div class="page-header-right">
  15. <el-button
  16. class="bs-el-button-default"
  17. @click="openNewWindow('https://www.yuque.com/chuinixiongkou/bigscreen/groovy_dataset')"
  18. >
  19. 帮助
  20. </el-button>
  21. <el-button
  22. v-if="isEdit"
  23. type="primary"
  24. @click="save('form')"
  25. >
  26. 保存
  27. </el-button>
  28. <el-button
  29. class="bs-el-button-default"
  30. @click="goBack"
  31. >
  32. 返回
  33. </el-button>
  34. </div>
  35. </div>
  36. </template>
  37. </el-page-header>
  38. </div>
  39. <el-row style="margin: 16px 16px 0;">
  40. <el-col :span="isEdit ? 16 : 24">
  41. <el-form
  42. ref="form"
  43. :model="dataForm"
  44. :rules="rules"
  45. label-width="120px"
  46. style="padding: 16px 16px 0;"
  47. class="bs-el-form"
  48. >
  49. <el-row :gutter="20">
  50. <el-col :span="12">
  51. <el-form-item
  52. label="名称"
  53. prop="name"
  54. >
  55. <el-input
  56. v-model="dataForm.name"
  57. class="bs-el-input"
  58. clearable
  59. :disabled="!isEdit"
  60. />
  61. </el-form-item>
  62. </el-col>
  63. <el-col :span="12">
  64. <el-form-item
  65. label="分组"
  66. >
  67. <el-select
  68. ref="selectParentName"
  69. v-model="dataForm.typeId"
  70. class="bs-el-select"
  71. popper-class="bs-el-select"
  72. placeholder="请选择分组"
  73. clearable
  74. :disabled="!isEdit"
  75. @clear="clearType"
  76. @visible-change="setCurrentNode"
  77. >
  78. <el-option
  79. style="height: auto;padding: 0;"
  80. :label="typeName"
  81. :value="dataForm.typeId"
  82. >
  83. <div class="tree-box">
  84. <el-tree
  85. ref="categorySelectTree"
  86. :data="categoryData"
  87. node-key="id"
  88. :indent="0"
  89. :props="{ label: 'name', children: 'children' }"
  90. :default-expand-all="true"
  91. :highlight-current="true"
  92. :expand-on-click-node="false"
  93. class="bs-el-tree"
  94. @node-click="selectParentCategory"
  95. >
  96. <span
  97. slot-scope="{ data }"
  98. class="custom-tree-node"
  99. >
  100. <span>
  101. <i
  102. :class="data.children && data.children.length ? 'el-icon el-icon-folder' : 'el-icon el-icon-document'"
  103. />
  104. {{ data.name }}
  105. </span>
  106. </span>
  107. </el-tree>
  108. </div>
  109. </el-option>
  110. </el-select>
  111. </el-form-item>
  112. </el-col>
  113. </el-row>
  114. <el-row :gutter="20">
  115. <el-col :span="12">
  116. <el-form-item
  117. label="描述"
  118. prop="remark"
  119. >
  120. <el-input
  121. v-model="dataForm.remark"
  122. class="bs-el-input"
  123. :disabled="!isEdit"
  124. />
  125. </el-form-item>
  126. </el-col>
  127. <el-col :span="12">
  128. <el-form-item
  129. label="调用方式"
  130. prop="config.requestType"
  131. >
  132. <el-select
  133. v-model="dataForm.config.requestType"
  134. class="bs-el-select"
  135. popper-class="bs-el-select"
  136. @change="changeRequestType($event)"
  137. >
  138. <el-option
  139. label="前台代理"
  140. value="frontend"
  141. />
  142. <el-option
  143. label="后台代理"
  144. value="backend"
  145. />
  146. </el-select>
  147. </el-form-item>
  148. </el-col>
  149. </el-row>
  150. <el-row :gutter="20">
  151. <el-col :span="21">
  152. <el-form-item
  153. label="请求地址"
  154. prop="config.url"
  155. >
  156. <el-input
  157. v-model="dataForm.config.url"
  158. autocomplete="off"
  159. class="bs-el-input"
  160. placeholder="请输入静态请求地址或动态请求地址,动态请求地址必须以${baseUrl}开头"
  161. clearable
  162. />
  163. </el-form-item>
  164. </el-col>
  165. </el-row>
  166. <el-row>
  167. <el-col :span="12">
  168. <el-form-item
  169. label="请求类型"
  170. prop="config.method"
  171. >
  172. <el-radio-group
  173. v-model="dataForm.config.method"
  174. class="bs-radio-wrap"
  175. >
  176. <el-radio-button label="get">
  177. GET
  178. </el-radio-button>
  179. <el-radio-button label="post">
  180. POST
  181. </el-radio-button>
  182. </el-radio-group>
  183. </el-form-item>
  184. </el-col>
  185. <el-col :span="12">
  186. <el-form-item
  187. label="标签"
  188. prop="labelIds"
  189. >
  190. <LabelSelect
  191. :dataset-id="datasetId"
  192. :id-list="dataForm.labelIds"
  193. @commit="(ids) =>{dataForm.labelIds = ids}"
  194. />
  195. </el-form-item>
  196. </el-col>
  197. </el-row>
  198. <el-tabs
  199. v-model="activeName"
  200. class="bs-el-tabs tabs-box"
  201. >
  202. <el-tab-pane
  203. label="请求头"
  204. name="head"
  205. >
  206. <el-form-item
  207. prop="config.headers"
  208. label-width="0px"
  209. >
  210. <el-row
  211. v-for="(item,index) in dataForm.config.headers"
  212. :key="index"
  213. :gutter="10"
  214. :span="24"
  215. style="margin-top: 10px"
  216. >
  217. <el-col :span="11">
  218. <el-form-item
  219. label="键"
  220. :prop="'config.headers.'+index+'.key'"
  221. label-width="50px"
  222. :rules="rules.key"
  223. >
  224. <el-input
  225. v-model="dataForm.config.headers[index].key"
  226. placeholder="请输入键"
  227. clearable
  228. @blur="dataForm.config.headers[index].key = inputChange($event)"
  229. />
  230. </el-form-item>
  231. </el-col>
  232. <el-col :span="11">
  233. <el-form-item
  234. label="值"
  235. :prop="'config.headers.'+index+'.value'"
  236. label-width="50px"
  237. :rules="rules.value"
  238. >
  239. <el-input
  240. v-model="dataForm.config.headers[index].value"
  241. placeholder="请输入值"
  242. clearable
  243. @blur="dataForm.config.headers[index].value = inputChange($event)"
  244. />
  245. </el-form-item>
  246. </el-col>
  247. <el-col
  248. :span="2"
  249. style="text-align: center"
  250. >
  251. <span
  252. class="delete-btn"
  253. @click="delHeader(index)"
  254. >
  255. 移除
  256. </span>
  257. </el-col>
  258. </el-row>
  259. <el-row>
  260. <el-col
  261. :span="12"
  262. :offset="6"
  263. >
  264. <div
  265. class="add-btn"
  266. @click="addHeader"
  267. >
  268. 增加
  269. </div>
  270. </el-col>
  271. </el-row>
  272. </el-form-item>
  273. </el-tab-pane>
  274. <el-tab-pane
  275. label="请求参数"
  276. name="param"
  277. >
  278. <el-form-item
  279. prop="config.params"
  280. label-width="0px"
  281. :rules="dataForm.config.method==='get'?rules.params:[{ required: false}]"
  282. >
  283. <el-row
  284. v-for="(item,index) in dataForm.config.params"
  285. :key="index"
  286. :gutter="10"
  287. :span="24"
  288. style="margin-top: 10px"
  289. >
  290. <el-col :span="11">
  291. <el-form-item
  292. label="键"
  293. :prop="'config.params.'+index+'.key'"
  294. label-width="50px"
  295. :rules="rules.key"
  296. >
  297. <el-input
  298. v-model="dataForm.config.params[index].key"
  299. placeholder="请输入键"
  300. clearable
  301. @blur="dataForm.config.params[index].key = inputChange($event)"
  302. />
  303. </el-form-item>
  304. </el-col>
  305. <el-col :span="11">
  306. <el-form-item
  307. label="值"
  308. :prop="'config.params.'+index+'.value'"
  309. label-width="50px"
  310. :rules="rules.value"
  311. >
  312. <el-input
  313. v-model="dataForm.config.params[index].value"
  314. placeholder="请输入值"
  315. clearable
  316. @blur="dataForm.config.params[index].value = inputChange($event)"
  317. />
  318. </el-form-item>
  319. </el-col>
  320. <el-col
  321. :span="2"
  322. style="text-align: center"
  323. >
  324. <span
  325. class="delete-btn"
  326. @click="delParam(index)"
  327. >
  328. 移除
  329. </span>
  330. </el-col>
  331. </el-row>
  332. <el-row>
  333. <el-col
  334. :span="12"
  335. :offset="6"
  336. >
  337. <div
  338. class="add-btn"
  339. @click="addParam"
  340. >
  341. 增加
  342. </div>
  343. </el-col>
  344. </el-row>
  345. </el-form-item>
  346. </el-tab-pane>
  347. <el-tab-pane
  348. v-if="dataForm.config.method === 'post'"
  349. label="请求体"
  350. name="second"
  351. >
  352. <el-form-item
  353. prop="requestScript"
  354. label-width="0px"
  355. >
  356. <el-input
  357. v-model="dataForm.config.body"
  358. class="bs-el-input"
  359. type="textarea"
  360. :autosize="{ minRows: 10, maxRows: 10}"
  361. clearable
  362. />
  363. <div class="bs-codemirror-bottom-text">
  364. <strong>请求体设置规则: 请求体已经内置参数body,如需添加请求体参数,可直接加入到body对象中。<br> 例如:<span style="color: red;">body.test='test'</span>
  365. </strong>
  366. </div>
  367. </el-form-item>
  368. </el-tab-pane>
  369. <el-tab-pane
  370. label="请求脚本"
  371. name="reqScript"
  372. >
  373. <el-form-item
  374. prop="requestScript"
  375. label-width="0px"
  376. >
  377. <codemirror
  378. v-if="activeName==='reqScript'"
  379. v-model.trim="dataForm.config.requestScript"
  380. :options="codemirrorOption"
  381. class="code"
  382. />
  383. <div
  384. v-if="dataForm.config.requestType === 'frontend'"
  385. class="bs-codemirror-bottom-text"
  386. >
  387. <strong>请求脚本设置规则: 请求脚本已经内置参数req,可参考请求拦截的回调参数config直接使用(修改url中的参数例外),
  388. <br> 如修改请求头中对应参数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: red;">req.headers.name='tom'</span>
  389. <br> 如修改url中对应参数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: red;">req.urlKey.age=17</span>
  390. </strong>
  391. </div>
  392. </el-form-item>
  393. </el-tab-pane>
  394. <el-tab-pane
  395. label="响应脚本"
  396. name="respScript"
  397. >
  398. <el-form-item
  399. prop="responseScript"
  400. label-width="0px"
  401. >
  402. <codemirror
  403. v-if="activeName==='respScript'"
  404. v-model.trim="dataForm.config.responseScript"
  405. :options="codemirrorOption"
  406. class="code"
  407. />
  408. <div
  409. v-if="dataForm.config.requestType === 'frontend'"
  410. class="bs-codemirror-bottom-text"
  411. >
  412. <strong>响应脚本设置规则: 接口返回数据已经内置到参数response中,可直接使用,但是必须要返回设置后的数据。<br> 例如:<span style="color: red;">let data =response.data; return data;</span>
  413. </strong>
  414. </div>
  415. </el-form-item>
  416. </el-tab-pane>
  417. </el-tabs>
  418. </el-form>
  419. <div
  420. v-if="isEdit"
  421. class="sql-config"
  422. >
  423. <div style="text-align: center; padding: 16px 0;">
  424. <el-button
  425. type="primary"
  426. @click="scriptExecute()"
  427. >
  428. 解析并执行
  429. </el-button>
  430. </div>
  431. </div>
  432. </el-col>
  433. <el-col
  434. v-if="isEdit"
  435. :span="8"
  436. >
  437. <div class="right-setting">
  438. <div class="paramConfig">
  439. <div class="title-style bs-title-style">
  440. 动态参数
  441. <el-button
  442. type="text"
  443. style="float: right;border: none;margin-top: -4px;"
  444. @click="$refs.paramsSettingDialog.open()"
  445. >
  446. 配置
  447. </el-button>
  448. </div>
  449. <div class="field-wrap bs-field-wrap bs-scrollbar">
  450. <div
  451. v-for="param in dataForm.config.paramsList"
  452. :key="param.name"
  453. class="field-item"
  454. @click="$refs.paramsSettingDialog.open()"
  455. >
  456. <span>{{ param.name }}</span>&nbsp;<span
  457. v-show="param.remark"
  458. style="color: #909399;"
  459. >
  460. ({{ param.remark }})
  461. </span>
  462. <el-button
  463. class="edit_field"
  464. type="text"
  465. style="float: right;border: none;margin-top: 2px;"
  466. @click="$refs.paramsSettingDialog.open()"
  467. >
  468. 配置
  469. </el-button>
  470. </div>
  471. </div>
  472. </div>
  473. <div class="structure">
  474. <div class="title-style bs-title-style">
  475. 输出字段
  476. <el-button
  477. type="text"
  478. style="float: right;border: none;margin-top: -4px;"
  479. @click="$refs.outputFieldDialog.open()"
  480. >
  481. 配置
  482. </el-button>
  483. </div>
  484. <div class="field-wrap bs-field-wrap bs-scrollbar">
  485. <div
  486. v-for="(field, key) in outputFieldList"
  487. :key="key"
  488. class="field-item"
  489. @click="$refs.outputFieldDialog.open()"
  490. >
  491. <span>{{ field.fieldName }}</span>&nbsp;
  492. <span
  493. v-show="field.fieldDesc"
  494. style="color: #909399;"
  495. >
  496. ({{ field.fieldDesc }})</span>
  497. <el-button
  498. class="edit_field"
  499. type="text"
  500. style="float: right;border: none;margin-top: 2px;"
  501. @click="$refs.outputFieldDialog.open()"
  502. >
  503. 配置
  504. </el-button>
  505. </div>
  506. </div>
  507. </div>
  508. </div>
  509. </el-col>
  510. </el-row>
  511. <div
  512. v-if="isEdit"
  513. class="dataPreView"
  514. style="margin-top: 12px;"
  515. >
  516. <div class="result-view">
  517. 数据预览
  518. </div>
  519. <div
  520. v-loading="tableLoading"
  521. class="bs-table-box is-Edit bs-scrollbar"
  522. >
  523. <el-table
  524. align="center"
  525. :data="dataPreviewList"
  526. max-height="300"
  527. :border="true"
  528. class="bs-el-table bs-scrollba preview-table"
  529. >
  530. <el-table-column
  531. v-for="(value, key) in dataPreviewList[0]"
  532. :key="key"
  533. :label="key"
  534. align="center"
  535. show-overflow-tooltip
  536. :render-header="renderHeader"
  537. >
  538. <template slot-scope="scope">
  539. <span>{{ scope.row[key] }}</span>
  540. </template>
  541. </el-table-column>
  542. </el-table>
  543. </div>
  544. </div>
  545. <div
  546. v-if="!isEdit"
  547. class="dataPreView"
  548. >
  549. <el-tabs
  550. v-model="activeName"
  551. >
  552. <el-tab-pane
  553. v-loading="tableLoading"
  554. label="数据预览"
  555. name="data"
  556. >
  557. <div class="bs-table-box">
  558. <el-table
  559. v-if="dataPreviewList && dataPreviewList.length"
  560. align="center"
  561. :data="dataPreviewList"
  562. max-height="400"
  563. :border="true"
  564. class="bs-el-table"
  565. >
  566. <el-table-column
  567. v-for="(value, key) in dataPreviewList[0]"
  568. :key="key"
  569. :label="key"
  570. align="center"
  571. show-overflow-tooltip
  572. :render-header="renderHeader"
  573. >
  574. <template slot-scope="scope">
  575. <span>{{ scope.row[key] }}</span>
  576. </template>
  577. </el-table-column>
  578. </el-table>
  579. <el-empty v-else />
  580. </div>
  581. </el-tab-pane>
  582. <el-tab-pane
  583. v-loading="tableLoading"
  584. label="数据集结构"
  585. name="structure"
  586. >
  587. <div class="bs-table-box">
  588. <el-table
  589. max-height="400"
  590. :data="outputFieldList"
  591. :border="true"
  592. align="center"
  593. >
  594. <el-table-column
  595. align="center"
  596. show-overflow-tooltip
  597. prop="fieldName"
  598. label="字段值"
  599. />
  600. <el-table-column
  601. align="center"
  602. prop="fieldDesc"
  603. label="字段描述"
  604. >
  605. <template slot-scope="scope">
  606. <el-input
  607. v-if="isEdit"
  608. v-model="scope.row.fieldDesc"
  609. size="small"
  610. class="labeldsc bs-el-input"
  611. />
  612. <span v-else>{{ scope.row.fieldDesc }}</span>
  613. </template>
  614. </el-table-column>
  615. </el-table>
  616. </div>
  617. </el-tab-pane>
  618. </el-tabs>
  619. </div>
  620. <ParamsSettingDialog
  621. ref="paramsSettingDialog"
  622. :params-list="dataForm.config.paramsList"
  623. :newParamsList="newParamsList"
  624. @saveParams="saveParams"
  625. @saveNewParams="saveNewParams"
  626. @getData="getData"
  627. />
  628. <OutputFieldDialog
  629. ref="outputFieldDialog"
  630. :output-field-list="outputFieldList"
  631. @setFieldList="(list) => { outputFieldList = list }"
  632. />
  633. </el-scrollbar>
  634. <FieldFillDialog
  635. ref="fieldFillDialog"
  636. @fieldDescFill="fieldDescFill"
  637. @fieldDescEdit="fieldDescEdit"
  638. @toSave="toSave"
  639. />
  640. </div>
  641. </template>
  642. <script>
  643. import LabelSelect from 'data-room-ui/DataSetLabelManagement/src/LabelSelect.vue'
  644. import ParamsSettingDialog from './JsComponents/ParamsSettingDialog.vue'
  645. import OutputFieldDialog from './JsComponents/OutputFieldDialog.vue'
  646. import FieldFillDialog from './JsComponents/FieldFillDialog.vue'
  647. import { nameCheckRepeat, datasetAdd, datasetUpdate, getDataset, getCategoryTree, datasetExecuteTest } from 'data-room-ui/js/utils/datasetConfigService'
  648. import { codemirror } from 'vue-codemirror'
  649. import 'codemirror/mode/javascript/javascript'
  650. import 'codemirror/lib/codemirror.css'
  651. import 'codemirror/theme/nord.css'
  652. import axiosFormatting from '../../js/utils/httpParamsFormatting'
  653. import _ from 'lodash'
  654. export default {
  655. name: 'HttpEditForm',
  656. components: {
  657. codemirror,
  658. FieldFillDialog,
  659. ParamsSettingDialog,
  660. OutputFieldDialog,
  661. LabelSelect
  662. },
  663. props: {
  664. config: {
  665. type: Object,
  666. default: () => { }
  667. },
  668. isEdit: {
  669. type: Boolean,
  670. default: false
  671. },
  672. datasetId: {
  673. type: String,
  674. default: null
  675. },
  676. typeId: {
  677. type: String,
  678. default: ''
  679. },
  680. appCode: {
  681. type: String,
  682. default: ''
  683. }
  684. },
  685. data () {
  686. const validateName = (rule, value, callback) => {
  687. nameCheckRepeat({
  688. id: this.datasetId,
  689. name: value,
  690. moduleCode: this.appCode
  691. }).then((r) => {
  692. if (r) {
  693. callback(new Error('数据集名称已存在'))
  694. } else {
  695. callback()
  696. }
  697. })
  698. }
  699. const validateUrl = (rule, value, callback) => {
  700. // eslint-disable-next-line no-template-curly-in-string
  701. if (value.startsWith('${baseUrl}/')) {
  702. callback()
  703. }
  704. const reg = /(https?|ftp|file):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/
  705. if (!reg.test(value)) {
  706. // eslint-disable-next-line no-template-curly-in-string
  707. callback(new Error('请输入正确的静态请求地址或动态请求地址,动态请求地址必须以${baseUrl}/开头'))
  708. } else {
  709. callback()
  710. }
  711. }
  712. return {
  713. newParamsList: [], // 存放临时的动态参数值
  714. activeName: 'head',
  715. options: [{
  716. value: 'string',
  717. label: '字符串'
  718. }, {
  719. value: 'boolean',
  720. label: '布尔值'
  721. }, {
  722. value: 'int',
  723. label: '数字'
  724. }, {
  725. value: 'date',
  726. label: '日期'
  727. }],
  728. newDataForm: {}, // 替换完参数后的配置
  729. dataForm: {
  730. id: '',
  731. name: '',
  732. typeId: '',
  733. remark: '',
  734. labelIds: [],
  735. config: {
  736. className: 'com.gccloud.dataset.entity.config.HttpDataSetConfig',
  737. requestType: 'backend',
  738. method: 'get',
  739. url: '',
  740. headers: [],
  741. params: [],
  742. body: '',
  743. paramsList: [],
  744. requestScript: '',
  745. responseScript: ''
  746. }
  747. },
  748. rules: {
  749. name: [
  750. { required: true, message: '请输入数据集名称', trigger: 'blur' },
  751. { validator: validateName, trigger: 'blur' }
  752. ],
  753. 'config.requestType': [
  754. { required: true, message: '请选择调用方式', trigger: 'change' }
  755. ],
  756. key: [{ required: true, message: '键不能为空', trigger: 'blur' }],
  757. value: [{ required: true, message: '值不能为空', trigger: 'blur' }],
  758. 'config.method': [{ required: true, message: '请求类型不能为空', trigger: 'blur' }],
  759. 'config.url': [
  760. { required: true, message: '请求地址不能为空', trigger: 'blur' },
  761. { validator: validateUrl, trigger: 'blur' }
  762. ]
  763. },
  764. codemirrorOption: {
  765. mode: 'text/x-groovy',
  766. lineNumbers: true,
  767. lineWrapping: true,
  768. theme: 'nord',
  769. extraKey: { Ctrl: 'autocomplete' },
  770. hintOptions: {
  771. completeSingle: true
  772. }
  773. },
  774. dataPreviewList: [],
  775. outputFieldList: [],
  776. structurePreviewListCopy: [],
  777. typeName: '',
  778. categoryData: [],
  779. // fieldDescVisible: false,
  780. fieldsetVisible: false,
  781. paramsVisible: false,
  782. tableLoading: false,
  783. saveloading: false,
  784. saveText: '',
  785. // paramsListCopy: [],
  786. isSet: false, // 参数是否配置状态
  787. passTest: false,
  788. fieldDesc: null // 字段描述
  789. }
  790. },
  791. watch: {
  792. 'dataForm.config.script' (val) {
  793. if (!val) {
  794. this.passTest = false
  795. }
  796. }
  797. },
  798. mounted () {
  799. this.init()
  800. },
  801. methods: {
  802. async init () {
  803. this.categoryData = await getCategoryTree({ tableName: 'dataset', moduleCode: this.appCode })
  804. if (this.typeId) {
  805. this.dataForm.typeId = this.typeId
  806. this.$nextTick(() => {
  807. try {
  808. this.typeName = this.$refs.categorySelectTree.getNode(this.dataForm.typeId).data.name
  809. } catch (error) {
  810. console.error(error)
  811. }
  812. })
  813. }
  814. if (this.datasetId) {
  815. getDataset(this.datasetId).then(res => {
  816. const { id, name, typeId, remark, datasetType, moduleCode, editable, sourceId, config } = res
  817. const { script, paramsList, fieldDesc, fieldList } = config
  818. this.dataForm = { id, name, typeId, remark, datasetType, moduleCode, editable, sourceId, config: { ...config } }
  819. this.fieldDesc = fieldDesc
  820. this.outputFieldList = fieldList
  821. this.newParamsList = _.cloneDeep(paramsList)
  822. this.codemirrorOption.mode = this.dataForm.config.requestType === 'frontend' ? 'text/javascript' : 'text/x-groovy'
  823. // this.replaceParams(paramsList)
  824. this.scriptExecute(true)
  825. })
  826. }
  827. },
  828. // 保存数据集
  829. save (formName, nochecktosave = false) {
  830. if (!nochecktosave) {
  831. const temp = this.outputFieldList.some(item => {
  832. return item.fieldDesc === '' || !item.hasOwnProperty('fieldDesc')
  833. }) // true-存在为空
  834. if (temp) {
  835. this.$refs.fieldFillDialog.open()
  836. // this.fieldDescVisible = true
  837. return
  838. }
  839. }
  840. this.$refs[formName].validate((valid) => {
  841. if (valid) {
  842. this.saveloading = true
  843. this.saveText = '正在保存...'
  844. const { datasetId, dataForm, appCode, fieldDesc, outputFieldList } = this
  845. const form = {
  846. id: datasetId,
  847. name: dataForm.name,
  848. typeId: dataForm.typeId,
  849. remark: dataForm.remark,
  850. datasetType: 'http',
  851. moduleCode: appCode,
  852. editable: appCode ? 1 : 0,
  853. labelIds: dataForm.labelIds,
  854. config: {
  855. className: 'com.gccloud.dataset.entity.config.HttpDataSetConfig',
  856. method: dataForm.config.method,
  857. url: dataForm.config.url,
  858. headers: dataForm.config.headers,
  859. params: dataForm.config.params,
  860. body: dataForm.config.body,
  861. requestScript: dataForm.config.requestScript,
  862. responseScript: dataForm.config.responseScript,
  863. requestType: dataForm.config.requestType,
  864. fieldDesc,
  865. paramsList: dataForm.config.paramsList,
  866. fieldList: this.outputFieldList
  867. }
  868. }
  869. const datasetSave = this.dataForm.id === '' ? datasetAdd : datasetUpdate
  870. datasetSave(form).then(() => {
  871. this.$message.success('操作成功')
  872. this.$parent.init(false)
  873. this.$parent.setType = null
  874. this.saveloading = false
  875. this.saveText = ''
  876. this.goBack()
  877. }).catch(() => {
  878. this.saveloading = false
  879. this.saveText = ''
  880. })
  881. }
  882. })
  883. },
  884. changeRequestType (value) {
  885. if (value === 'frontend') {
  886. this.$set(this.codemirrorOption, 'mode', 'text/javascript')
  887. } else {
  888. this.$set(this.codemirrorOption, 'mode', 'text/x-groovy')
  889. }
  890. },
  891. // 增加header
  892. addHeader () {
  893. const header = { key: '', type: 'string', value: '', remark: '' }
  894. this.dataForm.config.headers.push(_.cloneDeep(header))
  895. },
  896. // 移除header
  897. delHeader (index) {
  898. this.dataForm.config.headers.splice(index, 1)
  899. },
  900. // 增加请求参数
  901. addParam () {
  902. const param = { key: '', value: '', remark: '' }
  903. this.dataForm.config.params.push(_.cloneDeep(param))
  904. },
  905. // 移除请求参数
  906. delParam (index) {
  907. this.dataForm.config.params.splice(index, 1)
  908. },
  909. saveParams (val) {
  910. debugger
  911. this.dataForm.config.paramsList = val
  912. },
  913. saveNewParams (val) {
  914. console.log(val)
  915. this.newParamsList = val
  916. },
  917. // 取消操作
  918. // cancelField () {
  919. // this.structurePreviewListCopy = cloneDeep(this.outputFieldList)
  920. // this.fieldsetVisible = false
  921. // },
  922. // 设置输出字段
  923. setField () {
  924. // this.outputFieldList = cloneDeep(this.structurePreviewListCopy)
  925. // if (this.outputFieldList.length) {
  926. // this.fieldDesc = {}
  927. // this.outputFieldList.forEach(key => {
  928. // this.fieldDesc[key.fieldName] = key.fieldDesc
  929. // })
  930. // } else {
  931. // this.fieldDesc = null
  932. // }
  933. // this.fieldsetVisible = false
  934. },
  935. // 字段值填充
  936. fieldDescFill () {
  937. this.fieldDesc = {}
  938. this.outputFieldList.forEach(field => {
  939. if (field.fieldDesc === '' || !field.hasOwnProperty('fieldDesc')) {
  940. field.fieldDesc = field.fieldName
  941. this.fieldDesc[field.fieldName] = field.fieldName
  942. } else {
  943. this.fieldDesc[field.fieldName] = field.fieldDesc
  944. }
  945. })
  946. this.save('form')
  947. this.$refs.fieldFillDialog.close()
  948. // this.fieldDescVisible = false
  949. },
  950. // 进入编辑
  951. fieldDescEdit () {
  952. this.$refs.fieldFillDialog.close()
  953. // this.fieldDescVisible = false
  954. this.fieldsetVisible = true
  955. },
  956. // 继续保存
  957. toSave () {
  958. this.fieldDesc = {}
  959. this.outputFieldList.forEach(field => {
  960. this.fieldDesc[field.fieldName] = field.fieldDesc
  961. })
  962. this.save('form', true)
  963. this.$refs.fieldFillDialog.close()
  964. // this.fieldDescVisible = false
  965. },
  966. // 字段描述构建及同步
  967. buildFieldDesc () {
  968. const fieldDesc = {}
  969. this.outputFieldList.forEach(field => {
  970. if (this.fieldDesc.hasOwnProperty(field.fieldName)) {
  971. field.fieldDesc = this.fieldDesc[field.fieldName]
  972. }
  973. fieldDesc[field.fieldName] = field.fieldDesc
  974. })
  975. this.fieldDesc = fieldDesc
  976. },
  977. // 获取请求地址、请求头、请求参数、请求体中所有的变量,在动态参数中进行变量
  978. getPramsList () {
  979. const paramNames1 = this.getValName(this.dataForm.config.url)
  980. const paramNames2 = this.dataForm.config?.headers.map(obj => obj.value.match(/\$\{(.+?)\}/)?.[1]).filter(Boolean)
  981. const paramNames3 = this.dataForm.config?.params.map(obj => obj.value.match(/\$\{(.+?)\}/)?.[1]).filter(Boolean)
  982. const paramNames4 = this.getValName(this.dataForm.config.body)
  983. const paramNames = new Set([...paramNames1, ...paramNames2, ...paramNames3, ...paramNames4])
  984. const names = this.dataForm.config?.paramsList?.map(item => item.name)
  985. const params = []
  986. paramNames.forEach(name => {
  987. if (names.includes(name)) {
  988. const param = this.dataForm.config?.paramsList?.find(item => item.name === name)
  989. params.push(param)
  990. } else {
  991. params.push({
  992. name: name,
  993. type: 'String',
  994. value: '',
  995. status: 1,
  996. require: 1,
  997. remark: ''
  998. })
  999. }
  1000. })
  1001. this.dataForm.config.paramsList = _.cloneDeep(params)
  1002. },
  1003. // 获取字符串中${变量名}中的变量名
  1004. getValName (str) {
  1005. // 定义正则表达式模式
  1006. const pattern = /\${(.*?)\}/g
  1007. // 使用正则表达式提取变量名
  1008. const variables = []
  1009. let match
  1010. while (match = pattern.exec(str)) {
  1011. variables.push(match[1])
  1012. }
  1013. return variables
  1014. },
  1015. // 点击解析按钮
  1016. scriptExecute (isInit = false) {
  1017. this.getPramsList()
  1018. // 如果动态参数未配置,则直接打开配置弹窗
  1019. // const flag = this.dataForm.config.paramsList.some(item => !item.value)
  1020. // 每次执行时只要有动态参数就会打开参数配置的弹窗进行设置
  1021. if (this.dataForm.config.paramsList && this.dataForm.config.paramsList.length) {
  1022. this.$refs.paramsSettingDialog.open(true)
  1023. } else {
  1024. this.getData()
  1025. }
  1026. },
  1027. // 调接口
  1028. getData () {
  1029. // 如果是前端代理,则自行组装接口及参数并调接口
  1030. if (this.dataForm.config.requestType === 'frontend') {
  1031. // this.replaceParams(this.dataForm.config.paramsList)
  1032. axiosFormatting({ ...this.dataForm.config, paramsList: this.newParamsList }).then((res) => {
  1033. // this.dataPreviewList = res.data && Array.isArray(res.data) ? res.data : []
  1034. this.dataPreviewList = [{}]
  1035. for (const item in res) {
  1036. this.dataPreviewList[0][item] = res[item]
  1037. }
  1038. // 获取数据后更新输出字段
  1039. this.updateOoutputFieldList(this.dataPreviewList)
  1040. this.$message.success('解析并执行成功')
  1041. })
  1042. } else {
  1043. // 如果是后端代理,则将配置传到后端
  1044. const script = JSON.stringify(this.dataForm.config)
  1045. const executeParams = {
  1046. script,
  1047. params: this.dataForm.paramsList,
  1048. dataSetType: 'http'
  1049. }
  1050. datasetExecuteTest(executeParams).then(res => {
  1051. this.dataPreviewList = res.data && Array.isArray(res.data) ? res.data : []
  1052. // 获取数据后更新输出字段
  1053. this.updateOoutputFieldList(this.dataPreviewList)
  1054. this.$message.success('解析并执行成功')
  1055. }).catch((e) => {
  1056. })
  1057. }
  1058. },
  1059. updateOoutputFieldList (dataList) {
  1060. if (dataList && dataList.length) {
  1061. const newList = Object.keys(dataList?.[0])?.map(key => {
  1062. return {
  1063. fieldName: key,
  1064. fieldDesc: ''
  1065. }
  1066. })
  1067. this.outputFieldList = this.compareArr(newList, this.outputFieldList)
  1068. } else {
  1069. this.outputFieldList = []
  1070. }
  1071. },
  1072. // 用来对两个数组进行对比
  1073. compareArr (newList, oldList) {
  1074. // 创建一个空数组,用于存储最终的结果
  1075. const result = []
  1076. // 遍历A数组中的每个对象
  1077. for (const objA of newList) {
  1078. let found = false // 标志变量,用于表示是否在B数组中找到对应的属性
  1079. // 遍历B数组中的每个对象
  1080. for (const objB of oldList) {
  1081. if (objA.fieldName === objB.fieldName) {
  1082. // 如果A和B中的fieldName相同,则将B中该属性的属性值赋值给A,并将该对象添加到结果数组中
  1083. objA.fieldDesc = objB.fieldDesc
  1084. result.push(objA)
  1085. found = true
  1086. break
  1087. }
  1088. }
  1089. // 如果在B数组中没有找到对应的属性,则直接将该对象添加到结果数组中
  1090. if (!found) {
  1091. result.push(objA)
  1092. }
  1093. }
  1094. return result
  1095. },
  1096. // 清空分类
  1097. clearType () {
  1098. this.typeName = ''
  1099. this.dataForm.typeId = ''
  1100. },
  1101. // 分类展开高亮
  1102. setCurrentNode ($event) {
  1103. if ($event) {
  1104. const key = this.dataForm.typeId || null
  1105. this.$refs.categorySelectTree.setCurrentKey(key)
  1106. }
  1107. },
  1108. // 分类选择
  1109. selectParentCategory (value) {
  1110. this.dataForm.typeId = value.id
  1111. this.typeName = value.name
  1112. this.$refs.selectParentName.blur()
  1113. },
  1114. goBack () {
  1115. this.$emit('back')
  1116. },
  1117. renderHeader (h, { column, index }) {
  1118. const labelLong = column.label.length // 表头label长度
  1119. const size = 14 // 根据需要定义标尺,直接使用字体大小确定就行,也可以根据需要定义
  1120. column.minWidth = labelLong * size < 120 ? 120 : labelLong * size // 根据label长度计算该表头最终宽度
  1121. return h('span', { class: 'cell-content', style: { width: '100%' } }, [column.label])
  1122. },
  1123. openNewWindow (url) {
  1124. window.open(url, '_blank')
  1125. }
  1126. }
  1127. }
  1128. </script>
  1129. <style lang="scss" scoped>
  1130. @import '../../assets/style/bsTheme.scss';
  1131. .data-set-scrollbar {
  1132. height: 100%;
  1133. overflow-y: auto;
  1134. overflow-x: none;
  1135. .el-scrollbar__view {
  1136. height: 100%;
  1137. }
  1138. }
  1139. ::v-deep .el-input__inner {
  1140. width: 100% !important;
  1141. }
  1142. .page-header {
  1143. display: flex;
  1144. position: relative;
  1145. .page-header-right {
  1146. position: absolute;
  1147. right: 16px;
  1148. }
  1149. }
  1150. .sql-config {
  1151. padding: 0 16px;
  1152. }
  1153. .operation {
  1154. ::v-deep .el-select {
  1155. width: 200px !important;
  1156. margin-right: 16px;
  1157. }
  1158. display: flex;
  1159. }
  1160. ::v-deep .CodeMirror {
  1161. height: 180px !important;
  1162. font-family: Helvetica, Tahoma;
  1163. }
  1164. .no-border {
  1165. border: 0;
  1166. }
  1167. ::v-deep .fieldDescCheck {
  1168. .el-dialog__body {
  1169. height: fit-content !important;
  1170. min-height: unset !important;
  1171. }
  1172. }
  1173. .title-style {
  1174. padding: 8px 12px;
  1175. background-color: #f6f7fb;
  1176. border-left: 5px solid var(--bs-el-color-primary);
  1177. margin: 16px 16px 0 0;
  1178. }
  1179. .field-wrap {
  1180. // max-height: 110px;
  1181. overflow: auto;
  1182. margin-right: 16px;
  1183. cursor: pointer;
  1184. .field-item {
  1185. line-height: 32px;
  1186. padding: 0 12px 0 16px;
  1187. .edit_field {
  1188. display: none;
  1189. }
  1190. &:hover {
  1191. background-color: #f2f7fe;
  1192. .edit_field {
  1193. display: block;
  1194. }
  1195. }
  1196. }
  1197. }
  1198. .right-setting {
  1199. height: 358px;
  1200. overflow: hidden;
  1201. display: flex;
  1202. flex-direction: column;
  1203. .paramConfig {
  1204. max-height: 179px;
  1205. .field-wrap {
  1206. max-height: 127px;
  1207. }
  1208. }
  1209. .structure {
  1210. flex: 1;
  1211. overflow: hidden;
  1212. .field-wrap {
  1213. height: calc(100% - 40px);
  1214. }
  1215. }
  1216. }
  1217. .result-view {
  1218. font-size: 14px;
  1219. font-weight: 600;
  1220. color: var(--bs-el-text);
  1221. position: relative;
  1222. padding: 16px 0;
  1223. padding-left: 12px;
  1224. border-bottom: 1px solid var(--bs-background-1);
  1225. &::before {
  1226. content: "";
  1227. height: 14px;
  1228. position: absolute;
  1229. left: 0;
  1230. top: 50%;
  1231. transform: translateY(-50%);
  1232. border-left: 4px solid var(--bs-el-color-primary);
  1233. }
  1234. }
  1235. //::v-deep .bs-table-box.is-Edit .el-table {
  1236. // max-height: unset !important;
  1237. //
  1238. // .el-table__body-wrapper {
  1239. // max-height: unset !important;
  1240. // }
  1241. //}
  1242. .bs-table-box {
  1243. padding: 0;
  1244. height: 100% !important;
  1245. margin-bottom: 0 !important;
  1246. }
  1247. .tree-box {
  1248. padding: 0;
  1249. }
  1250. .tabs-box{
  1251. margin-left: 45px;
  1252. }
  1253. .add-btn{
  1254. width: 100%;
  1255. text-align: center;
  1256. border: 1px dashed #696A6E;
  1257. color: #fff;
  1258. &:hover{
  1259. cursor: pointer;
  1260. border: 1px dashed var(--bs-el-color-primary);
  1261. color: var(--bs-el-color-primary);
  1262. }
  1263. }
  1264. .delete-btn{
  1265. color: rgb(228, 116, 112);
  1266. &:hover{
  1267. cursor: pointer;
  1268. }
  1269. }
  1270. .preview-table{
  1271. max-height: 300px!important;
  1272. }
  1273. </style>