├── .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 |
8 |
9 |
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 |
8 |
9 |
10 | {{ title }}
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
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 |
8 |
25 |
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 |
8 |
9 |
10 |
11 | {{ label }}
12 |
13 |
14 |
15 | *
16 | {{ label }}
17 |
18 |
19 |
20 |
21 |
{{ description }}
22 |
23 |
24 |
25 |
26 |
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 |
8 |
9 |
13 |
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 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 |
8 |
9 |
10 |
11 |
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 |
8 |
9 | {{ leftStr }}
10 | {{ emphasizeStr }}
16 | {{ rightStr }}
17 |
18 |
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 |
8 |
9 |
10 |
11 | {{ title }}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
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 |
8 |
9 |
10 |
11 |
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 |
8 |
19 |
20 |
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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
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 |
8 |
9 |
10 | {{ label }}
11 |
12 | {{ value }}
13 |
14 |
15 |
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 |
8 |
9 |
10 |
{{ loadingText }}
11 |
12 |
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 |
8 |
9 |
10 |
11 |
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 |
8 | {{ tip }}
9 |
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 |
8 |
9 |
404
10 |
![logo]()
11 |
返回登录页面
12 |
13 |
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 |
8 | aa
9 |
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 |
8 |
11 |
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 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {{ $t("保存") }}
15 | {{ $t("取消") }}
16 |
17 |
18 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ $t("保存") }}
14 | {{ $t("取消") }}
15 |
16 |
17 |
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 |
7 |
8 |
9 |
10 |
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 |
8 |
9 |
10 |
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 |
8 |
9 |
10 |
Query {{ $t("参数") }}
11 |
12 |
Path {{ $t("参数") }}
13 |
14 |
15 |
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 |
8 |
11 |
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 |
8 |
9 |
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 |
8 |
9 |
10 | {{ item.title }}
11 |
12 |
13 | {{ mime.alias }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 |
8 |
9 |
10 | {{ item.title }}
11 |
12 |
13 | {{ mime.code }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ $t("保存") }}
14 | {{ $t("取消") }}
15 |
16 |
17 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ scope.row.value }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
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 |
8 |
18 |
19 |
20 |
49 |
50 |
64 |
--------------------------------------------------------------------------------
/src/renderer/pages/modules/apidoc/doc-edit/content/apiflow/components/line/line.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
34 |
35 |
40 |
--------------------------------------------------------------------------------
/src/renderer/pages/modules/apidoc/doc-edit/content/apiflow/components/selection/selection.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
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 |
8 |
9 |
10 |
![logo]()
11 |
{{ $t("当前版本") }}{{ config.localization.version }}
12 |
13 |
14 |
{{ $t("今日新增") }}:
15 |
{{ docsOfToday.length }}
16 |
17 |
18 |
{{ $t("接口总数") }}:
19 |
{{ allDocs.length }}
20 |
21 |
22 |
23 |
24 |
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 |
8 |
9 |
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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ $t("确定") }}
14 | {{ $t("取消") }}
15 |
16 |
17 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ $t("确定") }}
14 | {{ $t("取消") }}
15 |
16 |
17 |
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 |
8 |
9 |
10 |
14 |
15 |
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 |
8 | aa
9 |
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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{ $t("项目列表") }}
17 |
18 |
19 |
20 |
30 |
31 |
32 |
33 |
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 |
8 | {{ $t("团队管理") }}
9 |
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 |
8 |
9 |
10 |
11 |
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 |
8 | aa
9 |
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 |
8 |
9 |
10 |
11 | 格式化JSON
12 |
13 |
14 |
15 |
16 |
17 |
18 | 确认导入
19 | 取消
20 |
21 |
22 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | 保存
14 | 取消
15 |
16 |
17 |
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 |
8 |
9 |
10 |
11 | {{ $t("点击隐藏默认") }}
12 |
13 |
14 |
15 |
16 | {{ $t("个隐藏", { msg: defaultHeaders.length.toString()}) }}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 |
8 |
9 |
10 |
Query {{ $t("参数") }}
11 |
12 |
Path {{ $t("参数") }}
13 |
14 |
15 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ scope.row.value }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
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 |
8 |
18 |
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 |
8 |
9 |
10 |
11 |
12 |
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 |
8 |
9 |
10 |
11 |
{{ $t("当前版本") }}{{ config.localization.version }}
12 |
13 |
14 |
{{ $t("今日新增") }}:
15 |
{{ docsOfToday.length }}
16 |
17 |
18 |
{{ $t("接口总数") }}:
19 |
{{ allDocs.length }}
20 |
21 |
22 |
23 |
24 |
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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{ $t("确定") }}
16 | {{ $t("取消") }}
17 |
18 |
19 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ $t("确定") }}
14 | {{ $t("取消") }}
15 |
16 |
17 |
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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {{ $t("确定") }}
15 | {{ $t("取消") }}
16 |
17 |
18 |
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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {{ $t('确定') }}
15 | {{ $t('取消') }}
16 |
17 |
18 |
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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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 |
8 |
27 |
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 |
8 |
27 |
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 |
8 |
9 |
10 |
11 |
12 |
13 | {{ $t("确定") }}
14 | {{ $t("取消") }}
15 |
16 |
17 |
18 |
19 |
77 |
78 |
80 |
--------------------------------------------------------------------------------
/src/renderer/pages/modules/permission/user/reset-pwd/reset-pwd.vue:
--------------------------------------------------------------------------------
1 | /*
2 | 创建者:shuxiaokai
3 | 模块名称:重置密码
4 | 备注:
5 | */
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{ $t("确定") }}
14 | {{ $t("取消") }}
15 |
16 |
17 |
18 |
19 |
20 |
79 |
--------------------------------------------------------------------------------
/src/renderer/pages/test/test.vue:
--------------------------------------------------------------------------------
1 | /*
2 | 创建者:shuxiaokai
3 | 创建时间:2021-06-08 19:36
4 | 模块名称:test页面
5 | 备注:
6 | */
7 |
8 |
11 |
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 |
--------------------------------------------------------------------------------