test.vue 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. <template>
  2. <!-- 测试devkind = 'APP' -->
  3. <div style="width: 100%;;display: flex;">
  4. <div style="width: 15%;;background-color: #F2F6FC;max-height: 85vh;overflow: auto;">
  5. <div style="display: flex;padding-top: 1%;padding-top: 5%;">
  6. <el-input
  7. v-model="inputNode"
  8. style="width:90%;margin-left: 5%;background-color: #ebeef5;"
  9. class="w-50 m-2"
  10. :prefix-icon="Search"
  11. />
  12. <!-- <el-button style="margin-left: 2%;width: 10%;background-color: #F7F7F7" :icon="Filter"/> -->
  13. <!-- <el-button type="primary" @click="showAdd" style="margin-left: 5%;width: 10%;" :icon="Plus"/> -->
  14. </div>
  15. <!-- <Plus style="width: 1em; height: 1em; margin-left:90%;cursor: pointer;color: #337ecc;" @click="showAddTree"/> -->
  16. <el-tree :expand-on-click-node="false" ref="treeRef" :filter-node-method="filterNode" :current-node-key="currentNodeKey" class="treeLeft" :data="data" @node-click="handleNodeClick" node-key="id" style="margin-left: 5%;margin-top: 5%;width: 90%;background-color: transparent;" default-expand-all :key="valueKet">
  17. <template #default="{ node, data }">
  18. <span style="justify-content: space-between;display: flex;width: 100%;align-items: center;">
  19. <div class="custom-tree-node">
  20. <svg-icon icon-class="model2" style="color: #eebe77;" v-if="data.nodeType=='MODEL'"/>
  21. <svg-icon icon-class="model" dstyle="color: #13E03B;" v-if="data.nodeType=='SERVICE'"/>
  22. <svg-icon svg-icon icon-class="cate" style="color: red;" v-if="data.nodeType=='TREE'"/>
  23. <span>{{ node.label }}</span>
  24. </div>
  25. <!-- <div style="margin-right: 1%;position: absolute;margin-left: 75%;">
  26. <el-dropdown trigger="hover" @click.stop v-if="currentNodeKey === data.id&&data.nodeType!=='SERVICE'">
  27. <el-icon class="el-icon--right" style="color: black;">
  28. <plus />
  29. </el-icon>
  30. <template #dropdown>
  31. <el-dropdown-menu>
  32. <el-dropdown-item style="display: flex;" @click="add1Level">
  33. <el-icon class="el-icon--right" style="color: black;">
  34. <CirclePlus />
  35. </el-icon>
  36. <div>
  37. 添加同级
  38. </div>
  39. </el-dropdown-item>
  40. <el-dropdown-item style="display: flex;" @click="addNextLevel">
  41. <el-icon class="el-icon--right" style="color: black;">
  42. <Connection />
  43. </el-icon>
  44. <div>
  45. 新建下级
  46. </div>
  47. </el-dropdown-item>
  48. <divider/>
  49. <el-dropdown-item style="display: flex;" @click="delAll" divided>
  50. <el-icon class="el-icon--right" style="color: black;">
  51. <CircleClose />
  52. </el-icon>
  53. <div>
  54. 删除节点
  55. </div>
  56. </el-dropdown-item>
  57. </el-dropdown-menu>
  58. </template>
  59. </el-dropdown>
  60. </div> -->
  61. </span>
  62. </template>
  63. </el-tree>
  64. </div>
  65. <div style="width: 84%;margin-left: 1%;padding-top: 0.5%;" class="tab-container">
  66. <div>
  67. <el-table
  68. :data="tableData"
  69. style="width: 98%;margin-left: 1%;margin-top: 0.5%;"
  70. :cell-style="{ padding:'5px' }"
  71. :header-cell-style="{height: heightAll*0.01+'px',}"
  72. :row-style="{ fontSize: '17px',textAlign:'center'}"
  73. border >
  74. <el-table-column type="index" label="序号" width="80">
  75. <template #default="{ $index }">
  76. <div style="text-align: center;">
  77. {{ $index + 1 }}
  78. </div>
  79. </template>
  80. </el-table-column>
  81. <el-table-column prop="name" label="服务名称" width="200">
  82. <template #default="scope">
  83. <div style="color: #409EFF;cursor: pointer;" @click="showDe(scope.row)">
  84. {{scope.row.name}}
  85. </div>
  86. </template>
  87. </el-table-column>
  88. <el-table-column prop="type" label="接口类型" width="200">
  89. </el-table-column>
  90. <el-table-column prop="url" label="接口地址" show-overflow-tooltip/>
  91. <el-table-column prop="rqtype" label="请求方式" width="200"/>
  92. <el-table-column prop="rptype" label="响应类型" width="150">
  93. <template #default="scope">
  94. <div style="text-align: center;display: flex;" v-if="scope.row.rptype=='1'">
  95. JSON
  96. </div>
  97. <div style="text-align: center;display: flex;" v-if="scope.row.rptype=='2'">
  98. XML
  99. </div>
  100. <div style="text-align: center;display: flex;" v-if="scope.row.rptype=='3'">
  101. HTML
  102. </div>
  103. </template>
  104. </el-table-column>
  105. <el-table-column prop="audit" label="测试状态" width="100">
  106. <template #default="scope">
  107. <div style="text-align: center;display: flex;color:#67C23A" v-if="scope.row.senState==1">
  108. 测试成功
  109. </div>
  110. <div style="text-align: center;display: flex;color:#F56C6C" v-if="scope.row.senState==0">
  111. 测试失败
  112. </div>
  113. <div style="text-align: center;display: flex;color:#E6A23C" v-if="scope.row.senState==null">
  114. 未测试
  115. </div>
  116. </template>
  117. </el-table-column>
  118. <el-table-column prop="address" label="操作" width="150">
  119. <template #default="scope">
  120. <div style="display: flex;">
  121. <el-button @click="testSer(scope.row)" type="primary" text size="mini" style="margin-left: 0%;">测试</el-button>
  122. <el-button @click="showLog(scope.row)" type="primary" text size="mini" style="margin-left: 0%;">日志</el-button>
  123. </div>
  124. </template>
  125. </el-table-column>
  126. </el-table>
  127. </div>
  128. <el-dialog @close="clearAdd" v-model="dialogVisible" title="" width="60%" destroy-on-close :key="tableKey">
  129. <div style="display: flex;align-items: center;">
  130. <div v-if="detailJson.rqtype==='GET'">
  131. <el-tag class="ml-2" type="warning">GET</el-tag>
  132. </div>
  133. <div v-if="detailJson.rqtype==='POST'">
  134. <el-tag class="ml-2" type="warning">POST</el-tag>
  135. </div>
  136. <div style="margin-left: 1%;">
  137. {{ detailJson.name }}:
  138. </div>
  139. <div style="margin-left: 1%;">
  140. {{ detailJson.url }}
  141. </div>
  142. </div>
  143. <el-descriptions style="margin-top: 1%;" :column="3" border>
  144. <el-descriptions-item label="接口类型">{{ detailJson.type }}</el-descriptions-item>
  145. <el-descriptions-item label="请求方式">{{ detailJson.rqtype }}</el-descriptions-item>
  146. <el-descriptions-item label="响应类型">{{ detailJson.rptype }}</el-descriptions-item>
  147. <el-descriptions-item label="服务分类">{{ detailJson.cateCode }}</el-descriptions-item>
  148. </el-descriptions>
  149. <div style="margin-top:4%;font-size: 18px;">
  150. 请求参数
  151. </div>
  152. <el-table
  153. style="margin-top: 1%;width: 98%;"
  154. :data="tableDataCan"
  155. :cell-style="{ textAlign: 'center',padding:'2px 0' }"
  156. :header-cell-style="{ textAlign: 'center'}"
  157. :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',textAlign:'center' }"
  158. border >
  159. <el-table-column prop="paramCode" label="参数字段">
  160. </el-table-column>
  161. <el-table-column prop="paramName" label="参数名称">
  162. </el-table-column>
  163. <el-table-column prop="paramType" label="参数类型" width="200">
  164. </el-table-column>
  165. <el-table-column prop="paramValue" label="参数示例">
  166. </el-table-column>
  167. <el-table-column prop="paramNote" label="参数说明" show-overflow-tooltip>
  168. </el-table-column>
  169. </el-table>
  170. <div style="margin-top:4%;font-size: 18px;">
  171. 返回参数
  172. </div>
  173. <el-input readonly placeholder="" :rows="8" type="textarea" v-model="dataJsonXiang" size="mini" text style="margin-top: 1%;width: 98%;" ></el-input>
  174. <template #footer>
  175. <span class="dialog-footer">
  176. <el-button type="primary" @click="dialogVisible = false" size="mini">
  177. 确定
  178. </el-button>
  179. </span>
  180. </template>
  181. </el-dialog>
  182. <el-dialog @close="clearAdd" v-model="dialogVisibleTest" :title="titleTest" width="60%" destroy-on-close :key="tableKey">
  183. <div style="margin-left: 1%;">
  184. {{ detailJson.name }}:
  185. </div>
  186. <div style="display: flex;align-items: center;width: 98%;margin-top: 1%;">
  187. <div v-if="detailJson.rqtype==='GET'">
  188. <el-tag class="ml-2" type="warning">GET</el-tag>
  189. </div>
  190. <div v-if="detailJson.rqtype==='POST'">
  191. <el-tag class="ml-2" type="warning">POST</el-tag>
  192. </div>
  193. <div style="margin-left: 1%;">
  194. {{ detailJson.url }}
  195. </div>
  196. <!-- <svg-icon @click="test" icon-class="startTest" style="margin-left: 1%;width: 50px;height: 25px;cursor: pointer;"/> -->
  197. <el-button @click="test" size="mini" type="primary" style="margin-left: 1%;cursor: pointer;" plain>点击测试</el-button>
  198. </div>
  199. <div style="margin-top:2%;font-size: 18px;">
  200. 请求参数
  201. </div>
  202. <el-table
  203. style="margin-top: 1%;width: 98%;"
  204. :data="tableDataCan"
  205. :cell-style="{ textAlign: 'center',padding:'2px 0' }"
  206. :header-cell-style="{ textAlign: 'center'}"
  207. :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',textAlign:'center' }"
  208. border >
  209. <el-table-column prop="paramCode" label="参数字段">
  210. </el-table-column>
  211. <el-table-column prop="paramName" label="参数名称">
  212. </el-table-column>
  213. <el-table-column prop="paramType" label="参数类型" width="200">
  214. </el-table-column>
  215. <el-table-column prop="paramValue" label="测试值">
  216. <template #default="scope">
  217. <div style="width: 100%;">
  218. <el-input placeholder="请填写" type="primary" class="noBor" v-model="scope.row.paramValue" size="mini" text style="margin-left: 0%;"></el-input>
  219. </div>
  220. </template>
  221. </el-table-column>
  222. <el-table-column prop="paramNote" label="参数说明" show-overflow-tooltip>
  223. </el-table-column>
  224. </el-table>
  225. <div style="margin-top:4%;font-size: 18px;">
  226. 测试结果
  227. </div>
  228. <el-input :style="isError ? '--el-input-text-color: red' : ''" placeholder="" :rows="8" type="textarea" v-model="dataReturn" size="mini" text style="margin-top: 1%;width: 98%;color: red;" ></el-input>
  229. <template #footer>
  230. <span class="dialog-footer">
  231. </span>
  232. </template>
  233. </el-dialog>
  234. <el-dialog @close="clearFromLev" title="测试日志" draggable v-model="dialogVisibleLevel" width="50%" destroy-on-close :key="tableKey">
  235. <div style="margin-top:0%;font-size: 18px;">
  236. {{titleTest}}
  237. </div>
  238. <el-table
  239. style="margin-top: 2%;width: 98%;height: 40vh;"
  240. :data="tableDataLog"
  241. :cell-style="{ textAlign: 'center',padding:'3px 0' }"
  242. :header-cell-style="{ textAlign: 'center'}"
  243. :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',textAlign:'center' }"
  244. border >
  245. <el-table-column prop="createBy" label="测试发起人">
  246. </el-table-column>
  247. <el-table-column prop="runTm" label="测试时间">
  248. </el-table-column>
  249. <el-table-column prop="execTm" label="测试耗时" show-overflow-tooltip>
  250. </el-table-column>
  251. <el-table-column prop="returnData" label="测试返回结果" show-overflow-tooltip>
  252. </el-table-column>
  253. <el-table-column prop="audit" label="测试状态" width="100">
  254. <template #default="scope">
  255. <div style="text-align: center;display: flex;color:#67C23A" v-if="scope.row.senState==1">
  256. 测试成功
  257. </div>
  258. <div style="text-align: center;display: flex;color:#F56C6C" v-if="scope.row.senState==0">
  259. 测试失败
  260. </div>
  261. <div style="text-align: center;display: flex;color:#E6A23C" v-if="scope.row.senState==null">
  262. 未测试
  263. </div>
  264. </template>
  265. </el-table-column>
  266. <el-table-column prop="errorMessage" label="错误信息" show-overflow-tooltip>
  267. <template #default="scope">
  268. <div style="text-align: center;display: flex;color:#F56C6C" v-if="scope.row.errorMessage!==null">
  269. {{scope.row.errorMessage}}
  270. </div>
  271. <div style="text-align: center;display: flex;color:#67C23A" v-if="scope.row.errorMessage==null">
  272. /
  273. </div>
  274. </template>
  275. </el-table-column>
  276. </el-table>
  277. <template #footer>
  278. <span class="dialog-footer">
  279. <el-button type="primary" @click="dialogVisibleLevel = false" size="mini">
  280. 确定
  281. </el-button>
  282. </span>
  283. </template>
  284. </el-dialog>
  285. <el-dialog v-model="dialogVisibleDe" title="" width="50%" @close="" destroy-on-close class="custom-dialog-bg">
  286. <el-form size="mini" :key="tableKey" style="margin-top:1%;width: 100%;" :model="formJi" label-position="right"
  287. ref="formRefJi" label-width="120px" :rules="rulesJi">
  288. <el-row :gutter="48">
  289. <el-col :span="10">
  290. <el-form-item label="服务名称:" prop="name" style="">
  291. {{formJi.name}}
  292. </el-form-item>
  293. </el-col>
  294. <el-col :span="10">
  295. <el-form-item label="接口类型:" prop="" style="">
  296. <div style="display: flex;width: 100%;justify-content: space-between;">
  297. {{formJi.type}}
  298. </div>
  299. </el-form-item>
  300. </el-col>
  301. </el-row>
  302. <el-row :gutter="48">
  303. <el-col :span="20">
  304. <el-form-item label="接口地址:" prop="url" style="">
  305. {{formJi.url}}
  306. </el-form-item>
  307. </el-col>
  308. <el-col :span="10">
  309. <el-form-item label="请求方式:" prop="" style="">
  310. {{formJi.rqtype}}
  311. </el-form-item>
  312. </el-col>
  313. </el-row>
  314. <el-row :gutter="48">
  315. <el-col :span="10">
  316. <el-form-item label="响应类型:" prop="" style="display: flex; align-items: center;">
  317. {{formJi.rptype}}
  318. </el-form-item>
  319. </el-col>
  320. <el-col :span="10">
  321. <el-form-item label="服务分类:" prop="cateCode" style="">
  322. {{formJi.cateCode}}
  323. <!-- <el-cascader :disabled="isEdit" v-model="formJi.cateCode" :options="cascaderOptions" clearable
  324. style="width: 100%;"></el-cascader> -->
  325. </el-form-item>
  326. </el-col>
  327. </el-row>
  328. <el-row :gutter="48">
  329. <el-col :span="13">
  330. <el-form-item label="服务说明:">
  331. {{formJi.intro}}
  332. </el-form-item>
  333. </el-col>
  334. </el-row>
  335. </el-form>
  336. </el-dialog>
  337. </div>
  338. </div>
  339. </template>
  340. <script setup>
  341. import {getCatalog} from "@/api/service/catalog";
  342. import { Plus,Search,Filter,Promotion,Check } from '@element-plus/icons-vue'
  343. import { reactive } from 'vue'
  344. import { modelTreeSelect,getSerDe,addService,addServiceParam,delService,addTree,deTree,getServiceInfo,testService,testLog } from "@/api/service/info";
  345. import { ref, onMounted, onUnmounted, nextTick,onBeforeMount } from 'vue';
  346. import JsonViewer from 'vue-json-viewer'
  347. import 'vue-json-viewer/style.css'
  348. import JsonEditorVue from 'json-editor-vue3'
  349. import { cloneDeep } from 'lodash'
  350. import { useClipboard } from "@vueuse/core";
  351. const titleTest = ref('')
  352. const isError = ref(false)
  353. const { proxy } = getCurrentInstance();
  354. const JsonAdd= ref(JSON.stringify({ data: "初始值1" }))
  355. const exampleAdd = ref('')
  356. const dialogVisibleLevel = ref(false)
  357. const dialogVisibleDe = ref(false)
  358. const detail = ref({
  359. name:'',
  360. rqtype:'',
  361. rptype:''
  362. })
  363. const tableDataLog = ref([])
  364. const show1Lev = ref(true)
  365. const inputNode =ref('')
  366. const isEdit = ref(true)
  367. const dataReturn = ref('')
  368. const optionsCan = ref([
  369. {
  370. label:"string",
  371. value:'string'
  372. },
  373. {
  374. label:"int",
  375. value:'int'
  376. },
  377. {
  378. label:"boolean",
  379. value:'boolean'
  380. },
  381. {
  382. label:"array",
  383. value:'array'
  384. },
  385. {
  386. label:"object",
  387. value:'object'
  388. },
  389. {
  390. label:"number",
  391. value:'number'
  392. },
  393. {
  394. label:"null",
  395. value:'null'
  396. },
  397. {
  398. label:"any",
  399. value:'any'
  400. },
  401. ])
  402. const currentNodeKey = ref('')
  403. const options = ref([
  404. {label:'开发中',
  405. value:'1'
  406. },
  407. {label:'运行中',
  408. value:'2'
  409. },
  410. ])
  411. const dataJsonXiang = ref([])
  412. const parTree = ref({})
  413. const valueKet = ref(0)
  414. const tableDataCan = ref([
  415. {
  416. itemName:'',
  417. itemCode:'',
  418. paramType:'',
  419. paramNote:''
  420. }
  421. ])
  422. const dialogVisibleTest = ref(false)
  423. const optionsMdid = ref([])
  424. const optionsRqtype = ref([
  425. {label:'GET',
  426. value:'GET'
  427. },
  428. {label:'POST',
  429. value:'POST'
  430. },
  431. ])
  432. const optionsType= ref([
  433. {label:'RESTful',
  434. value:'RESTful'
  435. },
  436. {label:'WebService',
  437. value:'WebService'
  438. },
  439. {label:'HTTP',
  440. value:'HTTP'
  441. },
  442. {label:'WebSocket',
  443. value:'WebSocket'
  444. },
  445. ])
  446. const data = ref([])
  447. const select = ref('1')
  448. const activeName = ref('first')
  449. const title = ref('')
  450. const titleTree = ref('')
  451. const currentPage = ref(1)
  452. const total = ref(1)
  453. const tableData = ref([])
  454. const tableheight = window.innerHeight*0.7
  455. const heightAll = window.innerHeight
  456. const dialogVisible = ref(false)
  457. const dialogVisibleTree = ref(false)
  458. const isAdd = ref(false)
  459. const isAddTa = ref(false)
  460. const treeId = ref('');
  461. const valueSta = ref('1');
  462. const parMdid = ref('')
  463. const example = ref('');
  464. const tableDataCanAdd = ref([
  465. {
  466. itemName:'',
  467. itemCode:'',
  468. paramType:'',
  469. paramNote:''
  470. }
  471. ])
  472. const formZu = ref({
  473. itemName:'',
  474. itemTp:'',
  475. itemEn:'',
  476. itemTp:'',
  477. itemDataTp:'',
  478. itemDefaultVal:'',
  479. itemUnit:'',
  480. itemNotes:'',
  481. });
  482. const parId= ref('')
  483. const formJi = ref({
  484. name:'',
  485. cateCode:'',
  486. type:'',
  487. url:'',
  488. rqtype:'',
  489. rptype:'',
  490. intro:'',
  491. });
  492. const rulesJi = reactive({
  493. name: [{ required: true, message: '必填', trigger: 'blur' }],
  494. url: [{ required: true, message: '必填', trigger: 'blur' }],
  495. cateCode: [{ required: true, message: '必填', trigger: 'blur' }],
  496. });
  497. const formRefJi = ref();
  498. const formAdd = ref({
  499. name:'',
  500. cateCode:'',
  501. type:'',
  502. url:'',
  503. rqtype:'',
  504. rptype:'',
  505. intro:'',
  506. mdid:''
  507. });
  508. const rulesAdd = reactive({
  509. mdid: [{ required: true, message: '必填', trigger: 'blur' }],
  510. name: [{ required: true, message: '必填', trigger: 'blur' }],
  511. url: [{ required: true, message: '必填', trigger: 'blur' }],
  512. cateCode: [{ required: true, message: '必填', trigger: 'blur' }],
  513. });
  514. const formRefAdd = ref();
  515. const treeRef = ref(null);
  516. const formTree = ref({
  517. itemName:'',
  518. catePid:'',
  519. itemNo:'',
  520. itemNotes:''
  521. });
  522. const rulesTree = reactive({
  523. itemNo: [{ required: true, message: '必填', trigger: 'blur' }],
  524. catePid: [{ required: true, message: '必填', trigger: 'blur' }],
  525. itemName: [{ required: true, message: '必填', trigger: 'blur' }],
  526. });
  527. const formRefTree = ref();
  528. const formLev = ref({
  529. itemName:'',
  530. itemNo:'',
  531. itemNotes:'',
  532. });
  533. const rulesLev = reactive({
  534. itemNotes: [{ required: true, message: '必填', trigger: 'blur' }],
  535. itemNo: [{ required: true, message: '必填', trigger: 'blur' }],
  536. itemName: [{ required: true, message: '必填', trigger: 'blur' }],
  537. });
  538. const formRefLev = ref();
  539. const cascaderOptions = ref([])
  540. const props1 = ref({
  541. checkStrictly: true,
  542. })
  543. const detailJson = ref('')
  544. const parOptions = ref([])
  545. watch(inputNode, (val) => {
  546. treeRef.value?.filter(val); // 调用树的过滤方法
  547. });
  548. const filterNode = (value, data) => {
  549. if (!value) return true; // 空搜索时显示所有节点
  550. return data.label.includes(value); // 检查节点标签是否包含关键字
  551. };
  552. const copied = ref(false);
  553. function showLog(row){
  554. dialogVisibleLevel.value = true
  555. var par = {
  556. serId:row.srvId
  557. }
  558. testLog(par).then(res=>{
  559. tableDataLog.value = res.rows
  560. })
  561. }
  562. function test(){
  563. var par = detailJson.value
  564. par.params = tableDataCan.value
  565. testService(par).then(res=>{
  566. if(res.code===444){
  567. isError.value = true
  568. }else{
  569. isError.value = false
  570. }
  571. console.log(res)
  572. dataReturn.value = res.msg
  573. var par1 = {
  574. data:{id:parMdid.value}
  575. }
  576. handleNodeClick(null,par1,null)
  577. })
  578. }
  579. function testSer(row){
  580. getSerDe(row.srvId).then(res=>{
  581. if(res.code===200){
  582. detailJson.value = res.data.ptService
  583. console.log(detailJson.value)
  584. dialogVisibleTest.value = true
  585. tableDataCan.value = res.data.list
  586. }
  587. })
  588. }
  589. function showDe(row){
  590. getSerDe(row.srvId).then(res=>{
  591. if(res.code===200){
  592. dialogVisibleDe.value = true
  593. parOptions.value.forEach(item=>{
  594. if(res.data.ptService.cateCode === item.cateCode){
  595. res.data.ptService.cateCode = item.cateName
  596. }
  597. })
  598. if(res.data.ptService.rptype === '1'){
  599. res.data.ptService.rptype = 'JSON'
  600. }
  601. if(res.data.ptService.rptype === '2'){
  602. res.data.ptService.rptype = 'XML'
  603. }
  604. if(res.data.ptService.rptype === '3'){
  605. res.data.ptService.rptype = 'HTML'
  606. }
  607. formJi.value = res.data.ptService
  608. }
  609. })
  610. }
  611. function filterModelNodes(nodes) {
  612. if (!Array.isArray(nodes)) return [];
  613. const result = [];
  614. for (const node of nodes) {
  615. // 递归处理子节点(如果有)
  616. const filteredChildren = node.children ? filterModelNodes(node.children) : [];
  617. if (node.nodeType === 'MODEL') {
  618. // 保留当前节点,并更新其子节点
  619. node.value = node.id
  620. result.push({
  621. ...node,
  622. children: filteredChildren
  623. });
  624. } else {
  625. // 删除当前节点,将其子节点提升到当前层级
  626. result.push(...filteredChildren);
  627. }
  628. }
  629. return result;
  630. }
  631. function clearAdd(){
  632. tableDataCan.value = [
  633. ]
  634. dataReturn.value = ''
  635. }
  636. function extractModelNodesDFSIterative(root) {
  637. const result = [];
  638. const stack = root;
  639. while (stack.length > 0) {
  640. const node = stack.pop();
  641. if (node.nodeType === 'MODEL') {
  642. result.push(node);
  643. }
  644. // 子节点逆序入栈(保证从左到右遍历)
  645. if (node.children) {
  646. for (let i = node.children.length - 1; i >= 0; i--) {
  647. stack.push(node.children[i]);
  648. }
  649. }
  650. }
  651. return result;
  652. }
  653. function delAll(){
  654. proxy.$modal.confirm('是否确认删除?').then(function () {
  655. return deTree(parTree.value.id);
  656. }).then(() => {
  657. getTreeLeft();
  658. proxy.$modal.msgSuccess("删除成功");
  659. dialogVisibleLevel.value = false
  660. }).catch(() => {});
  661. }
  662. function clearFromLev(){
  663. tableDataLog.value = []
  664. }
  665. function addNextLevel(){
  666. dialogVisibleLevel.value = true
  667. show1Lev.value = false
  668. }
  669. function saveAddNextLevel(){
  670. formRefLev.value.validate((valid) => {
  671. if(valid){
  672. var par = formLev.value
  673. par.treeType = 'MODEL'
  674. par.treePid = parTree.value.id
  675. addTree(par).then(res=>{
  676. if(res.code===200){
  677. proxy.$modal.msgSuccess("新增成功");
  678. getTreeLeft()
  679. dialogVisibleLevel.value = false
  680. }
  681. })
  682. }
  683. });
  684. }
  685. function add1Level(){
  686. dialogVisibleLevel.value = true
  687. show1Lev.value = true
  688. }
  689. function saveAdd1Level(){
  690. formRefLev.value.validate((valid) => {
  691. if(valid){
  692. var par = formLev.value
  693. par.treeType = 'MODEL'
  694. par.treePid = parTree.value.pid
  695. addTree(par).then(res=>{
  696. if(res.code===200){
  697. proxy.$modal.msgSuccess("新增成功");
  698. getTreeLeft()
  699. dialogVisibleLevel.value = false
  700. }
  701. })
  702. }
  703. });
  704. }
  705. async function delSer(){
  706. proxy.$modal.confirm('是否确认删除?').then(function () {
  707. return delService(parId.value.id);
  708. }).then(() => {
  709. getTreeLeft();
  710. proxy.$modal.msgSuccess("删除成功");
  711. }).catch(() => {});
  712. }
  713. async function addSer(){
  714. console.log(JsonAdd.value)
  715. var valid
  716. await formRefAdd.value.validate((valid1) => {
  717. valid = valid1
  718. });
  719. console.log(valid)
  720. if(valid){
  721. var par = formAdd.value
  722. par.example = exampleAdd.value
  723. par.rpcontent = JsonAdd.value
  724. par.cateCode = par.cateCode[0]
  725. console.log(par)
  726. await addService(par).then(res=>{
  727. if(res.code===200){
  728. var parCan = tableDataCanAdd.value
  729. parCan.srvId = res.data.srvId
  730. addServiceParam(parCan).then(res1=>{
  731. if(res1.code===200){
  732. proxy.$modal.msgSuccess("新增成功");
  733. getTreeLeft()
  734. }
  735. })
  736. }
  737. })
  738. }
  739. }
  740. function showAdd(){
  741. dialogVisible.value = true
  742. }
  743. async function handleNodeClick(node,data,event){
  744. console.log(data)
  745. titleTest.value = data.data.label
  746. parMdid.value = data.data.id
  747. var par = {
  748. mdid:data.data.id
  749. }
  750. console.log(data.data.id)
  751. await getServiceInfo(par).then(res=>{
  752. if(res.data){
  753. tableData.value = res.data.serviceList
  754. }
  755. })
  756. parOptions.value.forEach(option => {
  757. option.label = option.cateName;
  758. option.value = option.cateCode;
  759. });
  760. console.log(parOptions.value)
  761. for(var i = 0; i < parOptions.value.length; i++){
  762. for(var i1 = 0; i1 < tableData.value.length; i1++){
  763. console.log(i1);
  764. if(parOptions.value[i].value === tableData.value[i1].cateCode){
  765. tableData.value[i1].cateCode = parOptions.value[i].label
  766. }
  767. }
  768. }
  769. var par = [
  770. {
  771. value:'1',
  772. label:'JSON'
  773. },
  774. {
  775. value:'2',
  776. label:'XML'
  777. },
  778. {
  779. value:'3',
  780. label:'HTML'
  781. }
  782. ]
  783. for(var i = 0; i < par.length; i++){
  784. for(var i1 = 0; i1 < tableData.value.length; i1++){
  785. if(par[i].value === tableData.value[i1].rptype){
  786. tableData.value[i1].rptype = par[i].label
  787. }
  788. }
  789. }
  790. }
  791. async function getTreeLeft(){
  792. var par = {
  793. params:{
  794. level:'2',
  795. devkind:'APP'
  796. }
  797. }
  798. await modelTreeSelect(par).then(res=>{
  799. par = res.data
  800. data.value = res.data
  801. firstMdid.value = res.data[0].children[0].id
  802. })
  803. optionsMdid.value = filterModelNodes(par)
  804. console.log(optionsMdid.value)
  805. var par1 = {
  806. data:{id:firstMdid.value}
  807. }
  808. handleNodeClick(null,par1,null)
  809. }
  810. const firstMdid = ref('')
  811. function renameTreeProperties(tree) {
  812. // 深拷贝避免修改原始数据(可选,根据需求)
  813. const newTree = cloneDeep(tree); // 使用 lodash
  814. // 或:const newTree = JSON.parse(JSON.stringify(tree)); // 原生方法(不兼容函数等)
  815. // 递归处理函数
  816. const processNode = (node) => {
  817. // 重命名属性
  818. if ('cateName' in node) {
  819. node.label = node.cateName;
  820. delete node.cateName;
  821. }
  822. if ('cateCode' in node) {
  823. node.value = node.cateCode;
  824. delete node.cateCode;
  825. }
  826. // 递归处理子节点
  827. if (node.children && node.children.length > 0) {
  828. node.children.forEach(child => processNode(child));
  829. }
  830. };
  831. // 遍历根节点
  832. newTree.forEach(rootNode => processNode(rootNode));
  833. return newTree;
  834. }
  835. function fetchData() {
  836. getCatalog().then((r) => {
  837. parOptions.value = r.data
  838. cascaderOptions.value = renameTreeProperties(buildTree(r.data))
  839. console.log(parOptions.value)
  840. });
  841. }
  842. function buildTree(flatData, rootValue = '0') {
  843. const nodeMap = new Map();
  844. const tree = [];
  845. flatData.forEach(item => {
  846. nodeMap.set(item.cateCode, { ...item, children: [] });
  847. });
  848. for (const [code, node] of nodeMap) {
  849. const parentCode = node.catePcode;
  850. if (parentCode === rootValue || !parentCode) {
  851. tree.push(node);
  852. continue;
  853. }
  854. const parent = nodeMap.get(parentCode);
  855. if (parent) {
  856. parent.children.push(node);
  857. } else {
  858. console.warn(`Orphan node detected: ${code}. Parent ${parentCode} not found`);
  859. }
  860. }
  861. return tree;
  862. }
  863. function addPa(){
  864. var par = {
  865. itemName:''
  866. }
  867. tableDataCan.value.push(par)
  868. }
  869. function delCan(index){
  870. tableDataCan.value.splice(index, 1)
  871. }
  872. function addCanAdd(){
  873. var par = {
  874. parName:''
  875. }
  876. tableDataCanAdd.value.push(par)
  877. }
  878. function delCanAdd(index){
  879. tableDataCanAdd.value.splice(index, 1)
  880. }
  881. onMounted(() => {
  882. fetchData()
  883. getTreeLeft()
  884. });
  885. </script>
  886. <style scoped>
  887. .noBorSel :deep(.el-select__wrapper){
  888. box-shadow: none !important; /* 去除阴影边框 */
  889. border: 1px solid transparent !important; /* 设置透明边框 */
  890. background-color: transparent !important; /* 可选:透明背景 */
  891. }
  892. .noBor :deep(.el-input__wrapper) {
  893. box-shadow: none !important; /* 去除阴影边框 */
  894. border: 1px solid transparent !important; /* 设置透明边框 */
  895. background-color: transparent !important; /* 可选:透明背景 */
  896. }
  897. /* 节点垂直间距 */
  898. :deep(.el-tree-node) {
  899. margin-bottom:5px !important; /* 增大节点间距 */
  900. }
  901. .el-popover.custom-popover {
  902. min-width: 50px;
  903. padding: 8px; /* 可选:调整内边距 */
  904. }
  905. </style>
  906. <style>
  907. .dot {
  908. width: 20px; /* 控制圆点直径 */
  909. height: 20px;
  910. background-color: #333; /* 实心颜色 */
  911. border-radius: 50%; /* 关键属性 */
  912. display: inline-block; /* 确保与其他元素并排 */
  913. }
  914. /* 全局透明样式(不使用 scoped) */
  915. .transparent-select .el-select__wrapper {
  916. background-color: transparent !important;
  917. border-color: transparent !important;
  918. box-shadow: none !important;
  919. }
  920. .transparent-select .el-select__selection {
  921. background-color: transparent;
  922. }
  923. /* 处理悬停和聚焦状态 */
  924. .transparent-select .el-select__wrapper:hover,
  925. .transparent-select .el-select__wrapper.is-focused {
  926. border-color: transparent !important;
  927. box-shadow: none !important;
  928. }
  929. /* 下拉箭头图标 */
  930. .transparent-select .el-select__caret {
  931. color: rgba(0, 0, 0, 0.5); /* 半透明图标 */
  932. }
  933. </style>
  934. <style scoped>
  935. :deep(.treeLeft) .el-tree-node__content {
  936. display: flex !important;
  937. height: 28px; /* 按设计稿调整高度 */
  938. align-items: center;
  939. padding-top: 0 !important;
  940. }
  941. :deep(.treeLeft) .el-tree-node__content:hover {
  942. background-color: #e9e9eb;
  943. }
  944. :deep(.treeLeft) .el-tree-node__content:active {
  945. background-color: rgka(69,157,255,0.1) !important;
  946. }
  947. /* 选中态(Active) */
  948. :deep(.treeLeft) .el-tree-node.is-current > .el-tree-node__content {
  949. background-color: #c6e2ff !important;
  950. }
  951. .tab-container {
  952. height: 100vh; /* 关键:父容器明确高度 */
  953. display: flex;
  954. flex-direction: column;
  955. }
  956. .drag-handle {
  957. cursor: move;
  958. }
  959. .ghost {
  960. opacity: 0.5;
  961. background: #c8ebfb;
  962. }
  963. /* 防止文字选中 */
  964. :deep(.el-table__row) {
  965. user-select: none;
  966. -webkit-user-select: none;
  967. }
  968. </style>
  969. <style scoped lang="scss">
  970. .custom-tree-node {
  971. display: flex; /* 启用 Flex 布局 */
  972. align-items: center; /* 垂直居中 */
  973. gap: 8px; /* 图标与文字间距 */
  974. justify-content: space-between;
  975. }
  976. .el-table .el-table__row td {
  977. height: 60px !important; /* 行高 */
  978. }
  979. .custom-tree-node {
  980. display: flex; /* 启用 Flex 布局 */
  981. align-items: center; /* 垂直居中 */
  982. gap: 8px; /* 图标与文字间距 */
  983. }
  984. </style>