index.vue 39 KB

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