index.vue 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. <template>
  2. <div>
  3. <div>
  4. <Card :bordered="false" dis-hover class="mb10">
  5. <Tabs v-model="apiType">
  6. <TabPane label="后台接口" name="adminapi"></TabPane>
  7. <TabPane label="前台接口" name="api"></TabPane>
  8. <TabPane label="对外接口" name="outapi"></TabPane>
  9. <TabPane label="客服接口" name="kefuapi"></TabPane>
  10. </Tabs>
  11. </Card>
  12. <div class="main">
  13. <div class="ivu-mt mr20 card-tree">
  14. <div class="tree">
  15. <div class="main-btn">
  16. <Button class="mb5 mr10" style="flex: 1" type="primary" @click="clickMenu(4)" long>新增分类</Button>
  17. <Button class="mr10" type="success" @click="syncRoute()">同步</Button>
  18. <Button type="info" @click="debugging()">调试</Button>
  19. </div>
  20. <vue-tree-list
  21. class="tree-list"
  22. ref="treeList"
  23. @change-name="onChangeName"
  24. @delete-node="onDel"
  25. :model="treeData"
  26. default-tree-node-name="默认文件夹"
  27. default-leaf-node-name="默认接口名"
  28. v-bind:default-expanded="false"
  29. :expand-only-one="true"
  30. >
  31. <template v-slot:leafNameDisplay="slotProps">
  32. <div></div>
  33. <div
  34. class="tree-node"
  35. :class="{
  36. node: slotProps.model.method,
  37. open: formValidate.path == slotProps.model.path && formValidate.method == slotProps.model.method,
  38. }"
  39. @click.stop="onClick(slotProps.model)"
  40. >
  41. <span
  42. class=""
  43. :class="{
  44. open: formValidate.path == slotProps.model.path && formValidate.method == slotProps.model.method,
  45. }"
  46. >{{ slotProps.model.name }}</span
  47. >
  48. <Dropdown
  49. transfer
  50. @on-click="
  51. (name) => {
  52. clickMenu(name, slotProps.model);
  53. }
  54. "
  55. >
  56. <a href="javascript:void(0)">
  57. <Icon class="add" type="ios-more" />
  58. </a>
  59. <template #list>
  60. <DropdownMenu>
  61. <DropdownItem name="1" v-if="!slotProps.model.method">新增接口</DropdownItem>
  62. <DropdownItem name="2" v-if="!slotProps.model.method">编辑分类名</DropdownItem>
  63. <DropdownItem name="3">删除</DropdownItem>
  64. </DropdownMenu>
  65. </template>
  66. </Dropdown>
  67. </div>
  68. </template>
  69. <!-- 新建文件夹 -->
  70. <span class="icon" slot="addTreeNodeIcon"></span>
  71. <span class="icon" slot="addLeafNodeIcon">
  72. <!-- <Icon type="md-create" /> -->
  73. </span>
  74. <span class="icon" slot="editNodeIcon">
  75. <!-- <Icon type="md-create" /> -->
  76. </span>
  77. <span class="icon" slot="delNodeIcon">
  78. <!-- <Icon type="ios-cut" /> -->
  79. </span>
  80. <template v-slot:treeNodeIcon="slotProps">
  81. <span
  82. v-if="slotProps.model.method"
  83. class="req-method"
  84. :style="{
  85. color: methodsColor(slotProps.model.method),
  86. 'font-weight': slotProps.model.pid == formValidate.pid ? '500' : '500',
  87. }"
  88. >{{ slotProps.model.method }}</span
  89. >
  90. <!-- <span v-if="slotProps.model.method"></span> -->
  91. </template>
  92. </vue-tree-list>
  93. </div>
  94. </div>
  95. <Card :bordered="false" dis-hover class="ivu-mt right-card">
  96. <div class="data">
  97. <div class="eidt-sub">
  98. <div class="name">
  99. {{ formValidate.name }}
  100. </div>
  101. <div>
  102. <!-- <Button type="primary" class="submission mr20" @click="debugging()">调试</Button> -->
  103. <Button v-if="formValidate.id" type="primary" class="submission mr20" @click="isEdit = !isEdit">{{
  104. isEdit ? '返回' : '编辑'
  105. }}</Button>
  106. <Button v-if="isEdit" type="primary" class="submission" @click="handleSubmit('formValidate')"
  107. >保存</Button
  108. >
  109. </div>
  110. </div>
  111. <Form
  112. class="formValidate mt20"
  113. ref="formValidate"
  114. :rules="ruleValidate"
  115. :model="formValidate"
  116. :label-width="100"
  117. :label-position="labelPosition"
  118. @submit.native.prevent
  119. >
  120. <Row :gutter="24" type="flex">
  121. <Col span="24">
  122. <div class="title">接口信息</div>
  123. <FormItem label="接口名称:" prop="name">
  124. <Input
  125. v-if="isEdit"
  126. class="perW20"
  127. type="text"
  128. :rows="4"
  129. v-model.trim="formValidate.name"
  130. placeholder="请输入"
  131. />
  132. <span v-else>{{ formValidate.name || '' }}</span>
  133. </FormItem>
  134. <FormItem label="请求类型:" prop="name">
  135. <Select v-if="isEdit" v-model="formValidate.method" style="width: 120px">
  136. <Option v-for="(item, index) in requestTypeList" :key="index" :value="item.value">{{
  137. item.label
  138. }}</Option>
  139. </Select>
  140. <span v-else class="req-method" :style="'background-color:' + methodColor">{{
  141. formValidate.method || ''
  142. }}</span>
  143. </FormItem>
  144. <FormItem label="功能描述:" prop="name">
  145. <Input
  146. v-if="isEdit"
  147. class="perW20"
  148. type="textarea"
  149. :rows="4"
  150. v-model.trim="formValidate.describe"
  151. placeholder="请输入"
  152. />
  153. <span v-else class="text-area">{{ formValidate.describe || '--' }}</span>
  154. </FormItem>
  155. <FormItem label="所属分类:" prop="name" v-if="isEdit">
  156. <el-cascader
  157. v-model="formValidate.cate_id"
  158. size="small"
  159. :options="formValidate.cate_tree"
  160. :props="{ checkStrictly: true, multiple: false, emitPath: false, value: 'id', label: 'name' }"
  161. clearable
  162. ></el-cascader>
  163. </FormItem>
  164. <FormItem label="是否公共:" prop="name">
  165. <Switch v-if="isEdit" v-model="formValidate.type" :true-value="1" :false-value="0">
  166. <template #open>
  167. <span>是</span>
  168. </template>
  169. <template #close>
  170. <span>否</span>
  171. </template>
  172. </Switch>
  173. <span v-else class="text-area">{{ formValidate.type ? '是' : '否' }}</span>
  174. </FormItem>
  175. </Col>
  176. </Row>
  177. <Row :gutter="24" type="flex">
  178. <Col span="24">
  179. <div class="title">调用方式</div>
  180. <FormItem label="路由地址:" prop="path">
  181. <span>{{ formValidate.path || '' }}</span>
  182. </FormItem>
  183. <FormItem label="文件地址:" prop="path">
  184. <span>{{ formValidate.file_path || '' }}</span>
  185. </FormItem>
  186. <FormItem label="方法名:" prop="path">
  187. <span>{{ formValidate.action || '' }}</span>
  188. </FormItem>
  189. <FormItem label="请求参数:">
  190. <vxe-table
  191. resizable
  192. show-overflow
  193. keep-source
  194. ref="xTable"
  195. row-id="id"
  196. :print-config="{}"
  197. :export-config="{}"
  198. :loading="loading"
  199. :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
  200. :data="formValidate.request"
  201. >
  202. <!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
  203. <vxe-column field="attribute" width="300" title="属性" tree-node :edit-render="{}">
  204. <template #default="{ row }">
  205. <vxe-input v-if="isEdit" v-model="row.attribute" type="text"></vxe-input>
  206. <span v-else>{{ row.attribute || '' }}</span>
  207. </template>
  208. </vxe-column>
  209. <vxe-column field="type" title="类型" width="200" :edit-render="{}">
  210. <template #default="{ row }">
  211. <!-- <vxe-select v-if="isEdit" v-model="row.type" type="text" :optionGroups="typeList"></vxe-select> -->
  212. <vxe-select v-if="isEdit" v-model="row.type" transfer>
  213. <vxe-option
  214. v-for="item in typeList"
  215. :key="item.value"
  216. :value="item.value"
  217. :label="item.label"
  218. ></vxe-option>
  219. </vxe-select>
  220. <span v-else>{{ row.type || '' }}</span>
  221. <!-- <vxe-select v-model="row.type">
  222. <vxe-option v-for="num in 12" :key="num" :value="num" :label="num"></vxe-option>
  223. </vxe-select> -->
  224. </template>
  225. </vxe-column>
  226. <vxe-column field="must" title="必填" width="100" :edit-render="{}">
  227. <template #default="{ row }">
  228. <vxe-checkbox
  229. v-if="isEdit"
  230. v-model="row.must"
  231. :unchecked-value="'0'"
  232. :checked-value="'1'"
  233. ></vxe-checkbox>
  234. <span v-else>{{ row.must == '1' ? '是' : '否' }}</span>
  235. </template>
  236. </vxe-column>
  237. <vxe-column field="trip" title="说明" :edit-render="{}">
  238. <template #default="{ row }">
  239. <vxe-input v-if="isEdit" v-model="row.trip" type="text"></vxe-input>
  240. <span v-else>{{ row.trip || '' }}</span>
  241. </template>
  242. </vxe-column>
  243. <vxe-column title="操作" width="200" v-if="isEdit">
  244. <template #default="{ row }">
  245. <vxe-button
  246. type="text"
  247. v-if="row.type === 'array' || row.type === 'object'"
  248. status="primary"
  249. @click="insertRow(row, 'xTable')"
  250. >插入</vxe-button
  251. >
  252. <vxe-button type="text" status="primary" @click="removeRow(row, 'xTable')">删除</vxe-button>
  253. </template>
  254. </vxe-column>
  255. </vxe-table>
  256. <Button class="mt10" v-if="isEdit" type="primary" @click="insertEvent('xTable')">添加参数</Button>
  257. </FormItem>
  258. <FormItem label="返回参数:">
  259. <vxe-table
  260. resizable
  261. show-overflow
  262. keep-source
  263. ref="resTable"
  264. row-id="id"
  265. :print-config="{}"
  266. :export-config="{}"
  267. :loading="loading"
  268. :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
  269. :data="formValidate.response"
  270. >
  271. <!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
  272. <vxe-column field="attribute" title="属性" width="300" tree-node :edit-render="{}">
  273. <template #default="{ row }">
  274. <vxe-input v-if="isEdit" v-model="row.attribute" type="text"></vxe-input>
  275. <span v-else>{{ row.attribute || '' }}</span>
  276. </template>
  277. </vxe-column>
  278. <vxe-column field="type" title="类型" width="200" :edit-render="{}">
  279. <template #default="{ row }">
  280. <vxe-select v-if="isEdit" v-model="row.type" transfer>
  281. <vxe-option
  282. v-for="item in typeList"
  283. :key="item.value"
  284. :value="item.value"
  285. :label="item.label"
  286. ></vxe-option>
  287. </vxe-select>
  288. <span v-else>{{ row.type || '' }}</span>
  289. </template>
  290. </vxe-column>
  291. <!-- <vxe-column field="type" title="必填" :edit-render="{}">
  292. <template #default="{ row }">
  293. <vxe-checkbox v-model="row.must" :unchecked-value="0" :checked-value="1"></vxe-checkbox
  294. >{{ row.must }}
  295. </template>
  296. </vxe-column> -->
  297. <vxe-column field="trip" title="说明" :edit-render="{}">
  298. <template #default="{ row }">
  299. <vxe-input v-if="isEdit" v-model="row.trip" type="text"></vxe-input>
  300. <span v-else>{{ row.trip || '' }}</span>
  301. </template>
  302. </vxe-column>
  303. <vxe-column title="操作" width="200" v-if="isEdit">
  304. <template #default="{ row }">
  305. <vxe-button
  306. type="text"
  307. v-if="row.type === 'array' || row.type === 'object'"
  308. status="primary"
  309. @click="insertRow(row, 'resTable')"
  310. >插入</vxe-button
  311. >
  312. <vxe-button type="text" status="primary" @click="removeRow(row, 'resTable')">删除</vxe-button>
  313. </template>
  314. </vxe-column>
  315. </vxe-table>
  316. <Button class="mt10" v-if="isEdit" type="primary" @click="insertEvent('resTable')">添加参数</Button>
  317. </FormItem>
  318. </Col>
  319. </Row>
  320. <Row :gutter="24" type="flex">
  321. <Col span="24">
  322. <div class="title">调用示例</div>
  323. <FormItem label="请求数据示例:" prop="request_example">
  324. <Input
  325. v-if="isEdit"
  326. class="perW20"
  327. type="textarea"
  328. :rows="4"
  329. v-model.trim="formValidate.request_example"
  330. placeholder="请输入"
  331. />
  332. <span v-else class="text-area">{{ formValidate.request_example || '' }}</span>
  333. </FormItem>
  334. <FormItem label="返回数据示例:" prop="response_example">
  335. <Input
  336. v-if="isEdit"
  337. class="perW20"
  338. type="textarea"
  339. :rows="4"
  340. v-model.trim="formValidate.response_example"
  341. placeholder="请输入"
  342. />
  343. <span v-else class="text-area">{{ formValidate.response_example || '' }}</span>
  344. </FormItem>
  345. <FormItem label="错误码:">
  346. <vxe-table
  347. resizable
  348. show-overflow
  349. keep-source
  350. ref="codeTable"
  351. row-id="id"
  352. is-tree-view
  353. :print-config="{}"
  354. :export-config="{}"
  355. :loading="loading"
  356. :tree-config="{ rowField: 'id', parentField: 'parentId' }"
  357. :data="formValidate.error_code"
  358. >
  359. <!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
  360. <vxe-column field="code" title="错误码" tree-node :edit-render="{}">
  361. <template #default="{ row }">
  362. <vxe-input v-if="isEdit" v-model="row.code" type="text"></vxe-input>
  363. <span v-else>{{ row.code || '' }}</span>
  364. </template>
  365. </vxe-column>
  366. <vxe-column field="value" title="错误码取值" :edit-render="{}">
  367. <template #default="{ row }">
  368. <vxe-input v-if="isEdit" v-model="row.value" type="text"></vxe-input>
  369. <span v-else>{{ row.value || '' }}</span>
  370. </template>
  371. </vxe-column>
  372. <vxe-column field="solution" title="解决方案" :edit-render="{}">
  373. <template #default="{ row }">
  374. <vxe-input v-if="isEdit" v-model="row.solution" type="text"></vxe-input>
  375. <span v-else>{{ row.solution || '' }}</span>
  376. </template>
  377. </vxe-column>
  378. <vxe-column title="操作" v-if="isEdit">
  379. <template #default="{ row }">
  380. <vxe-button type="text" status="primary" @click="removeRow(row, 'codeTable')"
  381. >删除</vxe-button
  382. >
  383. </template>
  384. </vxe-column>
  385. </vxe-table>
  386. <Button class="mt10" v-if="isEdit" type="primary" @click="insertEvent('codeTable')"
  387. >添加参数</Button
  388. >
  389. </FormItem>
  390. </Col>
  391. </Row>
  392. <!-- <Row :gutter="24" type="flex">
  393. <Col span="24">
  394. <FormItem>
  395. <Button type="primary" class="submission" @click="handleSubmit('formValidate')">保存</Button>
  396. </FormItem>
  397. </Col>
  398. </Row> -->
  399. </Form>
  400. </div>
  401. <!-- <div v-else class="nothing">
  402. <div class="box" @click="clickMenu(4)">
  403. <div class="icon">
  404. <Icon type="ios-folder" />
  405. </div>
  406. <div class="text">新建文件</div>
  407. </div>
  408. <div class="box" @click="clickMenu(1)">
  409. <div class="icon">
  410. <Icon type="logo-linkedin" />
  411. </div>
  412. <div class="text">新建接口</div>
  413. </div>
  414. </div> -->
  415. </Card>
  416. </div>
  417. </div>
  418. <Modal v-model="nameModal" title="分组名称" :loading="loading" @on-ok="asyncOK">
  419. <label>分组名称:</label>
  420. <Input v-model="value" placeholder="请输入分组名称" style="width: 85%" />
  421. </Modal>
  422. <Drawer v-model="debuggingModal" :title="formValidate.name" width="70%" footer-hide :loading="loading">
  423. <debugging
  424. v-if="debuggingModal"
  425. :formValidate="formValidate"
  426. :typeList="intTypeList"
  427. :requestTypeList="requestTypeList"
  428. :apiType="apiType"
  429. />
  430. </Drawer>
  431. </div>
  432. </template>
  433. <script>
  434. import {
  435. routeCate,
  436. syncRoute,
  437. routeList,
  438. routeDet,
  439. routeSave,
  440. interfaceEditName,
  441. routeDel,
  442. routeEdit,
  443. routeCateDel,
  444. } from '@/api/systemBackendRouting';
  445. import { VueTreeList, Tree, TreeNode } from 'vue-tree-list';
  446. import debugging from './debugging.vue';
  447. import { mapState } from 'vuex';
  448. export default {
  449. name: 'systemOutInterface',
  450. components: {
  451. VueTreeList,
  452. debugging,
  453. },
  454. data() {
  455. return {
  456. value: '',
  457. isEdit: false,
  458. nameModal: false,
  459. debuggingModal: false,
  460. formValidate: {},
  461. grid: {
  462. xl: 7,
  463. lg: 7,
  464. md: 12,
  465. sm: 24,
  466. xs: 24,
  467. },
  468. ruleValidate: {
  469. title: [{ message: '请输入正确的描述 (不能多于200位数)', trigger: 'blur', max: 200 }],
  470. },
  471. loading: false,
  472. intTypeList: [
  473. {
  474. value: 'string',
  475. label: 'String',
  476. },
  477. // {
  478. // value: 'array',
  479. // label: 'Array',
  480. // },
  481. // {
  482. // value: 'object',
  483. // label: 'Object',
  484. // },
  485. {
  486. value: 'number',
  487. label: 'Number',
  488. },
  489. {
  490. value: 'boolean',
  491. label: 'Boolean',
  492. },
  493. {
  494. value: 'null',
  495. label: 'Null',
  496. },
  497. {
  498. value: 'any',
  499. label: 'Any',
  500. },
  501. ],
  502. typeList: [
  503. {
  504. value: 'string',
  505. label: 'String',
  506. },
  507. {
  508. value: 'array',
  509. label: 'Array',
  510. },
  511. {
  512. value: 'object',
  513. label: 'Object',
  514. },
  515. {
  516. value: 'number',
  517. label: 'Number',
  518. },
  519. {
  520. value: 'boolean',
  521. label: 'Boolean',
  522. },
  523. {
  524. value: 'null',
  525. label: 'Null',
  526. },
  527. {
  528. value: 'any',
  529. label: 'Any',
  530. },
  531. ],
  532. requestTypeList: [
  533. {
  534. value: 'GET',
  535. label: 'GET',
  536. },
  537. {
  538. value: 'POST',
  539. label: 'POST',
  540. },
  541. {
  542. value: 'DELETE',
  543. label: 'DELETE',
  544. },
  545. {
  546. value: 'PUT',
  547. label: 'PUT',
  548. },
  549. ],
  550. contextData: null, //左侧导航右键点击是产生的数据对象
  551. treeData: undefined,
  552. buttonProps: {
  553. type: 'default',
  554. size: 'small',
  555. },
  556. methodColor: '#fff',
  557. apiType: 'adminapi',
  558. paramsId: 0,
  559. };
  560. },
  561. watch: {
  562. ['formValidate.method']: {
  563. deep: true,
  564. handler(newVal, oldVal) {
  565. console.log(newVal);
  566. if (newVal) {
  567. let method = newVal.toUpperCase();
  568. if (method == 'GET') {
  569. this.methodColor = '#61affe';
  570. } else if (method == 'POST') {
  571. this.methodColor = '#49cc90';
  572. } else if (method == 'PUT') {
  573. this.methodColor = '#fca130';
  574. } else if (method == 'DEL' || method == 'DELETE') {
  575. this.methodColor = '#f93e3e';
  576. }
  577. }
  578. },
  579. },
  580. apiType(newVal) {
  581. if (newVal) {
  582. this.getInterfaceList('one');
  583. }
  584. },
  585. },
  586. computed: {
  587. ...mapState('media', ['isMobile']),
  588. labelWidth() {
  589. return this.isMobile ? undefined : 50;
  590. },
  591. labelPosition() {
  592. return this.isMobile ? 'top' : 'right';
  593. },
  594. },
  595. created() {
  596. this.getInterfaceList('one');
  597. },
  598. methods: {
  599. syncRoute() {
  600. this.$Modal.confirm({
  601. title: '立即同步',
  602. content: '同步之后,路由文件中新增的接口添加到接口列表中,路由文件中删除的路由会同步的在接口列表中删除',
  603. onOk: () => {
  604. syncRoute(this.apiType).then((res) => {
  605. this.getInterfaceList('one');
  606. this.$Message.success(res.msg);
  607. this.$Modal.remove();
  608. });
  609. },
  610. });
  611. },
  612. debugging() {
  613. this.debuggingModal = true;
  614. },
  615. onClicksss(e) {},
  616. methodsColor(newVal) {
  617. let method = newVal.toUpperCase();
  618. if (method == 'GET') {
  619. return '#61affe';
  620. } else if (method == 'POST') {
  621. return '#49cc90';
  622. } else if (method == 'PUT') {
  623. return '#fca130';
  624. } else if (method == 'DEL' || method == 'DELETE') {
  625. return '#f93e3e';
  626. }
  627. },
  628. insertBefore(params) {},
  629. insertAfter(params) {},
  630. moveInto(params) {},
  631. async addTableData() {
  632. const { row: data } = await $table.insertAt(newRow, -1);
  633. await $table.setActiveCell(data, 'name');
  634. },
  635. getInterfaceList(disk_type) {
  636. try {
  637. routeList(this.apiType)
  638. .then((res) => {
  639. if (res.data.length) {
  640. res.data[0].expand = false;
  641. this.treeData = new Tree(res.data);
  642. this.$nextTick((e) => {
  643. if (disk_type) {
  644. if (res.data[0].children[0].children.length) {
  645. document.querySelectorAll('.vtl-icon-caret-right')[0].click();
  646. document.querySelectorAll('.vtl-icon-caret-right')[1].click();
  647. } else {
  648. document.querySelectorAll('.vtl-icon-caret-right')[0].click();
  649. }
  650. }
  651. });
  652. if (res.data[0].children && res.data[0].children.length) {
  653. this.onClick(res.data[0]?.children[0]?.children[0]);
  654. }
  655. } else {
  656. // this.$refs.treeList.clear();
  657. this.treeData = new Tree({});
  658. this.formValidate = {};
  659. }
  660. })
  661. .catch((err) => {
  662. console.log(err);
  663. this.$Message.error(err);
  664. });
  665. } catch (error) {
  666. console.log(error);
  667. }
  668. },
  669. onClick(params) {
  670. try {
  671. if (params.method) {
  672. this.isEdit = false;
  673. this.paramsId = params.id;
  674. this.getRoteData(params.id);
  675. }
  676. } catch (error) {}
  677. },
  678. getRoteData(id) {
  679. routeDet(id)
  680. .then((res) => {
  681. this.formValidate = res.data;
  682. })
  683. .catch((err) => {
  684. this.$Message.error(err);
  685. });
  686. },
  687. async handleSubmit() {
  688. if (!this.formValidate.name) {
  689. return this.$Message.warning('请输入接口名称');
  690. } else if (!this.formValidate.method) {
  691. return this.$Message.warning('请选择请求类型');
  692. } else if (!this.formValidate.path) {
  693. return this.$Message.warning('请输入路由地址');
  694. }
  695. this.formValidate.request = await this.$refs.xTable.getTableData().tableData;
  696. this.formValidate.response = await this.$refs.resTable.getTableData().tableData;
  697. this.formValidate.error_code = await this.$refs.codeTable.getTableData().tableData;
  698. this.formValidate.apiType = this.apiType;
  699. await routeSave(this.formValidate)
  700. .then((res) => {
  701. this.isEdit = false;
  702. this.$Message.success(res.msg);
  703. this.getRoteData(this.paramsId);
  704. })
  705. .catch((err) => {
  706. this.$Message.error(err);
  707. });
  708. },
  709. async insertEvent(type) {
  710. const $table = this.$refs[type];
  711. let newRow;
  712. if (type == 'xTable') {
  713. newRow = {
  714. attribute: '',
  715. type: '',
  716. must: 0,
  717. trip: '',
  718. };
  719. } else if (type == 'resTable') {
  720. newRow = {
  721. attribute: '',
  722. type: '',
  723. trip: '',
  724. };
  725. } else {
  726. newRow = {
  727. code: '',
  728. value: '',
  729. solution: '',
  730. };
  731. }
  732. // $table.insert(newRow).then(({ row }) => $table.setEditRow(row, -1));
  733. const { row: data } = await $table.insertAt(newRow, -1);
  734. await $table.setActiveCell(data, 'name');
  735. },
  736. async insertRow(currRow, type) {
  737. const $table = this.$refs[type];
  738. // 如果 null 则插入到目标节点顶部
  739. // 如果 -1 则插入到目标节点底部
  740. // 如果 row 则有插入到效的目标节点该行的位置
  741. let record;
  742. if (type == 'xTable') {
  743. record = {
  744. attribute: '',
  745. type: '',
  746. must: 0,
  747. trip: '',
  748. id: Date.now(),
  749. parentId: currRow.id, // 需要指定父节点,自动插入该节点中
  750. };
  751. } else if (type == 'resTable') {
  752. record = {
  753. attribute: '',
  754. type: '',
  755. trip: '',
  756. id: Date.now(),
  757. parentId: currRow.id, // 需要指定父节点,自动插入该节点中
  758. };
  759. } else {
  760. record = {
  761. code: '',
  762. value: '',
  763. solution: '',
  764. id: Date.now(),
  765. parentId: currRow.id, // 需要指定父节点,自动插入该节点中
  766. };
  767. }
  768. const { row: newRow } = await $table.insertAt(record, -1);
  769. await $table.setTreeExpand(currRow, true); // 将父节点展开
  770. await $table.setActiveRow(newRow); // 插入子节点
  771. },
  772. async removeRow(row, type) {
  773. const $table = this.$refs[type];
  774. await $table.remove(row);
  775. },
  776. // 修改名字
  777. add() {
  778. this.value = '';
  779. this.formValidate.id = 0;
  780. this.nameModal = true;
  781. },
  782. // 点击菜单
  783. clickMenu(name, params) {
  784. if (name == 1) {
  785. this.formValidate = {};
  786. this.formValidate.cate_id = params ? params.id : 0;
  787. this.formValidate.id = 0;
  788. this.isEdit = true;
  789. } else if (name == 2) {
  790. // this.value = params.name || '';
  791. // this.formValidate.cate_id = params ? params.id : 0;
  792. // this.nameModal = true;
  793. // this.onEdit(params);
  794. this.$modalForm(routeEdit(params.id, this.apiType)).then(() => this.getInterfaceList());
  795. } else if (name == 3) {
  796. this.onDel(params);
  797. } else if (name == 4) {
  798. // this.add();
  799. this.$modalForm(routeCate(this.apiType)).then(() => this.getInterfaceList());
  800. }
  801. },
  802. addFac(params) {
  803. this.formValidate = {
  804. id: params ? params.id : 0,
  805. };
  806. this.isEdit = true;
  807. },
  808. asyncOK() {
  809. let data = {
  810. id: this.formValidate.id || 0,
  811. type: 0,
  812. name: this.value,
  813. };
  814. routeSave(data)
  815. .then((res) => {
  816. this.$Message.success(res.msg);
  817. this.getInterfaceList();
  818. })
  819. .catch((err) => {
  820. this.$Message.error(err);
  821. });
  822. },
  823. //侧边栏右键点击事件
  824. handleContextMenu(data, event, position) {
  825. position.left = Number(position.left.slice(0, -2)) + 75 + 'px';
  826. this.contextData = data;
  827. },
  828. handleContextCreateFolder() {},
  829. handleContextCreateFile() {},
  830. // 自定义显示
  831. renderContent(h, { root, node, data }) {
  832. let that = this;
  833. return h(
  834. 'span',
  835. {
  836. style: {
  837. display: 'inline-block',
  838. width: '100%',
  839. },
  840. },
  841. [
  842. h('span', [
  843. h(resolveComponent('Icon'), {
  844. type: 'ios-paper-outline',
  845. style: {
  846. marginRight: '8px',
  847. },
  848. }),
  849. h('span', data.title),
  850. ]),
  851. h(
  852. 'span',
  853. {
  854. style: {
  855. display: 'inline-block',
  856. float: 'right',
  857. marginRight: '32px',
  858. },
  859. },
  860. [
  861. h(resolveComponent('Button'), {
  862. ...this.buttonProps,
  863. icon: 'ios-add',
  864. style: {
  865. marginRight: '8px',
  866. },
  867. onClick: () => {
  868. this.append(data);
  869. },
  870. }),
  871. h(resolveComponent('Button'), {
  872. ...this.buttonProps,
  873. icon: 'ios-remove',
  874. onClick: () => {
  875. this.remove(root, node, data);
  876. },
  877. }),
  878. ],
  879. ),
  880. ],
  881. );
  882. },
  883. /**
  884. * 侧边栏点击事件
  885. * @param {Object} data
  886. */
  887. clickDir(data, root, node) {
  888. let that = this;
  889. that.navItem = data;
  890. that.pathname = data.pathname;
  891. },
  892. append(data) {
  893. const children = data.children || [];
  894. children.push({
  895. title: 'appended node',
  896. expand: true,
  897. });
  898. this.$set(data, 'children', children);
  899. },
  900. remove(root, node, data) {
  901. const parentKey = root.find((el) => el === node).parent;
  902. const parent = root.find((el) => el.nodeKey === parentKey).node;
  903. const index = parent.children.indexOf(data);
  904. parent.children.splice(index, 1);
  905. },
  906. onMouseOver(root, node, data, e, d) {
  907. console.log(root, node, data);
  908. },
  909. onMouseOver(root, node, data, e, d) {
  910. console.log(root, node, data, e, d);
  911. },
  912. //
  913. onDel(node) {
  914. let method = node.cate_id ? routeDel : routeCateDel;
  915. this.$Modal.confirm({
  916. title: '警告',
  917. content: '<p>删除后无法恢复,请确认后删除!</p>',
  918. onOk: () => {
  919. method(node.id)
  920. .then((res) => {
  921. this.$Message.success(res.msg);
  922. node.remove();
  923. })
  924. .catch((err) => {
  925. this.$Message.error(err);
  926. });
  927. },
  928. onCancel: () => {},
  929. });
  930. },
  931. onChangeName(params) {
  932. if (params.eventType == 'blur') {
  933. let data = {
  934. name: params.newName,
  935. id: params.id,
  936. };
  937. interfaceEditName(data)
  938. .then((res) => {
  939. this.$Message.success(res.msg);
  940. })
  941. .catch((err) => {
  942. this.$Message.error(err);
  943. });
  944. }
  945. },
  946. onAddNode(params) {
  947. // this.$router.push({
  948. // path: '/admin/setting/system_out_interface/add',
  949. // query: {
  950. // pid: params.pid,
  951. // },
  952. // });
  953. },
  954. addNode() {
  955. var node = new TreeNode({ name: 'new node', isLeaf: false });
  956. if (!this.data.children) this.data.children = [];
  957. this.data.addChildren(node);
  958. },
  959. getNewTree() {
  960. var vm = this;
  961. function _dfs(oldNode) {
  962. var newNode = {};
  963. for (var k in oldNode) {
  964. if (k !== 'children' && k !== 'parent') {
  965. newNode[k] = oldNode[k];
  966. }
  967. }
  968. if (oldNode.children && oldNode.children.length > 0) {
  969. newNode.children = [];
  970. for (var i = 0, len = oldNode.children.length; i < len; i++) {
  971. newNode.children.push(_dfs(oldNode.children[i]));
  972. }
  973. }
  974. return newNode;
  975. }
  976. vm.newTree = _dfs(vm.data);
  977. },
  978. },
  979. };
  980. </script>
  981. <style lang="stylus" scoped>
  982. .reset {
  983. margin-left: 10px;
  984. }
  985. .card-tree {
  986. background: #fff;
  987. height: 72px;
  988. box-sizing: border-box;
  989. overflow-x: scroll; /* 设置溢出滚动 */
  990. white-space: nowrap;
  991. overflow-y: hidden;
  992. /* 隐藏滚动条 */
  993. border-radius: 4px;
  994. scrollbar-width: none; /* firefox */
  995. -ms-overflow-style: none; /* IE 10+ */
  996. }
  997. .card-tree::-webkit-scrollbar {
  998. display: none; /* Chrome Safari */
  999. }
  1000. .main {
  1001. width: 100%;
  1002. display: flex;
  1003. .main-btn {
  1004. display:flex;
  1005. position: sticky;
  1006. padding: 15px 15px 0 15px;
  1007. width: 100%;
  1008. background: #fff;
  1009. top: 0px;
  1010. background-color: rgba(255, 255, 255, 0.6);
  1011. backdrop-filter: blur(4px);
  1012. }
  1013. .card-tree{
  1014. width: 290px;
  1015. height: calc(100vh - 115px);
  1016. overflow-y: scroll;
  1017. }
  1018. >>> .tree {
  1019. .tree-list{
  1020. margin-left:10px;
  1021. padding: 0 15px;
  1022. margin-top: 10px;
  1023. }
  1024. .vtl-caret{
  1025. padding-right: 2px;
  1026. }
  1027. .req-method {
  1028. display:block;
  1029. padding: 0px 2px;
  1030. font-size: 13px;
  1031. line-height: 13px;
  1032. margin-right: 5px;
  1033. border-radius: 4px;
  1034. text-transform: uppercase;
  1035. }
  1036. .tree-node {
  1037. display: flex;
  1038. align-items: center;
  1039. justify-content: space-between;
  1040. cursor: pointer;
  1041. // width:200px;
  1042. padding: 3px 7px 3px 0;
  1043. }
  1044. .node{
  1045. padding:3px 2px 3px 0px;
  1046. }
  1047. .open {
  1048. // background-color: #fff1ef;
  1049. font-weight: 500;
  1050. color: #333;
  1051. }
  1052. }
  1053. >>> .vtl-node-main .vtl-operation {
  1054. position: absolute;
  1055. right: 20px;
  1056. }
  1057. >>> .vtl-node-content {
  1058. width: 100%;
  1059. }
  1060. .pop-menu {
  1061. display: flex;
  1062. justify-content: space-between;
  1063. }
  1064. >>> .vtl-node-content .add {
  1065. display: none;
  1066. margin-right: 10px;
  1067. }
  1068. >>> .vtl-node-content:hover .add {
  1069. display: flex;
  1070. justify-content: center;
  1071. align-items: center;
  1072. border-radius: 50%;
  1073. width: 18px;
  1074. height: 18px;
  1075. }
  1076. >>> .vtl-node-content:hover .add:hover {
  1077. background-color: #fff;
  1078. .pop-menu {
  1079. font-size: 16px;
  1080. }
  1081. }
  1082. >>> .vtl-node-main{
  1083. padding:0;
  1084. }
  1085. >>> .line1 {
  1086. display: table-caption;
  1087. white-space: nowrap;
  1088. width: 120px;
  1089. overflow: hidden;
  1090. text-overflow: ellipsis;
  1091. }
  1092. >>> .ivu-form-item{
  1093. margin-bottom: 10px;
  1094. }
  1095. .right-card {
  1096. flex: 1;
  1097. max-height: calc(100vh - 115px);
  1098. overflow-y: scroll;
  1099. }
  1100. .data {
  1101. flex: 1;
  1102. .req-method {
  1103. text-transform: uppercase;
  1104. border-radius: 4px;
  1105. color: #fff;
  1106. padding: 3px 7px;
  1107. }
  1108. .eidt-sub {
  1109. display: flex;
  1110. justify-content: space-between;
  1111. .name {
  1112. font-size: 20px;
  1113. font-weight: 500;
  1114. }
  1115. }
  1116. .title {
  1117. font-size: 16px;
  1118. font-weight: 500;
  1119. margin-bottom: 15px;
  1120. }
  1121. .perW20 {
  1122. width: 500px;
  1123. }
  1124. .text-area {
  1125. white-space: pre-wrap;
  1126. word-break: break-word;
  1127. }
  1128. }
  1129. >>> .ivu-tree-title {
  1130. width: 100% !important;
  1131. }
  1132. >>> .vtl-tree-margin{
  1133. margin-left: 15px;
  1134. }
  1135. >>> .ivu-btn-icon-only.ivu-btn-small {
  1136. width: 28px;
  1137. }
  1138. >>> .tree-node > span{
  1139. font-size: 14px
  1140. }
  1141. >>> .tree-node.node > span{
  1142. font-size: 13px
  1143. }
  1144. .nothing {
  1145. display: flex;
  1146. align-items: center;
  1147. justify-content: center;
  1148. min-height: 800px;
  1149. .box:hover {
  1150. border: 1px solid pink;
  1151. }
  1152. .box {
  1153. display: flex;
  1154. align-items: center;
  1155. justify-content: center;
  1156. flex-direction: column;
  1157. width: 150px;
  1158. height: 200px;
  1159. margin: 0 20px;
  1160. border-radius: 10px;
  1161. cursor: pointer;
  1162. overflow: hidden;
  1163. border: 1px solid #fff;
  1164. .icon {
  1165. display: flex;
  1166. align-items: center;
  1167. justify-content: center;
  1168. width: 100%;
  1169. height: 150px;
  1170. font-size: 40px;
  1171. color: #2d8cf0;
  1172. background: #f1f1f1;
  1173. }
  1174. .text {
  1175. width: 100%;
  1176. height: 50px;
  1177. background: #ddd;
  1178. text-align: center;
  1179. line-height: 50px;
  1180. font-size: 14px;
  1181. font-weight: 500;
  1182. }
  1183. }
  1184. }
  1185. }
  1186. </style>