index.vue 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414
  1. <template>
  2. <!-- 测试devkind = 'SYS' -->
  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. <el-tabs
  66. v-model="activeName"
  67. type="card"
  68. class="demo-tabs"
  69. style="margin-left: 1%;width: 84%;"
  70. @tab-change="getTaskReturn"
  71. >
  72. <el-tab-pane :disabled="!parMdid" label="任务详情" name="first">
  73. <el-button :disabled="!parMdid" @click="addTask" style="margin-top: 0%;margin-right: 1%;float:right;" type="primary" size="mini" plain>新增</el-button>
  74. <div style="width: 100%;margin-left: 0%;padding-top: 0%;" class="tab-container">
  75. <div>
  76. <el-table
  77. :data="tableData"
  78. style="width: 98%;margin-left: 1%;margin-top: 0.5%;height: 73vh;"
  79. :cell-style="{ padding:'5px' }"
  80. :header-cell-style="{fontSize: '14px',height: heightAll*0.01+'px',}"
  81. :row-style="{ fontSize: '17px',textAlign:'center'}"
  82. border >
  83. <el-table-column type="index" label="序号" width="80">
  84. <template #default="{ $index }">
  85. <div style="text-align: center;">
  86. {{ $index + 1 }}
  87. </div>
  88. </template>
  89. </el-table-column>
  90. <el-table-column prop="flowJobName" label="任务名称" width="200">
  91. </el-table-column>
  92. <!-- <el-table-column prop="type" label="建模方案" width="300">
  93. </el-table-column> -->
  94. <el-table-column prop="chargeBy" label="责任人" width="200" show-overflow-tooltip/>
  95. <el-table-column prop="chargePhone" label="联系方式" />
  96. <el-table-column prop="jobStatus" label="任务状态" width="170">
  97. <template #default="scope">
  98. <el-switch @change="changejobStatus(scope.row)" v-model="scope.row.jobStatus"/>
  99. </template>
  100. </el-table-column>
  101. <el-table-column prop="address" label="操作" width="150">
  102. <template #default="scope">
  103. <div style="display: flex;">
  104. <el-button @click="getEdit(scope.row)" type="primary" text size="mini" style="margin-left: 0%;">编辑</el-button>
  105. <el-button @click="delTaskDe(scope.row)" type="danger" text size="mini" style="margin-left: 0%;">删除</el-button>
  106. </div>
  107. </template>
  108. </el-table-column>
  109. </el-table>
  110. <el-pagination
  111. v-if="total>20"
  112. small
  113. background
  114. style="margin-top: 0.8%;float: right;margin-right: 1%;"
  115. layout="prev, pager, next"
  116. :total="total"
  117. v-model="pageNum"
  118. @change="changePage"
  119. class="mt-4"
  120. />
  121. </div>
  122. <el-dialog @close="clearAdd" v-model="dialogVisible" title="" width="60%" destroy-on-close :key="tableKey">
  123. <div style="display: flex;align-items: center;">
  124. <div v-if="detailJson.rqtype==='GET'">
  125. <el-tag class="ml-2" type="warning">GET</el-tag>
  126. </div>
  127. <div v-if="detailJson.rqtype==='POST'">
  128. <el-tag class="ml-2" type="warning">POST</el-tag>
  129. </div>
  130. <div style="margin-left: 1%;">
  131. {{ detailJson.name }}:
  132. </div>
  133. <div style="margin-left: 1%;">
  134. {{ detailJson.url }}
  135. </div>
  136. </div>
  137. <el-descriptions style="margin-top: 1%;" :column="3" border>
  138. <el-descriptions-item label="接口类型">{{ detailJson.type }}</el-descriptions-item>
  139. <el-descriptions-item label="请求方式">{{ detailJson.rqtype }}</el-descriptions-item>
  140. <el-descriptions-item label="响应类型">{{ detailJson.rptype }}</el-descriptions-item>
  141. <el-descriptions-item label="服务分类">{{ detailJson.cateCode }}</el-descriptions-item>
  142. </el-descriptions>
  143. <div style="margin-top:4%;font-size: 18px;">
  144. 请求参数
  145. </div>
  146. <el-table
  147. style="margin-top: 1%;width: 98%;"
  148. :data="tableDataCan"
  149. :cell-style="{ textAlign: 'center',padding:'2px 0' }"
  150. :header-cell-style="{fontSize: '14px', textAlign: 'center'}"
  151. :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',textAlign:'center' }"
  152. border >
  153. <el-table-column prop="paramCode" label="参数字段">
  154. </el-table-column>
  155. <el-table-column prop="paramName" label="参数名称">
  156. </el-table-column>
  157. <el-table-column prop="paramType" label="参数类型" width="200">
  158. </el-table-column>
  159. <el-table-column prop="paramValue" label="参数示例">
  160. </el-table-column>
  161. <el-table-column prop="paramNote" label="参数说明" show-overflow-tooltip>
  162. </el-table-column>
  163. </el-table>
  164. <div style="margin-top:4%;font-size: 18px;">
  165. 返回参数
  166. </div>
  167. <el-input readonly placeholder="" :rows="8" type="textarea" v-model="dataJsonXiang" size="mini" text style="margin-top: 1%;width: 98%;" ></el-input>
  168. <template #footer>
  169. <span class="dialog-footer">
  170. <el-button type="primary" @click="dialogVisible = false" size="mini">
  171. 确定
  172. </el-button>
  173. </span>
  174. </template>
  175. </el-dialog>
  176. <el-dialog @close="clearAdd" v-model="dialogVisibleTest" draggable :title="titleDe" width="60%" destroy-on-close :key="tableKey">
  177. <el-form size="mini" style="margin-top: 0%;width: 98%;" :model="formJi" label-position="right" ref="formRefJi" label-width="120px" :rules="rulesJi">
  178. <el-row :gutter="48">
  179. <el-col :span="8">
  180. <el-form-item label="任务名称:" prop="flowJobName" style="">
  181. <div style="display: flex;width: 100%;justify-content: space-between;">
  182. <el-input v-model="formJi.flowJobName" style="width: 100%;"/>
  183. </div>
  184. </el-form-item>
  185. </el-col>
  186. <el-col :span="8">
  187. </el-col>
  188. </el-row>
  189. <el-form-item label="状态:" prop="jobStatus" v-if="isAdd">
  190. <el-radio-group v-model="formJi.jobStatus" class="custom-radio-group" style="width: 100%;margin-top: -1%;">
  191. <el-radio :label=1 size="large">启用</el-radio>
  192. <el-radio :label=0 size="large">禁用</el-radio>
  193. </el-radio-group>
  194. </el-form-item>
  195. <el-row :gutter="48">
  196. <el-col :span="15">
  197. </el-col>
  198. </el-row>
  199. <el-row :gutter="48">
  200. <el-col :span="8">
  201. <el-form-item label="负责人:" prop="chargeBy" style="">
  202. <div style="display: flex;width: 100%;justify-content: space-between;">
  203. <el-input v-model="formJi.chargeBy" style="width: 100%;"/>
  204. </div>
  205. </el-form-item>
  206. </el-col>
  207. <el-col :span="8">
  208. <el-form-item label="联系方式" prop="chargePhone" style="">
  209. <div style="display: flex;width: 100%;justify-content: space-between;">
  210. <el-input v-model="formJi.chargePhone" style="width: 100%;"/>
  211. </div>
  212. </el-form-item>
  213. </el-col>
  214. </el-row>
  215. <el-row :gutter="48">
  216. <el-col :span="8">
  217. <el-form-item label="任务开发引擎:" prop="executorInfo">
  218. <el-select
  219. v-model="formJi.executorInfo"
  220. class=""
  221. placeholder=""
  222. style="width: 100%;margin-left: 0%;"
  223. >
  224. <el-option
  225. v-for="item in optionsYinqing"
  226. :key="item.value"
  227. :label="item.dictLabel"
  228. :value="item.dictCode"
  229. />
  230. </el-select>
  231. </el-form-item>
  232. </el-col>
  233. <el-col :span="8">
  234. <el-form-item label="任务类型:" prop="taskType">
  235. <el-select
  236. v-model="formJi.taskType"
  237. class=""
  238. placeholder=""
  239. style="width: 100%;margin-left: 0%;"
  240. >
  241. <el-option
  242. v-for="item in optionsTaskType"
  243. :key="item.value"
  244. :label="item.label"
  245. :value="item.value"
  246. />
  247. </el-select>
  248. </el-form-item>
  249. </el-col>
  250. </el-row>
  251. <div style="margin-top: 0%;">
  252. <el-row :gutter="48">
  253. <el-col :span="8">
  254. <el-form-item label="路由策略:" prop="routeKey">
  255. <el-select
  256. v-model="formJi.routeKey"
  257. class=""
  258. placeholder=""
  259. style="width: 100%;margin-left: 0%;"
  260. >
  261. <el-option label="Hash" :value="1" />
  262. <el-option label="随机" :value="2" />
  263. <el-option label="LRU" :value="3" />
  264. <el-option label="轮询" :value="4" />
  265. <el-option label="匹配第一个" :value="5" />
  266. <el-option label="匹配最后一个" :value="6" />
  267. </el-select>
  268. </el-form-item>
  269. </el-col>
  270. <el-col :span="8">
  271. <el-form-item label="阻塞策略:" prop="blockStrategy">
  272. <el-select
  273. v-model="formJi.blockStrategy"
  274. class=""
  275. placeholder=""
  276. style="width: 100%;margin-left: 0%;"
  277. >
  278. <el-option label="丢弃" :value="1" />
  279. <el-option label="覆盖" :value="2" />
  280. <el-option label="并行" :value="3" />
  281. </el-select>
  282. </el-form-item>
  283. </el-col>
  284. </el-row>
  285. <el-row :gutter="48">
  286. <el-col :span="8">
  287. <el-form-item label="触发类型:" prop="triggerType">
  288. <el-select
  289. v-model="formJi.triggerType"
  290. class=""
  291. placeholder=""
  292. style="width: 100%;margin-left: 0%;"
  293. >
  294. <el-option label="固定时间" :value="2" />
  295. <el-option label="CRON 表达式" :value="3" />
  296. <el-option label="工作流" :value="99" />
  297. </el-select>
  298. </el-form-item>
  299. </el-col>
  300. <el-col :span="8">
  301. <el-form-item label="间隔时长:" prop="triggerInterval">
  302. <el-input-number
  303. v-model="formJi.triggerInterval"
  304. v-if="formJi.triggerType==2"
  305. style="width: 100%;"
  306. class="mx-4"
  307. :min="1"
  308. controls-position="right"
  309. @CHANGE="handleChange"
  310. />
  311. <el-input v-if="formJi.triggerType==3" v-model="formJi.triggerInterval" placeholder="请输入cron执行表达式">
  312. <template #append>
  313. <el-button type="primary" @click="handleShowCron">
  314. 生成表达式
  315. <i class="el-icon-time el-icon--right"></i>
  316. </el-button>
  317. </template>
  318. </el-input>
  319. </el-form-item>
  320. </el-col>
  321. </el-row>
  322. <el-row :gutter="48">
  323. <el-col :span="8">
  324. <el-form-item label="超时时间(秒):" prop="executorTimeout">
  325. <el-input-number
  326. v-model="formJi.executorTimeout"
  327. style="width: 100%;"
  328. class="mx-4"
  329. :min="1"
  330. controls-position="right"
  331. @change="handleChange"
  332. />
  333. </el-form-item>
  334. </el-col>
  335. <el-col :span="8">
  336. <el-form-item label="最大重试次数:" prop="maxRetryTimes">
  337. <el-input-number
  338. v-model="formJi.maxRetryTimes"
  339. style="width: 100%;"
  340. class="mx-4"
  341. :min="1"
  342. controls-position="right"
  343. @change="handleChange"
  344. />
  345. </el-form-item>
  346. </el-col>
  347. </el-row>
  348. <el-row :gutter="48">
  349. <el-col :span="8">
  350. <el-form-item label="重试间隔:" prop="retryInterval">
  351. <el-input-number
  352. v-model="formJi.retryInterval"
  353. style="width: 100%;"
  354. class="mx-4"
  355. :min="1"
  356. controls-position="right"
  357. @change="handleChange"
  358. />
  359. </el-form-item>
  360. </el-col>
  361. </el-row>
  362. <el-form-item label="描述:" >
  363. <el-input v-model="formJi.description" style="width: 75%;" placeholder="" type="textarea" :row="2" resize="none"/>
  364. </el-form-item>
  365. </div>
  366. </el-form>
  367. <div style="display: flex;align-items: center;line-height: 1.5;margin-top: 1%;">
  368. <el-button @click="addStart" style="margin-top: 0%;margin-left: 1%;" type="success" size="mini" plain>新增参数</el-button>
  369. <!-- <div style="margin-left: 1%;color: #909399;">需要至少一条输入参数</div> -->
  370. </div>
  371. <el-table
  372. style="margin-top: 1%;width: 100%;"
  373. :data="tableDataCanStart"
  374. :cell-style="{ textAlign: 'center',padding:'2px 0' }"
  375. :header-cell-style="{fontSize: '14px', textAlign: 'center'}"
  376. :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',textAlign:'center' }"
  377. border >
  378. <el-table-column prop="itemName" label="参数名称">
  379. <template #default="scope">
  380. <div style="width: 100%;">
  381. <el-input placeholder="请填写参数名称" type="primary" class="noBor" v-model="scope.row.name" size="mini" text style="margin-left: 0%;"></el-input>
  382. </div>
  383. </template>
  384. </el-table-column>
  385. <el-table-column prop="itemName" label="参数值" >
  386. <template #default="scope">
  387. <div style="width: 100%;">
  388. <el-input type="primary" class="noBor" v-model="scope.row.value" size="mini" text style="margin-left: 0%;"></el-input>
  389. </div>
  390. </template>
  391. </el-table-column>
  392. <el-table-column prop="address" label="操作" width="100">
  393. <template #default="scope">
  394. <div style="width: 100%;">
  395. <el-button type="danger" @click="delCanStart(scope.$index)" size="mini" text style="margin-left: 0%;">删除</el-button>
  396. </div>
  397. </template>
  398. </el-table-column>
  399. </el-table>
  400. <template #footer>
  401. <span class="dialog-footer">
  402. <el-button size="mini" @click="dialogVisibleTest = false">取消</el-button>
  403. <el-button type="primary" @click="addRen" size="mini" v-if="isAdd">
  404. 提交
  405. </el-button>
  406. <el-button type="primary" @click="saveEdit" size="mini" v-if="!isAdd">
  407. 提交
  408. </el-button>
  409. </span>
  410. </template>
  411. </el-dialog>
  412. <el-dialog title="Cron表达式生成器" v-model="openCron" append-to-body destroy-on-close>
  413. <crontab ref="crontabRef" @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
  414. </el-dialog>
  415. <el-dialog v-model="dialogVisibleDe" title="" width="50%" @close="" destroy-on-close class="custom-dialog-bg">
  416. <el-form size="mini" :key="tableKey" style="margin-top:1%;width: 100%;" :model="formJi" label-position="right">
  417. <el-row :gutter="48">
  418. <el-col :span="10">
  419. <el-form-item label="服务名称:" prop="name" style="">
  420. {{formJi.name}}
  421. </el-form-item>
  422. </el-col>
  423. <el-col :span="10">
  424. <el-form-item label="接口类型:" prop="" style="">
  425. <div style="display: flex;width: 100%;justify-content: space-between;">
  426. {{formJi.type}}
  427. </div>
  428. </el-form-item>
  429. </el-col>
  430. </el-row>
  431. <el-row :gutter="48">
  432. <el-col :span="20">
  433. <el-form-item label="接口地址:" prop="url" style="">
  434. {{formJi.url}}
  435. </el-form-item>
  436. </el-col>
  437. <el-col :span="10">
  438. <el-form-item label="请求方式:" prop="" style="">
  439. {{formJi.rqtype}}
  440. </el-form-item>
  441. </el-col>
  442. </el-row>
  443. <el-row :gutter="48">
  444. <el-col :span="10">
  445. <el-form-item label="响应类型:" prop="" style="display: flex; align-items: center;">
  446. {{formJi.rptype}}
  447. </el-form-item>
  448. </el-col>
  449. <el-col :span="10">
  450. <el-form-item label="服务分类:" prop="cateCode" style="">
  451. {{formJi.cateCode}}
  452. <!-- <el-cascader :disabled="isEdit" v-model="formJi.cateCode" :options="cascaderOptions" clearable
  453. style="width: 100%;"></el-cascader> -->
  454. </el-form-item>
  455. </el-col>
  456. </el-row>
  457. <el-row :gutter="48">
  458. <el-col :span="13">
  459. <el-form-item label="服务说明:">
  460. {{formJi.intro}}
  461. </el-form-item>
  462. </el-col>
  463. </el-row>
  464. </el-form>
  465. </el-dialog>
  466. </div>
  467. </el-tab-pane>
  468. <el-tab-pane label="执行结果" name="second" :disabled="!parMdid">
  469. <div style="display: flex;width: 98%;align-items: center;margin-left: 1%;">
  470. <!-- <div>
  471. 组名称
  472. </div>
  473. <el-input size="mini" v-model="groupName" style="width: 10%;margin-left: 1%;" placeholder="" /> -->
  474. <div style="margin-left: 0%;">
  475. 任务名称
  476. </div>
  477. <el-input size="mini" v-model="jobName" style="width: 10%;margin-left: 1%;" placeholder="" />
  478. <div style="margin-left: 2%;">
  479. 创建时间
  480. </div>
  481. <div style="width:15%;margin-left: 1%;">
  482. <el-date-picker
  483. v-model="createTime"
  484. type="datetimerange"
  485. format="YYYY-MM-DD HH:mm:ss"
  486. style="width:100%;margin-left: 1%;"
  487. value-format="YYYY-MM-DD"
  488. />
  489. </div>
  490. <div style="margin-left: 2%;">
  491. 状态
  492. </div>
  493. <el-select
  494. v-model="taskBatchStatus"
  495. class="noBorSel"
  496. placeholder=""
  497. style="width: 10%;margin-left: 1%;"
  498. >
  499. <el-option label="待处理" :value="1" />
  500. <el-option label="运行中" :value="2" />
  501. <el-option label="处理成功" :value="3" />
  502. <el-option label="处理失败" :value="4" />
  503. <el-option label="任务停止" :value="5" />
  504. <el-option label="取消" :value="6" />
  505. </el-select>
  506. <!-- <el-button type="" @click="" size="mini" style="margin-left:auto;" :icon="RefreshRight">重置 </el-button> -->
  507. <el-button type="primary" @click="getTaskReturn" size="mini" style="margin-left:auto;" :icon="Search">搜索 </el-button>
  508. </div>
  509. <el-table
  510. :data="tableDataDatareturn"
  511. style="width: 98%;margin-left: 1%;margin-top: 1.5%;;height: 73vh;"
  512. :cell-style="{ padding:'5px' }"
  513. :header-cell-style="{fontSize: '14px',height: heightAll*0.01+'px',}"
  514. :row-style="{ fontSize: '17px',textAlign:'center'}"
  515. border >
  516. <el-table-column type="index" label="序号" width="80">
  517. <template #default="{ $index }">
  518. <div style="text-align: center;">
  519. {{ $index + 1 }}
  520. </div>
  521. </template>
  522. </el-table-column>
  523. <el-table-column prop="jobName" label="任务名称" width="200">
  524. </el-table-column>
  525. <el-table-column prop="chargeBy" label="责任人" >
  526. </el-table-column>
  527. <el-table-column prop="taskType" label="任务类型" >
  528. <template #default="scope">
  529. <div style="display: flex;">
  530. <div v-if="scope.row.taskType===1">集群</div>
  531. <div v-else-if="scope.row.taskType===2">广播</div>
  532. <div v-else-if="scope.row.taskType===3">Sharding</div>
  533. <div v-else-if="scope.row.taskType===4">Map</div>
  534. <div v-else-if="scope.row.taskType===5">MapReduce</div>
  535. </div>
  536. </template>
  537. </el-table-column>
  538. <el-table-column prop="createDt" label="开始执行时间" width="220">
  539. </el-table-column>
  540. <el-table-column prop="executionAtMi" label="执行时长(秒)" >
  541. </el-table-column>
  542. <el-table-column prop="taskBatchStatus" label="状态">
  543. <template #default="scope">
  544. <div style="display: flex;">
  545. <div v-if="scope.row.taskBatchStatus===1" style="color: #E6A23C;">待处理</div>
  546. <div v-else-if="scope.row.taskBatchStatus===2" style="color: #409EFF;">运行中</div>
  547. <div v-else-if="scope.row.taskBatchStatus===3" style="color: #67C23A;">处理成功</div>
  548. <div v-else-if="scope.row.taskBatchStatus===4" style="color: red;">处理失败</div>
  549. <div v-else-if="scope.row.taskBatchStatus===5" style="color: red;">任务停止</div>
  550. <div v-else-if="scope.row.taskBatchStatus===6" style="color: red;">取消</div>
  551. </div>
  552. </template>
  553. </el-table-column>
  554. <el-table-column prop="operationReason" label="操作原因" >
  555. <template #default="scope">
  556. <div style="display: flex;">
  557. <div v-if="scope.row.operationReason===0" style="color: red;">无</div>
  558. <div v-else-if="scope.row.operationReason===1" style="color: #409EFF;">有</div>
  559. </div>
  560. </template>
  561. </el-table-column>
  562. <el-table-column prop="address" label="操作" width="150">
  563. <template #default="scope">
  564. <div style="display: flex;">
  565. <el-button @click="getLog(scope.row)" type="primary" text size="mini" style="margin-left: 0%;">日志</el-button>
  566. </div>
  567. </template>
  568. </el-table-column>
  569. </el-table>
  570. <el-pagination
  571. v-if="total1>20"
  572. small
  573. background
  574. style="margin-top: 0.4%;float: right;margin-right: 1%;"
  575. layout="prev, pager, next"
  576. :total="total1"
  577. v-model="pageNum1"
  578. @change="changePage1"
  579. class="mt-4"
  580. />
  581. </el-tab-pane>
  582. </el-tabs>
  583. <el-dialog @close="clearAdd" v-model="dialogVisibleLog" title="" width="60%" destroy-on-close :key="tableKey">
  584. <el-table
  585. :data="tableDataLogRes"
  586. style="width: 98%;margin-left: 1%;margin-top: 0.5%;height: 73vh;"
  587. :cell-style="{ padding:'5px' }"
  588. :header-cell-style="{fontSize: '14px',height: heightAll*0.01+'px',}"
  589. :row-style="{ fontSize: '17px',textAlign:'center'}"
  590. border >
  591. <el-table-column prop="taskStatus" label="状态">
  592. <template #default="scope">
  593. <div style="display: flex;">
  594. <div v-if="scope.row.taskStatus===1" style="color: #E6A23C;">待处理</div>
  595. <div v-else-if="scope.row.taskStatus===2" style="color: #409EFF;">运行中</div>
  596. <div v-else-if="scope.row.taskStatus===3" style="color: #67C23A;">处理成功</div>
  597. <div v-else-if="scope.row.taskStatus===4" style="color: red;">处理失败</div>
  598. <div v-else-if="scope.row.taskStatus===5" style="color: red;">任务停止</div>
  599. <div v-else-if="scope.row.taskStatus===6" style="color: red;">取消</div>
  600. </div>
  601. </template>
  602. </el-table-column>
  603. <el-table-column prop="taskName" label="参数名称">
  604. </el-table-column>
  605. <el-table-column prop="resultMessage" label="结果" width="200" show-overflow-tooltip>
  606. </el-table-column>
  607. <el-table-column prop="retryCount" label="重试次数" show-overflow-tooltip>
  608. </el-table-column>
  609. <el-table-column prop="createDt" label="开始执行时间" show-overflow-tooltip>
  610. </el-table-column>
  611. </el-table>
  612. <el-pagination
  613. v-if="total2>10"
  614. small
  615. background
  616. style="margin-top: 0.4%;float: right;margin-right: 1%;padding-bottom: 2%;"
  617. layout="prev, pager, next"
  618. :total="total2"
  619. v-model="pageNum2"
  620. @change="changePage2"
  621. class="mt-4"
  622. />
  623. <template #footer>
  624. <span class="dialog-footer">
  625. </span>
  626. </template>
  627. </el-dialog>
  628. </div>
  629. </template>
  630. <script setup>
  631. import {getCatalog} from "@/api/service/catalog";
  632. import { Plus,Search,Filter,Promotion,Check } from '@element-plus/icons-vue'
  633. import { reactive } from 'vue'
  634. import {getModellist} from '@/api/standardization/modeling'
  635. import { modelTreeSelect,getSerDe,addService,addServiceParam,getJobTaskPageLog,getYinqing
  636. ,getBatchDataTable,editTask,getDataRen,getTaskDe,delTask,flowDispatch } from "@/api/service/info";
  637. import { ref, onMounted, onUnmounted, nextTick,onBeforeMount } from 'vue';
  638. import JsonViewer from 'vue-json-viewer'
  639. import 'vue-json-viewer/style.css'
  640. import JsonEditorVue from 'json-editor-vue3'
  641. import { cloneDeep } from 'lodash'
  642. import { useClipboard } from "@vueuse/core";
  643. import Crontab from '@/components/Crontab'
  644. import { routerKey } from "vue-router";
  645. import {snailSta } from "@/api/service/timing";
  646. const titleTest = ref('')
  647. const tableDataLogRes = ref([])
  648. const { proxy } = getCurrentInstance();
  649. const JsonAdd= ref(JSON.stringify({ data: "初始值1" }))
  650. const exampleAdd = ref('')
  651. const dialogVisibleLevel = ref(false)
  652. const dialogVisibleDe = ref(false)
  653. const total1 = ref(0)
  654. const pageNum1 = ref(1)
  655. const detail = ref({
  656. name:'',
  657. rqtype:'',
  658. rptype:''
  659. })
  660. const createTime = ref([])
  661. const taskBatchStatus = ref('')
  662. const jobName = ref('')
  663. const tableDataLog = ref([])
  664. const show1Lev = ref(true)
  665. const inputNode =ref('')
  666. const isEdit = ref(true)
  667. const dataReturn = ref('')
  668. const optionsYinqing = ref([])
  669. const optionsCan = ref([
  670. {
  671. label:"string",
  672. value:'string'
  673. },
  674. {
  675. label:"int",
  676. value:'int'
  677. },
  678. {
  679. label:"boolean",
  680. value:'boolean'
  681. },
  682. {
  683. label:"array",
  684. value:'array'
  685. },
  686. {
  687. label:"object",
  688. value:'object'
  689. },
  690. {
  691. label:"number",
  692. value:'number'
  693. },
  694. {
  695. label:"null",
  696. value:'null'
  697. },
  698. {
  699. label:"any",
  700. value:'any'
  701. },
  702. ])
  703. const currentNodeKey = ref('')
  704. const options = ref([
  705. {label:'开发中',
  706. value:'1'
  707. },
  708. {label:'运行中',
  709. value:'2'
  710. },
  711. ])
  712. const dataJsonXiang = ref([])
  713. const parTree = ref({})
  714. const valueKet = ref(0)
  715. const tableDataCan = ref([
  716. {
  717. itemName:'',
  718. itemCode:'',
  719. paramType:'',
  720. paramNote:''
  721. }
  722. ])
  723. const dialogVisibleTest = ref(false)
  724. const optionsMdid = ref([])
  725. const optionsRqtype = ref([
  726. {label:'GET',
  727. value:'GET'
  728. },
  729. {label:'POST',
  730. value:'POST'
  731. },
  732. ])
  733. const tableDataDatareturn = ref([])
  734. const optionsType= ref([
  735. {label:'RESTful',
  736. value:'RESTful'
  737. },
  738. {label:'WebService',
  739. value:'WebService'
  740. },
  741. {label:'HTTP',
  742. value:'HTTP'
  743. },
  744. {label:'WebSocket',
  745. value:'WebSocket'
  746. },
  747. ])
  748. const optionsTaskType = ref([
  749. {
  750. label:'集群',
  751. value:1
  752. },
  753. {
  754. label:'广播',
  755. value:2
  756. },
  757. {
  758. label:'Sharding',
  759. value:3
  760. },
  761. {
  762. label:'Map',
  763. value:4
  764. },
  765. {
  766. label:'MapReduce',
  767. value:5
  768. },
  769. ])
  770. const data = ref([])
  771. const select = ref('1')
  772. const activeName = ref('first')
  773. const title = ref('')
  774. const titleTree = ref('')
  775. const currentPage = ref(1)
  776. const total = ref(1)
  777. const pageNum = ref(1)
  778. const tableData = ref([])
  779. const tableheight = window.innerHeight*0.7
  780. const heightAll = window.innerHeight
  781. const dialogVisible = ref(false)
  782. const dialogVisibleTree = ref(false)
  783. const isAdd = ref(false)
  784. const isAddTa = ref(false)
  785. const treeId = ref('');
  786. const valueSta = ref('1');
  787. const parMdid = ref('')
  788. const example = ref('');
  789. const tableDataCanAdd = ref([
  790. {
  791. itemName:'',
  792. itemCode:'',
  793. paramType:'',
  794. paramNote:''
  795. }
  796. ])
  797. const formZu = ref({
  798. itemName:'',
  799. itemTp:'',
  800. itemEn:'',
  801. itemTp:'',
  802. itemDataTp:'',
  803. itemDefaultVal:'',
  804. itemUnit:'',
  805. itemNotes:'',
  806. });
  807. const parId= ref('')
  808. const formJi = ref({
  809. routeKey:4,
  810. blockStrategy:1,
  811. triggerType:2,
  812. triggerInterval:10,
  813. executorTimeout:10,
  814. maxRetryTimes:3,
  815. retryInterval:1,
  816. jobStatus:1,
  817. });
  818. const rulesJi = reactive({
  819. flowJobName: [{ required: true, message: '必填', trigger: 'blur' }],
  820. routeKey: [{ required: true, message: '必填', trigger: 'blur' }],
  821. triggerType: [{ required: true, message: '必填', trigger: 'blur' }],
  822. triggerInterval: [{ required: true, message: '必填', trigger: 'blur' }],
  823. executorTimeout: [{ required: true, message: '必填', trigger: 'blur' }],
  824. maxRetryTimes: [{ required: true, message: '必填', trigger: 'blur' }],
  825. retryInterval: [{ required: true, message: '必填', trigger: 'blur' }],
  826. chargeBy: [{ required: true, message: '必填', trigger: 'blur' }],
  827. chargePhone: [{ required: true, message: '必填', trigger: 'blur' }],
  828. taskType: [{ required: true, message: '必填', trigger: 'blur' }],
  829. blockStrategy: [{ required: true, message: '必填', trigger: 'blur' }],
  830. jobStatus: [{ required: true, message: '必填', trigger: 'blur' }],
  831. executorInfo: [{ required: true, message: '必填', trigger: 'blur' }]
  832. });
  833. const formRefJi = ref();
  834. const titleDe = ref('')
  835. const formAdd = ref({
  836. name:'',
  837. cateCode:'',
  838. type:'',
  839. url:'',
  840. rqtype:'',
  841. rptype:'',
  842. intro:'',
  843. mdid:''
  844. });
  845. const rulesAdd = reactive({
  846. mdid: [{ required: true, message: '必填', trigger: 'blur' }],
  847. name: [{ required: true, message: '必填', trigger: 'blur' }],
  848. url: [{ required: true, message: '必填', trigger: 'blur' }],
  849. cateCode: [{ required: true, message: '必填', trigger: 'blur' }],
  850. });
  851. const formRefAdd = ref();
  852. const treeRef = ref(null);
  853. const formTree = ref({
  854. itemName:'',
  855. catePid:'',
  856. itemNo:'',
  857. itemNotes:''
  858. });
  859. const rulesTree = reactive({
  860. itemNo: [{ required: true, message: '必填', trigger: 'blur' }],
  861. catePid: [{ required: true, message: '必填', trigger: 'blur' }],
  862. itemName: [{ required: true, message: '必填', trigger: 'blur' }],
  863. });
  864. const formRefTree = ref();
  865. const formLev = ref({
  866. itemName:'',
  867. itemNo:'',
  868. itemNotes:'',
  869. });
  870. const rulesLev = reactive({
  871. itemNotes: [{ required: true, message: '必填', trigger: 'blur' }],
  872. itemNo: [{ required: true, message: '必填', trigger: 'blur' }],
  873. itemName: [{ required: true, message: '必填', trigger: 'blur' }],
  874. });
  875. const formRefLev = ref();
  876. const cascaderOptions = ref([])
  877. const props1 = ref({
  878. checkStrictly: true,
  879. })
  880. const detailJson = ref('')
  881. const parOptions = ref([])
  882. const openCron = ref(false)
  883. const tableDataCanStart = ref([
  884. ])
  885. const expression = ref('')
  886. watch(inputNode, (val) => {
  887. treeRef.value?.filter(val); // 调用树的过滤方法
  888. });
  889. const filterNode = (value, data) => {
  890. if (!value) return true; // 空搜索时显示所有节点
  891. return data.label.includes(value); // 检查节点标签是否包含关键字
  892. };
  893. const copied = ref(false);
  894. function changePage(val){
  895. pageNum.value = val
  896. getDataRen()
  897. }
  898. function getYinData(){
  899. getYinqing().then(res=>{
  900. if(res.data){
  901. optionsYinqing.value = res.data
  902. formJi.value.executorInfo = optionsYinqing.value[0].dictCode
  903. }
  904. })
  905. }
  906. async function changejobStatus(row){
  907. var par = {
  908. jobId:row.id,
  909. status:row.jobStatus===true?1:0
  910. }
  911. await snailSta(par).then(res=>{
  912. if(res.code===200){
  913. proxy.$modal.msgSuccess("修改成功");
  914. }
  915. })
  916. }
  917. function changePage1(val){
  918. pageNum1.value = val
  919. getTaskReturn()
  920. }
  921. function changePage2(val){
  922. pageNum2.value = val
  923. getLog(parRow )
  924. }
  925. const parRow = ref()
  926. function getLog(row){
  927. parRow.value = row
  928. dialogVisibleLog.value = true
  929. var par = {
  930. taskBatchId:row.id,
  931. pageNum:pageNum2.value,
  932. pageSize:10
  933. }
  934. getJobTaskPageLog(par).then(res=>{
  935. if(res.rows){
  936. tableDataLogRes.value = res.rows
  937. total2.value = res.total
  938. }
  939. })
  940. }
  941. const total2 = ref(0)
  942. const pageNum2 = ref(1)
  943. const dialogVisibleLog = ref(false)
  944. function saveEdit(){
  945. formRefJi.value.validate((valid) => {
  946. if (valid) {
  947. formJi.value.appId = parMdid.value
  948. formJi.value.flowParam = {}
  949. if(tableDataCanStart.value.length>0){
  950. tableDataCanStart.value.forEach(item=>{
  951. formJi.value.flowParam[item.name] = item.value
  952. })
  953. }
  954. editTask(formJi.value).then(res=>{
  955. if(res.code===200){
  956. proxy.$message({
  957. message: '操作成功',
  958. type: 'success'
  959. });
  960. dialogVisibleTest.value = false
  961. getList()
  962. }else{
  963. proxy.$message({
  964. message: res.message,
  965. type: 'error'
  966. });
  967. }
  968. })
  969. }
  970. })
  971. }
  972. function addRen() {
  973. formRefJi.value.validate((valid) => {
  974. if (valid) {
  975. formJi.value.appId = parMdid.value
  976. formJi.value.flowParam = {}
  977. if(tableDataCanStart.value.length>0){
  978. tableDataCanStart.value.forEach(item=>{
  979. formJi.value.flowParam[item.name] = item.value
  980. })
  981. }
  982. flowDispatch(formJi.value).then(res=>{
  983. if(res.code===200){
  984. proxy.$message({
  985. message: '操作成功',
  986. type: 'success'
  987. });
  988. dialogVisibleTest.value = false
  989. getList()
  990. }else{
  991. proxy.$message({
  992. message: res.message,
  993. type: 'error'
  994. });
  995. }
  996. })
  997. }
  998. })
  999. }
  1000. function addStart(){
  1001. tableDataCanStart.value.push({})
  1002. }
  1003. function delCanStart(index){
  1004. tableDataCanStart.value.splice(index,1)
  1005. }
  1006. function delTaskDe(row){
  1007. proxy.$modal.confirm('是否确认删除?').then(function () {
  1008. return delTask(row.flowJobId);
  1009. }).then(() => {
  1010. proxy.$modal.msgSuccess("删除成功");
  1011. var par = {
  1012. data:{appId:parMdid.value,
  1013. pageNum:1,
  1014. pageSize:20}
  1015. }
  1016. handleNodeClick(null,par,null)
  1017. }).catch(() => {});
  1018. }
  1019. function handleShowCron() {
  1020. expression.value = formJi.value.triggerInterval;
  1021. openCron.value = true;
  1022. }
  1023. function crontabFill(value) {
  1024. formJi.value.triggerInterval = value;
  1025. }
  1026. function addTask(row){
  1027. isAdd.value = true
  1028. dialogVisibleTest.value = true
  1029. }
  1030. function getEdit(row){
  1031. isAdd.value = false
  1032. titleDe.value = '编辑任务-'+row.flowJobName
  1033. dialogVisibleTest.value = true
  1034. tableDataCanStart.value = []
  1035. getTaskDe(row.flowJobId).then(res=>{
  1036. formJi.value = res.data
  1037. const keys = Object.keys(res.data.flowParam)
  1038. keys.forEach(key => {
  1039. var par = {
  1040. name:key,
  1041. value:res.data.flowParam[key]
  1042. }
  1043. tableDataCanStart.value.push(par)
  1044. });
  1045. })
  1046. }
  1047. function showDe(row){
  1048. getSerDe(row.srvId).then(res=>{
  1049. if(res.code===200){
  1050. dialogVisibleDe.value = true
  1051. parOptions.value.forEach(item=>{
  1052. if(res.data.ptService.cateCode === item.cateCode){
  1053. res.data.ptService.cateCode = item.cateName
  1054. }
  1055. })
  1056. if(res.data.ptService.rptype === '1'){
  1057. res.data.ptService.rptype = 'JSON'
  1058. }
  1059. if(res.data.ptService.rptype === '2'){
  1060. res.data.ptService.rptype = 'XML'
  1061. }
  1062. if(res.data.ptService.rptype === '3'){
  1063. res.data.ptService.rptype = 'HTML'
  1064. }
  1065. formJi.value = res.data.ptService
  1066. }
  1067. })
  1068. }
  1069. function filterModelNodes(nodes) {
  1070. if (!Array.isArray(nodes)) return [];
  1071. const result = [];
  1072. for (const node of nodes) {
  1073. // 递归处理子节点(如果有)
  1074. const filteredChildren = node.children ? filterModelNodes(node.children) : [];
  1075. if (node.nodeType === 'MODEL') {
  1076. // 保留当前节点,并更新其子节点
  1077. node.value = node.id
  1078. result.push({
  1079. ...node,
  1080. children: filteredChildren
  1081. });
  1082. } else {
  1083. // 删除当前节点,将其子节点提升到当前层级
  1084. result.push(...filteredChildren);
  1085. }
  1086. }
  1087. return result;
  1088. }
  1089. function clearAdd(){
  1090. formJi.value = {
  1091. routeKey:4,
  1092. blockStrategy:1,
  1093. triggerType:2,
  1094. triggerInterval:10,
  1095. executorTimeout:10,
  1096. maxRetryTimes:3,
  1097. retryInterval:1,
  1098. jobStatus:1,
  1099. executorInfo: optionsYinqing.value[0].dictCode
  1100. }
  1101. tableDataCanStart.value = []
  1102. }
  1103. function clearFromLev(){
  1104. tableDataLog.value = []
  1105. }
  1106. async function handleNodeClick(node,data,event){
  1107. console.log(data)
  1108. parMdid.value = data.data.appId
  1109. var par = {
  1110. appId:data.data.appId,
  1111. pageNum:1,
  1112. pageSize:20
  1113. }
  1114. activeName.value = 'first'
  1115. await getDataRen(par).then(res=>{
  1116. if(res.rows){
  1117. tableData.value = res.rows
  1118. tableData.value.forEach(item=>{
  1119. item.type = titleTest.value
  1120. if(item.jobStatus===1){
  1121. item.jobStatus = true
  1122. }else{
  1123. item.jobStatus = false
  1124. }
  1125. })
  1126. total.value = res.total
  1127. }
  1128. })
  1129. titleTest.value = data.data.label
  1130. }
  1131. function getAbsoluteTimeDifference(dateTimeString, otherTimestamp) {
  1132. // 将日期字符串转换为毫秒时间戳
  1133. const targetTimestamp = new Date(dateTimeString).getTime();
  1134. // 计算与另一个时间戳的绝对差值
  1135. return Math.abs(targetTimestamp - otherTimestamp);
  1136. }
  1137. function getTaskReturn(){
  1138. if(activeName.value==='second'){
  1139. var par = {
  1140. appId:parMdid.value,
  1141. pageNum:pageNum1.value,
  1142. pageSize:20,
  1143. jobName:jobName.value,
  1144. taskBatchStatus:taskBatchStatus.value,
  1145. beginTime:createTime.value.length>1?createTime.value[0]:'',
  1146. endTime:createTime.value.length>1?createTime.value[1]:''
  1147. }
  1148. getBatchDataTable(par).then(res=>{
  1149. if(res.rows){
  1150. tableDataDatareturn.value = res.rows
  1151. tableDataDatareturn.value.forEach(item=>{
  1152. item.type = titleTest.value
  1153. item.executionAt = getAbsoluteTimeDifference(item.createDt, item.executionAt)*0.001
  1154. })
  1155. tableDataDatareturn.value.forEach(item=>{
  1156. console.log(typeof item.executionAt)
  1157. // item.executionAt = item.executionAt.toSring().substring(0, 4)
  1158. })
  1159. total1.value = res.total
  1160. }
  1161. })
  1162. }
  1163. }
  1164. async function getTreeLeft(){
  1165. var par = {
  1166. params:{
  1167. level:'2',
  1168. devkind:'SYS'
  1169. }
  1170. }
  1171. await modelTreeSelect(par).then(res=>{
  1172. par = res.data
  1173. data.value = res.data
  1174. })
  1175. optionsMdid.value = filterModelNodes(par)
  1176. console.log(optionsMdid.value)
  1177. }
  1178. function renameTreeProperties(tree) {
  1179. // 深拷贝避免修改原始数据(可选,根据需求)
  1180. const newTree = cloneDeep(tree); // 使用 lodash
  1181. // 或:const newTree = JSON.parse(JSON.stringify(tree)); // 原生方法(不兼容函数等)
  1182. // 递归处理函数
  1183. const processNode = (node) => {
  1184. // 重命名属性
  1185. if ('cateName' in node) {
  1186. node.label = node.cateName;
  1187. delete node.cateName;
  1188. }
  1189. if ('cateCode' in node) {
  1190. node.value = node.cateCode;
  1191. delete node.cateCode;
  1192. }
  1193. // 递归处理子节点
  1194. if (node.children && node.children.length > 0) {
  1195. node.children.forEach(child => processNode(child));
  1196. }
  1197. };
  1198. // 遍历根节点
  1199. newTree.forEach(rootNode => processNode(rootNode));
  1200. return newTree;
  1201. }
  1202. function fetchData() {
  1203. getCatalog().then((r) => {
  1204. parOptions.value = r.data
  1205. cascaderOptions.value = renameTreeProperties(buildTree(r.data))
  1206. console.log(parOptions.value)
  1207. });
  1208. }
  1209. function buildTree(flatData, rootValue = '0') {
  1210. const nodeMap = new Map();
  1211. const tree = [];
  1212. flatData.forEach(item => {
  1213. nodeMap.set(item.cateCode, { ...item, children: [] });
  1214. });
  1215. for (const [code, node] of nodeMap) {
  1216. const parentCode = node.catePcode;
  1217. if (parentCode === rootValue || !parentCode) {
  1218. tree.push(node);
  1219. continue;
  1220. }
  1221. const parent = nodeMap.get(parentCode);
  1222. if (parent) {
  1223. parent.children.push(node);
  1224. } else {
  1225. console.warn(`Orphan node detected: ${code}. Parent ${parentCode} not found`);
  1226. }
  1227. }
  1228. return tree;
  1229. }
  1230. function addPa(){
  1231. var par = {
  1232. itemName:''
  1233. }
  1234. tableDataCan.value.push(par)
  1235. }
  1236. function delCan(index){
  1237. tableDataCan.value.splice(index, 1)
  1238. }
  1239. function addCanAdd(){
  1240. var par = {
  1241. parName:''
  1242. }
  1243. tableDataCanAdd.value.push(par)
  1244. }
  1245. function delCanAdd(index){
  1246. tableDataCanAdd.value.splice(index, 1)
  1247. }
  1248. async function getList() {
  1249. await getModellist().then(res => {
  1250. data.value = res.rows
  1251. data.value.forEach(item=>{
  1252. item.label = item.appTitle
  1253. item.value = item.appId
  1254. })
  1255. })
  1256. console.log(data.value)
  1257. parMdid.value = data.value[0].value
  1258. var par = {
  1259. appId:parMdid.value,
  1260. pageNum:1,
  1261. pageSize:20
  1262. }
  1263. await getDataRen(par).then(res=>{
  1264. if(res.rows){
  1265. tableData.value = res.rows
  1266. tableData.value.forEach(item=>{
  1267. item.type = titleTest.value
  1268. if(item.jobStatus===1){
  1269. item.jobStatus = true
  1270. }else{
  1271. item.jobStatus = false
  1272. }
  1273. })
  1274. total.value = res.total
  1275. }
  1276. })
  1277. }
  1278. onMounted(() => {
  1279. getList()
  1280. getYinData()
  1281. });
  1282. </script>
  1283. <style scoped>
  1284. . :deep(.el-select__wrapper){
  1285. box-shadow: none !important; /* 去除阴影边框 */
  1286. border: 1px solid transparent !important; /* 设置透明边框 */
  1287. background-color: transparent !important; /* 可选:透明背景 */
  1288. }
  1289. .noBor :deep(.el-input__wrapper) {
  1290. box-shadow: none !important; /* 去除阴影边框 */
  1291. border: 1px solid transparent !important; /* 设置透明边框 */
  1292. background-color: transparent !important; /* 可选:透明背景 */
  1293. }
  1294. /* 节点垂直间距 */
  1295. :deep(.el-tree-node) {
  1296. margin-bottom:5px !important; /* 增大节点间距 */
  1297. }
  1298. .el-popover.custom-popover {
  1299. min-width: 50px;
  1300. padding: 8px; /* 可选:调整内边距 */
  1301. }
  1302. </style>
  1303. <style>
  1304. .dot {
  1305. width: 20px; /* 控制圆点直径 */
  1306. height: 20px;
  1307. background-color: #333; /* 实心颜色 */
  1308. border-radius: 50%; /* 关键属性 */
  1309. display: inline-block; /* 确保与其他元素并排 */
  1310. }
  1311. /* 全局透明样式(不使用 scoped) */
  1312. .transparent-select .el-select__wrapper {
  1313. background-color: transparent !important;
  1314. border-color: transparent !important;
  1315. box-shadow: none !important;
  1316. }
  1317. .transparent-select .el-select__selection {
  1318. background-color: transparent;
  1319. }
  1320. /* 处理悬停和聚焦状态 */
  1321. .transparent-select .el-select__wrapper:hover,
  1322. .transparent-select .el-select__wrapper.is-focused {
  1323. border-color: transparent !important;
  1324. box-shadow: none !important;
  1325. }
  1326. /* 下拉箭头图标 */
  1327. .transparent-select .el-select__caret {
  1328. color: rgba(0, 0, 0, 0.5); /* 半透明图标 */
  1329. }
  1330. </style>
  1331. <style scoped>
  1332. :deep(.treeLeft) .el-tree-node__content {
  1333. display: flex !important;
  1334. height: 28px; /* 按设计稿调整高度 */
  1335. align-items: center;
  1336. padding-top: 0 !important;
  1337. }
  1338. :deep(.treeLeft) .el-tree-node__content:hover {
  1339. background-color: #e9e9eb;
  1340. }
  1341. :deep(.treeLeft) .el-tree-node__content:active {
  1342. background-color: rgka(69,157,255,0.1) !important;
  1343. }
  1344. /* 选中态(Active) */
  1345. :deep(.treeLeft) .el-tree-node.is-current > .el-tree-node__content {
  1346. background-color: #c6e2ff !important;
  1347. }
  1348. .tab-container {
  1349. height: 100vh; /* 关键:父容器明确高度 */
  1350. display: flex;
  1351. flex-direction: column;
  1352. }
  1353. .drag-handle {
  1354. cursor: move;
  1355. }
  1356. .ghost {
  1357. opacity: 0.5;
  1358. background: #c8ebfb;
  1359. }
  1360. /* 防止文字选中 */
  1361. :deep(.el-table__row) {
  1362. user-select: none;
  1363. -webkit-user-select: none;
  1364. }
  1365. </style>
  1366. <style scoped lang="scss">
  1367. .custom-tree-node {
  1368. display: flex; /* 启用 Flex 布局 */
  1369. align-items: center; /* 垂直居中 */
  1370. gap: 8px; /* 图标与文字间距 */
  1371. justify-content: space-between;
  1372. }
  1373. .el-table .el-table__row td {
  1374. height: 60px !important; /* 行高 */
  1375. }
  1376. .custom-tree-node {
  1377. display: flex; /* 启用 Flex 布局 */
  1378. align-items: center; /* 垂直居中 */
  1379. gap: 8px; /* 图标与文字间距 */
  1380. }
  1381. </style>