├── .browserslistrc ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .yarnrc ├── LICENSE ├── README.md ├── babel.config.js ├── build ├── default.config.js ├── html.config.js └── share.config.js ├── local-update.yml ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── font │ ├── iconfont.css │ ├── iconfont.js │ ├── iconfont.json │ ├── iconfont.ttf │ ├── iconfont.woff │ └── iconfont.woff2 ├── icons │ ├── 1024x1024.png │ ├── 128x128.png │ ├── 16x16.png │ ├── 24x24.png │ ├── 256x256.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 512x512.png │ ├── 64x64.png │ ├── icon.icns │ └── icon.ico ├── index.html ├── mock-file │ ├── mock.doc │ ├── mock.docx │ ├── mock.pdf │ ├── mock.png │ ├── mock.xls │ ├── mock.xlsx │ └── mock.zip └── sandbox │ ├── apidoc-info.js │ ├── collection-variables.js │ ├── common │ └── json5.js │ ├── hook │ └── worker.js │ ├── pre-request │ ├── global │ │ ├── global.js │ │ └── import-script.js │ ├── helper │ │ └── helper.js │ ├── request │ │ ├── formdata.js │ │ ├── headers.js │ │ ├── json.js │ │ ├── path.js │ │ ├── query.js │ │ ├── raw.js │ │ └── urlencoded.js │ ├── send-request │ │ └── send-request.js │ ├── variables │ │ └── variables.js │ └── worker.js │ ├── state │ └── state.js │ ├── url.js │ ├── utils.js │ └── variables.js ├── src ├── @types │ ├── apiflow.d.ts │ ├── config.d.ts │ ├── global.d.ts │ ├── globalProperties.d.ts │ ├── helper.d.ts │ ├── shims-scss.d.ts │ ├── shims-vue.d.ts │ └── store.d.ts ├── config │ └── config.ts ├── main │ ├── background.ts │ └── update.ts └── renderer │ ├── App.vue │ ├── api │ └── api.ts │ ├── assets │ ├── css │ │ └── index.css │ └── imgs │ │ ├── apidoc │ │ ├── body-tip.png │ │ ├── file.png │ │ ├── folder.png │ │ ├── prefix.gif │ │ ├── prefix.png │ │ └── send-request.gif │ │ └── logo.png │ ├── cache │ ├── apidoc.ts │ ├── cache.ts │ └── database.ts │ ├── components │ ├── apidoc │ │ ├── mock │ │ │ ├── g-mock.vue │ │ │ └── mock-enum.ts │ │ ├── params-tree │ │ │ ├── g-params-tree.vue │ │ │ └── g-params-tree2.vue │ │ ├── params-view │ │ │ ├── composables │ │ │ │ └── astJson.ts │ │ │ └── g-params-view.vue │ │ └── raw-editor │ │ │ └── g-raw-editor.vue │ ├── common │ │ ├── card │ │ │ └── g-card.vue │ │ ├── collapse-card │ │ │ └── g-collapse-card.vue │ │ ├── collapse │ │ │ └── g-collapse.vue │ │ ├── config │ │ │ └── g-config.vue │ │ ├── contextmenu │ │ │ ├── g-contextmenu-item.vue │ │ │ └── g-contextmenu.vue │ │ ├── dialog │ │ │ └── g-dialog.vue │ │ ├── download │ │ │ └── g-download.vue │ │ ├── ellipsis-content │ │ │ └── g-ellipsis-content.vue │ │ ├── emphasize │ │ │ └── g-emphasize.vue │ │ ├── fieldset │ │ │ └── g-fieldset.vue │ │ ├── forms │ │ │ ├── col │ │ │ │ └── g-col.vue │ │ │ ├── form │ │ │ │ ├── composables │ │ │ │ │ └── rules.ts │ │ │ │ ├── g-form-item.vue │ │ │ │ └── g-form.vue │ │ │ ├── inputs │ │ │ │ ├── g-input.vue │ │ │ │ └── g-select.vue │ │ │ └── search │ │ │ │ ├── g-search-item.vue │ │ │ │ └── g-search.vue │ │ ├── json-editor │ │ │ └── g-json-editor.vue │ │ ├── label-value │ │ │ └── g-label-value.vue │ │ ├── left-right │ │ │ └── g-left-right.vue │ │ ├── loading │ │ │ └── g-loading.vue │ │ ├── mock-json-editor │ │ │ ├── g-mock-json-editor.vue │ │ │ └── registerCompletionItem.ts │ │ ├── remote-select │ │ │ ├── g-remote-select-item.vue │ │ │ └── g-remote-select.vue │ │ ├── resize │ │ │ ├── g-resize-x.vue │ │ │ └── g-resize-y.vue │ │ ├── sms-button │ │ │ └── g-sms-button.vue │ │ ├── table │ │ │ └── g-table.vue │ │ ├── upload │ │ │ └── g-upload-plain.vue │ │ └── valid-input │ │ │ └── g-valid-input.vue │ └── index.ts │ ├── directive │ └── directive.ts │ ├── helper │ ├── apidoc-format.ts │ ├── index.ts │ └── tips.ts │ ├── i18n │ ├── en.ts │ ├── i18n.ts │ ├── zh-cn.ts │ └── zh-tw.ts │ ├── main.ts │ ├── mixin │ ├── computed │ │ └── index.ts │ ├── data │ │ └── index.ts │ ├── filters │ │ └── index.ts │ ├── index.ts │ ├── methods │ │ ├── index.ts │ │ └── tips.ts │ └── props │ │ └── index.ts │ ├── pages │ ├── layout │ │ ├── 404 │ │ │ └── 404.vue │ │ └── layout.vue │ ├── login │ │ ├── components │ │ │ ├── login-account.vue │ │ │ ├── login-phone.vue │ │ │ ├── register.vue │ │ │ └── reset-password.vue │ │ └── login.vue │ ├── modules │ │ ├── apidoc │ │ │ ├── doc-edit │ │ │ │ ├── banner │ │ │ │ │ ├── banner.vue │ │ │ │ │ ├── composables │ │ │ │ │ │ ├── banner-data.ts │ │ │ │ │ │ └── curd-node.ts │ │ │ │ │ └── tool │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ └── tool.vue │ │ │ │ ├── content │ │ │ │ │ ├── apidoc │ │ │ │ │ │ ├── apidoc.vue │ │ │ │ │ │ ├── dialog │ │ │ │ │ │ │ ├── curd-host │ │ │ │ │ │ │ │ └── curd-host.vue │ │ │ │ │ │ │ └── import-params │ │ │ │ │ │ │ │ └── import-params.vue │ │ │ │ │ │ ├── operation │ │ │ │ │ │ │ ├── composables │ │ │ │ │ │ │ │ ├── host.ts │ │ │ │ │ │ │ │ ├── method.ts │ │ │ │ │ │ │ │ ├── operation.ts │ │ │ │ │ │ │ │ └── url.ts │ │ │ │ │ │ │ ├── operation.vue │ │ │ │ │ │ │ └── tag │ │ │ │ │ │ │ │ └── tag.vue │ │ │ │ │ │ ├── params │ │ │ │ │ │ │ ├── after-request │ │ │ │ │ │ │ │ ├── after-request.vue │ │ │ │ │ │ │ │ └── editor │ │ │ │ │ │ │ │ │ ├── after-editor.vue │ │ │ │ │ │ │ │ │ ├── registerCompletionItem.ts │ │ │ │ │ │ │ │ │ └── registerHoverProvider.ts │ │ │ │ │ │ │ ├── body │ │ │ │ │ │ │ │ ├── body.vue │ │ │ │ │ │ │ │ └── dialog │ │ │ │ │ │ │ │ │ ├── body-use-case │ │ │ │ │ │ │ │ │ └── body-use-case.vue │ │ │ │ │ │ │ │ │ └── params-template │ │ │ │ │ │ │ │ │ └── params-template.vue │ │ │ │ │ │ │ ├── headers │ │ │ │ │ │ │ │ ├── headers.vue │ │ │ │ │ │ │ │ └── mind-headers.ts │ │ │ │ │ │ │ ├── hook │ │ │ │ │ │ │ │ └── hook.vue │ │ │ │ │ │ │ ├── mock │ │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ │ │ ├── mock-headers │ │ │ │ │ │ │ │ │ │ └── mock-headers.vue │ │ │ │ │ │ │ │ │ └── mock-response │ │ │ │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ │ │ │ ├── custom-editor.vue │ │ │ │ │ │ │ │ │ │ ├── registerCompletionItem.ts │ │ │ │ │ │ │ │ │ │ └── registerHoverProvider.ts │ │ │ │ │ │ │ │ │ │ └── mock-response.vue │ │ │ │ │ │ │ │ └── mock.vue │ │ │ │ │ │ │ ├── params.vue │ │ │ │ │ │ │ ├── params │ │ │ │ │ │ │ │ └── params.vue │ │ │ │ │ │ │ ├── pre-request │ │ │ │ │ │ │ │ ├── editor │ │ │ │ │ │ │ │ │ ├── pre-editor.vue │ │ │ │ │ │ │ │ │ ├── registerCompletionItem.ts │ │ │ │ │ │ │ │ │ └── registerHoverProvider.ts │ │ │ │ │ │ │ │ └── pre-request.vue │ │ │ │ │ │ │ ├── remarks │ │ │ │ │ │ │ │ └── remarks.vue │ │ │ │ │ │ │ ├── response │ │ │ │ │ │ │ │ ├── children │ │ │ │ │ │ │ │ │ ├── mime.ts │ │ │ │ │ │ │ │ │ ├── mime.vue │ │ │ │ │ │ │ │ │ ├── status.ts │ │ │ │ │ │ │ │ │ └── status.vue │ │ │ │ │ │ │ │ ├── compsables │ │ │ │ │ │ │ │ │ ├── import-params.ts │ │ │ │ │ │ │ │ │ └── params-template.ts │ │ │ │ │ │ │ │ ├── dialog │ │ │ │ │ │ │ │ │ └── params-template │ │ │ │ │ │ │ │ │ │ └── params-template.vue │ │ │ │ │ │ │ │ └── response.vue │ │ │ │ │ │ │ └── view │ │ │ │ │ │ │ │ └── view.vue │ │ │ │ │ │ └── response │ │ │ │ │ │ │ ├── base-info │ │ │ │ │ │ │ └── base-info.vue │ │ │ │ │ │ │ ├── body │ │ │ │ │ │ │ └── body.vue │ │ │ │ │ │ │ ├── cookie │ │ │ │ │ │ │ └── cookie.vue │ │ │ │ │ │ │ ├── headers │ │ │ │ │ │ │ └── headers.vue │ │ │ │ │ │ │ ├── request │ │ │ │ │ │ │ └── request.vue │ │ │ │ │ │ │ ├── res-info │ │ │ │ │ │ │ └── res-info.vue │ │ │ │ │ │ │ └── response.vue │ │ │ │ │ ├── apiflow │ │ │ │ │ │ ├── apiflow.vue │ │ │ │ │ │ ├── common │ │ │ │ │ │ │ ├── common.ts │ │ │ │ │ │ │ ├── quadrant │ │ │ │ │ │ │ │ └── quardant.ts │ │ │ │ │ │ │ ├── quadrant2 │ │ │ │ │ │ │ │ └── quadrant2.ts │ │ │ │ │ │ │ ├── quadrant3 │ │ │ │ │ │ │ │ └── quadrant3.ts │ │ │ │ │ │ │ └── quadrant4 │ │ │ │ │ │ │ │ └── quadrant4.ts │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── line │ │ │ │ │ │ │ │ └── line.vue │ │ │ │ │ │ │ ├── node │ │ │ │ │ │ │ │ └── node.vue │ │ │ │ │ │ │ ├── selection │ │ │ │ │ │ │ │ ├── selected-node-area.vue │ │ │ │ │ │ │ │ └── selection.vue │ │ │ │ │ │ │ └── tools │ │ │ │ │ │ │ │ └── tools.vue │ │ │ │ │ │ └── mouse-handler │ │ │ │ │ │ │ ├── mousedown.ts │ │ │ │ │ │ │ ├── mousemove.ts │ │ │ │ │ │ │ └── mouseup.ts │ │ │ │ │ ├── common-header │ │ │ │ │ │ └── common-header.vue │ │ │ │ │ ├── config │ │ │ │ │ │ └── config.vue │ │ │ │ │ ├── content.vue │ │ │ │ │ ├── export │ │ │ │ │ │ ├── export.vue │ │ │ │ │ │ └── fork │ │ │ │ │ │ │ └── fork.vue │ │ │ │ │ ├── guide │ │ │ │ │ │ └── guide.vue │ │ │ │ │ ├── history │ │ │ │ │ │ └── history.vue │ │ │ │ │ ├── hook │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── add │ │ │ │ │ │ │ │ └── add.vue │ │ │ │ │ │ │ ├── edit │ │ │ │ │ │ │ │ └── edit.vue │ │ │ │ │ │ │ ├── editor │ │ │ │ │ │ │ │ ├── editor.vue │ │ │ │ │ │ │ │ ├── registerCompletionItem.ts │ │ │ │ │ │ │ │ └── registerHoverProvider.ts │ │ │ │ │ │ │ └── list │ │ │ │ │ │ │ │ └── list.vue │ │ │ │ │ │ └── hook.vue │ │ │ │ │ ├── import │ │ │ │ │ │ ├── import.vue │ │ │ │ │ │ ├── openapi.ts │ │ │ │ │ │ └── postman.ts │ │ │ │ │ ├── link │ │ │ │ │ │ ├── dialog │ │ │ │ │ │ │ ├── add.vue │ │ │ │ │ │ │ └── edit.vue │ │ │ │ │ │ └── link.vue │ │ │ │ │ ├── mind-params │ │ │ │ │ │ └── mind-params.vue │ │ │ │ │ ├── package │ │ │ │ │ │ └── package.vue │ │ │ │ │ ├── params-template │ │ │ │ │ │ └── params-template.vue │ │ │ │ │ ├── recycler │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ └── doc-detail.vue │ │ │ │ │ │ └── recycler.vue │ │ │ │ │ └── variable │ │ │ │ │ │ └── variable.vue │ │ │ │ ├── dialog │ │ │ │ │ ├── add-file │ │ │ │ │ │ └── add-file.vue │ │ │ │ │ ├── add-folder │ │ │ │ │ │ └── add-folder.vue │ │ │ │ │ └── save-doc │ │ │ │ │ │ └── save-doc.vue │ │ │ │ ├── doc-edit.vue │ │ │ │ └── nav │ │ │ │ │ └── nav.vue │ │ │ ├── doc-list │ │ │ │ ├── dialog │ │ │ │ │ ├── add-project │ │ │ │ │ │ └── add-project.vue │ │ │ │ │ ├── edit-project │ │ │ │ │ │ └── edit-project.vue │ │ │ │ │ └── permission │ │ │ │ │ │ ├── permission.vue │ │ │ │ │ │ ├── setting │ │ │ │ │ │ └── setting.vue │ │ │ │ │ │ └── user │ │ │ │ │ │ └── user.vue │ │ │ │ ├── doc-list.vue │ │ │ │ ├── tab-a │ │ │ │ │ └── tab-a.vue │ │ │ │ └── tab-b │ │ │ │ │ └── tab-b.vue │ │ │ └── doc-view │ │ │ │ ├── App.vue │ │ │ │ ├── api │ │ │ │ └── api.ts │ │ │ │ ├── check │ │ │ │ └── check.vue │ │ │ │ ├── main.ts │ │ │ │ ├── router │ │ │ │ └── index.ts │ │ │ │ ├── store │ │ │ │ ├── apidoc │ │ │ │ │ ├── apidoc.ts │ │ │ │ │ ├── banner.ts │ │ │ │ │ ├── base-info.ts │ │ │ │ │ ├── response.ts │ │ │ │ │ └── tabs.ts │ │ │ │ └── index.ts │ │ │ │ ├── test-data │ │ │ │ └── data.ts │ │ │ │ └── view │ │ │ │ ├── banner │ │ │ │ ├── banner.vue │ │ │ │ ├── composables │ │ │ │ │ ├── banner-data.ts │ │ │ │ │ └── curd-node.ts │ │ │ │ └── tool │ │ │ │ │ ├── operations.ts │ │ │ │ │ └── tool.vue │ │ │ │ ├── content │ │ │ │ ├── apidoc │ │ │ │ │ ├── apidoc.vue │ │ │ │ │ ├── operation │ │ │ │ │ │ ├── composables │ │ │ │ │ │ │ ├── host.ts │ │ │ │ │ │ │ ├── method.ts │ │ │ │ │ │ │ ├── operation.ts │ │ │ │ │ │ │ └── url.ts │ │ │ │ │ │ ├── operation.vue │ │ │ │ │ │ └── tag │ │ │ │ │ │ │ └── tag.vue │ │ │ │ │ ├── params │ │ │ │ │ │ ├── body │ │ │ │ │ │ │ ├── body.vue │ │ │ │ │ │ │ └── dialog │ │ │ │ │ │ │ │ ├── import-params │ │ │ │ │ │ │ │ └── import-params.vue │ │ │ │ │ │ │ │ └── params-template │ │ │ │ │ │ │ │ └── params-template.vue │ │ │ │ │ │ ├── headers │ │ │ │ │ │ │ └── headers.vue │ │ │ │ │ │ ├── params.vue │ │ │ │ │ │ ├── params │ │ │ │ │ │ │ └── params.vue │ │ │ │ │ │ ├── response │ │ │ │ │ │ │ └── response.vue │ │ │ │ │ │ └── view │ │ │ │ │ │ │ └── view.vue │ │ │ │ │ └── response │ │ │ │ │ │ ├── base-info │ │ │ │ │ │ └── base-info.vue │ │ │ │ │ │ ├── body │ │ │ │ │ │ └── body.vue │ │ │ │ │ │ ├── cookie │ │ │ │ │ │ └── cookie.vue │ │ │ │ │ │ ├── headers │ │ │ │ │ │ └── headers.vue │ │ │ │ │ │ ├── res-info │ │ │ │ │ │ └── res-info.vue │ │ │ │ │ │ └── response.vue │ │ │ │ ├── content.vue │ │ │ │ └── guide │ │ │ │ │ └── guide.vue │ │ │ │ ├── nav │ │ │ │ └── nav.vue │ │ │ │ └── view.vue │ │ ├── permission │ │ │ ├── client-routes │ │ │ │ ├── add │ │ │ │ │ └── add.vue │ │ │ │ ├── client-routes.vue │ │ │ │ └── edit │ │ │ │ │ ├── edit.vue │ │ │ │ │ └── edit2.vue │ │ │ ├── menu │ │ │ │ ├── add │ │ │ │ │ └── add.vue │ │ │ │ ├── edit │ │ │ │ │ └── edit.vue │ │ │ │ └── menu.vue │ │ │ ├── permission.vue │ │ │ ├── role │ │ │ │ ├── add │ │ │ │ │ ├── add.vue │ │ │ │ │ └── components │ │ │ │ │ │ ├── client-menus.vue │ │ │ │ │ │ ├── client-routes.vue │ │ │ │ │ │ └── server-routes.vue │ │ │ │ ├── edit │ │ │ │ │ ├── components │ │ │ │ │ │ ├── client-menus.vue │ │ │ │ │ │ ├── client-routes.vue │ │ │ │ │ │ └── server-routes.vue │ │ │ │ │ └── edit.vue │ │ │ │ └── role.vue │ │ │ ├── server-routes │ │ │ │ ├── add │ │ │ │ │ └── add.vue │ │ │ │ ├── edit │ │ │ │ │ ├── edit.vue │ │ │ │ │ └── edit2.vue │ │ │ │ └── server-routes.vue │ │ │ └── user │ │ │ │ ├── add │ │ │ │ └── add.vue │ │ │ │ ├── edit │ │ │ │ └── edit.vue │ │ │ │ ├── reset-pwd │ │ │ │ └── reset-pwd.vue │ │ │ │ └── user.vue │ │ └── settings │ │ │ └── user │ │ │ └── user.vue │ └── test │ │ └── test.vue │ ├── router │ └── index.ts │ ├── scss │ ├── global │ │ ├── _global.scss │ │ └── _mend.scss │ ├── helpers │ │ ├── _functions.scss │ │ └── _mixin.scss │ ├── index.scss │ ├── utils │ │ └── _utils.scss │ └── variables │ │ └── _variables.scss │ ├── server │ ├── mock │ │ ├── mock-server.ts │ │ └── mock.ts │ └── request │ │ ├── browser.ts │ │ ├── config.ts │ │ ├── electron.ts │ │ ├── filters.ts │ │ ├── request.ts │ │ └── utils.ts │ └── store │ ├── apidoc │ ├── apidoc.ts │ ├── apiflow.ts │ ├── banner.ts │ ├── base-info.ts │ ├── mock.ts │ ├── request.ts │ ├── response.ts │ ├── tabs.ts │ └── worker-state.ts │ ├── apiflow │ ├── config.ts │ ├── container.ts │ ├── create-line-state.ts │ ├── history.ts │ ├── line-state.ts │ ├── lines.ts │ ├── node-state.ts │ ├── nodes.ts │ ├── render-area.ts │ ├── resize-node-state.ts │ └── selection.ts │ ├── index.ts │ └── permission │ └── permission.ts ├── tsconfig.json ├── vue.config.js └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | public/ 2 | node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | globals: { 4 | defineProps: "readonly", 5 | defineEmits: "readonly", 6 | defineExpose: "readonly", 7 | withDefaults: "readonly", 8 | config: "readonly", 9 | $t: "readonly", 10 | }, 11 | env: { 12 | node: true, 13 | }, 14 | extends: [ 15 | "plugin:vue/vue3-recommended", 16 | "@vue/typescript/recommended", 17 | "@vue/airbnb", 18 | ], 19 | parserOptions: { 20 | ecmaVersion: 2020, 21 | }, 22 | rules: { 23 | "import/order": "off", 24 | "no-console": process.env.NODE_ENV === "production" ? "off" : "off", 25 | "vue/html-indent": ["error", 2], 26 | "vue/script-indent": ["error", 2], 27 | "vue/max-attributes-per-line": "off", 28 | "vue/html-self-closing": "off", 29 | "vue/singleline-html-element-content-newline": "off", 30 | "space-before-function-paren": "off", 31 | "no-unused-expressions": "off", 32 | "import/no-extraneous-dependencies": [ 33 | "off", 34 | { packageDir: "./build/" }, 35 | ], 36 | indent: ["error", 2], 37 | // "@typescript-eslint/indent": ["error", 2], 38 | semi: "off", //结尾分号无所谓 39 | "comma-dangle": "off", 40 | quotes: ["error", "single"], 41 | "max-len": ["error", { code: 400 }], //最大代码长度为400行 42 | "no-param-reassign": ["error", { props: false }], //函数参数非对象情况不允许直接改变 43 | "linebreak-style": ["off", "windows"], 44 | "spaced-comment": "off", //注释不做限制 45 | "prefer-destructuring": [ 46 | "error", 47 | { 48 | //申明变量解构有限,赋值可以不必解构 49 | VariableDeclarator: { 50 | array: false, 51 | object: true, 52 | }, 53 | AssignmentExpression: { 54 | array: false, 55 | object: true, 56 | }, 57 | }, 58 | ], 59 | "import/prefer-default-export": "off", 60 | "class-methods-use-this": "off", 61 | "no-underscore-dangle": "off", 62 | "import/no-unresolved": "off", 63 | "@typescript-eslint/no-unused-vars": ["error"], 64 | "arrow-parens": "off", 65 | "object-curly-newline": "off", 66 | "import/no-cycle": "off", 67 | "no-continue": "off", 68 | "array-callback-return": "off", 69 | "arrow-body-style": "off", 70 | "prefer-destructuring": "off", 71 | }, 72 | }; 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/videos/ 6 | /tests/e2e/screenshots/ 7 | 8 | 9 | # local env files 10 | .env.local 11 | .env.*.local 12 | 13 | # Log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | pnpm-debug.log* 18 | 19 | # Editor directories and files 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | #Electron-builder output 29 | /dist_electron -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # 国内源相关配置 2 | ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ 3 | ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/ 4 | registry=https://registry.npmmirror.com -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | registry "https://registry.npmmirror.com" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 舒小凯 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/cli-plugin-babel/preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /local-update.yml: -------------------------------------------------------------------------------- 1 | version: 0.7.0 2 | files: 3 | - url: 快乐摸鱼 Setup 0.7.0.exe 4 | sha512: eu7AKe5n4UWpCBj9vd/pX++MbMV9STKbcLImeMh2hNzzf6yabLC8CPh2V4mkwjQtc374Ho8phAjkXERpl8wOMA== 5 | size: 61702243 6 | path: 快乐摸鱼 Setup 0.7.0.exe 7 | sha512: eu7AKe5n4UWpCBj9vd/pX++MbMV9STKbcLImeMh2hNzzf6yabLC8CPh2V4mkwjQtc374Ho8phAjkXERpl8wOMA== 8 | releaseDate: '2021-09-13T11:08:24.958Z' 9 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/favicon.ico -------------------------------------------------------------------------------- /public/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/font/iconfont.ttf -------------------------------------------------------------------------------- /public/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/font/iconfont.woff -------------------------------------------------------------------------------- /public/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/font/iconfont.woff2 -------------------------------------------------------------------------------- /public/icons/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/1024x1024.png -------------------------------------------------------------------------------- /public/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/128x128.png -------------------------------------------------------------------------------- /public/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/16x16.png -------------------------------------------------------------------------------- /public/icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/24x24.png -------------------------------------------------------------------------------- /public/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/256x256.png -------------------------------------------------------------------------------- /public/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/32x32.png -------------------------------------------------------------------------------- /public/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/48x48.png -------------------------------------------------------------------------------- /public/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/512x512.png -------------------------------------------------------------------------------- /public/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/64x64.png -------------------------------------------------------------------------------- /public/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/icon.icns -------------------------------------------------------------------------------- /public/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/icons/icon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <% if (process.env.NODE_ENV === "production") { %> 11 | 21 | 24 | <% } %> 25 | 26 | 27 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /public/mock-file/mock.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/mock-file/mock.doc -------------------------------------------------------------------------------- /public/mock-file/mock.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/mock-file/mock.docx -------------------------------------------------------------------------------- /public/mock-file/mock.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/mock-file/mock.pdf -------------------------------------------------------------------------------- /public/mock-file/mock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/mock-file/mock.png -------------------------------------------------------------------------------- /public/mock-file/mock.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/mock-file/mock.xls -------------------------------------------------------------------------------- /public/mock-file/mock.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/public/mock-file/mock.xlsx -------------------------------------------------------------------------------- /public/mock-file/mock.zip: -------------------------------------------------------------------------------- 1 | PK -------------------------------------------------------------------------------- /public/sandbox/collection-variables.js: -------------------------------------------------------------------------------- 1 | Object.setPrototypeOf(collectionVariables, { 2 | /** 3 | * 根据变量名称获取变量值 4 | */ 5 | get(variableName) { 6 | return collectionVariables[variableName] 7 | }, 8 | /** 9 | * 设置一个变量 10 | */ 11 | set(variableName, value) { 12 | collectionVariables[variableName] = value; 13 | }, 14 | /** 15 | * 删除一个变量 16 | */ 17 | unset() { 18 | delete collectionVariables[variableName] 19 | }, 20 | /** 21 | * 删除一个变量 22 | */ 23 | delete() { 24 | delete collectionVariables[variableName] 25 | }, 26 | /** 27 | * 更新一个变量 28 | */ 29 | update(variableName, value) { 30 | if (collectionVariables[variableName] != null) { 31 | collectionVariables[variableName] = value; 32 | } 33 | }, 34 | /** 35 | * 更新一个变量,如果没有则新增 36 | */ 37 | upsert(variableName, value) { 38 | collectionVariables[variableName] = value; 39 | }, 40 | /** 41 | * 判断当前变量是否存在 42 | */ 43 | has(variableName) { 44 | return collectionVariables[variableName] != null 45 | }, 46 | /** 47 | * 清空所有变量 48 | */ 49 | clear() { 50 | Object.keys(collectionVariables).forEach(key => { 51 | delete collectionVariables[key] 52 | }) 53 | }, 54 | /** 55 | * 将变量以对象形式输出 56 | */ 57 | toObject() { 58 | return JSON.parse(JSON.stringify(collectionVariables)) 59 | }, 60 | }) -------------------------------------------------------------------------------- /public/sandbox/hook/worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 代码生成钩子函数 3 | */ 4 | 5 | const apidocInfo = {}; 6 | self.addEventListener("message", (e) => { 7 | if (e.data && e.data.type === "generate-code") { 8 | const execResult = eval(` 9 | ${e.data.value} 10 | codeHook(apidocInfo) 11 | `); 12 | const result = (typeof execResult === "object") ? JSON.stringify(execResult, null, 2) : execResult.toString() 13 | self.postMessage({ 14 | type: "success", 15 | value: result 16 | }) 17 | } 18 | if (e.data && e.data.type === "init") { 19 | Object.assign(apidocInfo, e.data.value) 20 | } 21 | }) -------------------------------------------------------------------------------- /public/sandbox/pre-request/global/global.js: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | 全局数据 4 | |-------------------------------------------------------------------------- 5 | | 属性参考: src/@types/global.d.ts/ApidocDetail 6 | */ 7 | const GlobalData = { 8 | /** 9 | * 当前文档id值 10 | */ 11 | _id: "", 12 | /** 13 | * 公共请求头 14 | */ 15 | commonHeaders: {}, 16 | /** 17 | * 文档数据:参考src/@types/global.d.ts/ApidocDetail 18 | */ 19 | apidocInfo: {}, 20 | /** 21 | * 项目内变量 Record 22 | */ 23 | projectVaribles: {}, 24 | /** 25 | * 仅当前接口生效变量 26 | */ 27 | tempVariables: {}, 28 | /** 29 | * 全局安装包 30 | */ 31 | packages: [] 32 | } 33 | -------------------------------------------------------------------------------- /public/sandbox/pre-request/global/import-script.js: -------------------------------------------------------------------------------- 1 | 2 | async function importScript(url) { 3 | if (url.match(/^https?:\/\//)) { 4 | const data = await fetch(url); 5 | const textData = await data.text(); 6 | return textData 7 | } else { 8 | const matchedData = GlobalData.packages.find(v => v.name === url) 9 | if (matchedData) { 10 | return matchedData.code; 11 | } 12 | return "" 13 | } 14 | } -------------------------------------------------------------------------------- /public/sandbox/pre-request/helper/helper.js: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | 全局工具函数 4 | |-------------------------------------------------------------------------- 5 | */ 6 | const Helper = { 7 | /** 8 | * 将数组类型的key,value转换为 9 | */ 10 | convertArrayDataToObjectData(arrData) { 11 | const result = {}; 12 | arrData.forEach(v => { 13 | if (v.key) { 14 | result[v.key] = v.value; 15 | } 16 | }) 17 | return result; 18 | } 19 | } -------------------------------------------------------------------------------- /public/sandbox/pre-request/request/formdata.js: -------------------------------------------------------------------------------- 1 | /** 2 | * formdata请求参数 3 | */ 4 | const _formdata = {}; //为了初始化的时候不执行赋值操作 5 | const formdata = new Proxy(_formdata, { 6 | get(target, key) { 7 | if (typeof target[key] === "object") { 8 | console.warn(`formdata不支持嵌套`); 9 | } else { 10 | return target[key]; 11 | } 12 | }, 13 | set(obj, prop, value) { 14 | let realValue = value; 15 | if (typeof value === "number") { 16 | console.warn( 17 | `formdata在给 【${prop}】 字段赋值时,值不为string类型,将通过toString进行转换` 18 | ); 19 | realValue = value.toString(); 20 | } else if (typeof value !== "string") { 21 | console.warn( 22 | `formdata在给 【${prop}】 字段赋值时出错,formdata类型只能为字符串` 23 | ); 24 | } 25 | obj[prop] = realValue; 26 | self.postMessage({ 27 | type: "pre-request-change-formdata", 28 | value: JSON.parse(JSON.stringify(formdata)), 29 | }); 30 | return true; 31 | }, 32 | deleteProperty(target, prop) { 33 | delete target[prop]; 34 | self.postMessage({ 35 | type: "pre-request-change-formdata", 36 | value: JSON.parse(JSON.stringify(formdata)), 37 | }); 38 | }, 39 | }); 40 | -------------------------------------------------------------------------------- /public/sandbox/pre-request/request/headers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 请求头 3 | */ 4 | const _headers = {}; //为了初始化的时候不执行赋值操作 5 | const headers = new Proxy(_headers, { 6 | get(target, key) { 7 | if (typeof target[key] === "object") { 8 | console.warn(`请求头不支持嵌套`) 9 | } else { 10 | return target[key]; 11 | } 12 | }, 13 | set(obj, prop, value) { 14 | let realValue = value; 15 | if (typeof value === "number") { 16 | console.warn(`请求头在给 【${prop}】 字段赋值时,值不为string类型,将通过toString进行转换`) 17 | realValue = value.toString(); 18 | } else if (typeof value !== "string") { 19 | console.warn(`请求头在给 【${prop}】 字段赋值时出错,请求头类型只能为字符串`) 20 | } 21 | obj[prop] = realValue; 22 | self.postMessage({ 23 | type: "pre-request-change-headers", 24 | value: JSON.parse(JSON.stringify(headers)) 25 | }) 26 | return true; 27 | }, 28 | deleteProperty(target, prop) { 29 | delete target[prop]; 30 | self.postMessage({ 31 | type: "pre-request-change-headers", 32 | value: JSON.parse(JSON.stringify(headers)) 33 | }) 34 | }, 35 | }) -------------------------------------------------------------------------------- /public/sandbox/pre-request/request/json.js: -------------------------------------------------------------------------------- 1 | /** 2 | * json参数 3 | */ 4 | const _json = {}; //为了初始化的时候不执行赋值操作 5 | const jsonValidator = { 6 | get(target, key) { 7 | if (typeof target[key] === "object" && target[key] !== null) { 8 | return new Proxy(target[key], jsonValidator) 9 | } else { 10 | return target[key]; 11 | } 12 | }, 13 | set(obj, prop, value) { 14 | if (typeof value === "object" && value !== null) { 15 | obj[prop] = new Proxy(value, jsonValidator); 16 | } else { 17 | obj[prop] = value; 18 | } 19 | self.postMessage({ 20 | type: "pre-request-change-json-params", 21 | value: JSON.stringify(json), 22 | }); 23 | return true; 24 | }, 25 | deleteProperty(target, prop) { 26 | delete target[prop]; 27 | self.postMessage({ 28 | type: "pre-request-change-json-params", 29 | value: JSON.stringify(json), 30 | }); 31 | }, 32 | } 33 | const json = new Proxy(_json, jsonValidator); 34 | -------------------------------------------------------------------------------- /public/sandbox/pre-request/request/path.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 路径参数 3 | */ 4 | const _pathParams = {}; //为了初始化的时候不执行赋值操作 5 | const pathParams = new Proxy(_pathParams, { 6 | get(target, key) { 7 | if (typeof target[key] === "object") { 8 | console.warn(`path参数不支持嵌套`) 9 | } else { 10 | return target[key]; 11 | } 12 | }, 13 | set(obj, prop, value) { 14 | let realValue = value; 15 | if (typeof value === "number") { 16 | console.warn(`path参数在给 【${prop}】 字段赋值时,值不为string类型,将通过toString进行转换`) 17 | realValue = value.toString(); 18 | } else if (typeof value !== "string") { 19 | console.warn(`path参数在给 【${prop}】 字段赋值时出错,path参数类型只能为字符串`) 20 | } 21 | obj[prop] = realValue; 22 | self.postMessage({ 23 | type: "pre-request-change-path-params", 24 | value: JSON.parse(JSON.stringify(pathParams)) 25 | }) 26 | return true; 27 | }, 28 | deleteProperty(target, prop) { 29 | delete target[prop]; 30 | self.postMessage({ 31 | type: "pre-request-change-path-params", 32 | value: JSON.parse(JSON.stringify(pathParams)) 33 | }) 34 | }, 35 | }) -------------------------------------------------------------------------------- /public/sandbox/pre-request/request/query.js: -------------------------------------------------------------------------------- 1 | /** 2 | * query参数 3 | */ 4 | const _queryParams = {}; //为了初始化的时候不执行赋值操作 5 | const queryParams = new Proxy(_queryParams, { 6 | get(target, key) { 7 | if (typeof target[key] === "object") { 8 | console.warn(`query参数不支持嵌套`) 9 | } else { 10 | return target[key]; 11 | } 12 | }, 13 | set(obj, prop, value) { 14 | let realValue = value; 15 | if (typeof value === "number") { 16 | console.warn(`query参数在给 【${prop}】 字段赋值时,值不为string类型,将通过toString进行转换`) 17 | realValue = value.toString(); 18 | } else if (typeof value !== "string") { 19 | console.warn(`query参数在给 【${prop}】 字段赋值时出错,query参数类型只能为字符串`) 20 | } 21 | obj[prop] = realValue; 22 | self.postMessage({ 23 | type: "pre-request-change-query-params", 24 | value: JSON.parse(JSON.stringify(queryParams)) 25 | }) 26 | return true; 27 | }, 28 | deleteProperty(target, prop) { 29 | delete target[prop]; 30 | self.postMessage({ 31 | type: "pre-request-change-query-params", 32 | value: JSON.parse(JSON.stringify(queryParams)) 33 | }) 34 | }, 35 | }) -------------------------------------------------------------------------------- /public/sandbox/pre-request/request/raw.js: -------------------------------------------------------------------------------- 1 | const rawData = new Proxy({ value: "" }, { 2 | get(target) { 3 | return target.value 4 | }, 5 | set(obj, prop, value) { 6 | obj.value = value; 7 | self.postMessage({ 8 | type: "pre-request-change-raw-params", 9 | value, 10 | }); 11 | return true; 12 | } 13 | }) -------------------------------------------------------------------------------- /public/sandbox/pre-request/request/urlencoded.js: -------------------------------------------------------------------------------- 1 | /** 2 | * urlencoded请求参数 3 | */ 4 | const _urlencoded = {}; //为了初始化的时候不执行赋值操作 5 | const urlencoded = new Proxy(_urlencoded, { 6 | get(target, key) { 7 | if (typeof target[key] === "object") { 8 | console.warn(`urlencoded不支持嵌套`); 9 | } else { 10 | return target[key]; 11 | } 12 | }, 13 | set(obj, prop, value) { 14 | let realValue = value; 15 | if (typeof value === "number") { 16 | console.warn( 17 | `urlencoded在给 【${prop}】 字段赋值时,值不为string类型,将通过toString进行转换` 18 | ); 19 | realValue = value.toString(); 20 | } else if (typeof value !== "string") { 21 | console.warn( 22 | `urlencoded在给 【${prop}】 字段赋值时出错,urlencoded类型只能为字符串` 23 | ); 24 | } 25 | obj[prop] = realValue; 26 | self.postMessage({ 27 | type: "pre-request-change-urlencoded", 28 | value: JSON.parse(JSON.stringify(urlencoded)), 29 | }); 30 | return true; 31 | }, 32 | deleteProperty(target, prop) { 33 | delete target[prop]; 34 | self.postMessage({ 35 | type: "pre-request-change-urlencoded", 36 | value: JSON.parse(JSON.stringify(urlencoded)), 37 | }); 38 | }, 39 | }); 40 | -------------------------------------------------------------------------------- /public/sandbox/pre-request/send-request/send-request.js: -------------------------------------------------------------------------------- 1 | //老版本调用方式 2 | let isSendRequest = false; 3 | const sendRequest = (url, cb) => { 4 | let realUrl = url; 5 | if (!url.toString().match(/^https?:\/\//)) { 6 | realUrl = `http://${url}` 7 | } 8 | isSendRequest = true; 9 | requestCb = cb; 10 | self.postMessage({ 11 | type: "pre-request-send-request", 12 | value: realUrl 13 | }) 14 | } 15 | 16 | const request = (method, url = "", options = {}) => { 17 | isSendRequest = true; 18 | return new Promise((resolve, reject) => { 19 | const { headers = {}, params = {}, body = {} } = options; 20 | let realUrl = url; 21 | if (!url.toString().match(/^https?:\/\//)) { 22 | realUrl = `http://${url}` 23 | } 24 | //发送请求 25 | self.postMessage({ 26 | type: "pre-request-http", 27 | value: { 28 | method, 29 | url: realUrl, 30 | params, 31 | headers, 32 | body, 33 | } 34 | }) 35 | //接受请求 36 | self.addEventListener("message", (e) => { 37 | if (e.data && e.data.type === "pre-request-http-success") { 38 | resolve(e.data.value); 39 | self.postMessage({ 40 | type: "pre-request-finish", 41 | }) 42 | isSendRequest = false; 43 | } 44 | if (e.data && e.data.type === "pre-request-http-error") { 45 | reject(e.data.value); 46 | self.postMessage({ 47 | type: "pre-request-finish", 48 | }) 49 | isSendRequest = false; 50 | } 51 | }) 52 | }) 53 | } 54 | 55 | const http = { 56 | get(url, options) { 57 | return request("GET", url, options); 58 | }, 59 | post(url, options) { 60 | return request("POST", url, options); 61 | }, 62 | put(url, options) { 63 | return request("PUT", url, options); 64 | }, 65 | delete(url, options) { 66 | return request("DELETE", url, options); 67 | }, 68 | } 69 | 70 | const sendRequestById = (id) => { 71 | isSendRequest = true; 72 | return new Promise((resolve, reject) => { 73 | self.postMessage({ 74 | type: "pre-request-send-request-by-id", 75 | value: { 76 | id, 77 | } 78 | }) 79 | }) 80 | } -------------------------------------------------------------------------------- /public/sandbox/pre-request/variables/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 全局变量 3 | */ 4 | const _variables = {}; //为了初始化的时候不执行赋值操作 5 | const variablesValidator = { 6 | get(target, key) { 7 | if (typeof target[key] === "object" && target[key] !== null) { 8 | return new Proxy(target[key], variablesValidator) 9 | } else { 10 | return target[key]; 11 | } 12 | }, 13 | set(obj, prop, value) { 14 | if (typeof value === "object" && value !== null) { 15 | obj[prop] = new Proxy(value, variablesValidator); 16 | } else { 17 | obj[prop] = value; 18 | } 19 | self.postMessage({ 20 | type: "pre-request-change-variables", 21 | value: JSON.parse(JSON.stringify(variables)), 22 | }); 23 | return true; 24 | }, 25 | deleteProperty(target, prop) { 26 | delete target[prop]; 27 | self.postMessage({ 28 | type: "pre-request-change-variables", 29 | value: JSON.parse(JSON.stringify(variables)), 30 | }); 31 | }, 32 | } 33 | const variables = new Proxy(_variables, variablesValidator); 34 | -------------------------------------------------------------------------------- /public/sandbox/url.js: -------------------------------------------------------------------------------- 1 | Object.setPrototypeOf(url, { 2 | 3 | }) -------------------------------------------------------------------------------- /public/sandbox/variables.js: -------------------------------------------------------------------------------- 1 | Object.setPrototypeOf(tempVariables, { 2 | /** 3 | * 根据变量名称获取变量值 4 | */ 5 | get(variableName) { 6 | return tempVariables[variableName] 7 | }, 8 | /** 9 | * 设置一个变量 10 | */ 11 | set(variableName, value) { 12 | tempVariables[variableName] = value; 13 | }, 14 | /** 15 | * 删除一个变量 16 | */ 17 | unset() { 18 | delete tempVariables[variableName] 19 | }, 20 | /** 21 | * 删除一个变量 22 | */ 23 | delete() { 24 | delete tempVariables[variableName] 25 | }, 26 | /** 27 | * 更新一个变量 28 | */ 29 | update(variableName, value) { 30 | if (tempVariables[variableName] != null) { 31 | tempVariables[variableName] = value; 32 | } 33 | }, 34 | /** 35 | * 更新一个变量,如果没有则新增 36 | */ 37 | upsert(variableName, value) { 38 | tempVariables[variableName] = value; 39 | }, 40 | /** 41 | * 判断当前变量是否存在 42 | */ 43 | has(variableName) { 44 | return tempVariables[variableName] != null 45 | }, 46 | /** 47 | * 清空所有变量 48 | */ 49 | clear() { 50 | Object.keys(tempVariables).forEach(key => { 51 | delete tempVariables[key] 52 | }) 53 | }, 54 | /** 55 | * 将变量以对象形式输出 56 | */ 57 | toObject() { 58 | return JSON.parse(JSON.stringify(tempVariables)) 59 | }, 60 | }) -------------------------------------------------------------------------------- /src/@types/globalProperties.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { Store } from "vuex" 3 | import { ElMessageBoxShortcutMethod } from "element-plus" 4 | import { AxiosInstance } from "axios" 5 | import type { Config } from "./config" 6 | import { State } from "@@/store" 7 | import { Helper } from "@@/helper" 8 | // import { MessagePartial } from "element-plus/lib/message/src/message" 9 | import { TreeNodeOptions } from "element-plus/lib/components/tree/src/tree.type" 10 | import { IElDropdownInstance } from "element-plus/lib/dropdown/src/dropdown" 11 | import { ICaceh } from "@/cache/cache" 12 | import { $t } from "@/i18n/i18n" 13 | 14 | type Data = Record; 15 | type Message = { 16 | closeAll(): void; 17 | success: (msg?: string) => void; 18 | warning: (msg?: string) => void; 19 | info: (msg?: string) => void; 20 | error: (msg?: string) => void; 21 | } 22 | 23 | declare module "@vue/runtime-core" { 24 | export interface ComponentCustomProperties { 25 | $refs: { 26 | form: { 27 | validate: (fn: (valid: boolean) => void) => void, 28 | validateField: (field: string) => void, 29 | resetFields: () => void, 30 | $el: HTMLElement, 31 | formInfo: Data, 32 | } 33 | table: { 34 | /** 35 | * 获取表格数据 36 | */ 37 | getData: (params?: T) => Promise, 38 | /** 39 | * 表格数据 40 | */ 41 | tableData: unknown[], 42 | /** 43 | * 表格数据总量 44 | */ 45 | total: number, 46 | $el: HTMLElement, 47 | }, 48 | tree: TreeNodeOptions["store"], 49 | dropdown: IElDropdownInstance, 50 | }, 51 | $store: Store, 52 | $confirm: typeof ElMessageBoxShortcutMethod, 53 | $alert: typeof ElMessageBoxShortcutMethod, 54 | $message: Message, 55 | $nextTick: (fn: () => void) => void, 56 | axios: AxiosInstance, 57 | $helper: Helper, 58 | $t: typeof $t, 59 | config: Config 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/@types/shims-scss.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.scss' { 2 | const content: Record; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /src/@types/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue' 3 | 4 | const component: DefineComponent, Record, unknown> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /src/main/update.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自动更新 3 | * @author shuxiaokai 4 | * @create 2020-09-30 22:28 5 | */ 6 | import path from 'path'; 7 | import { autoUpdater } from 'electron-updater'; 8 | // eslint-disable-next-line import/no-extraneous-dependencies 9 | import { BrowserWindow, ipcMain } from 'electron'; 10 | import config from '../config/config'; 11 | 12 | function update(): void { 13 | const { url } = config.updateConfig; 14 | const winId = BrowserWindow.getFocusedWindow()?.id; 15 | const win = BrowserWindow.fromId(winId as number); 16 | if (process.env.NODE_ENV === 'development') { 17 | autoUpdater.updateConfigPath = path.join(__dirname, '../local-update.yml'); 18 | } 19 | //=====================================render进程事件====================================// 20 | ipcMain.on('vue-check-update', () => { 21 | autoUpdater.checkForUpdates(); 22 | }); 23 | ipcMain.on('vue-quit-and-install', () => { 24 | autoUpdater.quitAndInstall(); 25 | }); 26 | //=====================================参数设置====================================// 27 | autoUpdater.setFeedURL(url); 28 | //=====================================反馈更新事件给render进程====================================// 29 | //存在可用更新 30 | autoUpdater.on('update-available', (progressObj) => { 31 | win?.webContents.send('vue-update-available', progressObj); 32 | }); 33 | //不存在可用更新 34 | autoUpdater.on('update-not-available', (progressObj) => { 35 | win?.webContents.send('vue-update-not-available', progressObj); 36 | }); 37 | //下载完成 38 | autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => { 39 | win?.webContents.send('vue-update-downloaded', { 40 | event, 41 | releaseNotes, 42 | releaseName, 43 | }); 44 | }); 45 | //下载过程 46 | autoUpdater.on('download-progress', (progressObj) => { 47 | win?.webContents.send('vue-download-progress', progressObj); 48 | }); 49 | //更新错误 50 | autoUpdater.on('error', (error) => { 51 | console.error(error); 52 | win?.webContents.send('vue-download-error', error); 53 | }); 54 | } 55 | export default update; 56 | -------------------------------------------------------------------------------- /src/renderer/App.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-08 19:20 4 | 模块名称:首页 5 | 备注: 6 | */ 7 | 10 | 11 | 43 | 44 | 50 | -------------------------------------------------------------------------------- /src/renderer/assets/imgs/apidoc/body-tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/src/renderer/assets/imgs/apidoc/body-tip.png -------------------------------------------------------------------------------- /src/renderer/assets/imgs/apidoc/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/src/renderer/assets/imgs/apidoc/file.png -------------------------------------------------------------------------------- /src/renderer/assets/imgs/apidoc/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/src/renderer/assets/imgs/apidoc/folder.png -------------------------------------------------------------------------------- /src/renderer/assets/imgs/apidoc/prefix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/src/renderer/assets/imgs/apidoc/prefix.gif -------------------------------------------------------------------------------- /src/renderer/assets/imgs/apidoc/prefix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/src/renderer/assets/imgs/apidoc/prefix.png -------------------------------------------------------------------------------- /src/renderer/assets/imgs/apidoc/send-request.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/src/renderer/assets/imgs/apidoc/send-request.gif -------------------------------------------------------------------------------- /src/renderer/assets/imgs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueleaf/moyu/76f36451824cf1df6300dc764adfe821f0543b83/src/renderer/assets/imgs/logo.png -------------------------------------------------------------------------------- /src/renderer/cache/cache.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * apidoc文档缓存 3 | */ 4 | 5 | import { GlobalConfig } from '@@/global'; 6 | 7 | class GlobalCache { 8 | constructor() { 9 | if (!localStorage.getItem('cache/globalConfig')) { 10 | localStorage.setItem('cache/globalConfig', '{}'); 11 | } 12 | } 13 | 14 | /** 15 | * @description 获取全局配置信息 16 | * @author shuxiaokai 17 | * @create 2021-09-06 21:50 18 | */ 19 | getGlobalConfig(): Partial { 20 | try { 21 | const localData: Partial = JSON.parse(localStorage.getItem('cache/globalConfig') || '{}'); 22 | return localData; 23 | } catch (error) { 24 | console.error(error); 25 | localStorage.setItem('cache/globalConfig', '{}') 26 | return {}; 27 | } 28 | } 29 | 30 | /** 31 | * @description 重置全局配置 32 | * @author shuxiaokai 33 | * @create 2021-09-06 21:50 34 | * @param {GlobalConfig} config - 全局配置信息 35 | */ 36 | changeGlobalConfig(config: GlobalConfig): void { 37 | try { 38 | localStorage.setItem('cache/globalConfig', JSON.stringify(config)); 39 | } catch (error) { 40 | console.error(error); 41 | localStorage.setItem('cache/globalConfig', '{}'); 42 | } 43 | } 44 | } 45 | 46 | export const globalCache = new GlobalCache(); 47 | -------------------------------------------------------------------------------- /src/renderer/cache/database.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 数据库和数据表定义 3 | * @author shuxiaokai 4 | * @create 2021-7-13 22:50 5 | */ 6 | import Dexie from 'dexie'; 7 | 8 | type ScriptInfo = { 9 | id?: number, 10 | name: string, 11 | code: string 12 | } 13 | class MoyuDatabase extends Dexie { 14 | scriptList!: Dexie.Table 15 | 16 | public constructor() { 17 | super('moyuDataBase'); 18 | this.version(1).stores({ 19 | scriptList: '++id, name, code' 20 | }); 21 | } 22 | } 23 | 24 | const db = new MoyuDatabase(); 25 | 26 | export default db; 27 | -------------------------------------------------------------------------------- /src/renderer/components/common/card/g-card.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-15 22:22 4 | 模块名称:全局卡片 5 | 备注: 6 | */ 7 | 21 | 22 | 53 | 54 | 90 | -------------------------------------------------------------------------------- /src/renderer/components/common/collapse/g-collapse.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-09-04 15:20 4 | 模块名称:折叠面板 5 | 备注: 6 | */ 7 | 26 | 27 | 67 | 68 | 87 | -------------------------------------------------------------------------------- /src/renderer/components/common/config/g-config.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-09-24 22:47 4 | 模块名称:配置块 5 | 备注: 6 | */ 7 | 27 | 28 | 67 | 68 | 87 | -------------------------------------------------------------------------------- /src/renderer/components/common/contextmenu/g-contextmenu-item.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-30 22:39 4 | 模块名称:contextmenu-item 5 | 备注: 6 | */ 7 | 14 | 15 | 64 | 65 | 93 | -------------------------------------------------------------------------------- /src/renderer/components/common/dialog/g-dialog.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-23 21:14 4 | 模块名称:弹窗组件 5 | 备注: 6 | */ 7 | 24 | 25 | 62 | 63 | 66 | -------------------------------------------------------------------------------- /src/renderer/components/common/download/g-download.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-23 22:36 4 | 模块名称:下载组件 5 | 备注: 6 | */ 7 | 12 | 13 | 73 | 74 | 81 | -------------------------------------------------------------------------------- /src/renderer/components/common/emphasize/g-emphasize.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-29 22:36 4 | 模块名称:文字强调组件 5 | 备注: 6 | */ 7 | 19 | 20 | 98 | 99 | 102 | -------------------------------------------------------------------------------- /src/renderer/components/common/fieldset/g-fieldset.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-28 22:38 4 | 模块名称: 5 | 备注: 6 | */ 7 | 21 | 22 | 42 | 43 | 71 | -------------------------------------------------------------------------------- /src/renderer/components/common/forms/col/g-col.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-21 23:39 4 | 模块名称:el-row el-col 5 | 备注: 6 | */ 7 | 12 | 13 | 64 | 65 | 68 | -------------------------------------------------------------------------------- /src/renderer/components/common/forms/inputs/g-input.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-21 23:48 4 | 模块名称: 5 | 备注: 6 | */ 7 | 21 | 22 | 80 | 81 | 84 | -------------------------------------------------------------------------------- /src/renderer/components/common/forms/search/g-search-item.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-15 22:49 4 | 模块名称:搜索数据项 5 | 备注: 6 | */ 7 | 21 | 22 | 87 | 88 | 91 | -------------------------------------------------------------------------------- /src/renderer/components/common/label-value/g-label-value.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-09-04 15:11 4 | 模块名称:label-value 5 | 备注: 6 | */ 7 | 16 | 17 | 63 | 64 | 88 | -------------------------------------------------------------------------------- /src/renderer/components/common/loading/g-loading.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-23 19:03 4 | 模块名称:加载框 5 | 备注: 6 | */ 7 | 13 | 14 | 45 | 46 | 60 | -------------------------------------------------------------------------------- /src/renderer/components/common/mock-json-editor/registerCompletionItem.ts: -------------------------------------------------------------------------------- 1 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; 2 | 3 | type Suggestions = { 4 | label: { 5 | label: string, 6 | description: string 7 | }, 8 | kind: monaco.languages.CompletionItemKind, 9 | insertText: string, 10 | keyword: string, 11 | sortText?: string 12 | }[] 13 | 14 | const suggestions: Suggestions = [{ 15 | label: { 16 | label: '@name', 17 | description: '中文名称' 18 | }, 19 | kind: monaco.languages.CompletionItemKind.Function, 20 | insertText: '"@name"', 21 | keyword: '@name', 22 | }] 23 | 24 | export function useCompletionItem(): monaco.IDisposable { 25 | return monaco.languages.registerCompletionItemProvider('json', { 26 | triggerCharacters: ['.'], 27 | provideCompletionItems(model, position) { 28 | const currentLineStr = model.getValueInRange({ 29 | startLineNumber: position.lineNumber, 30 | startColumn: 0, 31 | endLineNumber: position.lineNumber, 32 | endColumn: position.column 33 | }); 34 | const lineStrArr = currentLineStr.replace('\t', '').split(' '); 35 | const activeStr = lineStrArr[lineStrArr.length - 1]; 36 | const matchedSuggestions = suggestions.filter(v => { 37 | const activeStrArr = activeStr.split('.'); 38 | const keywordArr = v.keyword.split('.'); 39 | for (let i = 0; i < activeStrArr.length - 1; i += 1) { 40 | if (activeStrArr[i] !== keywordArr[i]) { 41 | return false; 42 | } 43 | } 44 | if (activeStrArr.length < keywordArr.length) return false; 45 | // console.log(v.keyword, activeStr) 46 | const matchedTrigger = v.keyword.includes(activeStr); 47 | return matchedTrigger 48 | }); 49 | const word = model.getWordUntilPosition(position); 50 | const range = { 51 | startLineNumber: position.lineNumber, 52 | endLineNumber: position.lineNumber, 53 | startColumn: word.startColumn, 54 | endColumn: word.endColumn 55 | }; 56 | const result: monaco.languages.CompletionItem[] = matchedSuggestions.map(v => { 57 | const data = { 58 | label: v.label, 59 | kind: v.kind, 60 | insertText: v.insertText, 61 | range, 62 | sortText: v.sortText || v.label.label, 63 | preselect: true 64 | } 65 | return data; 66 | }) 67 | return { 68 | suggestions: result 69 | }; 70 | } 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /src/renderer/components/common/remote-select/g-remote-select-item.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-13 22:31 4 | 模块名称:远程搜索item 5 | 备注: 6 | */ 7 | 12 | 13 | 25 | 26 | 38 | -------------------------------------------------------------------------------- /src/renderer/components/common/sms-button/g-sms-button.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2020-05-19 21:42 4 | 模块名称:短信验证码按钮,具备倒计时功能 5 | 备注: 6 | */ 7 | 10 | 11 | 98 | 99 | 102 | -------------------------------------------------------------------------------- /src/renderer/components/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | 3 | export function registeGlobalComponent(app: App): void { 4 | const requireComponent = require.context( 5 | // 其组件目录的相对路径 6 | './', 7 | // 是否查询其子目录 8 | true, 9 | // 匹配基础组件文件名的正则表达式 10 | /g-.+\.(vue|js)$/, 11 | ); 12 | requireComponent.keys().forEach((fileName: string) => { 13 | // 获取组件配置 14 | const componentConfig = requireComponent(fileName); 15 | let componentName = ''; 16 | const gName = fileName.match(/\/([^/]*)\.(vue|js)/) 17 | if (!gName) { 18 | throw new Error('公共组件必须在components下'); 19 | } else { 20 | componentName = `s-${gName[1].replace(/g-/, '')}`; 21 | } 22 | app.component(componentName, componentConfig.default || componentConfig) 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /src/renderer/helper/tips.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 提示信息 3 | */ 4 | export default [ 5 | '【接口管理】Ctrl+鼠标左键可以对banner进行批量操作', 6 | '【接口管理】按住ctrl移动到菜单上可以查看菜单详情', 7 | ]; 8 | -------------------------------------------------------------------------------- /src/renderer/i18n/en.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 基于Vue和Electron的接口文档工具: '基于Vue和Electron的接口文档工具', 3 | 项目列表: '项目列表', 4 | } 5 | -------------------------------------------------------------------------------- /src/renderer/i18n/i18n.ts: -------------------------------------------------------------------------------- 1 | import { App, ref, Ref } from 'vue'; 2 | import { Language } from '@@/global'; 3 | import zhCn from './zh-cn' 4 | import zhTw from './zh-tw' 5 | import en from './en' 6 | 7 | //=========================================================================// 8 | let localLanguage = localStorage.getItem('language') as (Language | null); 9 | if (!localLanguage) { 10 | localLanguage = 'zh-cn'; 11 | } else if (localLanguage !== 'en' && localLanguage !== 'ja' && localLanguage !== 'zh-cn' && localLanguage !== 'zh-tw') { 12 | localLanguage = 'zh-cn'; 13 | } 14 | const languageType: Ref = ref(localLanguage); 15 | //=========================================================================// 16 | function replaceVariable(rawStr: string, replacement?: Record): string { 17 | if (!rawStr) { 18 | return '' 19 | } 20 | const hasSlot = rawStr.match(/\{[^}]+\}/g); 21 | let result = '' 22 | if (hasSlot && replacement) { 23 | result = rawStr.replace(/\{([^}]+)\}/g, (foo, key) => { 24 | const replaceVal = replacement[key]; 25 | return replaceVal || ''; 26 | }) 27 | } else { 28 | return rawStr; 29 | } 30 | return `${result}`; 31 | } 32 | 33 | export const $t = (str: string, replacement?: Record): string => { 34 | const cnValue = (zhCn as Record)[str]; 35 | if (languageType.value === 'zh-cn') { 36 | const mapedStr = (zhCn as Record)[str] || ''; 37 | if (!mapedStr) { 38 | console.warn('未匹配到当前字段的翻译信息', str) 39 | return str 40 | } 41 | return replaceVariable(mapedStr, replacement); 42 | } 43 | if (languageType.value === 'zh-tw') { 44 | const mapedStr = (zhTw as Record)[str] || (zhCn as Record)[str]; 45 | if (!mapedStr) { 46 | console.warn('未匹配到當前字段的翻譯信息', str) 47 | } 48 | return replaceVariable(mapedStr, replacement); 49 | } 50 | if (languageType.value === 'en') { 51 | const mapedStr = (en as Record)[str] || (zhCn as Record)[str]; 52 | if (!mapedStr) { 53 | console.warn('translation error', str) 54 | } 55 | return replaceVariable(mapedStr, replacement); 56 | } 57 | return cnValue; 58 | } 59 | export default { 60 | install(app: App): void { 61 | app.config.globalProperties.$t = $t; 62 | }, 63 | } 64 | //改变当前语言 65 | export const changeLanguage = (type: Language): void => { 66 | languageType.value = type; 67 | localStorage.setItem('language', type); 68 | } 69 | -------------------------------------------------------------------------------- /src/renderer/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import ElementPlus from 'element-plus'; 3 | import { createPinia } from 'pinia' 4 | import zhCn from 'element-plus/es/locale/lang/zh-cn' 5 | import config from '@/../config/config' 6 | import { axiosPlugin } from '@/api/api' 7 | import * as helper from '@/helper/index' 8 | import 'element-plus/dist/index.css' 9 | import { mockServer } from '@/server/mock/mock-server' 10 | import '@/../../public/font/iconfont' 11 | import '@/../../public/font/iconfont.css' 12 | import { registeGlobalComponent } from '@/components' 13 | import '@/assets/css/index.css' 14 | import i18n from '@/i18n/i18n' 15 | import App from './App.vue' 16 | import { router } from './router' 17 | import registeDirective from './directive/directive'; 18 | import { store, key } from './store' 19 | import db from './cache/database'; 20 | 21 | mockServer(); 22 | const app = createApp(App) 23 | const pinia = createPinia() 24 | 25 | app.config.globalProperties.$helper = helper; //挂载全局辅助函数 26 | app.config.globalProperties.config = config; //挂载全局辅助函数 27 | app.config.globalProperties.db = db; //挂载全局数据库 28 | 29 | registeGlobalComponent(app); //注册全局组件 30 | registeDirective(app); //注册全局指令 31 | app.use(pinia) 32 | app.use(store, key); 33 | app.use(axiosPlugin).use(ElementPlus, { locale: zhCn }).use(router).use(i18n); 34 | app.mount('#app') 35 | -------------------------------------------------------------------------------- /src/renderer/mixin/computed/index.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /src/renderer/mixin/data/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 全局Data混入,提供一些常用数据,主要为配置相关数据 3 | * @author shuxiaokai 4 | * @create 2020-09-30 22:55 5 | */ 6 | 7 | import config from '@/../config/config' 8 | 9 | export default { 10 | config, 11 | }; 12 | -------------------------------------------------------------------------------- /src/renderer/mixin/filters/index.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /src/renderer/mixin/index.ts: -------------------------------------------------------------------------------- 1 | import computed from './computed'; 2 | import props from './props'; 3 | import filters from './filters'; 4 | 5 | export default { 6 | filters, 7 | props, 8 | computed, 9 | }; 10 | -------------------------------------------------------------------------------- /src/renderer/mixin/methods/index.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /src/renderer/mixin/methods/tips.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | '大部分情况下你可以使用鼠标右键进行快捷操作', 3 | '【接口管理】按住ctrl移动到菜单上可以查看菜单详情', 4 | ]; 5 | -------------------------------------------------------------------------------- /src/renderer/mixin/props/index.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /src/renderer/pages/layout/404/404.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-10 21:39 4 | 模块名称:404页面 5 | 备注: 6 | */ 7 | 14 | 15 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/banner/composables/banner-data.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取banner数据 3 | */ 4 | 5 | import { useRoute } from 'vue-router' 6 | import { useStore } from '@/store/index' 7 | 8 | type ReturnData = { 9 | /** 10 | * 获取banner数据 11 | */ 12 | getBannerData: () => Promise, 13 | }; 14 | 15 | export function useBannerData(): ReturnData { 16 | const store = useStore(); 17 | const route = useRoute() 18 | const projectId = route.query.id; 19 | const getBannerData = async () => { 20 | if (store.state['apidoc/banner'].loading) { 21 | return 22 | } 23 | store.commit('apidoc/banner/changeBannerLoading', true) 24 | await store.dispatch('apidoc/banner/getDocBanner', { projectId }); 25 | store.commit('apidoc/banner/changeBannerLoading', false) 26 | } 27 | getBannerData(); 28 | return { 29 | getBannerData, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/banner/tool/operations.ts: -------------------------------------------------------------------------------- 1 | import { $t } from '@/i18n/i18n'; 2 | 3 | export default [{ 4 | name: $t('新增文件夹'), 5 | icon: '#iconxinzengwenjian', 6 | op: 'addRootFolder', 7 | shortcut: [], 8 | pin: true, 9 | }, { 10 | name: $t('新增文件'), 11 | icon: '#iconwenjian', 12 | op: 'addRootFile', 13 | shortcut: [], 14 | pin: true, 15 | }, { 16 | name: $t('刷新banner'), 17 | icon: '#iconshuaxin', 18 | op: 'freshBanner', 19 | shortcut: [], 20 | pin: true, 21 | viewOnly: true, 22 | }, { 23 | name: $t('全局设置'), 24 | icon: '#iconshezhi', 25 | op: 'config', 26 | shortcut: ['Ctrl', ','], 27 | pin: true, 28 | }, { 29 | name: $t('回收站'), 30 | icon: '#iconhuishouzhan', 31 | op: 'recycler', 32 | shortcut: ['Ctrl', 'Alt', 'R'], 33 | pin: true, 34 | }, { 35 | name: $t('在线链接'), 36 | icon: '#iconlink', 37 | op: 'generateLink', 38 | shortcut: ['Ctrl', 'L'], 39 | pin: false, 40 | }, { 41 | name: $t('导出文档'), 42 | icon: '#icondaochu1', 43 | op: 'exportDoc', 44 | shortcut: ['Ctrl', 'E'], 45 | pin: false, 46 | }, { 47 | name: $t('导入文档'), 48 | icon: '#icondaoru', 49 | op: 'importDoc', 50 | shortcut: ['Ctrl', 'I'], 51 | pin: false, 52 | }, { 53 | name: $t('操作审计'), 54 | icon: '#iconlishi', 55 | op: 'history', 56 | shortcut: ['Ctrl', 'H'], 57 | pin: false, 58 | viewOnly: true, 59 | }, { 60 | name: $t('生成代码'), 61 | icon: '#iconshengchengdaima', 62 | op: 'hook', 63 | shortcut: ['Ctrl', 'H'], 64 | pin: false, 65 | viewOnly: true, 66 | }, { 67 | name: $t('接口编排'), 68 | icon: '#iconbianpaixin', 69 | op: 'apiflow', 70 | shortcut: [], 71 | pin: false, 72 | viewOnly: true, 73 | }]; 74 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/operation/composables/host.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Host相关处理 4 | |-------------------------------------------------------------------------- 5 | | 6 | */ 7 | import { ref, Ref, computed, WritableComputedRef, ComputedRef } from 'vue' 8 | // import { handleFormatUrl } from "./url" 9 | import type { ApidocProjectHost } from '@@/store' 10 | import { useStore } from '@/store/index' 11 | import globalConfig from '@/../config/config' 12 | import { apidocCache } from '@/cache/apidoc' 13 | import { router } from '@/router/index' 14 | 15 | type HostReturn = { 16 | /** 17 | * mock服务器地址 18 | */ 19 | mockServer: Ref, 20 | /** 21 | * host弹窗 22 | */ 23 | hostDialogVisible: Ref, 24 | /** 25 | * host值 26 | */ 27 | host: WritableComputedRef, 28 | /** 29 | * host枚举值 30 | */ 31 | hostEnum: ComputedRef, 32 | /** 33 | * 改变host值 34 | */ 35 | handleChangeHost: (host: string | number | boolean) => void, 36 | } 37 | 38 | export default (): HostReturn => { 39 | const store = useStore(); 40 | //mock服务器地址 41 | const mockServer = computed(() => `http://${globalConfig.renderConfig.mock.ip}:${store.state['apidoc/mock'].mockServerPort}`); 42 | //host弹窗 43 | const hostDialogVisible = ref(false); 44 | //host值 45 | const host = computed({ 46 | get() { 47 | return store.state['apidoc/apidoc'].apidoc.item.url.host 48 | }, 49 | set(val) { 50 | store.commit('apidoc/apidoc/changeApidocHost', val); 51 | }, 52 | }); 53 | //改变host的值 54 | const handleChangeHost = (server: string | number | boolean) => { 55 | const projectId = router.currentRoute.value.query.id as string; 56 | apidocCache.setPreviousServer(projectId, server as string); 57 | } 58 | //host枚举值 59 | const hostEnum = computed(() => { 60 | const projectId = router.currentRoute.value.query.id as string; 61 | const localData: Ref = ref([]) 62 | localData.value = apidocCache.getApidocServer(projectId) 63 | return store.state['apidoc/baseInfo'].hosts.concat(localData.value) 64 | }) 65 | return { 66 | mockServer, 67 | hostDialogVisible, 68 | host, 69 | hostEnum, 70 | handleChangeHost, 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/operation/composables/method.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | 请求方法相关处理 4 | |-------------------------------------------------------------------------- 5 | | 6 | */ 7 | import { ComputedRef, computed, WritableComputedRef } from 'vue' 8 | import type { ApidocRequestMethodRule } from '@@/store' 9 | import { useStore } from '@/store/index' 10 | import { $t } from '@/i18n/i18n' 11 | 12 | type MethodReturn = { 13 | /** 14 | * 请求地址 15 | */ 16 | requestMethod: WritableComputedRef, 17 | /** 18 | * 请求方法枚举 19 | */ 20 | requestMethodEnum: ComputedRef, 21 | /** 22 | * 禁用请求方法后提示信息 23 | */ 24 | disabledTip: (item: ApidocRequestMethodRule) => void, 25 | } 26 | 27 | export default (): MethodReturn => { 28 | const store = useStore(); 29 | //请求方法 30 | const requestMethod = computed({ 31 | get() { 32 | return store.state['apidoc/apidoc'].apidoc.item.method; 33 | }, 34 | set(method: string) { 35 | store.commit('apidoc/apidoc/changeApidocMethod', method) 36 | }, 37 | }); 38 | //禁用请求方法后提示信息 39 | const disabledTip = (item: ApidocRequestMethodRule) => { 40 | if (!item.enabled) { 41 | return $t('当前请求方法被禁止,可以在全局配置中进行相关配置'); 42 | } 43 | return ''; 44 | } 45 | //请求方法枚举 46 | const requestMethodEnum = computed(() => store.state['apidoc/baseInfo'].rules.requestMethods); 47 | 48 | return { 49 | requestMethod, 50 | disabledTip, 51 | requestMethodEnum, 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/operation/composables/operation.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | 请求操作:刷新、保存接口、发送请求等 4 | |-------------------------------------------------------------------------- 5 | | 6 | */ 7 | import { ref, Ref, computed } from 'vue' 8 | import { useStore } from '@/store/index' 9 | import { router } from '@/router/index' 10 | import { sendRequest, stopRequest } from '@/server/request/request' 11 | import { apidocCache } from '@/cache/apidoc' 12 | 13 | type OperationReturn = { 14 | /** 15 | * 保存接口 16 | */ 17 | loading2: Ref, 18 | /** 19 | * 刷新接口 20 | */ 21 | loading3: Ref, 22 | /** 23 | * 发送请求 24 | */ 25 | handleSendRequest: () => void, 26 | /** 27 | * 停止请求 28 | */ 29 | handleStopRequest: () => void, 30 | /** 31 | * 刷新文档 32 | */ 33 | handleFreshApidoc: () => void, 34 | } 35 | 36 | export default (): OperationReturn => { 37 | const store = useStore(); 38 | const loading2 = ref(false); //保存接口 39 | const loading3 = ref(false); //刷新接口 40 | const projectId = router.currentRoute.value.query.id as string; 41 | const currentSelectTab = computed(() => { 42 | const tabs = store.state['apidoc/tabs'].tabs[projectId]; 43 | const currentTab = tabs?.find((tab) => tab.selected) || null; 44 | return currentTab; 45 | }); 46 | //发送请求 47 | const handleSendRequest = () => { 48 | sendRequest(); 49 | } 50 | //停止请求 51 | const handleStopRequest = () => { 52 | stopRequest(); 53 | }; 54 | //刷新文档 55 | const handleFreshApidoc = () => { 56 | loading3.value = true; 57 | store.commit('apidoc/response/clearResponseInfo') 58 | if (currentSelectTab.value) { 59 | apidocCache.deleteResponse(currentSelectTab.value._id); 60 | } 61 | if (currentSelectTab.value?._id.startsWith('local_')) { //通过+按钮新增的空白文档 62 | const cpOriginApidoc = store.state['apidoc/apidoc'].originApidoc; 63 | store.commit('apidoc/apidoc/changeApidoc', JSON.parse(JSON.stringify(cpOriginApidoc))) 64 | loading3.value = false; 65 | return; 66 | } 67 | store.dispatch('apidoc/apidoc/getApidocDetail', { 68 | id: currentSelectTab.value?._id, 69 | projectId, 70 | }).then(() => { 71 | loading3.value = false; 72 | }) 73 | }; 74 | return { 75 | loading2, 76 | loading3, 77 | handleSendRequest, 78 | handleStopRequest, 79 | // handleSaveApidoc, 80 | handleFreshApidoc, 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/operation/tag/tag.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-19 21:37 4 | 模块名称: 5 | 备注: 6 | */ 7 | 10 | 11 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/after-request/after-request.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-12-08 21:12 4 | 模块名称:前置脚本 5 | 备注: 6 | */ 7 | 12 | 13 | 28 | 29 | 38 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/after-request/editor/registerHoverProvider.ts: -------------------------------------------------------------------------------- 1 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; 2 | 3 | export function useHoverProvider(): monaco.IDisposable { 4 | return monaco.languages.registerHoverProvider('javascript', { 5 | provideHover(model, position) { 6 | const wordInfo = model.getWordAtPosition(position); 7 | if (wordInfo?.word !== 'pm') { 8 | return null; 9 | } 10 | return { 11 | range: new monaco.Range( 12 | position.lineNumber, 13 | position.column, 14 | model.getLineCount(), 15 | model.getLineMaxColumn(model.getLineCount()) 16 | ), 17 | contents: [ 18 | { value: '**标题**' }, 19 | ] 20 | }; 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/body/dialog/body-use-case/body-use-case.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 模块名称:body参数用例 4 | 备注: 5 | */ 6 | 19 | 20 | 76 | 77 | 80 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/body/dialog/params-template/params-template.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-29 10:49 4 | 模块名称:保存参数为模板 5 | 备注: 6 | */ 7 | 18 | 19 | 74 | 75 | 78 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/headers/mind-headers.ts: -------------------------------------------------------------------------------- 1 | import { apidocGenerateProperty, uuid } from '@/helper' 2 | import { ApidocProperty } from '@@/global'; 3 | 4 | //https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers 5 | const standarHeaders = [{ 6 | name: 'Accept', 7 | description: '用户代理期望的MIME 类型列表', 8 | }, { 9 | name: 'Accept-Charset', 10 | description: '列出用户代理支持的字符集', 11 | }, { 12 | name: 'Accept-Encoding', 13 | description: '列出用户代理支持的压缩方法', 14 | }, { 15 | name: 'Accept-Language', 16 | description: '列出用户代理期望的页面语言', 17 | }, { 18 | name: 'Access-Control-Allow-Credentials', 19 | description: '跨域头,是否允许携带凭证', 20 | }, { 21 | name: 'Access-Control-Allow-Origin', 22 | description: '跨域头,允许跨域的origin', 23 | }, { 24 | name: 'Access-Control-Allow-Methods', 25 | description: '跨域头,允许跨域的请求方法', 26 | }, { 27 | name: 'Access-Control-Allow-Headers', 28 | description: '跨域头,允许客户端添加额外的HTTP请求头', 29 | }, { 30 | name: 'Access-Control-Max-Age', 31 | description: '跨域头,多长时间内不再发送预请求', 32 | }, { 33 | name: 'Access-Control-Expose-Headers', 34 | description: '跨域头,允许客户端获取的额外请求头', 35 | }, { 36 | name: 'Accept', 37 | description: '用户代理期望的MIME 类型列表', 38 | }, { 39 | name: 'Cookie', 40 | description: 'Cookie', 41 | }] 42 | 43 | const headers: ApidocProperty[] = [{ 44 | _id: uuid(), 45 | key: 'Authorization', 46 | value: '', 47 | type: 'string', 48 | required: true, 49 | description: '服务器用于验证用户代理身份的凭证', 50 | select: true, 51 | editor: '', 52 | editorId: '', 53 | children: [], 54 | }] 55 | standarHeaders.forEach(header => { 56 | const property = apidocGenerateProperty(); 57 | property.key = header.name; 58 | property.description = header.description; 59 | headers.push(property) 60 | }) 61 | 62 | export default headers 63 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/mock/components/mock-headers/mock-headers.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 模块名称:自定义返回头 4 | 备注: 5 | */ 6 | 11 | 12 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/mock/components/mock-response/components/custom-editor.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-12-12 12:27 4 | 模块名称:monaco-editor 5 | 备注: 6 | */ 7 | 11 | 12 | 77 | 78 | 86 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/mock/components/mock-response/components/registerHoverProvider.ts: -------------------------------------------------------------------------------- 1 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; 2 | 3 | export function useHoverProvider(): monaco.IDisposable { 4 | return monaco.languages.registerHoverProvider('javascript', { 5 | provideHover(model, position) { 6 | const wordInfo = model.getWordAtPosition(position); 7 | if (wordInfo?.word !== 'pm') { 8 | return null; 9 | } 10 | return { 11 | range: new monaco.Range( 12 | position.lineNumber, 13 | position.column, 14 | model.getLineCount(), 15 | model.getLineMaxColumn(model.getLineCount()) 16 | ), 17 | contents: [ 18 | { value: '**标题**' }, 19 | ] 20 | }; 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/params/params.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-20 22:30 4 | 模块名称:query参数、path参数 5 | 备注: 6 | */ 7 | 16 | 17 | 38 | 46 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/pre-request/editor/registerHoverProvider.ts: -------------------------------------------------------------------------------- 1 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; 2 | 3 | export function useHoverProvider(): monaco.IDisposable { 4 | return monaco.languages.registerHoverProvider('javascript', { 5 | provideHover(model, position) { 6 | const wordInfo = model.getWordAtPosition(position); 7 | if (wordInfo?.word !== 'pm') { 8 | return null; 9 | } 10 | return { 11 | range: new monaco.Range( 12 | position.lineNumber, 13 | position.column, 14 | model.getLineCount(), 15 | model.getLineMaxColumn(model.getLineCount()) 16 | ), 17 | contents: [ 18 | { value: '**标题**' }, 19 | ] 20 | }; 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/pre-request/pre-request.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-12-08 21:12 4 | 模块名称:前置脚本 5 | 备注: 6 | */ 7 | 12 | 13 | 28 | 29 | 36 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/remarks/remarks.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-12-02 21:22 4 | 模块名称: 5 | 备注: 6 | */ 7 | 10 | 11 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/response/children/mime.ts: -------------------------------------------------------------------------------- 1 | export default [{ 2 | title: '常用', 3 | values: [{ 4 | alias: 'JSON', 5 | mimeType: 'application/json' 6 | }, { 7 | alias: 'SVG', 8 | mimeType: 'image/svg+xml' 9 | }, { 10 | alias: 'HTM,HTML', 11 | mimeType: 'text/html' 12 | }, { 13 | alias: 'CSV', 14 | mimeType: 'text/csv' 15 | }, { 16 | alias: 'GIF', 17 | mimeType: 'image/gif' 18 | }, { 19 | alias: 'JPEG JPG', 20 | mimeType: 'image/jpeg' 21 | }, { 22 | alias: 'PNG', 23 | mimeType: 'image/png' 24 | }, { 25 | alias: 'PDF', 26 | mimeType: 'application/pdf' 27 | }, { 28 | alias: 'application/octet-stream', 29 | mimeType: 'application/octet-stream' 30 | }, { 31 | alias: 'text/plain', 32 | mimeType: 'text/plain' 33 | }] 34 | }, { 35 | title: '办公文件', 36 | values: [{ 37 | alias: 'DOC', 38 | mimeType: 'application/msword' 39 | }, { 40 | alias: 'DOCX', 41 | mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' 42 | }, { 43 | alias: 'XLS', 44 | mimeType: 'application/vnd.ms-excel' 45 | }, { 46 | alias: 'XLSX', 47 | mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 48 | }] 49 | }, { 50 | title: '文本类型', 51 | values: [{ 52 | alias: 'text/plain', 53 | mimeType: 'text/plain' 54 | }, { 55 | alias: 'text/css', 56 | mimeType: 'text/css' 57 | }, { 58 | alias: 'text/html', 59 | mimeType: 'text/html' 60 | }, { 61 | alias: 'text/javascript', 62 | mimeType: 'text/javascript' 63 | }, { 64 | alias: 'XML', 65 | mimeType: 'application/xml' 66 | }] 67 | }, { 68 | title: '图片类型', 69 | values: [{ 70 | alias: 'GIF', 71 | mimeType: 'image/gif' 72 | }, { 73 | alias: 'JPG JPEG', 74 | mimeType: 'image/jpeg' 75 | }, { 76 | alias: 'PNG', 77 | mimeType: 'image/png' 78 | }, { 79 | alias: 'SVG', 80 | mimeType: 'image/svg+xml' 81 | }] 82 | }, { 83 | title: '音视频', 84 | values: [{ 85 | alias: 'audio/webm', 86 | mimeType: 'audio/webm' 87 | }, { 88 | alias: 'video/webm', 89 | mimeType: 'video/webm' 90 | }, { 91 | alias: 'audio/ogg', 92 | mimeType: 'audio/ogg' 93 | }, { 94 | alias: 'video/ogg', 95 | mimeType: 'video/ogg' 96 | }, { 97 | alias: 'application/ogg', 98 | mimeType: 'application/ogg' 99 | }] 100 | }] 101 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/response/children/mime.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-11-30 17:02 4 | 模块名称:返回格式popover 5 | 备注: 6 | */ 7 | 24 | 25 | 36 | 37 | 58 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/response/children/status.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-11-30 17:02 4 | 模块名称:状态码popover 5 | 备注: 6 | */ 7 | 24 | 25 | 38 | 39 | 60 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/response/compsables/import-params.ts: -------------------------------------------------------------------------------- 1 | import { ref, Ref } from 'vue' 2 | import type { ApidocProperty, ApidocPropertyType } from '@@/global' 3 | import { forEachForest } from '@/helper'; 4 | import { store } from '@/store/index' 5 | 6 | type Response = { 7 | importParamsdialogVisible: Ref; 8 | handleOpenImportParams: (index: number) => void; 9 | handleConvertSuccess: (result: ApidocProperty[]) => void; 10 | } 11 | 12 | export default function useImportParams(): Response { 13 | const importParamsdialogVisible = ref(false); //导入参数弹窗 14 | const currentEditResponseIndex = ref(0); 15 | //打开导入参数弹窗 16 | const handleOpenImportParams = (index: number) => { 17 | currentEditResponseIndex.value = index; 18 | importParamsdialogVisible.value = true; 19 | } 20 | //处理导入成功回调 21 | const handleConvertSuccess = (result: ApidocProperty[]) => { 22 | const responseMindParams = store.state['apidoc/baseInfo'].mindParams.filter(v => v.paramsPosition === 'responseParams') 23 | forEachForest(result, (data) => { 24 | const matchedData = responseMindParams.find(v => v.key === data.key); 25 | const isSimple = data.type === 'string' || data.type === 'boolean' || data.type === 'number' 26 | if (matchedData && isSimple && (data.value == null || data.value === '')) { 27 | data.value = matchedData.value; 28 | } 29 | if (matchedData && (data.description == null || data.description === '')) { 30 | data.description = matchedData.description; 31 | } 32 | }) 33 | store.commit('apidoc/apidoc/changeResponseByIndex', { 34 | index: currentEditResponseIndex.value, 35 | value: result, 36 | }); 37 | } 38 | return { 39 | importParamsdialogVisible, 40 | handleOpenImportParams, 41 | handleConvertSuccess 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/response/compsables/params-template.ts: -------------------------------------------------------------------------------- 1 | import { ref, Ref, computed, ComputedRef, onMounted, onBeforeUnmount } from 'vue' 2 | import { ApidocProjectParamsTemplate } from '@@/store' 3 | import { router } from '@/router/index' 4 | import { store } from '@/store/index' 5 | import { $t } from '@/i18n/i18n' 6 | 7 | type Response = { 8 | showTemplateIndex: Ref; 9 | templateFilterString: Ref; 10 | paramsTemplatedialogVisible: Ref; 11 | jsonTemplateList: ComputedRef; 12 | curentOperationIndex: Ref; 13 | handleOpenTempateTab: () => void; 14 | handleOpenTemplateDialog: (index: number) => void; 15 | } 16 | 17 | export default function useImportParams(): Response { 18 | const showTemplateIndex = ref(-1);//是否显示模板 19 | const templateFilterString = ref('');//模板过滤参数 20 | const paramsTemplatedialogVisible = ref(false); //模板维护弹窗 21 | const curentOperationIndex = ref(0); //当前操作数据index值 22 | //模板列表 23 | const jsonTemplateList = computed(() => { 24 | const templates = store.state['apidoc/baseInfo'].paramsTemplate; 25 | const result = templates.filter(template => template.presetParamsType === 'responseParams').filter(template => { 26 | if (!templateFilterString.value) { 27 | return true; 28 | } 29 | return template.name.includes(templateFilterString.value); 30 | }) 31 | return result; 32 | }) 33 | const projectId = router.currentRoute.value.query.id as string; 34 | const handleOpenTempateTab = () => { 35 | store.commit('apidoc/tabs/addTab', { 36 | _id: 'paramsTemplate', 37 | projectId, 38 | tabType: 'paramsTemplate', 39 | label: $t('模板维护'), 40 | head: { 41 | icon: 'iconvariable', 42 | color: '' 43 | }, 44 | saved: true, 45 | fixed: true, 46 | selected: true, 47 | }); 48 | } 49 | //打开保存参数模板弹窗 50 | const handleOpenTemplateDialog = (index: number) => { 51 | paramsTemplatedialogVisible.value = true; 52 | curentOperationIndex.value = index; 53 | } 54 | //处理模板点击空白区域关闭 55 | const bindClick = () => { 56 | showTemplateIndex.value = -1; 57 | } 58 | onMounted(() => { 59 | document.documentElement.addEventListener('click', bindClick) 60 | }) 61 | onBeforeUnmount(() => { 62 | document.documentElement.removeEventListener('click', bindClick) 63 | }) 64 | return { 65 | showTemplateIndex, 66 | paramsTemplatedialogVisible, 67 | templateFilterString, 68 | jsonTemplateList, 69 | curentOperationIndex, 70 | handleOpenTempateTab, 71 | handleOpenTemplateDialog, 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/params/response/dialog/params-template/params-template.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-29 10:49 4 | 模块名称:保存参数为模板 5 | 备注: 6 | */ 7 | 18 | 19 | 81 | 82 | 85 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/response/cookie/cookie.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-09-03 20:45 4 | 模块名称:返回cookie 5 | 备注: 6 | */ 7 | 25 | 26 | 47 | 48 | 61 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apidoc/response/headers/headers.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-09-03 20:45 4 | 模块名称:返回header 5 | 备注: 6 | */ 7 | 19 | 20 | 49 | 50 | 64 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apiflow/components/line/line.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 34 | 35 | 40 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/apiflow/components/selection/selection.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/guide/guide.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-15 16:28 4 | 模块名称:引导界面 5 | 备注: 6 | */ 7 | 25 | 26 | 68 | 69 | 84 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/hook/components/editor/editor.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-12-12 12:27 4 | 模块名称:monaco-editor 5 | 备注: 6 | */ 7 | 10 | 11 | 73 | 74 | 80 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/hook/components/editor/registerHoverProvider.ts: -------------------------------------------------------------------------------- 1 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; 2 | 3 | export function useHoverProvider(): monaco.IDisposable { 4 | return monaco.languages.registerHoverProvider('javascript', { 5 | provideHover(model, position) { 6 | const wordInfo = model.getWordAtPosition(position); 7 | if (wordInfo?.word !== 'pm') { 8 | return null; 9 | } 10 | return { 11 | range: new monaco.Range( 12 | position.lineNumber, 13 | position.column, 14 | model.getLineCount(), 15 | model.getLineMaxColumn(model.getLineCount()) 16 | ), 17 | contents: [ 18 | { value: '**标题**' }, 19 | ] 20 | }; 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/content/hook/hook.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2022-01-01 20:41 4 | 模块名称:接口转换功能 5 | 备注: 6 | */ 7 | 19 | 20 | 43 | 44 | 49 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/dialog/add-file/add-file.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-02 21:25 4 | 模块名称:新增一个文档 5 | 备注: 6 | */ 7 | 18 | 19 | 76 | 77 | 80 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-edit/dialog/add-folder/add-folder.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-02 21:25 4 | 模块名称:新增一个文件夹 5 | 备注: 6 | */ 7 | 18 | 19 | 76 | 77 | 80 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-list/dialog/permission/permission.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-20 19:21 4 | 模块名称:成员管理 5 | 备注: 6 | */ 7 | 16 | 17 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-list/dialog/permission/setting/setting.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-20 2:39 4 | 模块名称:项目用户设置 5 | 备注: 6 | */ 7 | 10 | 11 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-list/doc-list.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-13 21:24 4 | 模块名称:文档列表 5 | 备注: 6 | */ 7 | 34 | 35 | 43 | 44 | 56 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-list/tab-b/tab-b.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-13 22:23 4 | 模块名称:团队管理 5 | 备注: 6 | */ 7 | 10 | 11 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/App.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-08 19:20 4 | 模块名称:首页 5 | 备注: 6 | */ 7 | 12 | 13 | 55 | 56 | 62 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' 2 | import check from '../check/check.vue' 3 | import view from '../view/view.vue' 4 | //=====================================路由====================================// 5 | const routes: Array = [ 6 | { 7 | path: '/', 8 | redirect: process.env.VUE_APP_BUILD_SHARE ? '/check' : '/view', 9 | }, 10 | { 11 | path: '/view', 12 | name: 'View', 13 | component: view, 14 | }, 15 | { 16 | path: '/check', 17 | name: 'Check', 18 | component: check, 19 | }, 20 | ] 21 | const router = createRouter({ 22 | history: createWebHashHistory(), 23 | routes 24 | }) 25 | 26 | export default router; 27 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/store/index.ts: -------------------------------------------------------------------------------- 1 | import { InjectionKey } from 'vue' 2 | import { createStore, Store, useStore as baseUseStore } from 'vuex' 3 | import { State } from '@@/store' 4 | import { banner } from './apidoc/banner'; 5 | import { baseInfo } from './apidoc/base-info'; 6 | import { tabs } from './apidoc/tabs'; 7 | import { apidoc } from './apidoc/apidoc'; 8 | import { response } from './apidoc/response'; 9 | 10 | export const key: InjectionKey> = Symbol('') 11 | 12 | export const store = createStore({ 13 | strict: process.env.NODE_ENV !== 'production', 14 | modules: { 15 | 'apidoc/banner': banner, 16 | 'apidoc/baseInfo': baseInfo, 17 | 'apidoc/tabs': tabs, 18 | 'apidoc/apidoc': apidoc, 19 | 'apidoc/response': response, 20 | } 21 | }); 22 | export const useStore = (): Store => baseUseStore(key); 23 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/test-data/data.ts: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | export default { 3 | projectInfo: { 4 | }, 5 | docs: [] 6 | } -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/banner/composables/banner-data.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取banner数据 3 | */ 4 | 5 | import { ref, Ref } from 'vue' 6 | import { useRoute } from 'vue-router' 7 | import { useStore } from '@/pages/modules/apidoc/doc-view/store/index' 8 | 9 | const isBuildHtml = process.env.VUE_APP_BUILD_HTML; 10 | type ReturnData = { 11 | /** 12 | * loading加载效果 13 | */ 14 | loading: Ref, 15 | /** 16 | * 获取banner数据 17 | */ 18 | getBannerData: () => Promise, 19 | }; 20 | 21 | export function useBannerData(): ReturnData { 22 | const store = useStore(); 23 | const route = useRoute() 24 | const shareId = route.query.share_id; 25 | const password = localStorage.getItem('share/password') || '' 26 | const loading = ref(false); 27 | const getBannerData = async () => { 28 | if (loading.value) { 29 | return 30 | } 31 | loading.value = true; 32 | await store.dispatch('apidoc/banner/getSharedDocBanner', { shareId, password }); 33 | loading.value = false; 34 | } 35 | if (!isBuildHtml) { 36 | getBannerData(); 37 | } 38 | return { 39 | loading, 40 | getBannerData, 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/banner/tool/operations.ts: -------------------------------------------------------------------------------- 1 | import { $t } from '@/i18n/i18n' 2 | 3 | export default [{ 4 | name: $t('新增文件夹'), 5 | icon: '#iconxinzengwenjian', 6 | op: 'addRootFolder', 7 | shortcut: [], 8 | pin: true, 9 | }, { 10 | name: $t('新增文件'), 11 | icon: '#iconwenjian', 12 | op: 'addRootFile', 13 | shortcut: [], 14 | pin: true, 15 | }, { 16 | name: $t('刷新banner'), 17 | icon: '#iconshuaxin', 18 | op: 'freshBanner', 19 | shortcut: [], 20 | pin: true, 21 | viewOnly: true, 22 | }, { 23 | name: $t('在线链接'), 24 | icon: '#iconlink', 25 | op: 'generateLink', 26 | shortcut: ['Ctrl', 'L'], 27 | pin: true, 28 | }, { 29 | name: $t('回收站'), 30 | icon: '#iconhuishouzhan', 31 | op: 'recycler', 32 | shortcut: ['Ctrl', 'Alt', 'R'], 33 | pin: true, 34 | }, { 35 | name: $t('导出文档'), 36 | icon: '#icondaochu1', 37 | op: 'exportDoc', 38 | shortcut: ['Ctrl', 'E'], 39 | pin: false, 40 | }, { 41 | name: $t('导入文档'), 42 | icon: '#icondaoru', 43 | op: 'importDoc', 44 | shortcut: ['Ctrl', 'I'], 45 | pin: false, 46 | }, { 47 | name: $t('操作审计'), 48 | icon: '#iconlishi', 49 | op: 'history', 50 | shortcut: ['Ctrl', 'H'], 51 | pin: false, 52 | viewOnly: true, 53 | }, { 54 | name: $t('全局设置'), 55 | icon: '#iconshezhi', 56 | op: 'config', 57 | shortcut: ['Ctrl', ','], 58 | pin: false, 59 | }]; 60 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/operation/composables/method.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | 请求方法相关处理 4 | |-------------------------------------------------------------------------- 5 | | 6 | */ 7 | import { ComputedRef, computed, WritableComputedRef } from 'vue' 8 | import type { ApidocRequestMethodRule } from '@@/store' 9 | import { useStore } from '@/pages/modules/apidoc/doc-view/store/index' 10 | import { $t } from '@/i18n/i18n' 11 | 12 | type MethodReturn = { 13 | /** 14 | * 请求地址 15 | */ 16 | requestMethod: WritableComputedRef, 17 | /** 18 | * 请求方法枚举 19 | */ 20 | requestMethodEnum: ComputedRef, 21 | /** 22 | * 禁用请求方法后提示信息 23 | */ 24 | disabledTip: (item: ApidocRequestMethodRule) => void, 25 | } 26 | 27 | export default (): MethodReturn => { 28 | const store = useStore(); 29 | //请求方法 30 | const requestMethod = computed({ 31 | get() { 32 | return store.state['apidoc/apidoc'].apidoc.item.method; 33 | }, 34 | set(method: string) { 35 | store.commit('apidoc/apidoc/changeApidocMethod', method) 36 | }, 37 | }); 38 | //禁用请求方法后提示信息 39 | const disabledTip = (item: ApidocRequestMethodRule) => { 40 | if (!item.enabled) { 41 | return $t('当前请求方法被禁止,可以在全局配置中进行相关配置'); 42 | } 43 | return ''; 44 | } 45 | //请求方法枚举 46 | const requestMethodEnum = computed(() => store.state['apidoc/baseInfo'].rules.requestMethods); 47 | 48 | return { 49 | requestMethod, 50 | disabledTip, 51 | requestMethodEnum, 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/operation/composables/operation.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | 请求操作:刷新、保存接口、发送请求等 4 | |-------------------------------------------------------------------------- 5 | | 6 | */ 7 | import { ref, Ref, computed } from 'vue' 8 | import { useStore } from '@/pages/modules/apidoc/doc-view/store/index' 9 | import { sendRequest, stopRequest } from '@/server/request/request' 10 | import shareRouter from '../../../../../router/index' 11 | 12 | type OperationReturn = { 13 | /** 14 | * 保存接口 15 | */ 16 | loading2: Ref, 17 | /** 18 | * 刷新接口 19 | */ 20 | loading3: Ref, 21 | /** 22 | * 发送请求 23 | */ 24 | handleSendRequest: () => void, 25 | /** 26 | * 停止请求 27 | */ 28 | handleStopRequest: () => void, 29 | /** 30 | * 刷新文档 31 | */ 32 | handleFreshApidoc: () => void, 33 | } 34 | 35 | export default (): OperationReturn => { 36 | const store = useStore(); 37 | const loading2 = ref(false); //保存接口 38 | const loading3 = ref(false); //刷新接口 39 | const projectId = shareRouter.currentRoute.value.query.id as string; 40 | const currentSelectTab = computed(() => { 41 | const tabs = store.state['apidoc/tabs'].tabs[projectId]; 42 | const selectedTab = tabs?.find((tab) => tab.selected) || null; 43 | return selectedTab; 44 | }); 45 | //发送请求 46 | const handleSendRequest = () => { 47 | sendRequest(); 48 | } 49 | //停止请求 50 | const handleStopRequest = () => { 51 | stopRequest(); 52 | }; 53 | //刷新文档 54 | const handleFreshApidoc = () => { 55 | loading3.value = true; 56 | const password = localStorage.getItem('share/password') || '' 57 | const shareId = shareRouter.currentRoute.value.query.share_id; 58 | store.dispatch('apidoc/apidoc/getSharedApidocDetail', { 59 | id: currentSelectTab.value?._id, 60 | projectId, 61 | password, 62 | shareId, 63 | }).then(() => { 64 | loading3.value = false; 65 | }) 66 | }; 67 | return { 68 | loading2, 69 | loading3, 70 | handleSendRequest, 71 | handleStopRequest, 72 | // handleSaveApidoc, 73 | handleFreshApidoc, 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/operation/tag/tag.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-19 21:37 4 | 模块名称: 5 | 备注: 6 | */ 7 | 10 | 11 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/params/body/dialog/import-params/import-params.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-29 10:49 4 | 模块名称:导入参数 5 | 备注: 6 | */ 7 | 23 | 24 | 88 | 89 | 92 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/params/body/dialog/params-template/params-template.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-29 10:49 4 | 模块名称:保存参数为模板 5 | 备注: 6 | */ 7 | 18 | 19 | 79 | 80 | 83 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/params/headers/headers.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-30 21:28 4 | 模块名称:headers参数录入 5 | 备注: 6 | */ 7 | 24 | 25 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/params/params/params.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-20 22:30 4 | 模块名称:query参数、path参数 5 | 备注: 6 | */ 7 | 16 | 17 | 38 | 46 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/response/cookie/cookie.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-09-03 20:45 4 | 模块名称:返回cookie 5 | 备注: 6 | */ 7 | 25 | 26 | 47 | 48 | 61 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/apidoc/response/headers/headers.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-09-03 20:45 4 | 模块名称:返回header 5 | 备注: 6 | */ 7 | 19 | 20 | 49 | 50 | 64 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/content.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-07-21 21:00 4 | 模块名称:内容编辑区域 5 | 备注: 6 | */ 7 | 13 | 14 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/apidoc/doc-view/view/content/guide/guide.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-08-15 16:28 4 | 模块名称:引导界面 5 | 备注: 6 | */ 7 | 25 | 26 | 68 | 69 | 83 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/client-routes/add/add.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-28 21:04 4 | 模块名称:新增前端路由 5 | 备注: 6 | */ 7 | 20 | 21 | 79 | 80 | 82 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/client-routes/edit/edit2.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-28 21:04 4 | 模块名称:批量修改前端路由类型 5 | 备注: 6 | */ 7 | 18 | 19 | 77 | 78 | 80 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/menu/add/add.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-28 21:04 4 | 模块名称:新增菜单 5 | 备注: 6 | */ 7 | 19 | 20 | 85 | 86 | 88 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/menu/edit/edit.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-28 21:04 4 | 模块名称:编辑菜单 5 | 备注: 6 | */ 7 | 19 | 20 | 85 | 86 | 88 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/permission.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-14 12:08 4 | 模块名称: 5 | 备注: 6 | */ 7 | 19 | 20 | 59 | 60 | 68 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/role/add/components/client-menus.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-29 15:05 4 | 模块名称: 5 | 备注: 6 | */ 7 | 28 | 29 | 67 | 68 | 101 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/role/edit/components/client-menus.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-29 15:05 4 | 模块名称: 5 | 备注: 6 | */ 7 | 28 | 29 | 67 | 68 | 101 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/server-routes/edit/edit2.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-28 21:04 4 | 模块名称:批量修改服务端路由类型 5 | 备注: 6 | */ 7 | 18 | 19 | 77 | 78 | 80 | -------------------------------------------------------------------------------- /src/renderer/pages/modules/permission/user/reset-pwd/reset-pwd.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 模块名称:重置密码 4 | 备注: 5 | */ 6 | 19 | 20 | 79 | -------------------------------------------------------------------------------- /src/renderer/pages/test/test.vue: -------------------------------------------------------------------------------- 1 | /* 2 | 创建者:shuxiaokai 3 | 创建时间:2021-06-08 19:36 4 | 模块名称:test页面 5 | 备注: 6 | */ 7 | 12 | 13 | 17 | 18 | 28 | -------------------------------------------------------------------------------- /src/renderer/scss/global/_global.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | //=====================================清除一些常见的样式====================================// 3 | :root { 4 | --el-transition-duration: 0, 5 | } 6 | * { 7 | box-sizing: border-box; 8 | } 9 | html { 10 | font-size: 14px; 11 | height: 100%; 12 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, 13 | Microsoft YaHei, SimSun, sans-serif; 14 | } 15 | body { 16 | margin: 0; 17 | padding: 0; 18 | width: 100%; 19 | height: 100%; 20 | overflow-x: hidden; 21 | color: $gray-700; 22 | } 23 | button, 24 | input, 25 | div, 26 | span, 27 | textarea { 28 | outline: none; 29 | padding: 0; 30 | } 31 | pre { 32 | margin: 0; 33 | overflow-x: auto; 34 | padding: 7px 10px; 35 | border: 1px solid #d1d5da; 36 | border-radius: 4px; 37 | background-color: #f0f0f0; 38 | white-space: pre-wrap; 39 | display: block; 40 | color: #212529; 41 | font-size: 87.5%; 42 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, 43 | Courier New, monospace; 44 | } 45 | 46 | .iconfont { 47 | font-family: "iconfont" !important; 48 | font-size: 16px; 49 | font-style: normal; 50 | -webkit-font-smoothing: antialiased; 51 | -webkit-text-stroke-width: 0.2px; 52 | -moz-osx-font-smoothing: grayscale; 53 | } -------------------------------------------------------------------------------- /src/renderer/scss/global/_mend.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | body { 3 | .el-popper { 4 | font-size: fz(14); 5 | } 6 | .el-dropdown-menu { 7 | max-height: size(300); 8 | overflow-y: auto; 9 | box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 4px 0px; 10 | .popper__arrow { 11 | display: none; 12 | } 13 | } 14 | .el-dropdown-menu__item:focus, .el-dropdown-menu__item:not(.is-disabled):hover { 15 | background: $gray-200; 16 | color: $theme-color; 17 | } 18 | .el-table .cell { 19 | line-height: size(24); //修复奇数高度文本错位 20 | } 21 | .el-image-viewer__close { 22 | background-color: $white; 23 | color: $red; 24 | } 25 | .el-form--label-top .el-form-item__label { 26 | padding: 0; 27 | } 28 | .el-dialog__body { 29 | padding-top: 0; 30 | padding-bottom: size(10); 31 | } 32 | .el-dialog__headerbtn { 33 | width: size(25); 34 | height: size(25); 35 | display: flex; 36 | align-items: center; 37 | justify-content: center; 38 | border-radius: 50%; 39 | right: size(10); 40 | &:hover { 41 | background-color: $gray-300; 42 | } 43 | .el-dialog__close { 44 | font-size: fz(20); 45 | &:hover { 46 | color: $red; 47 | } 48 | } 49 | } 50 | .el-input.is-disabled .el-input__inner { 51 | box-shadow: none; 52 | } 53 | .el-menu--horizontal { 54 | border-bottom: none; 55 | } 56 | .el-input.is-disabled { 57 | .el-input__inner { 58 | border-bottom: none; 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/renderer/scss/helpers/_functions.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | //映射字体大小 3 | @function fz($px) { 4 | @return $px + px; 5 | } 6 | //映射dom大小(只要和大小相关的都可以通过该方法映射) 7 | @function size($size) { 8 | @return $size + px; 9 | } 10 | -------------------------------------------------------------------------------- /src/renderer/scss/index.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import './helpers/functions';//--------------函数 3 | @import './helpers/mixin';//------------------mixin 4 | @import './variables/variables';//------------变量 5 | // @import './global/global';//------------------全局样式清除 6 | // @import './global/mend';//--------------------全局覆盖 7 | // @import './utils/utils';//--------------------辅助类 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/renderer/server/mock/mock.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import Mock from 'mockjs'; 3 | import { randomInt } from '@/helper'; 4 | import config from '@/../config/config'; 5 | 6 | const { Random } = Mock; 7 | let startTime = new Date(); 8 | 9 | Random.extend({ 10 | //时间戳 11 | timestamp() { 12 | return Date.now(); 13 | }, 14 | //时间戳精确到秒 15 | timestamp2() { 16 | return Date.now().toString().slice(0, 10); 17 | }, 18 | //开始时间 19 | startTime(date, rule) { 20 | const dateParams = date || new Date(`202${randomInt(0, 3)}-0${randomInt(1, 12)}-0${randomInt(1, 12)}`); 21 | startTime = dateParams; 22 | const realRule = rule || 'YYYY-MM-DD HH:mm' 23 | const result = dayjs(dateParams).format(realRule); 24 | return result; 25 | }, 26 | //结束时间 27 | endTime(date, rule) { 28 | const dateParams = date || new Date(new Date(startTime).getTime() + 24 * 1000 * 60 * 60 * randomInt(1, 30)); 29 | const realRule = rule || 'YYYY-MM-DD HH:mm' 30 | const result = dayjs(dateParams).format(realRule); 31 | return result; 32 | }, 33 | //图片 34 | image(w: string | number = 200, h: string | number = 200) { 35 | return `${config.renderConfig.httpRequest.url}/mock/image?w=${w}&h=${h}`; 36 | }, 37 | // //base64图片 38 | // dataImage(w: string | number = 200, h: string | number = 200) { 39 | // return Mock.dataImage(); 40 | // }, 41 | //文件 42 | file(type = 'doc') { //xls | xlsx | doc | docx | zip | image 43 | return `${config.renderConfig.httpRequest.url}/mock/file?type=${type}` 44 | } 45 | }); 46 | 47 | export default Mock; 48 | -------------------------------------------------------------------------------- /src/renderer/server/request/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | timeout: 600000, 3 | proxy: '', 4 | } 5 | -------------------------------------------------------------------------------- /src/renderer/server/request/filters.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | 支持的全局过滤函数 4 | |-------------------------------------------------------------------------- 5 | */ 6 | 7 | /** 8 | * 将字符串转换为json字符串 9 | */ 10 | export function toJsonStr(str: unknown): T { 11 | try { 12 | return JSON.stringify(str) as T; 13 | } catch (error) { 14 | return str as T; 15 | } 16 | } 17 | 18 | export const filters = { 19 | toJsonStr 20 | } 21 | -------------------------------------------------------------------------------- /src/renderer/server/request/request.ts: -------------------------------------------------------------------------------- 1 | import config from '@/../config/config' 2 | import { sendRequest as browserRequest, stopRequest as stopBrowserRequest } from './browser'; 3 | import { sendRequest as electronRequest, stopRequest as stopElectronRequest } from './electron'; 4 | 5 | export function sendRequest(): void { 6 | if (config.isElectron) { 7 | electronRequest(); 8 | } else { 9 | browserRequest(); 10 | } 11 | } 12 | 13 | export function stopRequest(): void { 14 | if (config.isElectron) { 15 | stopElectronRequest(); 16 | } else { 17 | stopBrowserRequest(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/renderer/store/apidoc/mock.ts: -------------------------------------------------------------------------------- 1 | import { ApidocDetail } from '@@/global'; 2 | import { ApidocMockState, ApidocMockMapInfo } from '@@/store' 3 | import { uniqueByKey } from '@/helper/index' 4 | import config from '@/../config/config' 5 | import { store } from '../index'; 6 | // import { apidocCache } from "@/cache/apidoc"; 7 | // import { router } from "@/router/index" 8 | 9 | const mock = { 10 | namespaced: true, 11 | state: { 12 | serverState: 'disconnect', //服务器状态 13 | mockServerPort: config.renderConfig.mock.port, // 端口 14 | httpStatusCode: 200, //http状态码 15 | urlMap: [], 16 | }, 17 | mutations: { 18 | //改变mock映射 19 | changeMockUrlMap(state: ApidocMockState, payload: ApidocMockMapInfo[]): void { 20 | state.urlMap = uniqueByKey(state.urlMap.concat(payload), 'id') 21 | }, 22 | //新增一条mock映射 23 | addMockUrl(state: ApidocMockState, payload: ApidocMockMapInfo): void { 24 | state.urlMap.push(payload); 25 | }, 26 | //根据id改变一条mock映射 27 | changeCustomMockUrlById(state: ApidocMockState, payload: { id: string, url: string }): void { 28 | const matchedMockInfo = state.urlMap.find(v => v.id === payload.id); 29 | if (matchedMockInfo) { 30 | matchedMockInfo.customMockUrl = payload.url 31 | } 32 | }, 33 | //改变当前mock映射 34 | changeCurrentMockUrl(state: ApidocMockState, payload: { id: string, apidoc: ApidocDetail }): void { 35 | const index = state.urlMap.findIndex(v => v.id === payload.id); 36 | if (index !== -1) { 37 | state.urlMap[index] = { 38 | id: payload.apidoc._id, 39 | projectId: payload.apidoc.projectId, 40 | url: payload.apidoc.item.url.path, 41 | method: payload.apidoc.item.method, 42 | customMockUrl: payload.apidoc.mockInfo.path, 43 | } 44 | } else if (payload.apidoc.projectId) { //不添加无效数据 45 | state.urlMap.push({ 46 | id: payload.apidoc._id, 47 | projectId: payload.apidoc.projectId, 48 | url: payload.apidoc.item.url.path, 49 | method: payload.apidoc.item.method, 50 | customMockUrl: payload.apidoc.mockInfo.path, 51 | }); 52 | } 53 | }, 54 | //改变mock端口 55 | changeMockServerPort(state: ApidocMockState, port: number): void { 56 | store.commit('apidoc/apidoc/changeApidocHost', `http://${config.renderConfig.mock.ip}:${port}`); 57 | state.mockServerPort = port; 58 | }, 59 | //改变服务器启动状态 60 | changeMockServerState(state: ApidocMockState, payload: 'disconnection' | 'connecting' | 'connection' | 'closing' | 'error'): void{ 61 | state.serverState = payload; 62 | }, 63 | }, 64 | } 65 | 66 | export { mock } 67 | -------------------------------------------------------------------------------- /src/renderer/store/apidoc/request.ts: -------------------------------------------------------------------------------- 1 | import { ApidocRequest } from '@@/store'; 2 | 3 | const request = { 4 | namespaced: true, 5 | state: { 6 | url: '', 7 | headers: {}, 8 | method: '', 9 | body: '', 10 | }, 11 | mutations: { 12 | //改变最终发送请求信息 13 | changeFinalRequestInfo(state: ApidocRequest, payload: ApidocRequest): void { 14 | state.url = payload.url; 15 | state.headers = payload.headers; 16 | state.method = payload.method; 17 | state.body = payload.body; 18 | }, 19 | }, 20 | } 21 | 22 | export { request } 23 | -------------------------------------------------------------------------------- /src/renderer/store/apidoc/worker-state.ts: -------------------------------------------------------------------------------- 1 | import type { ApidocWorkerState } from '@@/store' 2 | 3 | const workerState = { 4 | namespaced: true, 5 | state: { 6 | sessionState: {}, 7 | localState: {}, 8 | remoteState: {}, 9 | }, 10 | mutations: { 11 | changeSessionState(state: ApidocWorkerState, payload: { projectId: string, value: Record }): void { 12 | state.sessionState[payload.projectId] = payload.value; 13 | }, 14 | changeLocalState(state: ApidocWorkerState, payload: { projectId: string, value: Record }): void { 15 | state.localState[payload.projectId] = payload.value; 16 | }, 17 | }, 18 | } 19 | 20 | export { workerState } 21 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/config.ts: -------------------------------------------------------------------------------- 1 | import { FlowConfig } from '@@/apiflow' 2 | import { defineStore } from 'pinia' 3 | 4 | export const useFlowConfigStore = defineStore('flowConfig', { 5 | state: (): FlowConfig => { 6 | return { 7 | minLineWidth: 40, 8 | minLineHeight: 40, 9 | createLineDotSize: 10, 10 | resizeDotSize: 10, 11 | nodeMinWidth: 200, 12 | nodeMinHeight: 130, 13 | lineZIndex: 299, 14 | selectedNodeAreaZIndex: 301, 15 | selectionZIndex: 300, 16 | dragNodeZIndex: 298, 17 | zoom: 1, 18 | selectedNodeAreaPadding: 5, 19 | } 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/container.ts: -------------------------------------------------------------------------------- 1 | import { FlowContainerInfo } from '@@/apiflow' 2 | import { defineStore } from 'pinia' 3 | 4 | export const useFlowContainerStore = defineStore('container', { 5 | state: (): FlowContainerInfo => { 6 | return { 7 | clientX: 0, 8 | clientY: 0, 9 | width: 0, 10 | height: 0, 11 | } 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/create-line-state.ts: -------------------------------------------------------------------------------- 1 | import { FLowCreateLineDotState } from '@@/apiflow'; 2 | import { defineStore } from 'pinia'; 3 | 4 | export const useFlowCreateLineDotStateStore = defineStore('createLineDotState', { 5 | state: (): FLowCreateLineDotState => { 6 | return { 7 | hoverNodeId: '', 8 | isMouseDown: false, 9 | hoverPosition: 'left', 10 | }; 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/history.ts: -------------------------------------------------------------------------------- 1 | import { FlowHistory } from '@@/apiflow' 2 | import { defineStore } from 'pinia' 3 | 4 | type FlowHistoryStore = { 5 | readonly maxHistory: number; 6 | doingList: FlowHistory[]; 7 | redoList: FlowHistory[]; 8 | } 9 | export const useFlowHistoryStore = defineStore('flowHistory', { 10 | state: (): FlowHistoryStore => { 11 | return { 12 | maxHistory: 1000, 13 | doingList: [], 14 | redoList: [], 15 | } 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/line-state.ts: -------------------------------------------------------------------------------- 1 | import { FlowLineState } from '@@/apiflow'; 2 | import { defineStore } from 'pinia'; 3 | 4 | export const useFlowLineStateStore = defineStore('lineState', { 5 | state: (): FlowLineState => { 6 | return { 7 | hoverDragLineId: '', 8 | selectedLineId: '', 9 | hoverLineId: '', 10 | dragLineId: '', 11 | isHoverDragArrow: false, 12 | isMouseDownDragArrow: false, 13 | isMove: false, 14 | }; 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/lines.ts: -------------------------------------------------------------------------------- 1 | import { FlowLineInfo } from '@@/apiflow'; 2 | import { defineStore } from 'pinia'; 3 | 4 | export const useFlowLinesStore = defineStore('lines', { 5 | state: (): { lineList: FlowLineInfo[] } => { 6 | return { 7 | lineList: [], 8 | }; 9 | }, 10 | actions: { 11 | changeLineInfoById(id: string, payload: Partial) { 12 | const mathcedLine = this.lineList.find((line) => line.id === id); 13 | if (!mathcedLine) { 14 | return 15 | } 16 | if (payload.toPosition != null) { 17 | mathcedLine.toPosition = payload.toPosition; 18 | } 19 | if (payload.arrowInfo != null) { 20 | mathcedLine.arrowInfo = payload.arrowInfo; 21 | } 22 | 23 | if (payload.id != null) { 24 | mathcedLine.id = payload.id; 25 | } 26 | if (payload.width != null) { 27 | mathcedLine.width = payload.width; 28 | } 29 | if (payload.height != null) { 30 | mathcedLine.height = payload.height; 31 | } 32 | if (payload.offsetX != null) { 33 | mathcedLine.offsetX = payload.offsetX; 34 | } 35 | if (payload.offsetY != null) { 36 | mathcedLine.offsetY = payload.offsetY; 37 | } 38 | if (payload.fromPosition != null) { 39 | mathcedLine.fromPosition = payload.fromPosition; 40 | } 41 | if (payload.toPosition != null) { 42 | mathcedLine.toPosition = payload.toPosition; 43 | } 44 | if (payload.zIndex != null) { 45 | mathcedLine.zIndex = payload.zIndex; 46 | } 47 | if (payload.lineStartOffsetX != null) { 48 | mathcedLine.lineStartOffsetX = payload.lineStartOffsetX; 49 | } 50 | if (payload.lineStartOffsetY != null) { 51 | mathcedLine.lineStartOffsetY = payload.lineStartOffsetY; 52 | } 53 | if (payload.lineEndOffsetX != null) { 54 | mathcedLine.lineEndOffsetX = payload.lineEndOffsetX; 55 | } 56 | if (payload.lineEndOffsetY != null) { 57 | mathcedLine.lineEndOffsetY = payload.lineEndOffsetY; 58 | } 59 | if (payload.canHoverPosition != null) { 60 | mathcedLine.canHoverPosition = payload.canHoverPosition; 61 | } 62 | }, 63 | }, 64 | }); 65 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/node-state.ts: -------------------------------------------------------------------------------- 1 | import { FlowNodeState } from '@@/apiflow'; 2 | import { defineStore } from 'pinia'; 3 | 4 | export const useFlowNodeStateStore = defineStore('nodeState', { 5 | state: (): FlowNodeState => { 6 | return { 7 | hoverNodeId: '', 8 | dragNodeId: '', 9 | isMouseDown: false, 10 | isMouseDownDragArea: false, 11 | isMouseHoverDragArea: false, 12 | activeNodeId: '', 13 | mouseDownClientX: 0, 14 | mouseDownClientY: 0, 15 | isMove: false, 16 | nodeOffsetXWhenMouseDown: 0, 17 | nodeOffsetYWhenMouseDown: 0, 18 | }; 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/nodes.ts: -------------------------------------------------------------------------------- 1 | import { FlowLineInfo, FlowNodeInfo } from '@@/apiflow' 2 | import { defineStore } from 'pinia' 3 | 4 | type AddIncomingPayload = { 5 | fromNodeId: string; 6 | toNodeId: string; 7 | lineInfo: FlowLineInfo; 8 | } 9 | 10 | export const useFlowNodesStore = defineStore('nodes', { 11 | state: (): { nodeList: FlowNodeInfo[] } => { 12 | return { 13 | nodeList: [] 14 | } 15 | }, 16 | getters: { 17 | getNodeById(state) { 18 | return (nodeId: string) => { 19 | return state.nodeList.find(node => node.id === nodeId) 20 | } 21 | } 22 | }, 23 | actions: { 24 | changeNodeStyleInfoById(id: string, payload: Partial) { 25 | const matchedNode = this.nodeList.find(node => node.id === id); 26 | if (matchedNode && payload.height != null) { 27 | matchedNode.styleInfo.height = payload.height 28 | } 29 | if (matchedNode && payload.width != null) { 30 | matchedNode.styleInfo.width = payload.width 31 | } 32 | if (matchedNode && payload.offsetX != null) { 33 | matchedNode.styleInfo.offsetX = payload.offsetX 34 | } 35 | if (matchedNode && payload.offsetY != null) { 36 | matchedNode.styleInfo.offsetY = payload.offsetY 37 | } 38 | if (matchedNode && payload.dragZIndex != null) { 39 | matchedNode.styleInfo.dragZIndex = payload.dragZIndex 40 | } 41 | }, 42 | addIncoming(payload: AddIncomingPayload) { 43 | const { fromNodeId, toNodeId, lineInfo } = payload; 44 | const matchedToNode = this.nodeList.find(v => v.id === toNodeId); 45 | const matchedFromNode = this.nodeList.find(v => v.id === fromNodeId); 46 | const matchedOutcomingLine = matchedFromNode?.outcomingIds.find(outcomingId => outcomingId === lineInfo.id) 47 | const matchedIncomingLine = matchedToNode?.incomingIds.find(incomingId => incomingId === lineInfo.id) 48 | const matchedIncomingLineIndex = matchedToNode?.incomingIds.findIndex(incomingId => incomingId === lineInfo.id) as number; 49 | if (matchedToNode && !matchedIncomingLine && matchedOutcomingLine) { 50 | matchedToNode.incomingIds.push(matchedOutcomingLine) 51 | } else if (matchedToNode && matchedIncomingLine && matchedIncomingLineIndex !== -1 && matchedOutcomingLine) { 52 | matchedToNode.incomingIds[matchedIncomingLineIndex] = matchedOutcomingLine; 53 | } 54 | }, 55 | } 56 | }) 57 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/render-area.ts: -------------------------------------------------------------------------------- 1 | import { FlowRenderArea } from '@@/apiflow'; 2 | import { defineStore } from 'pinia'; 3 | 4 | export const useFlowRenderAreaStore = defineStore('renderArea', { 5 | state: (): FlowRenderArea => { 6 | return { 7 | width: 0, 8 | height: 0, 9 | offsetX: 0, 10 | offsetY: 0, 11 | gridUnit: 15, 12 | }; 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/resize-node-state.ts: -------------------------------------------------------------------------------- 1 | import { FLowResizeNodeDotState } from '@@/apiflow'; 2 | import { defineStore } from 'pinia'; 3 | 4 | export const useFlowResizeNodeStateStore = defineStore('resizeNodeState', { 5 | state: (): FLowResizeNodeDotState => { 6 | return { 7 | hoverNodeId: '', 8 | hoverPosition: 'leftTop', 9 | isMouseDown: false, 10 | mouseDownClientX: 0, 11 | mouseDownClientY: 0, 12 | nodeWidthWhenMouseDown: 0, 13 | nodeHeightWhenMouseDown: 0, 14 | nodeOffsetXWhenMouseDown: 0, 15 | nodeOffsetYWhenMouseDown: 0, 16 | nodeFixedX: 0, 17 | nodeFixedY: 0, 18 | }; 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /src/renderer/store/apiflow/selection.ts: -------------------------------------------------------------------------------- 1 | import { FlowSelection } from '@@/apiflow' 2 | import { defineStore } from 'pinia' 3 | 4 | export const useFlowSelectionStore = defineStore('flowSelection', { 5 | state: (): FlowSelection => { 6 | return { 7 | isMouseDown: false, 8 | isMouseDownSelectedArea: false, 9 | isMouseDownResizeDot: false, 10 | isMouseHoverResizeDot: false, 11 | isHover: false, 12 | isMove: false, 13 | startOffsetX: 0, 14 | startOffsetY: 0, 15 | endOffsetX: 0, 16 | endOffsetY: 0, 17 | nodeOffsetXWhenMouseDown: 0, 18 | nodeOffsetYWhenMouseDown: 0, 19 | width: 0, 20 | height: 0, 21 | offsetX: 0, 22 | offsetY: 0, 23 | selectedNodeArea: { 24 | width: 0, 25 | height: 0, 26 | offsetX: 0, 27 | offsetY: 0, 28 | }, 29 | selectedNodeIds: [], 30 | selectedNodeMouseDownOffsetInfo: [], 31 | } 32 | } 33 | }) 34 | -------------------------------------------------------------------------------- /src/renderer/store/index.ts: -------------------------------------------------------------------------------- 1 | import { InjectionKey } from 'vue' 2 | import { createStore, Store, useStore as baseUseStore } from 'vuex' 3 | import { State } from '@@/store' 4 | import { permission } from './permission/permission'; 5 | import { banner } from './apidoc/banner'; 6 | import { baseInfo } from './apidoc/base-info'; 7 | import { tabs } from './apidoc/tabs'; 8 | import { apidoc } from './apidoc/apidoc'; 9 | import { response } from './apidoc/response'; 10 | import { mock } from './apidoc/mock'; 11 | import { request } from './apidoc/request'; 12 | import { workerState } from './apidoc/worker-state'; 13 | import { apiflow } from './apidoc/apiflow'; 14 | 15 | export const key: InjectionKey> = Symbol('') 16 | 17 | export const store = createStore({ 18 | strict: process.env.NODE_ENV !== 'production', 19 | modules: { 20 | permission, 21 | 'apidoc/banner': banner, 22 | 'apidoc/baseInfo': baseInfo, 23 | 'apidoc/tabs': tabs, 24 | 'apidoc/apidoc': apidoc, 25 | 'apidoc/response': response, 26 | 'apidoc/mock': mock, 27 | 'apidoc/request': request, 28 | 'apidoc/workerState': workerState, 29 | 'apidoc/apiflow': apiflow, 30 | } 31 | }); 32 | export const useStore = (): Store => baseUseStore(key); 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": ["webpack-env", "element-plus/global"], 15 | "paths": { 16 | "@/*": ["src/renderer/*"], 17 | "@@/*": ["src/@types/*"], 18 | }, 19 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 20 | }, 21 | "include": [ 22 | "src/**/*.ts", 23 | "src/**/*.tsx", 24 | "src/**/*.vue", 25 | "tests/**/*.ts", 26 | "tests/**/*.tsx" 27 | ], 28 | "exclude": ["node_modules"] 29 | } 30 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const htmlBuildConfig = require('./build/html.config'); 3 | const defaultBuildConfig = require('./build/default.config'); 4 | const shareBuildConfig = require('./build/share.config'); 5 | 6 | const buildShare = process.argv.find(val => val === '--share'); 7 | const buildHtml = process.argv.find((val) => val === '--html'); 8 | process.env.VUE_APP_BUILD_TIME = new Date().toLocaleString(); 9 | process.env.VUE_APP_BUILD_SHARE = buildShare || ''; 10 | process.env.VUE_APP_BUILD_HTML = buildHtml || ''; 11 | 12 | let vueConfig = null; 13 | 14 | if (buildHtml) { 15 | vueConfig = htmlBuildConfig 16 | } else if (buildShare) { 17 | vueConfig = shareBuildConfig; 18 | } else { 19 | vueConfig = defaultBuildConfig 20 | } 21 | 22 | module.exports = vueConfig; 23 | --------------------------------------------------------------------------------