index.vue 33 KB

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