commit 8ae43bfba90a2e78639994cda59ff7026df55905 Author: hucan <951870319@qq.com> Date: Sun Jun 29 00:36:30 2025 +0800 1 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..86c88f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: 🆕 Create new issue + url: http://new-issue.go-admin.dev + about: The issue which is not created via http://new-issue.go-admin.dev will be closed immediately. + - name: 🆕 创建一个新 Issue + url: http://new-issue.go-admin.dev + about: 不是用 http://new-issue.go-admin.dev 创建的 issue 会被机器人自动关闭。 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..049421b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,66 @@ + + +[[中文版模板 / Chinese template](https://github.com/go-admin-team/go-admin/blob/master/.github/PULL_REQUEST_TEMPLATE/pr_cn.md)] + +### 🤔 This is a ... + +- [ ] New feature +- [ ] Bug fix +- [ ] Site / documentation update +- [ ] Demo update +- [ ] Component style update +- [ ] TypeScript definition update +- [ ] Bundle size optimization +- [ ] Performance optimization +- [ ] Enhancement feature +- [ ] Internationalization +- [ ] Refactoring +- [ ] Code style optimization +- [ ] Test Case +- [ ] Branch merge +- [ ] Other (about what?) + +### 🔗 Related issue link + + + +### 💡 Background and solution + + + +### 📝 Changelog + + + +| Language | Changelog | +| ---------- | --------- | +| 🇺🇸 English | | +| 🇨🇳 Chinese | | + +### ☑️ Self-Check before Merge + +⚠️ Please check all items below before review. ⚠️ + +- [ ] Doc is updated/provided or not needed +- [ ] Demo is updated/provided or not needed +- [ ] TypeScript's definition is updated/provided or not needed +- [ ] Changelog is provided or not needed diff --git a/.github/PULL_REQUEST_TEMPLATE/pr_cn.md b/.github/PULL_REQUEST_TEMPLATE/pr_cn.md new file mode 100644 index 0000000..ce155b6 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pr_cn.md @@ -0,0 +1,61 @@ + + +[[English Template / 英文模板](https://github.com/go-admin-team/go-admin/blob/master/.github/PULL_REQUEST_TEMPLATE.md)] + +### 🤔 这个变动的性质是? + +- [ ] 新特性提交 +- [ ] 日常 bug 修复 +- [ ] 站点、文档改进 +- [ ] 演示代码改进 +- [ ] 组件样式/交互改进 +- [ ] TypeScript 定义更新 +- [ ] 包体积优化 +- [ ] 性能优化 +- [ ] 功能增强 +- [ ] 国际化改进 +- [ ] 重构 +- [ ] 代码风格优化 +- [ ] 测试用例 +- [ ] 分支合并 +- [ ] 其他改动(是关于什么的改动?) + +### 🔗 相关 Issue + + + +### 💡 需求背景和解决方案 + + + +### 📝 更新日志 + + + +| 语言 | 更新描述 | +| ------- | -------- | +| 🇺🇸 英文 | | +| 🇨🇳 中文 | | + +### ☑️ 请求合并前的自查清单 + +⚠️ 请自检并全部**勾选全部选项**。⚠️ + +- [ ] 文档已补充或无须补充 +- [ ] 代码演示已提供或无须提供 +- [ ] TypeScript 定义已补充或无须补充 +- [ ] Changelog 已提供或无须提供 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..8e2fd89 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,57 @@ +name: Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + IMAGE_NAME: registry.ap-northeast-1.aliyuncs.com/go-admin/go-admin-api # 镜像名称 + TAG: ${{ github.sha }} + IMAGE_NAME_TAG: registry.ap-northeast-1.aliyuncs.com/go-admin/go-admin-api:${{ github.sha }} + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.18 + + - name: Tidy + run: go mod tidy + + - name: Build + run: env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -tags "sqlite3,json1" --ldflags "-extldflags -static" -o main . + + - name: Build the Docker image and push + run: | + docker login --username=${{ secrets.DOCKER_USERNAME }} registry.ap-northeast-1.aliyuncs.com --password=${{ secrets.DOCKER_PASSWORD }} + echo "************ docker login end" + docker build -t go-admin-api:latest . + echo "************ docker build end" + docker tag go-admin-api ${{ env.IMAGE_NAME_TAG }} + echo "************ docker tag end" + docker images + echo "************ docker images end" + docker push ${{ env.IMAGE_NAME_TAG }} # 推送 + echo "************ docker push end" + + - name: Restart server # 第五步,重启服务 + uses: appleboy/ssh-action@master + env: + GITHUB_SHA_X: ${GITHUB_SHA} + with: + host: ${{ secrets.SSH_HOST }} # 下面三个配置与上一步类似 + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.DEPLOY_KEY }} + # 重启的脚本,根据自身情况做相应改动,一般要做的是migrate数据库以及重启服务器 + script: | + sudo docker rm -f go-admin-api + sudo docker login --username=${{ secrets.DOCKER_USERNAME }} registry.ap-northeast-1.aliyuncs.com --password=${{ secrets.DOCKER_PASSWORD }} + sudo docker run -d -p 8000:8000 --name go-admin-api ${{ env.IMAGE_NAME_TAG }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..2e08b34 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,51 @@ +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..fb65e63 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,62 @@ +name: build + +on: + push: + branches: [ master, dev ] + pull_request: + branches: [ master ] +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + + build: + name: Build + runs-on: ubuntu-latest + steps: + + - name: Set up Go 1.18 + uses: actions/setup-go@v3 + with: + go-version: 1.18 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v3 + + - name: Get dependencies + run: go mod tidy + - name: Build + run: make build + + - name: Log in to the Container registry + uses: docker/login-action@v2 + if: startsWith(${{github.ref}}, 'refs/tags/') + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + if: startsWith(${{github.ref}}, 'refs/tags/') + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + flavor: | + latest=auto + tags: | + type=schedule + type=ref,event=tag + type=sha,prefix=,format=long,enable=true,priority=100 + + - name: Build and push Docker image + uses: docker/build-push-action@v3 + if: startsWith(${{github.ref}}, 'refs/tags/') + with: + context: . + file: scripts/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/issue-check-inactive.yml b/.github/workflows/issue-check-inactive.yml new file mode 100644 index 0000000..9a79731 --- /dev/null +++ b/.github/workflows/issue-check-inactive.yml @@ -0,0 +1,22 @@ +name: Issue Check Inactive + +on: + schedule: + - cron: "0 0 */15 * *" + +permissions: + contents: read + +jobs: + issue-check-inactive: + permissions: + issues: write # for actions-cool/issues-helper to update issues + pull-requests: write # for actions-cool/issues-helper to update PRs + runs-on: ubuntu-latest + steps: + - name: check-inactive + uses: actions-cool/issues-helper@v3 + with: + actions: 'check-inactive' + inactive-label: 'Inactive' + inactive-day: 30 diff --git a/.github/workflows/issue-close-require.yml b/.github/workflows/issue-close-require.yml new file mode 100644 index 0000000..f1fc9b6 --- /dev/null +++ b/.github/workflows/issue-close-require.yml @@ -0,0 +1,32 @@ +name: Issue Close Require + +on: + schedule: + - cron: "0 0 * * *" + +permissions: + contents: read + +jobs: + issue-close-require: + permissions: + issues: write # for actions-cool/issues-helper to update issues + pull-requests: write # for actions-cool/issues-helper to update PRs + runs-on: ubuntu-latest + steps: + - name: need reproduce + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + labels: '🤔 Need Reproduce' + inactive-day: 3 + + - name: needs more info + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + labels: 'needs-more-info' + inactive-day: 3 + body: | + Since the issue was labeled with `needs-more-info`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply. + 由于该 issue 被标记为需要更多信息,却 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。 diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml new file mode 100644 index 0000000..5211d3e --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,76 @@ +# Origin Source +# https://github.com/ant-design/ant-design/blob/79f566b7f8abb1012ef55b0d2793bfdf5595b85d/.github/workflows/issue-reply.yml +name: Issue Labeled + +on: + issues: + types: [labeled] + +permissions: + contents: read + +jobs: + issue-labeled: + permissions: + issues: write # for actions-cool/issues-helper to update issues + pull-requests: write # for actions-cool/issues-helper to update PRs + runs-on: ubuntu-latest + steps: + - name: help wanted + if: github.event.label.name == 'help wanted' + uses: actions-cool/issues-helper@v3 + with: + actions: 'create-comment' + token: ${{ secrets.ADMIN_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to [send us a Pull Request](https://help.github.com/en/articles/creating-a-pull-request) for it. Please send your Pull Request to proper branch (feature branch for the new feature, master for bugfix and other changes), fill the [Pull Request Template](https://github.com/go-admin-team/go-admin/blob/master/.github/PULL_REQUEST_TEMPLATE.md) here, provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution! + 你好 @${{ github.event.issue.user.login }},我们完全同意你的提议/反馈,欢迎直接在此仓库 [创建一个 Pull Request](https://help.github.com/en/articles/creating-a-pull-request) 来解决这个问题。请将 Pull Request 发到正确的分支(新特性发到 feature 分支,其他发到 master 分支),务必填写 Pull Request 内的[预设模板](https://github.com/go-admin-team/go-admin/blob/master/.github/PULL_REQUEST_TEMPLATE.md),提供改动所需相应的 changelog、TypeScript 定义、测试用例、文档等,并确保 CI 通过,我们会尽快进行 Review,提前感谢和期待您的贡献。 + ![giphy](https://user-images.githubusercontent.com/507615/62342668-4735dc00-b51a-11e9-92a7-d46fbb1cc0c7.gif) + - name: 🤔 Need Reproduce + if: github.event.label.name == '🤔 Need Reproduce' + uses: actions-cool/issues-helper@v3 + with: + actions: 'create-comment' + token: ${{ secrets.ADMIN_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking this link https://u.ant.design/codesandbox-repro or a minimal GitHub repository. Issues labeled by `Need Reproduce` will be closed if no activities in 3 days. + 你好 @${{ github.event.issue.user.login }}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击 [此处](https://u.ant.design/codesandbox-repro) 创建一个 codesandbox 或者提供一个最小化的 GitHub 仓库。3 天内未跟进此 issue 将会被自动关闭。 + ![](https://gw.alipayobjects.com/zos/antfincdn/y9kwg7DVCd/reproduce.gif) + - name: Usage + if: github.event.label.name == 'Usage' || github.event.label.name == 'Question' + uses: actions-cool/issues-helper@v3 + with: + actions: 'create-comment,close-issue' + token: ${{ secrets.ADMIN_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hello @${{ github.event.issue.user.login }}, we use GitHub issues to trace bugs or discuss plans of Ant Design. So, please [don't ask usage questions](https://github.com/ant-design/ant-design/issues/2320) here. You can try to open a new discussion in [antd discussions](https://github.com/ant-design/ant-design/discussions), select `Q&A` to ask questions, also can ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/antd) or [Segment Fault](https://segmentfault.com/t/antd), then apply tag `antd` and `react` to your question. + 你好 @${{ github.event.issue.user.login }},go-admin Issue 板块是用于 bug 反馈与需求讨论的地方。请[勿询问如何使用的问题](https://github.com/go-admin-te/ant-design/issues/699),你可以试着在 [antd discussions](https://github.com/ant-design/ant-design/discussions) 新开一个 discussion,选择 `Q&A` 类别进行提问,也可以在 [Stack Overflow](https://stackoverflow.com/questions/tagged/antd) 或者 [Segment Fault](https://segmentfault.com/t/antd) 中提问(记得添加 `antd` 和 `react` 标签哦~)。 + - name: 3.x + if: github.event.label.name == '3.x' + uses: actions-cool/issues-helper@v3 + with: + actions: 'create-comment,close-issue' + token: ${{ secrets.ADMIN_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hi @${{ github.event.issue.user.login }}. Current version (3.x) is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed. + 你好 @${{ github.event.issue.user.login }},当前版本(3.x)已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。 + - name: invalid + if: github.event.label.name == 'Invalid' + uses: actions-cool/issues-helper@v3 + with: + actions: 'create-comment,close-issue' + token: ${{ secrets.ADMIN_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hello @${{ github.event.issue.user.login }}, your issue has been closed because it does not conform to our issue requirements. Please use the [Issue Helper](https://new-issue.go-admin.dev) to create an issue, thank you! + 你好 @${{ github.event.issue.user.login }},为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为不符合要求而被自动关闭。你可以通过 [issue 助手](https://new-issue.go-admin.dev) 来创建 issue 以方便我们定位错误。谢谢配合! + - name: rtl + if: github.event.label.name == 'rtl' + uses: actions-cool/issues-helper@v3 + with: + actions: 'add-assignees' + assignees: 'xrkffgg' diff --git a/.github/workflows/mirror.yaml b/.github/workflows/mirror.yaml new file mode 100644 index 0000000..9249c8e --- /dev/null +++ b/.github/workflows/mirror.yaml @@ -0,0 +1,29 @@ +name: 'GitHub Actions Mirror' + +on: [push, delete] + +jobs: + mirror_to_gitee: + runs-on: ubuntu-latest + steps: + - name: 'Checkout' + uses: actions/checkout@v1 + - name: 'Mirror to gitee' + uses: pixta-dev/repository-mirroring-action@v1 + with: + target_repo_url: + git@gitee.com:go-admin-team/go-admin.git + ssh_private_key: + ${{ secrets.GITEE_KEY }} + mirror_to_gitlab: + runs-on: ubuntu-latest + steps: + - name: 'Checkout' + uses: actions/checkout@v1 + - name: 'Mirror to gitlab' + uses: pixta-dev/repository-mirroring-action@v1 + with: + target_repo_url: + git@gitlab.com:go-admin-team/go-admin.git + ssh_private_key: + ${{ secrets.GITLAB_KEY }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24cb16d --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.idea +.vscode +*/.DS_Store +static/uploadfile +main.exe +*.exe +go-admin +go-admin.exe +temp/ +!temp +vendor +config/settings.dev.yml +config/settings.dev.*.yml +config/settings.dev.*.yml.log +temp/logs +config/settings.dev.yml.log +config/settings.b.dev.yml +cmd/migrate/migration/version-local/* +!cmd/migrate/migration/version-local/doc.go + +# go sum +go.sum +config/settings.deva.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fb3e023 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM alpine + +# ENV GOPROXY https://goproxy.cn/ + +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories + +RUN apk update --no-cache +RUN apk add --update gcc g++ libc6-compat +RUN apk add --no-cache ca-certificates +RUN apk add --no-cache tzdata +ENV TZ Asia/Shanghai + +COPY ./main /main +COPY ./config/settings.demo.yml /config/settings.yml +COPY ./go-admin-db.db /go-admin-db.db +EXPOSE 8000 +RUN chmod +x /main +CMD ["/main","server","-c", "/config/settings.yml"] \ No newline at end of file diff --git a/Dockerfilebak b/Dockerfilebak new file mode 100644 index 0000000..c5e33a5 --- /dev/null +++ b/Dockerfilebak @@ -0,0 +1,28 @@ +FROM golang:alpine as builder + +MAINTAINER lwnmengjing + +ENV GOPROXY https://goproxy.cn/ + +WORKDIR /go/release +#RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories +RUN apk update && apk add tzdata + +COPY go.mod ./go.mod +RUN go mod tidy +COPY . . +RUN pwd && ls + +RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -installsuffix cgo -o go-admin . + +FROM alpine + +COPY --from=builder /go/release/go-admin / + +COPY --from=builder /go/release/config/settings.yml /config/settings.yml + +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + +EXPOSE 8000 + +CMD ["/go-admin","server","-c", "/config/settings.yml"] \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..36b35f4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 go-admin-team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..afdb1a1 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +PROJECT:=go-admin + +.PHONY: build +build: + CGO_ENABLED=0 go build -ldflags="-w -s" -a -installsuffix "" -o go-admin . + +# make build-linux +build-linux: + @docker build -t go-admin:latest . + @echo "build successful" + +build-sqlite: + go build -tags sqlite3 -ldflags="-w -s" -a -installsuffix -o go-admin . + +# make run +run: + # delete go-admin-api container + @if [ $(shell docker ps -aq --filter name=go-admin --filter publish=8000) ]; then docker rm -f go-admin; fi + + # 启动方法一 run go-admin-api container docker-compose 启动方式 + # 进入到项目根目录 执行 make run 命令 + @docker-compose up -d + + # 启动方式二 docker run 这里注意-v挂载的宿主机的地址改为部署时的实际决对路径 + #@docker run --name=go-admin -p 8000:8000 -v /home/code/go/src/go-admin/go-admin/config:/go-admin-api/config -v /home/code/go/src/go-admin/go-admin-api/static:/go-admin/static -v /home/code/go/src/go-admin/go-admin/temp:/go-admin-api/temp -d --restart=always go-admin:latest + + @echo "go-admin service is running..." + + # delete Tag= 的镜像 + @docker image prune -f + @docker ps -a | grep "go-admin" + +stop: + # delete go-admin-api container + @if [ $(shell docker ps -aq --filter name=go-admin --filter publish=8000) ]; then docker-compose down; fi + #@if [ $(shell docker ps -aq --filter name=go-admin --filter publish=8000) ]; then docker rm -f go-admin; fi + #@echo "go-admin stop success" + + +#.PHONY: test +#test: +# go test -v ./... -cover + +#.PHONY: docker +#docker: +# docker build . -t go-admin:latest + +# make deploy +deploy: + + #@git checkout master + #@git pull origin master + make build-linux + make run diff --git a/README.Zh-cn.md b/README.Zh-cn.md new file mode 100644 index 0000000..50d207e --- /dev/null +++ b/README.Zh-cn.md @@ -0,0 +1,353 @@ +# go-admin + + + + +[![Build Status](https://github.com/wenjianzhang/go-admin/workflows/build/badge.svg)](https://github.com/go-admin-team/go-admin) +[![Release](https://img.shields.io/github/release/go-admin-team/go-admin.svg?style=flat-square)](https://github.com/go-admin-team/go-admin/releases) +[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/go-admin-team/go-admin) + +[English](https://github.com/go-admin-team/go-admin/blob/master/README.md) | 简体中文 + +基于Gin + Vue + Element UI OR Arco Design OR Ant Design的前后端分离权限管理系统,系统初始化极度简单,只需要配置文件中,修改数据库连接,系统支持多指令操作,迁移指令可以让初始化数据库信息变得更简单,服务指令可以很简单的启动api服务 + +[在线文档](https://www.go-admin.pro) + +[前端项目](https://github.com/go-admin-team/go-admin-ui) + +[视频教程](https://space.bilibili.com/565616721/channel/detail?cid=125737) + +## 🎬 在线体验 + +Element UI vue体验:[https://vue2.go-admin.dev](https://vue2.go-admin.dev/#/login) +> ⚠️⚠️⚠️ 账号 / 密码: admin / 123456 + +Arco Design vue3 demo:[https://vue3.go-admin.dev](https://vue3.go-admin.dev/#/login) +> ⚠️⚠️⚠️ 账号 / 密码: admin / 123456 + +antd体验:[https://antd.go-admin.pro](https://antd.go-admin.pro/) +> ⚠️⚠️⚠️ 账号 / 密码: admin / 123456 + +## ✨ 特性 + +- 遵循 RESTful API 设计规范 + +- 基于 GIN WEB API 框架,提供了丰富的中间件支持(用户认证、跨域、访问日志、追踪ID等) + +- 基于Casbin的 RBAC 访问控制模型 + +- JWT 认证 + +- 支持 Swagger 文档(基于swaggo) + +- 基于 GORM 的数据库存储,可扩展多种类型数据库 + +- 配置文件简单的模型映射,快速能够得到想要的配置 + +- 代码生成工具 + +- 表单构建工具 + +- 多指令模式 + +- 多租户的支持 + +- TODO: 单元测试 + +## 🎁 内置 + +1. 多租户:系统默认支持多租户,按库分离,一个库一个租户。 +1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 +3. 岗位管理:配置系统用户所属担任职务。 +4. 菜单管理:配置系统菜单,操作权限,按钮权限标识,接口权限等。 +5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 +6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +7. 参数管理:对系统动态配置常用参数。 +8. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +9. 登录日志:系统登录日志记录查询包含登录异常。 +1. 接口文档:根据业务代码自动生成相关的api接口文档。 +1. 代码生成:根据数据表结构生成对应的增删改查相对应业务,全程可视化操作,让基本业务可以零代码实现。 +1. 表单构建:自定义页面样式,拖拉拽实现页面布局。 +1. 服务监控:查看一些服务器的基本信息。 +1. 内容管理:demo功能,下设分类管理、内容管理。可以参考使用方便快速入门。 +1. 定时任务:自动化任务,目前支持接口调用和函数调用。 + +## 准备工作 + +你需要在本地安装 [go] [gin] [node](http://nodejs.org/) 和 [git](https://git-scm.com/) + +同时配套了系列教程包含视频和文档,如何从下载完成到熟练使用,强烈建议大家先看完这些教程再来实践本项目!!! + +### 轻松实现go-admin写出第一个应用 - 文档教程 + +[步骤一 - 基础内容介绍](https://doc.zhangwj.com/guide/intro/tutorial01.html) + +[步骤二 - 实际应用 - 编写增删改查](https://doc.zhangwj.com/guide/intro/tutorial02.html) + +### 手把手教你从入门到放弃 - 视频教程 + +[如何启动go-admin](https://www.bilibili.com/video/BV1z5411x7JG) + +[使用生成工具轻松实现业务](https://www.bilibili.com/video/BV1Dg4y1i79D) + +[v1.1.0版本代码生成工具-释放双手](https://www.bilibili.com/video/BV1N54y1i71P) [进阶] + +[多命令启动方式讲解以及IDE配置](https://www.bilibili.com/video/BV1Fg4y1q7ph) + +[go-admin菜单的配置说明](https://www.bilibili.com/video/BV1Wp4y1D715) [必看] + +[如何配置菜单信息以及接口信息](https://www.bilibili.com/video/BV1zv411B7nG) [必看] + +[go-admin权限配置使用说明](https://www.bilibili.com/video/BV1rt4y197d3) [必看] + +[go-admin数据权限使用说明](https://www.bilibili.com/video/BV1LK4y1s71e) [必看] + +**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr ,视频教程和文档持续更新中** + +## 📦 本地开发 + +### 环境要求 + +go 1.18 + +node版本: v14.16.0 + +npm版本: 6.14.11 + +### 开发目录创建 + +```bash + +# 创建开发目录 +mkdir goadmin +cd goadmin +``` + +### 获取代码 + +> 重点注意:两个项目必须放在同一文件夹下; + +```bash +# 获取后端代码 +git clone https://github.com/go-admin-team/go-admin.git + +# 获取前端代码 +git clone https://github.com/go-admin-team/go-admin-ui.git + +``` + +### 启动说明 + +#### 服务端启动说明 + +```bash +# 进入 go-admin 后端项目 +cd ./go-admin + +# 更新整理依赖 +go mod tidy + +# 编译项目 +go build + +# 修改配置 +# 文件路径 go-admin/config/settings.yml +vi ./config/settings.yml + +# 1. 配置文件中修改数据库信息 +# 注意: settings.database 下对应的配置数据 +# 2. 确认log路径 +``` + +:::tip ⚠️注意 在windows环境如果没有安装中CGO,会出现这个问题; + +```bash +E:\go-admin>go build +# github.com/mattn/go-sqlite3 +cgo: exec /missing-cc: exec: "/missing-cc": file does not exist +``` + +or + +```bash +D:\Code\go-admin>go build +# github.com/mattn/go-sqlite3 +cgo: exec gcc: exec: "gcc": executable file not found in %PATH% +``` + +[解决cgo问题进入](https://doc.go-admin.dev/zh-CN/guide/faq#cgo-%E7%9A%84%E9%97%AE%E9%A2%98) + +::: + +#### 初始化数据库,以及服务启动 + +``` bash +# 首次配置需要初始化数据库资源信息 +# macOS or linux 下使用 +$ ./go-admin migrate -c config/settings.dev.yml + +# ⚠️注意:windows 下使用 +$ go-admin.exe migrate -c config/settings.dev.yml + + +# 启动项目,也可以用IDE进行调试 +# macOS or linux 下使用 +$ ./go-admin server -c config/settings.yml + + +# ⚠️注意:windows 下使用 +$ go-admin.exe server -c config/settings.yml +``` + +#### sys_api 表的数据如何添加 + +在项目启动时,使用`-a true` 系统会自动添加缺少的接口数据 +```bash +./go-admin server -c config/settings.yml -a true +``` + +#### 使用docker 编译启动 + +```shell +# 编译镜像 +docker build -t go-admin . + +# 启动容器,第一个go-admin是容器名字,第二个go-admin是镜像名称 +# -v 映射配置文件 本地路径:容器路径 +docker run --name go-admin -p 8000:8000 -v /config/settings.yml:/config/settings.yml -d go-admin-server +``` + +#### 文档生成 + +```bash +go generate +``` + +#### 交叉编译 + +```bash +# windows +env GOOS=windows GOARCH=amd64 go build main.go + +# or +# linux +env GOOS=linux GOARCH=amd64 go build main.go +``` + +### UI交互端启动说明 + +```bash +# 安装依赖 +npm install + +# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 +npm install --registry=https://registry.npmmirror.com + +# 启动服务 +npm run dev +``` + +## 📨 互动 + + + + + + + + + + + + + + +
wenjianzhang
微信公众号🔥🔥🔥go-admin技术交流乙号哔哩哔哩🔥🔥🔥
+ +## 💎 贡献者 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## JetBrains 开源证书支持 + +`go-admin` 项目一直以来都是在 JetBrains 公司旗下的 GoLand 集成开发环境中进行开发,基于 **free JetBrains Open Source license(s)** 正版免费授权,在此表达我的谢意。 + + + +## 🤝 特别感谢 + +1. [ant-design](https://github.com/ant-design/ant-design) +2. [ant-design-pro](https://github.com/ant-design/ant-design-pro) +2. [arco-design](https://github.com/arco-design/arco-design) +2. [arco-design-pro](https://github.com/arco-design/arco-design-pro) +4. [gin](https://github.com/gin-gonic/gin) +5. [casbin](https://github.com/casbin/casbin) +6. [spf13/viper](https://github.com/spf13/viper) +7. [gorm](https://github.com/jinzhu/gorm) +8. [gin-swagger](https://github.com/swaggo/gin-swagger) +9. [jwt-go](https://github.com/dgrijalva/jwt-go) +10. [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) +11. [ruoyi-vue](https://gitee.com/y_project/RuoYi-Vue) +12. [form-generator](https://github.com/JakHuang/form-generator) + + +## 🤟 打赏 + +> 如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink: + + + +## 🤝 链接 + +[Go开发者成长线路图](http://www.golangroadmap.com/) + +## 🔑 License + +[MIT](https://github.com/go-admin-team/go-admin/blob/master/LICENSE.md) + +Copyright (c) 2022 wenjianzhang diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa0825a --- /dev/null +++ b/README.md @@ -0,0 +1,342 @@ + +# go-admin + + + + +[![Build Status](https://github.com/wenjianzhang/go-admin/workflows/build/badge.svg)](https://github.com/go-admin-team/go-admin) +[![Release](https://img.shields.io/github/release/go-admin-team/go-admin.svg?style=flat-square)](https://github.com/go-admin-team/go-admin/releases) +[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/go-admin-team/go-admin) + +English | [简体中文](https://github.com/go-admin-team/go-admin/blob/master/README.Zh-cn.md) + +The front-end and back-end separation authority management system based on Gin + Vue + Element UI OR Arco Design is extremely simple to initialize the system. You only need to modify the database connection in the configuration file. The system supports multi-instruction operations. Migration instructions can make it easier to initialize database information. Service instructions It's easy to start the api service. + +[documentation](https://www.go-admin.dev) + +[Front-end project](https://github.com/go-admin-team/go-admin-ui) + +[Video tutorial](https://space.bilibili.com/565616721/channel/detail?cid=125737) + +## 🎬 Online Demo + +Element UI vue demo:[https://vue2.go-admin.dev](https://vue2.go-admin.dev/#/login) +> 账号 / 密码: admin / 123456 + +Arco Design vue3 demo:[https://vue3.go-admin.dev](https://vue3.go-admin.dev/#/login) +> 账号 / 密码: admin / 123456 + +antd demo:[https://antd.go-admin.pro](https://antd.go-admin.pro/) +> 账号 / 密码: admin / 123456 +> +## ✨ Feature + +- Follow RESTful API design specifications + +- Based on the GIN WEB API framework, it provides rich middleware support (user authentication, cross-domain, access log, tracking ID, etc.) + +- RBAC access control model based on Casbin + +- JWT authentication + +- Support Swagger documents (based on swaggo) + +- Database storage based on GORM, which can expand multiple types of databases + +- Simple model mapping of configuration files to quickly get the desired configuration + +- Code generation tool + +- Form builder + +- Multi-command mode + +- TODO: unit test + + +## 🎁 Internal + +1. User management: The user is the system operator, this function mainly completes the system user configuration. +2. Department management: configure the system organization (company, department, group), and display the tree structure to support data permissions. +3. Position management: configure the positions of system users. +4. Menu management: configure the system menu, operation authority, button authority identification, interface authority, etc. +5. Role management: Role menu permission assignment and role setting are divided into data scope permissions by organization. +6. Dictionary management: Maintain some relatively fixed data frequently used in the system. +7. Parameter management: dynamically configure common parameters for the system. +8. Operation log: system normal operation log record and query; system abnormal information log record and query. +9. Login log: The system login log record query contains login exceptions. +1. Interface documentation: Automatically generate related api interface documents according to the business code. +1. Code generation: According to the data table structure, generate the corresponding addition, deletion, modification, and check corresponding business, and the whole process of visual operation, so that the basic business can be implemented with zero code. +1. Form construction: Customize the page style, drag and drop to realize the page layout. +1. Service monitoring: View the basic information of some servers. +1. Content management: demo function, including classification management and content management. You can refer to the easy to use quick start. + +## Ready to work + +You need to install locally [go] [gin] [node](http://nodejs.org/) 和 [git](https://git-scm.com/) + +At the same time, a series of tutorials including videos and documents are provided. How to complete the downloading to the proficient use, it is strongly recommended that you read these tutorials before you practice this project! ! ! + +### Easily implement go-admin to write the first application-documentation tutorial + +[Step 1 - basic content introduction](https://doc.zhangwj.com/guide/intro/tutorial01.html) + +[Step 2 - Practical application - writing database operations](https://doc.zhangwj.com/guide/intro/tutorial02.html) + +### Teach you from getting started to giving up-video tutorial + +[How to start go-admin](https://www.bilibili.com/video/BV1z5411x7JG) + +[Easily implement business using build tools](https://www.bilibili.com/video/BV1Dg4y1i79D) + +[v1.1.0 version code generation tool-free your hands](https://www.bilibili.com/video/BV1N54y1i71P) [Advanced] + +[Explanation of multi-command startup mode and IDE configuration](https://www.bilibili.com/video/BV1Fg4y1q7ph) + +[Configuration instructions for go-admin menu](https://www.bilibili.com/video/BV1Wp4y1D715) [Must see] + +[How to configure menu information and interface information](https://www.bilibili.com/video/BV1zv411B7nG) [Must see] + +[go-admin permission configuration instructions](https://www.bilibili.com/video/BV1rt4y197d3) [Must see] + +[Instructions for use of go-admin data permissions](https://www.bilibili.com/video/BV1LK4y1s71e) [Must see] + +**If you have any questions, please read the above-mentioned usage documents and articles first. If you are not satisfied, welcome to issue and pr. Video tutorials and documents are being updated continuously.** + +## 📦 Local development + +### Environmental requirements + +go 1.18 + +nodejs: v14.16.0 + +npm: 6.14.11 + +### Development directory creation + +```bash + +# Create a development directory +mkdir goadmin +cd goadmin +``` + +### Get the code + +> Important note: the two projects must be placed in the same folder; + +```bash +# Get backend code +git clone https://github.com/go-admin-team/go-admin.git + +# Get the front-end code +git clone https://github.com/go-admin-team/go-admin-ui.git + +``` + +### Startup instructions + +#### Server startup instructions + +```bash +# Enter the go-admin backend project +cd ./go-admin + +# Update dependencies +go mod tidy + +# Compile the project +go build + +# Change setting +# File path go-admin/config/settings.yml +vi ./config/settings.yml + +# 1. Modify the database information in the configuration file +# Note: The corresponding configuration data under settings.database +# 2. Confirm the log path +``` + +:::tip ⚠️Note that this problem will occur if CGO is not installed in the windows10+ environment; + +```bash +E:\go-admin>go build +# github.com/mattn/go-sqlite3 +cgo: exec /missing-cc: exec: "/missing-cc": file does not exist +``` + +or + +```bash +D:\Code\go-admin>go build +# github.com/mattn/go-sqlite3 +cgo: exec gcc: exec: "gcc": executable file not found in %PATH% +``` + +[Solve the cgo problem and enter](https://doc.go-admin.dev/guide/faq#cgo-%E7%9A%84%E9%97%AE%E9%A2%98) + +::: + +#### Initialize the database, and start the service + +``` bash +# The first configuration needs to initialize the database resource information +# Use under macOS or linux +$ ./go-admin migrate -c config/settings.dev.yml + +# ⚠️Note: Use under windows +$ go-admin.exe migrate -c config/settings.dev.yml + +# Start the project, you can also use the IDE for debugging +# Use under macOS or linux +$ ./go-admin server -c config/settings.yml + +# ⚠️Note: Use under windows +$ go-admin.exe server -c config/settings.yml +``` + +#### Use docker to compile and start + +```shell +# Compile the image +docker build -t go-admin . + + +# Start the container, the first go-admin is the container name, and the second go-admin is the image name +# -v Mapping configuration file Local path: container path +docker run --name go-admin -p 8000:8000 -v /config/settings.yml:/config/settings.yml -d go-admin-server +``` + + + +#### Generation Document + +```bash +go generate +``` + +#### Cross compile +```bash +# windows +env GOOS=windows GOARCH=amd64 go build main.go + +# or +# linux +env GOOS=linux GOARCH=amd64 go build main.go +``` + +### UI interactive terminal startup instructions + +```bash +# Installation dependencies +npm install # or cnpm install + +# Start service +npm run dev +``` + +## 📨 Interactive + + + + + + + + + + + + + + +
wenjianzhang
WechatWechat公众号🔥🔥🔥go-admin技术交流乙号bilibili🔥🔥🔥
+ +## 💎 Contributors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## JetBrains open source certificate support + +The `go-admin` project has always been developed in the GoLand integrated development environment under JetBrains, based on the **free JetBrains Open Source license(s)** genuine free license. I would like to express my gratitude. + + + + +## 🤝 Thanks + +1. [ant-design](https://github.com/ant-design/ant-design) +2. [ant-design-pro](https://github.com/ant-design/ant-design-pro) +2. [arco-design](https://github.com/arco-design/arco-design) +2. [arco-design-pro](https://github.com/arco-design/arco-design-pro) +2. [gin](https://github.com/gin-gonic/gin) +2. [casbin](https://github.com/casbin/casbin) +2. [spf13/viper](https://github.com/spf13/viper) +2. [gorm](https://github.com/jinzhu/gorm) +2. [gin-swagger](https://github.com/swaggo/gin-swagger) +2. [jwt-go](https://github.com/dgrijalva/jwt-go) +2. [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) +2. [ruoyi-vue](https://gitee.com/y_project/RuoYi-Vue) +2. [form-generator](https://github.com/JakHuang/form-generator) + +## 🤟 Sponsor Us + +> If you think this project helped you, you can buy a glass of juice for the author to show encouragement :tropical_drink: + + + +## 🤝 Link +[Go developer growth roadmap](http://www.golangroadmap.com/) +[mss-boot-io](https://docs.mss-boot-io.top/) + +## 🔑 License + +[MIT](https://github.com/go-admin-team/go-admin/blob/master/LICENSE.md) + +Copyright (c) 2022 wenjianzhang diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..c419263 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file diff --git a/aggregate_translate_server b/aggregate_translate_server new file mode 100644 index 0000000..699132c Binary files /dev/null and b/aggregate_translate_server differ diff --git a/app/admin/apis/captcha.go b/app/admin/apis/captcha.go new file mode 100644 index 0000000..f5bccac --- /dev/null +++ b/app/admin/apis/captcha.go @@ -0,0 +1,37 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/captcha" +) + +type System struct { + api.Api +} + +// GenerateCaptchaHandler 获取验证码 +// @Summary 获取验证码 +// @Description 获取验证码 +// @Tags 登陆 +// @Success 200 {object} response.Response{data=string,id=string,msg=string} "{"code": 200, "data": [...]}" +// @Router /api/v1/captcha [get] +func (e System) GenerateCaptchaHandler(c *gin.Context) { + err := e.MakeContext(c).Errors + if err != nil { + e.Error(500, err, "服务初始化失败!") + return + } + id, b64s, err := captcha.DriverDigitFunc() + if err != nil { + e.Logger.Errorf("DriverDigitFunc error, %s", err.Error()) + e.Error(500, err, "验证码获取失败") + return + } + e.Custom(gin.H{ + "code": 200, + "data": b64s, + "id": id, + "msg": "success", + }) +} diff --git a/app/admin/apis/go_admin.go b/app/admin/apis/go_admin.go new file mode 100644 index 0000000..14a06dc --- /dev/null +++ b/app/admin/apis/go_admin.go @@ -0,0 +1,39 @@ +package apis + +import ( + "github.com/gin-gonic/gin" +) + +const INDEX = ` + + + + +GO-ADMIN欢迎您 + + + + + + + + +` + +func GoAdmin(c *gin.Context) { + c.Header("Content-Type", "text/html; charset=utf-8") + c.String(200, INDEX) +} diff --git a/app/admin/apis/sys_api.go b/app/admin/apis/sys_api.go new file mode 100644 index 0000000..c2d3474 --- /dev/null +++ b/app/admin/apis/sys_api.go @@ -0,0 +1,148 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type SysApi struct { + api.Api +} + +// GetPage 获取接口管理列表 +// @Summary 获取接口管理列表 +// @Description 获取接口管理列表 +// @Tags 接口管理 +// @Param name query string false "名称" +// @Param title query string false "标题" +// @Param path query string false "地址" +// @Param action query string false "类型" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.SysApi}} "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-api [get] +// @Security Bearer +func (e SysApi) GetPage(c *gin.Context) { + s := service.SysApi{} + req := dto.SysApiGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + //数据权限检查 + p := actions.GetPermissionFromContext(c) + list := make([]models.SysApi, 0) + var count int64 + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取接口管理 +// @Summary 获取接口管理 +// @Description 获取接口管理 +// @Tags 接口管理 +// @Param id path string false "id" +// @Success 200 {object} response.Response{data=models.SysApi} "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-api/{id} [get] +// @Security Bearer +func (e SysApi) Get(c *gin.Context) { + req := dto.SysApiGetReq{} + s := service.SysApi{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + p := actions.GetPermissionFromContext(c) + var object models.SysApi + err = s.Get(&req, p, &object).Error + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(object, "查询成功") +} + +// Update 修改接口管理 +// @Summary 修改接口管理 +// @Description 修改接口管理 +// @Tags 接口管理 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysApiUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/sys-api/{id} [put] +// @Security Bearer +func (e SysApi) Update(c *gin.Context) { + req := dto.SysApiUpdateReq{} + s := service.SysApi{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, "更新失败") + return + } + e.OK(req.GetId(), "更新成功") +} + +// DeleteSysApi 删除接口管理 +// @Summary 删除接口管理 +// @Description 删除接口管理 +// @Tags 接口管理 +// @Param data body dto.SysApiDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/sys-api [delete] +// @Security Bearer +func (e SysApi) DeleteSysApi(c *gin.Context) { + req := dto.SysApiDeleteReq{} + s := service.SysApi{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + return + } + p := actions.GetPermissionFromContext(c) + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, "删除失败") + return + } + e.OK(req.GetId(), "删除成功") +} \ No newline at end of file diff --git a/app/admin/apis/sys_config.go b/app/admin/apis/sys_config.go new file mode 100644 index 0000000..0a95c8b --- /dev/null +++ b/app/admin/apis/sys_config.go @@ -0,0 +1,313 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysConfig struct { + api.Api +} + +// GetPage 获取配置管理列表 +// @Summary 获取配置管理列表 +// @Description 获取配置管理列表 +// @Tags 配置管理 +// @Param configName query string false "名称" +// @Param configKey query string false "key" +// @Param configType query string false "类型" +// @Param isFrontend query int false "是否前端" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.SysApi}} "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-config [get] +// @Security Bearer +func (e SysConfig) GetPage(c *gin.Context) { + s := service.SysConfig{} + req := dto.SysConfigGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + return + } + + list := make([]models.SysConfig, 0) + var count int64 + err = s.GetPage(&req, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取配置管理 +// @Summary 获取配置管理 +// @Description 获取配置管理 +// @Tags 配置管理 +// @Param id path string false "id" +// @Success 200 {object} response.Response{data=models.SysConfig} "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-config/{id} [get] +// @Security Bearer +func (e SysConfig) Get(c *gin.Context) { + req := dto.SysConfigGetReq{} + s := service.SysConfig{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SysConfig + + err = s.Get(&req, &object) + if err != nil { + e.Error(500, err, err.Error()) + return + } + + e.OK(object, "查询成功") +} + +// Insert 创建配置管理 +// @Summary 创建配置管理 +// @Description 创建配置管理 +// @Tags 配置管理 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysConfigControl true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "创建成功"}" +// @Router /api/v1/sys-config [post] +// @Security Bearer +func (e SysConfig) Insert(c *gin.Context) { + s := service.SysConfig{} + req := dto.SysConfigControl{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, "创建失败") + return + } + e.OK(req.GetId(), "创建成功") +} + +// Update 修改配置管理 +// @Summary 修改配置管理 +// @Description 修改配置管理 +// @Tags 配置管理 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysConfigControl true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/sys-config/{id} [put] +// @Security Bearer +func (e SysConfig) Update(c *gin.Context) { + s := service.SysConfig{} + req := dto.SysConfigControl{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.Update(&req) + if err != nil { + e.Error(500, err, "更新失败") + return + } + e.OK(req.GetId(), "更新成功") +} + +// Delete 删除配置管理 +// @Summary 删除配置管理 +// @Description 删除配置管理 +// @Tags 配置管理 +// @Param ids body []int false "ids" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/sys-config [delete] +// @Security Bearer +func (e SysConfig) Delete(c *gin.Context) { + s := service.SysConfig{} + req := dto.SysConfigDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + + err = s.Remove(&req) + if err != nil { + e.Error(500, err, "删除失败") + return + } + e.OK(req.GetId(), "删除成功") +} + +// Get2SysApp 获取系统配置信息 +// @Summary 获取系统前台配置信息,主要注意这里不在验证权限 +// @Description 获取系统配置信息,主要注意这里不在验证权限 +// @Tags 配置管理 +// @Success 200 {object} response.Response{data=map[string]string} "{"code": 200, "data": [...]}" +// @Router /api/v1/app-config [get] +func (e SysConfig) Get2SysApp(c *gin.Context) { + req := dto.SysConfigGetToSysAppReq{} + s := service.SysConfig{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + return + } + // 控制只读前台的数据 + req.IsFrontend = "1" + list := make([]models.SysConfig, 0) + err = s.GetWithKeyList(&req, &list) + if err != nil { + e.Error(500, err, "查询失败") + return + } + mp := make(map[string]string) + for i := 0; i < len(list); i++ { + key := list[i].ConfigKey + if key != "" { + mp[key] = list[i].ConfigValue + } + } + e.OK(mp, "查询成功") +} + +// Get2Set 获取配置 +// @Summary 获取配置 +// @Description 界面操作设置配置值的获取 +// @Tags 配置管理 +// @Accept application/json +// @Product application/json +// @Success 200 {object} response.Response{data=map[string]interface{}} "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/set-config [get] +// @Security Bearer +func (e SysConfig) Get2Set(c *gin.Context) { + s := service.SysConfig{} + req := make([]dto.GetSetSysConfigReq, 0) + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + err = s.GetForSet(&req) + if err != nil { + e.Error(500, err, "查询失败") + return + } + m := make(map[string]interface{}, 0) + for _, v := range req { + m[v.ConfigKey] = v.ConfigValue + } + e.OK(m, "查询成功") +} + +// Update2Set 设置配置 +// @Summary 设置配置 +// @Description 界面操作设置配置值 +// @Tags 配置管理 +// @Accept application/json +// @Product application/json +// @Param data body []dto.GetSetSysConfigReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/set-config [put] +// @Security Bearer +func (e SysConfig) Update2Set(c *gin.Context) { + s := service.SysConfig{} + req := make([]dto.GetSetSysConfigReq, 0) + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + err = s.UpdateForSet(&req) + if err != nil { + e.Error(500, err, err.Error()) + return + } + + e.OK("", "更新成功") +} + +// GetSysConfigByKEYForService 根据Key获取SysConfig的Service +// @Summary 根据Key获取SysConfig的Service +// @Description 根据Key获取SysConfig的Service +// @Tags 配置管理 +// @Param configKey path string false "configKey" +// @Success 200 {object} response.Response{data=dto.SysConfigByKeyReq} "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-config/{id} [get] +// @Security Bearer +func (e SysConfig) GetSysConfigByKEYForService(c *gin.Context) { + var s = new(service.SysConfig) + var req = new(dto.SysConfigByKeyReq) + var resp = new(dto.GetSysConfigByKEYForServiceResp) + err := e.MakeContext(c). + MakeOrm(). + Bind(req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + err = s.GetWithKey(req, resp) + if err != nil { + e.Error(500, err, err.Error()) + return + } + e.OK(resp, s.Msg) +} diff --git a/app/admin/apis/sys_dept.go b/app/admin/apis/sys_dept.go new file mode 100644 index 0000000..f37eae4 --- /dev/null +++ b/app/admin/apis/sys_dept.go @@ -0,0 +1,238 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "go-admin/app/admin/models" + + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysDept struct { + api.Api +} + +// GetPage +// @Summary 分页部门列表数据 +// @Description 分页列表 +// @Tags 部门 +// @Param deptName query string false "deptName" +// @Param deptId query string false "deptId" +// @Param position query string false "position" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dept [get] +// @Security Bearer +func (e SysDept) GetPage(c *gin.Context) { + s := service.SysDept{} + req := dto.SysDeptGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + list := make([]models.SysDept, 0) + list, err = s.SetDeptPage(&req) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(list, "查询成功") +} + +// Get +// @Summary 获取部门数据 +// @Description 获取JSON +// @Tags 部门 +// @Param deptId path string false "deptId" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dept/{deptId} [get] +// @Security Bearer +func (e SysDept) Get(c *gin.Context) { + s := service.SysDept{} + req := dto.SysDeptGetReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SysDept + + err = s.Get(&req, &object) + if err != nil { + e.Error(500, err, "查询失败") + return + } + + e.OK(object, "查询成功") +} + +// Insert 添加部门 +// @Summary 添加部门 +// @Description 获取JSON +// @Tags 部门 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysDeptInsertReq true "data" +// @Success 200 {string} string "{"code": 200, "message": "添加成功"}" +// @Success 200 {string} string "{"code": -1, "message": "添加失败"}" +// @Router /api/v1/dept [post] +// @Security Bearer +func (e SysDept) Insert(c *gin.Context) { + s := service.SysDept{} + req := dto.SysDeptInsertReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + err = s.Insert(&req) + if err != nil { + e.Error(500, err, "创建失败") + return + } + e.OK(req.GetId(), "创建成功") +} + +// Update +// @Summary 修改部门 +// @Description 获取JSON +// @Tags 部门 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.SysDeptUpdateReq true "body" +// @Success 200 {string} string "{"code": 200, "message": "添加成功"}" +// @Success 200 {string} string "{"code": -1, "message": "添加失败"}" +// @Router /api/v1/dept/{deptId} [put] +// @Security Bearer +func (e SysDept) Update(c *gin.Context) { + s := service.SysDept{} + req := dto.SysDeptUpdateReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.Update(&req) + if err != nil { + e.Error(500, err, err.Error()) + return + } + e.OK(req.GetId(), "更新成功") +} + +// Delete +// @Summary 删除部门 +// @Description 删除数据 +// @Tags 部门 +// @Param data body dto.SysDeptDeleteReq true "body" +// @Success 200 {string} string "{"code": 200, "message": "删除成功"}" +// @Success 200 {string} string "{"code": -1, "message": "删除失败"}" +// @Router /api/v1/dept [delete] +// @Security Bearer +func (e SysDept) Delete(c *gin.Context) { + s := service.SysDept{} + req := dto.SysDeptDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + err = s.Remove(&req) + if err != nil { + e.Error(500, err, "删除失败") + return + } + e.OK(req.GetId(), "删除成功") +} + +// Get2Tree 用户管理 左侧部门树 +func (e SysDept) Get2Tree(c *gin.Context) { + s := service.SysDept{} + req := dto.SysDeptGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req,binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + list := make([]dto.DeptLabel, 0) + list, err = s.SetDeptTree(&req) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(list, "") +} + +// GetDeptTreeRoleSelect TODO: 此接口需要调整不应该将list和选中放在一起 +func (e SysDept) GetDeptTreeRoleSelect(c *gin.Context) { + s := service.SysDept{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + id, err := pkg.StringToInt(c.Param("roleId")) + result, err := s.SetDeptLabel() + if err != nil { + e.Error(500, err, err.Error()) + return + } + menuIds := make([]int, 0) + if id != 0 { + menuIds, err = s.GetWithRoleId(id) + if err != nil { + e.Error(500, err, err.Error()) + return + } + } + e.OK(gin.H{ + "depts": result, + "checkedKeys": menuIds, + }, "") +} \ No newline at end of file diff --git a/app/admin/apis/sys_dict_data.go b/app/admin/apis/sys_dict_data.go new file mode 100644 index 0000000..049fe99 --- /dev/null +++ b/app/admin/apis/sys_dict_data.go @@ -0,0 +1,220 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "go-admin/app/admin/models" + + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysDictData struct { + api.Api +} + +// GetPage +// @Summary 字典数据列表 +// @Description 获取JSON +// @Tags 字典数据 +// @Param status query string false "status" +// @Param dictCode query string false "dictCode" +// @Param dictType query string false "dictType" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/data [get] +// @Security Bearer +func (e SysDictData) GetPage(c *gin.Context) { + s := service.SysDictData{} + req := dto.SysDictDataGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + list := make([]models.SysDictData, 0) + var count int64 + err = s.GetPage(&req, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get +// @Summary 通过编码获取字典数据 +// @Description 获取JSON +// @Tags 字典数据 +// @Param dictCode path int true "字典编码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/data/{dictCode} [get] +// @Security Bearer +func (e SysDictData) Get(c *gin.Context) { + s := service.SysDictData{} + req := dto.SysDictDataGetReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + var object models.SysDictData + + err = s.Get(&req, &object) + if err != nil { + e.Logger.Warnf("Get error: %s", err.Error()) + e.Error(500, err, "查询失败") + return + } + + e.OK(object, "查询成功") +} + +// Insert +// @Summary 添加字典数据 +// @Description 获取JSON +// @Tags 字典数据 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysDictDataInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/dict/data [post] +// @Security Bearer +func (e SysDictData) Insert(c *gin.Context) { + s := service.SysDictData{} + req := dto.SysDictDataInsertReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetCreateBy(user.GetUserId(c)) + err = s.Insert(&req) + if err != nil { + e.Error(500, err, "创建失败") + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update +// @Summary 修改字典数据 +// @Description 获取JSON +// @Tags 字典数据 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysDictDataUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/dict/data/{dictCode} [put] +// @Security Bearer +func (e SysDictData) Update(c *gin.Context) { + s := service.SysDictData{} + req := dto.SysDictDataUpdateReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.Update(&req) + if err != nil { + e.Error(500, err, "更新失败") + return + } + e.OK(req.GetId(), "更新成功") +} + +// Delete +// @Summary 删除字典数据 +// @Description 删除数据 +// @Tags 字典数据 +// @Param dictCode body dto.SysDictDataDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/dict/data [delete] +// @Security Bearer +func (e SysDictData) Delete(c *gin.Context) { + s := service.SysDictData{} + req := dto.SysDictDataDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.Remove(&req) + if err != nil { + e.Error(500, err, "删除失败") + return + } + e.OK(req.GetId(), "删除成功") +} + +// GetAll 数据字典根据key获取 业务页面使用 +// @Summary 数据字典根据key获取 +// @Description 数据字典根据key获取 +// @Tags 字典数据 +// @Param dictType query int true "dictType" +// @Success 200 {object} response.Response{data=[]dto.SysDictDataGetAllResp} "{"code": 200, "data": [...]}" +// @Router /api/v1/dict-data/option-select [get] +// @Security Bearer +func (e SysDictData) GetAll(c *gin.Context) { + s := service.SysDictData{} + req := dto.SysDictDataGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + list := make([]models.SysDictData, 0) + err = s.GetAll(&req, &list) + if err != nil { + e.Error(500, err, "查询失败") + return + } + l := make([]dto.SysDictDataGetAllResp, 0) + for _, i := range list { + d := dto.SysDictDataGetAllResp{} + e.Translate(i, &d) + l = append(l, d) + } + + e.OK(l,"查询成功") +} diff --git a/app/admin/apis/sys_dict_type.go b/app/admin/apis/sys_dict_type.go new file mode 100644 index 0000000..b93035e --- /dev/null +++ b/app/admin/apis/sys_dict_type.go @@ -0,0 +1,210 @@ +package apis + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "go-admin/app/admin/models" + + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysDictType struct { + api.Api +} + +// GetPage 字典类型列表数据 +// @Summary 字典类型列表数据 +// @Description 获取JSON +// @Tags 字典类型 +// @Param dictName query string false "dictName" +// @Param dictId query string false "dictId" +// @Param dictType query string false "dictType" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/type [get] +// @Security Bearer +func (e SysDictType) GetPage(c *gin.Context) { + s := service.SysDictType{} + req :=dto.SysDictTypeGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + list := make([]models.SysDictType, 0) + var count int64 + err = s.GetPage(&req, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 字典类型通过字典id获取 +// @Summary 字典类型通过字典id获取 +// @Description 获取JSON +// @Tags 字典类型 +// @Param dictId path int true "字典类型编码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/type/{dictId} [get] +// @Security Bearer +func (e SysDictType) Get(c *gin.Context) { + s := service.SysDictType{} + req :=dto.SysDictTypeGetReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SysDictType + err = s.Get(&req, &object) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(object, "查询成功") +} + +//Insert 字典类型创建 +// @Summary 添加字典类型 +// @Description 获取JSON +// @Tags 字典类型 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysDictTypeInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/type [post] +// @Security Bearer +func (e SysDictType) Insert(c *gin.Context) { + s := service.SysDictType{} + req :=dto.SysDictTypeInsertReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetCreateBy(user.GetUserId(c)) + err = s.Insert(&req) + if err != nil { + e.Logger.Error(err) + e.Error(500, err,fmt.Sprintf(" 创建字典类型失败,详情:%s", err.Error())) + return + } + e.OK(req.GetId(), "创建成功") +} + +// Update +// @Summary 修改字典类型 +// @Description 获取JSON +// @Tags 字典类型 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysDictTypeUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/type/{dictId} [put] +// @Security Bearer +func (e SysDictType) Update(c *gin.Context) { + s := service.SysDictType{} + req :=dto.SysDictTypeUpdateReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Error(500, err, err.Error()) + e.Logger.Error(err) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.Update(&req) + if err != nil { + e.Logger.Error(err) + return + } + e.OK(req.GetId(), "更新成功") +} + +// Delete +// @Summary 删除字典类型 +// @Description 删除数据 +// @Tags 字典类型 +// @Param dictCode body dto.SysDictTypeDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/type [delete] +// @Security Bearer +func (e SysDictType) Delete(c *gin.Context) { + s := service.SysDictType{} + req :=dto.SysDictTypeDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.Remove(&req) + if err != nil { + e.Error(500, err, err.Error()) + return + } + e.OK(req.GetId(), "删除成功") +} + +// GetAll +// @Summary 字典类型全部数据 代码生成使用接口 +// @Description 获取JSON +// @Tags 字典类型 +// @Param dictName query string false "dictName" +// @Param dictId query string false "dictId" +// @Param dictType query string false "dictType" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/dict/type-option-select [get] +// @Security Bearer +func (e SysDictType) GetAll(c *gin.Context) { + s := service.SysDictType{} + req :=dto.SysDictTypeGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + list := make([]models.SysDictType, 0) + err = s.GetAll(&req, &list) + if err != nil { + e.Error(500, err, err.Error()) + return + } + e.OK(list, "查询成功") +} \ No newline at end of file diff --git a/app/admin/apis/sys_login_log.go b/app/admin/apis/sys_login_log.go new file mode 100644 index 0000000..6b6b4af --- /dev/null +++ b/app/admin/apis/sys_login_log.go @@ -0,0 +1,110 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "go-admin/app/admin/models" + + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysLoginLog struct { + api.Api +} + +// GetPage 登录日志列表 +// @Summary 登录日志列表 +// @Description 获取JSON +// @Tags 登录日志 +// @Param username query string false "用户名" +// @Param ipaddr query string false "ip地址" +// @Param loginLocation query string false "归属地" +// @Param status query string false "状态" +// @Param beginTime query string false "开始时间" +// @Param endTime query string false "结束时间" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-login-log [get] +// @Security Bearer +func (e SysLoginLog) GetPage(c *gin.Context) { + s := service.SysLoginLog{} + req :=dto.SysLoginLogGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + list := make([]models.SysLoginLog, 0) + var count int64 + err = s.GetPage(&req, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 登录日志通过id获取 +// @Summary 登录日志通过id获取 +// @Description 获取JSON +// @Tags 登录日志 +// @Param id path string false "id" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-login-log/{id} [get] +// @Security Bearer +func (e SysLoginLog) Get(c *gin.Context) { + s := service.SysLoginLog{} + req :=dto.SysLoginLogGetReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SysLoginLog + err = s.Get(&req, &object) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(object, "查询成功") +} + +// Delete 登录日志删除 +// @Summary 登录日志删除 +// @Description 登录日志删除 +// @Tags 登录日志 +// @Param data body dto.SysLoginLogDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-login-log [delete] +// @Security Bearer +func (e SysLoginLog) Delete(c *gin.Context) { + s := service.SysLoginLog{} + req :=dto.SysLoginLogDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + err = s.Remove(&req) + if err != nil { + e.Error(500, err, "删除失败") + return + } + e.OK(req.GetId(), "删除成功") +} \ No newline at end of file diff --git a/app/admin/apis/sys_menu.go b/app/admin/apis/sys_menu.go new file mode 100644 index 0000000..d6eab24 --- /dev/null +++ b/app/admin/apis/sys_menu.go @@ -0,0 +1,287 @@ +package apis + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + "go-admin/app/admin/models" + + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysMenu struct { + api.Api +} + +// GetPage Menu列表数据 +// @Summary Menu列表数据 +// @Description 获取JSON +// @Tags 菜单 +// @Param menuName query string false "menuName" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/menu [get] +// @Security Bearer +func (e SysMenu) GetPage(c *gin.Context) { + s := service.SysMenu{} + req := dto.SysMenuGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var list = make([]models.SysMenu, 0) + err = s.GetPage(&req, &list).Error + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(list, "查询成功") +} + +// Get 获取菜单详情 +// @Summary Menu详情数据 +// @Description 获取JSON +// @Tags 菜单 +// @Param id path string false "id" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/menu/{id} [get] +// @Security Bearer +func (e SysMenu) Get(c *gin.Context) { + req := dto.SysMenuGetReq{} + s := new(service.SysMenu) + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object = models.SysMenu{} + + err = s.Get(&req, &object).Error + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(object, "查询成功") +} + +// Insert 创建菜单 +// @Summary 创建菜单 +// @Description 获取JSON +// @Tags 菜单 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysMenuInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/menu [post] +// @Security Bearer +func (e SysMenu) Insert(c *gin.Context) { + req := dto.SysMenuInsertReq{} + s := new(service.SysMenu) + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + err = s.Insert(&req).Error + if err != nil { + e.Error(500, err, "创建失败") + return + } + e.OK(req.GetId(), "创建成功") +} + +// Update 修改菜单 +// @Summary 修改菜单 +// @Description 获取JSON +// @Tags 菜单 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.SysMenuUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/menu/{id} [put] +// @Security Bearer +func (e SysMenu) Update(c *gin.Context) { + req := dto.SysMenuUpdateReq{} + s := new(service.SysMenu) + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + req.SetUpdateBy(user.GetUserId(c)) + err = s.Update(&req).Error + if err != nil { + e.Error(500, err, "更新失败") + return + } + e.OK(req.GetId(), "更新成功") +} + +// Delete 删除菜单 +// @Summary 删除菜单 +// @Description 删除数据 +// @Tags 菜单 +// @Param data body dto.SysMenuDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/menu [delete] +// @Security Bearer +func (e SysMenu) Delete(c *gin.Context) { + control := new(dto.SysMenuDeleteReq) + s := new(service.SysMenu) + err := e.MakeContext(c). + MakeOrm(). + Bind(control, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + err = s.Remove(control).Error + if err != nil { + e.Logger.Errorf("RemoveSysMenu error, %s", err) + e.Error(500, err, "删除失败") + return + } + e.OK(control.GetId(), "删除成功") +} + +// GetMenuRole 根据登录角色名称获取菜单列表数据(左菜单使用) +// @Summary 根据登录角色名称获取菜单列表数据(左菜单使用) +// @Description 获取JSON +// @Tags 菜单 +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/menurole [get] +// @Security Bearer +func (e SysMenu) GetMenuRole(c *gin.Context) { + s := new(service.SysMenu) + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + result, err := s.SetMenuRole(user.GetRoleName(c)) + + if err != nil { + e.Error(500, err, "查询失败") + return + } + + e.OK(result, "") +} + +//// GetMenuIDS 获取角色对应的菜单id数组 +//// @Summary 获取角色对应的菜单id数组,设置角色权限使用 +//// @Description 获取JSON +//// @Tags 菜单 +//// @Param id path int true "id" +//// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +//// @Router /api/v1/menuids/{id} [get] +//// @Security Bearer +//func (e SysMenu) GetMenuIDS(c *gin.Context) { +// s := new(service.SysMenu) +// r := service.SysRole{} +// m := dto.SysRoleByName{} +// err := e.MakeContext(c). +// MakeOrm(). +// Bind(&m, binding.JSON). +// MakeService(&s.Service). +// MakeService(&r.Service). +// Errors +// if err != nil { +// e.Logger.Error(err) +// e.Error(500, err, err.Error()) +// return +// } +// var data models.SysRole +// err = r.GetWithName(&m, &data).Error +// +// //data.RoleName = c.GetString("role") +// //data.UpdateBy = user.GetUserId(c) +// //result, err := data.GetIDS(s.Orm) +// +// if err != nil { +// e.Logger.Errorf("GetIDS error, %s", err.Error()) +// e.Error(500, err, "获取失败") +// return +// } +// e.OK(result, "") +//} + +// GetMenuTreeSelect 根据角色ID查询菜单下拉树结构 +// @Summary 角色修改使用的菜单列表 +// @Description 获取JSON +// @Tags 菜单 +// @Accept application/json +// @Product application/json +// @Param roleId path int true "roleId" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/menuTreeselect/{roleId} [get] +// @Security Bearer +func (e SysMenu) GetMenuTreeSelect(c *gin.Context) { + m := service.SysMenu{} + r := service.SysRole{} + req :=dto.SelectRole{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&m.Service). + MakeService(&r.Service). + Bind(&req, nil). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + result, err := m.SetLabel() + if err != nil { + e.Error(500, err, "查询失败") + return + } + + menuIds := make([]int, 0) + if req.RoleId != 0 { + menuIds, err = r.GetRoleMenuId(req.RoleId) + if err != nil { + e.Error(500, err, "") + return + } + } + e.OK(gin.H{ + "menus": result, + "checkedKeys": menuIds, + }, "获取成功") +} \ No newline at end of file diff --git a/app/admin/apis/sys_opera_log.go b/app/admin/apis/sys_opera_log.go new file mode 100644 index 0000000..2803924 --- /dev/null +++ b/app/admin/apis/sys_opera_log.go @@ -0,0 +1,118 @@ +package apis + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysOperaLog struct { + api.Api +} + +// GetPage 操作日志列表 +// @Summary 操作日志列表 +// @Description 获取JSON +// @Tags 操作日志 +// @Param title query string false "title" +// @Param method query string false "method" +// @Param requestMethod query string false "requestMethod" +// @Param operUrl query string false "operUrl" +// @Param operIp query string false "operIp" +// @Param status query string false "status" +// @Param beginTime query string false "beginTime" +// @Param endTime query string false "endTime" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-opera-log [get] +// @Security Bearer +func (e SysOperaLog) GetPage(c *gin.Context) { + s := service.SysOperaLog{} + req := new(dto.SysOperaLogGetPageReq) + err := e.MakeContext(c). + MakeOrm(). + Bind(req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + list := make([]models.SysOperaLog, 0) + var count int64 + + err = s.GetPage(req, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 操作日志通过id获取 +// @Summary 操作日志通过id获取 +// @Description 获取JSON +// @Tags 操作日志 +// @Param id path string false "id" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-opera-log/{id} [get] +// @Security Bearer +func (e SysOperaLog) Get(c *gin.Context) { + s := new(service.SysOperaLog) + req :=dto.SysOperaLogGetReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SysOperaLog + err = s.Get(&req, &object) + if err != nil { + e.Error(500, err, "查询失败") + return + } + e.OK(object, "查询成功") +} + +// Delete 操作日志删除 +// DeleteSysMenu 操作日志删除 +// @Summary 删除操作日志 +// @Description 删除数据 +// @Tags 操作日志 +// @Param data body dto.SysOperaLogDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-opera-log [delete] +// @Security Bearer +func (e SysOperaLog) Delete(c *gin.Context) { + s := new(service.SysOperaLog) + req :=dto.SysOperaLogDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + err = s.Remove(&req) + if err != nil { + e.Logger.Error(err) + e.Error(500,err, fmt.Sprintf("删除失败!错误详情:%s", err.Error())) + return + } + e.OK(req.GetId(), "删除成功") +} diff --git a/app/admin/apis/sys_post.go b/app/admin/apis/sys_post.go new file mode 100644 index 0000000..a12d54a --- /dev/null +++ b/app/admin/apis/sys_post.go @@ -0,0 +1,184 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysPost struct { + api.Api +} + +// GetPage +// @Summary 岗位列表数据 +// @Description 获取JSON +// @Tags 岗位 +// @Param postName query string false "postName" +// @Param postCode query string false "postCode" +// @Param postId query string false "postId" +// @Param status query string false "status" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/post [get] +// @Security Bearer +func (e SysPost) GetPage(c *gin.Context) { + s := service.SysPost{} + req :=dto.SysPostPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + list := make([]models.SysPost, 0) + var count int64 + + err = s.GetPage(&req, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get +// @Summary 获取岗位信息 +// @Description 获取JSON +// @Tags 岗位 +// @Param id path int true "编码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/post/{postId} [get] +// @Security Bearer +func (e SysPost) Get(c *gin.Context) { + s := service.SysPost{} + req :=dto.SysPostGetReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SysPost + + err = s.Get(&req, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("岗位信息获取失败!错误详情:%s", err.Error())) + return + } + + e.OK(object, "查询成功") +} + +// Insert +// @Summary 添加岗位 +// @Description 获取JSON +// @Tags 岗位 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysPostInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/post [post] +// @Security Bearer +func (e SysPost) Insert(c *gin.Context) { + s := service.SysPost{} + req :=dto.SysPostInsertReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetCreateBy(user.GetUserId(c)) + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("新建岗位失败!错误详情:%s", err.Error())) + return + } + e.OK(req.GetId(), "创建成功") +} + +// Update +// @Summary 修改岗位 +// @Description 获取JSON +// @Tags 岗位 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysPostUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/post/{id} [put] +// @Security Bearer +func (e SysPost) Update(c *gin.Context) { + s := service.SysPost{} + req :=dto.SysPostUpdateReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + req.SetUpdateBy(user.GetUserId(c)) + + err = s.Update(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("岗位更新失败!错误详情:%s", err.Error())) + return + } + e.OK(req.GetId(), "更新成功") +} + +// Delete +// @Summary 删除岗位 +// @Description 删除数据 +// @Tags 岗位 +// @Param id body dto.SysPostDeleteReq true "请求参数" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/post [delete] +// @Security Bearer +func (e SysPost) Delete(c *gin.Context) { + s := service.SysPost{} + req :=dto.SysPostDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.Remove(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("岗位删除失败!错误详情:%s", err.Error())) + return + } + e.OK(req.GetId(), "删除成功") +} \ No newline at end of file diff --git a/app/admin/apis/sys_role.go b/app/admin/apis/sys_role.go new file mode 100644 index 0000000..d7ee1e7 --- /dev/null +++ b/app/admin/apis/sys_role.go @@ -0,0 +1,284 @@ +package apis + +import ( + "fmt" + "go-admin/common/global" + "net/http" + + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk" + "go-admin/app/admin/models" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" +) + +type SysRole struct { + api.Api +} + +// GetPage +// @Summary 角色列表数据 +// @Description Get JSON +// @Tags 角色/Role +// @Param roleName query string false "roleName" +// @Param status query string false "status" +// @Param roleKey query string false "roleKey" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/role [get] +// @Security Bearer +func (e SysRole) GetPage(c *gin.Context) { + s := service.SysRole{} + req := dto.SysRoleGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + list := make([]models.SysRole, 0) + var count int64 + + err = s.GetPage(&req, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get +// @Summary 获取Role数据 +// @Description 获取JSON +// @Tags 角色/Role +// @Param roleId path string false "roleId" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/role/{id} [get] +// @Security Bearer +func (e SysRole) Get(c *gin.Context) { + s := service.SysRole{} + req := dto.SysRoleGetReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, fmt.Sprintf(" %s ", err.Error())) + return + } + + var object models.SysRole + + err = s.Get(&req, &object) + if err != nil { + e.Error(http.StatusUnprocessableEntity, err, "查询失败") + return + } + + e.OK(object, "查询成功") +} + +// Insert +// @Summary 创建角色 +// @Description 获取JSON +// @Tags 角色/Role +// @Accept application/json +// @Product application/json +// @Param data body dto.SysRoleInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/role [post] +// @Security Bearer +func (e SysRole) Insert(c *gin.Context) { + s := service.SysRole{} + req := dto.SysRoleInsertReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // 设置创建人 + req.CreateBy = user.GetUserId(c) + if req.Status == "" { + req.Status = "2" + } + cb := sdk.Runtime.GetCasbinKey(c.Request.Host) + err = s.Insert(&req, cb) + if err != nil { + e.Logger.Error(err) + e.Error(500, err, "创建失败,"+err.Error()) + return + } + _, err = global.LoadPolicy(c) + if err != nil { + e.Logger.Error(err) + e.Error(500, err, "创建失败,"+err.Error()) + return + } + e.OK(req.GetId(), "创建成功") +} + +// Update 修改用户角色 +// @Summary 修改用户角色 +// @Description 获取JSON +// @Tags 角色/Role +// @Accept application/json +// @Product application/json +// @Param data body dto.SysRoleUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/role/{id} [put] +// @Security Bearer +func (e SysRole) Update(c *gin.Context) { + s := service.SysRole{} + req := dto.SysRoleUpdateReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + cb := sdk.Runtime.GetCasbinKey(c.Request.Host) + + req.SetUpdateBy(user.GetUserId(c)) + + err = s.Update(&req, cb) + if err != nil { + e.Logger.Error(err) + return + } + + _, err = global.LoadPolicy(c) + if err != nil { + e.Logger.Error(err) + e.Error(500, err, "更新失败,"+err.Error()) + return + } + + e.OK(req.GetId(), "更新成功") +} + +// Delete +// @Summary 删除用户角色 +// @Description 删除数据 +// @Tags 角色/Role +// @Param data body dto.SysRoleDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/role [delete] +// @Security Bearer +func (e SysRole) Delete(c *gin.Context) { + s := new(service.SysRole) + req := dto.SysRoleDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, fmt.Sprintf("删除角色 %v 失败,\r\n失败信息 %s", req.Ids, err.Error())) + return + } + + cb := sdk.Runtime.GetCasbinKey(c.Request.Host) + err = s.Remove(&req, cb) + if err != nil { + e.Logger.Error(err) + e.Error(500, err, "") + return + } + + e.OK(req.GetId(), fmt.Sprintf("删除角色角色 %v 状态成功!", req.GetId())) +} + +// Update2Status 修改用户角色状态 +// @Summary 修改用户角色 +// @Description 获取JSON +// @Tags 角色/Role +// @Accept application/json +// @Product application/json +// @Param data body dto.UpdateStatusReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/role-status/{id} [put] +// @Security Bearer +func (e SysRole) Update2Status(c *gin.Context) { + s := service.SysRole{} + req := dto.UpdateStatusReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, fmt.Sprintf("更新角色状态失败,失败原因:%s ", err.Error())) + return + } + req.SetUpdateBy(user.GetUserId(c)) + err = s.UpdateStatus(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("更新角色状态失败,失败原因:%s ", err.Error())) + return + } + e.OK(req.GetId(), fmt.Sprintf("更新角色 %v 状态成功!", req.GetId())) +} + +// Update2DataScope 更新角色数据权限 +// @Summary 更新角色数据权限 +// @Description 获取JSON +// @Tags 角色/Role +// @Accept application/json +// @Product application/json +// @Param data body dto.RoleDataScopeReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/role-status/{id} [put] +// @Security Bearer +func (e SysRole) Update2DataScope(c *gin.Context) { + s := service.SysRole{} + req := dto.RoleDataScopeReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + data := &models.SysRole{ + RoleId: req.RoleId, + DataScope: req.DataScope, + DeptIds: req.DeptIds, + } + data.UpdateBy = user.GetUserId(c) + err = s.UpdateDataScope(&req).Error + if err != nil { + e.Error(500, err, fmt.Sprintf("更新角色数据权限失败!错误详情:%s", err.Error())) + return + } + e.OK(nil, "操作成功") +} diff --git a/app/admin/apis/sys_user.go b/app/admin/apis/sys_user.go new file mode 100644 index 0000000..64eb501 --- /dev/null +++ b/app/admin/apis/sys_user.go @@ -0,0 +1,459 @@ +package apis + +import ( + "github.com/gin-gonic/gin/binding" + "go-admin/app/admin/models" + "golang.org/x/crypto/bcrypt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "github.com/google/uuid" + + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type SysUser struct { + api.Api +} + +// GetPage +// @Summary 列表用户信息数据 +// @Description 获取JSON +// @Tags 用户 +// @Param username query string false "username" +// @Success 200 {string} {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-user [get] +// @Security Bearer +func (e SysUser) GetPage(c *gin.Context) { + s := service.SysUser{} + req := dto.SysUserGetPageReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + //数据权限检查 + p := actions.GetPermissionFromContext(c) + + list := make([]models.SysUser, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, "查询失败") + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get +// @Summary 获取用户 +// @Description 获取JSON +// @Tags 用户 +// @Param userId path int true "用户编码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-user/{userId} [get] +// @Security Bearer +func (e SysUser) Get(c *gin.Context) { + s := service.SysUser{} + req := dto.SysUserById{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SysUser + //数据权限检查 + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(http.StatusUnprocessableEntity, err, "查询失败") + return + } + e.OK(object, "查询成功") +} + +// Insert +// @Summary 创建用户 +// @Description 获取JSON +// @Tags 用户 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysUserInsertReq true "用户数据" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-user [post] +// @Security Bearer +func (e SysUser) Insert(c *gin.Context) { + s := service.SysUser{} + req := dto.SysUserInsertReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + err = s.Insert(&req) + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update +// @Summary 修改用户数据 +// @Description 获取JSON +// @Tags 用户 +// @Accept application/json +// @Product application/json +// @Param data body dto.SysUserUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-user/{userId} [put] +// @Security Bearer +func (e SysUser) Update(c *gin.Context) { + s := service.SysUser{} + req := dto.SysUserUpdateReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + req.SetUpdateBy(user.GetUserId(c)) + + //数据权限检查 + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Logger.Error(err) + return + } + e.OK(req.GetId(), "更新成功") +} + +// Delete +// @Summary 删除用户数据 +// @Description 删除数据 +// @Tags 用户 +// @Param userId path int true "userId" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys-user/{userId} [delete] +// @Security Bearer +func (e SysUser) Delete(c *gin.Context) { + s := service.SysUser{} + req := dto.SysUserById{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // 设置编辑人 + req.SetUpdateBy(user.GetUserId(c)) + + // 数据权限检查 + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Logger.Error(err) + return + } + e.OK(req.GetId(), "删除成功") +} + +// InsetAvatar +// @Summary 修改头像 +// @Description 获取JSON +// @Tags 个人中心 +// @Accept multipart/form-data +// @Param file formData file true "file" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/user/avatar [post] +// @Security Bearer +func (e SysUser) InsetAvatar(c *gin.Context) { + s := service.SysUser{} + req := dto.UpdateSysUserAvatarReq{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 数据权限检查 + p := actions.GetPermissionFromContext(c) + form, _ := c.MultipartForm() + files := form.File["upload[]"] + guid := uuid.New().String() + filPath := "static/uploadfile/" + guid + ".jpg" + for _, file := range files { + e.Logger.Debugf("upload avatar file: %s", file.Filename) + // 上传文件至指定目录 + err = c.SaveUploadedFile(file, filPath) + if err != nil { + e.Logger.Errorf("save file error, %s", err.Error()) + e.Error(500, err, "") + return + } + } + req.UserId = p.UserId + req.Avatar = "/" + filPath + + err = s.UpdateAvatar(&req, p) + if err != nil { + e.Logger.Error(err) + return + } + e.OK(filPath, "修改成功") +} + +// UpdateStatus 修改用户状态 +// @Summary 修改用户状态 +// @Description 获取JSON +// @Tags 用户 +// @Accept application/json +// @Product application/json +// @Param data body dto.UpdateSysUserStatusReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/user/status [put] +// @Security Bearer +func (e SysUser) UpdateStatus(c *gin.Context) { + s := service.SysUser{} + req := dto.UpdateSysUserStatusReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON, nil). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + req.SetUpdateBy(user.GetUserId(c)) + + //数据权限检查 + p := actions.GetPermissionFromContext(c) + + err = s.UpdateStatus(&req, p) + if err != nil { + e.Logger.Error(err) + return + } + e.OK(req.GetId(), "更新成功") +} + +// ResetPwd 重置用户密码 +// @Summary 重置用户密码 +// @Description 获取JSON +// @Tags 用户 +// @Accept application/json +// @Product application/json +// @Param data body dto.ResetSysUserPwdReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/user/pwd/reset [put] +// @Security Bearer +func (e SysUser) ResetPwd(c *gin.Context) { + s := service.SysUser{} + req := dto.ResetSysUserPwdReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + req.SetUpdateBy(user.GetUserId(c)) + + //数据权限检查 + p := actions.GetPermissionFromContext(c) + + err = s.ResetPwd(&req, p) + if err != nil { + e.Logger.Error(err) + return + } + e.OK(req.GetId(), "更新成功") +} + +// UpdatePwd +// @Summary 修改密码 +// @Description 获取JSON +// @Tags 用户 +// @Accept application/json +// @Product application/json +// @Param data body dto.PassWord true "body" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/user/pwd/set [put] +// @Security Bearer +func (e SysUser) UpdatePwd(c *gin.Context) { + s := service.SysUser{} + req := dto.PassWord{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // 数据权限检查 + p := actions.GetPermissionFromContext(c) + var hash []byte + if hash, err = bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost); err != nil { + req.NewPassword = string(hash) + } + + err = s.UpdatePwd(user.GetUserId(c), req.OldPassword, req.NewPassword, p) + if err != nil { + e.Logger.Error(err) + e.Error(http.StatusForbidden, err, "密码修改失败") + return + } + + e.OK(nil, "密码修改成功") +} + +// GetProfile +// @Summary 获取个人中心用户 +// @Description 获取JSON +// @Tags 个人中心 +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/user/profile [get] +// @Security Bearer +func (e SysUser) GetProfile(c *gin.Context) { + s := service.SysUser{} + req := dto.SysUserById{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + req.Id = user.GetUserId(c) + + sysUser := models.SysUser{} + roles := make([]models.SysRole, 0) + posts := make([]models.SysPost, 0) + err = s.GetProfile(&req, &sysUser, &roles, &posts) + if err != nil { + e.Logger.Errorf("get user profile error, %s", err.Error()) + e.Error(500, err, "获取用户信息失败") + return + } + e.OK(gin.H{ + "user": sysUser, + "roles": roles, + "posts": posts, + }, "查询成功") +} + +// GetInfo +// @Summary 获取个人信息 +// @Description 获取JSON +// @Tags 个人中心 +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/getinfo [get] +// @Security Bearer +func (e SysUser) GetInfo(c *gin.Context) { + req := dto.SysUserById{} + s := service.SysUser{} + r := service.SysRole{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&r.Service). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + p := actions.GetPermissionFromContext(c) + var roles = make([]string, 1) + roles[0] = user.GetRoleName(c) + var permissions = make([]string, 1) + permissions[0] = "*:*:*" + var buttons = make([]string, 1) + buttons[0] = "*:*:*" + + var mp = make(map[string]interface{}) + mp["roles"] = roles + if user.GetRoleName(c) == "admin" || user.GetRoleName(c) == "系统管理员" { + mp["permissions"] = permissions + mp["buttons"] = buttons + } else { + list, _ := r.GetById(user.GetRoleId(c)) + mp["permissions"] = list + mp["buttons"] = list + } + sysUser := models.SysUser{} + req.Id = user.GetUserId(c) + err = s.Get(&req, p, &sysUser) + if err != nil { + e.Error(http.StatusUnauthorized, err, "登录失败") + return + } + mp["introduction"] = " am a super administrator" + mp["avatar"] = "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif" + if sysUser.Avatar != "" { + mp["avatar"] = sysUser.Avatar + } + mp["userName"] = sysUser.NickName + mp["userId"] = sysUser.UserId + mp["deptId"] = sysUser.DeptId + mp["name"] = sysUser.NickName + mp["code"] = 200 + e.OK(mp, "") +} diff --git a/app/admin/apis/tm_member.go b/app/admin/apis/tm_member.go new file mode 100644 index 0000000..997320c --- /dev/null +++ b/app/admin/apis/tm_member.go @@ -0,0 +1,306 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type TmMember struct { + api.Api +} + +// GetPage 获取会员表列表 +// @Summary 获取会员表列表 +// @Description 获取会员表列表 +// @Tags 会员表 +// @Param nickName query string false "用户昵称" +// @Param mobile query string false "手机号" +// @Param email query string false "邮箱号" +// @Param status query string false "状态 1-启用 2-禁用" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.TmMember}} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-member [get] +// @Security Bearer +func (e TmMember) GetPage(c *gin.Context) { + req := dto.TmMemberGetPageReq{} + s := service.TmMember{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]dto.TmMemberResp, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取会员表失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取会员表 +// @Summary 获取会员表 +// @Description 获取会员表 +// @Tags 会员表 +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.TmMember} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-member/{id} [get] +// @Security Bearer +func (e TmMember) Get(c *gin.Context) { + req := dto.TmMemberGetReq{} + s := service.TmMember{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.TmMember + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取会员表失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(object, "查询成功") +} + +// Insert 创建会员表 +// @Summary 创建会员表 +// @Description 创建会员表 +// @Tags 会员表 +// @Accept application/json +// @Product application/json +// @Param data body dto.TmMemberInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/tm-member [post] +// @Security Bearer +func (e TmMember) Insert(c *gin.Context) { + req := dto.TmMemberInsertReq{} + s := service.TmMember{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + data := models.TmMember{} + err = s.Insert(&req, &data) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建会员表失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改会员表 +// @Summary 修改会员表 +// @Description 修改会员表 +// @Tags 会员表 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.TmMemberUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/tm-member/{id} [put] +// @Security Bearer +func (e TmMember) Update(c *gin.Context) { + req := dto.TmMemberUpdateReq{} + s := service.TmMember{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改会员表失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "修改成功") +} + +// Delete 删除会员表 +// @Summary 删除会员表 +// @Description 删除会员表 +// @Tags 会员表 +// @Param data body dto.TmMemberDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/tm-member [delete] +// @Security Bearer +func (e TmMember) Delete(c *gin.Context) { + s := service.TmMember{} + req := dto.TmMemberDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除会员表失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "删除成功") +} + +// GetMyApiKey 获取我的apiKey +func (e TmMember) GetMyApiKey(c *gin.Context) { + s := service.TmMember{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // userId := user.GetUserId(c) + // data, err := s.GetMyApiKey(userId) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取apiKey失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK("", "获取apiKey成功") +} + +// 字符数充值 +func (e TmMember) Recharge(c *gin.Context) { + s := service.TmMember{} + req := dto.TmMemberRechargeReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + + if err != nil { + e.Logger.Errorf("字符充值失败:", err) + e.Error(500, err, err.Error()) + return + } + + userId := user.GetUserId(c) + p := actions.GetPermissionFromContext(c) + + err = s.Recharge(&req, p, userId) + if err != nil { + e.Error(500, err, fmt.Sprintf("字符充值失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(nil, "字符充值成功") +} + +// 修改状态 +func (e TmMember) ChangeStatus(c *gin.Context) { + s := service.TmMember{} + req := dto.TmMemberChangeStatusReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + + if err != nil { + e.Logger.Errorf("修改状态失败:", err) + e.Error(500, err, err.Error()) + return + } + + if err := req.Validate(); err != nil { + e.Logger.Errorf("修改状态失败:", err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + + err = s.ChangeStatus(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改状态失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(nil, "修改状态成功") +} + +// 获取个人的翻译平台信息 +func (e TmMember) GetPlatforms(c *gin.Context) { + s := service.TmMember{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + + if err != nil { + e.Logger.Errorf("获取个人的翻译平台信息失败:", err) + e.Error(500, err, err.Error()) + return + } + + userId := user.GetUserId(c) + + datas := make([]dto.TmMemberPlatformFrontedResp, 0) + + err = s.GetUserPlatforms(userId, &datas) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取个人的翻译平台信息失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(datas, "获取个人的翻译平台信息成功") +} diff --git a/app/admin/apis/tm_member_daily_usage.go b/app/admin/apis/tm_member_daily_usage.go new file mode 100644 index 0000000..d08a11f --- /dev/null +++ b/app/admin/apis/tm_member_daily_usage.go @@ -0,0 +1,191 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type TmMemberDailyUsage struct { + api.Api +} + +// GetPage 获取用户-使用量列表 +// @Summary 获取用户-使用量列表 +// @Description 获取用户-使用量列表 +// @Tags 用户-使用量 +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.TmMemberDailyUsage}} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-member-daily-usage [get] +// @Security Bearer +func (e TmMemberDailyUsage) GetPage(c *gin.Context) { + req := dto.TmMemberDailyUsageGetPageReq{} + s := service.TmMemberDailyUsage{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]models.TmMemberDailyUsage, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取用户-使用量失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取用户-使用量 +// @Summary 获取用户-使用量 +// @Description 获取用户-使用量 +// @Tags 用户-使用量 +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.TmMemberDailyUsage} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-member-daily-usage/{id} [get] +// @Security Bearer +func (e TmMemberDailyUsage) Get(c *gin.Context) { + req := dto.TmMemberDailyUsageGetReq{} + s := service.TmMemberDailyUsage{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.TmMemberDailyUsage + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取用户-使用量失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK( object, "查询成功") +} + +// Insert 创建用户-使用量 +// @Summary 创建用户-使用量 +// @Description 创建用户-使用量 +// @Tags 用户-使用量 +// @Accept application/json +// @Product application/json +// @Param data body dto.TmMemberDailyUsageInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/tm-member-daily-usage [post] +// @Security Bearer +func (e TmMemberDailyUsage) Insert(c *gin.Context) { + req := dto.TmMemberDailyUsageInsertReq{} + s := service.TmMemberDailyUsage{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建用户-使用量失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改用户-使用量 +// @Summary 修改用户-使用量 +// @Description 修改用户-使用量 +// @Tags 用户-使用量 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.TmMemberDailyUsageUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/tm-member-daily-usage/{id} [put] +// @Security Bearer +func (e TmMemberDailyUsage) Update(c *gin.Context) { + req := dto.TmMemberDailyUsageUpdateReq{} + s := service.TmMemberDailyUsage{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改用户-使用量失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "修改成功") +} + +// Delete 删除用户-使用量 +// @Summary 删除用户-使用量 +// @Description 删除用户-使用量 +// @Tags 用户-使用量 +// @Param data body dto.TmMemberDailyUsageDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/tm-member-daily-usage [delete] +// @Security Bearer +func (e TmMemberDailyUsage) Delete(c *gin.Context) { + s := service.TmMemberDailyUsage{} + req := dto.TmMemberDailyUsageDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除用户-使用量失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "删除成功") +} diff --git a/app/admin/apis/tm_member_platform.go b/app/admin/apis/tm_member_platform.go new file mode 100644 index 0000000..c23dfb1 --- /dev/null +++ b/app/admin/apis/tm_member_platform.go @@ -0,0 +1,224 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type TmMemberPlatform struct { + api.Api +} + +// GetPage 获取用户-翻译通道列表 +// @Summary 获取用户-翻译通道列表 +// @Description 获取用户-翻译通道列表 +// @Tags 用户-翻译通道 +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.TmMemberPlatform}} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-member-platform [get] +// @Security Bearer +func (e TmMemberPlatform) GetPage(c *gin.Context) { + req := dto.TmMemberPlatformGetPageReq{} + s := service.TmMemberPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]models.TmMemberPlatform, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取用户-翻译通道失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取用户-翻译通道 +// @Summary 获取用户-翻译通道 +// @Description 获取用户-翻译通道 +// @Tags 用户-翻译通道 +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.TmMemberPlatform} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-member-platform/{id} [get] +// @Security Bearer +func (e TmMemberPlatform) Get(c *gin.Context) { + req := dto.TmMemberPlatformGetReq{} + s := service.TmMemberPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.TmMemberPlatform + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取用户-翻译通道失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(object, "查询成功") +} + +// Insert 创建用户-翻译通道 +// @Summary 创建用户-翻译通道 +// @Description 创建用户-翻译通道 +// @Tags 用户-翻译通道 +// @Accept application/json +// @Product application/json +// @Param data body dto.TmMemberPlatformInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/tm-member-platform [post] +// @Security Bearer +func (e TmMemberPlatform) Insert(c *gin.Context) { + req := dto.TmMemberPlatformInsertReq{} + s := service.TmMemberPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建用户-翻译通道失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改用户-翻译通道 +// @Summary 修改用户-翻译通道 +// @Description 修改用户-翻译通道 +// @Tags 用户-翻译通道 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.TmMemberPlatformUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/tm-member-platform/{id} [put] +// @Security Bearer +func (e TmMemberPlatform) Update(c *gin.Context) { + req := dto.TmMemberPlatformUpdateReq{} + s := service.TmMemberPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改用户-翻译通道失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "修改成功") +} + +// Delete 删除用户-翻译通道 +// @Summary 删除用户-翻译通道 +// @Description 删除用户-翻译通道 +// @Tags 用户-翻译通道 +// @Param data body dto.TmMemberPlatformDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/tm-member-platform [delete] +// @Security Bearer +func (e TmMemberPlatform) Delete(c *gin.Context) { + s := service.TmMemberPlatform{} + req := dto.TmMemberPlatformDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除用户-翻译通道失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "删除成功") +} + +// 获取字符消耗折线图 +func (e TmMemberPlatform) GetStatistic(c *gin.Context) { + s := service.TmMemberDailyUsage{} + // req := dto.TmMemberPlatformStatisticReq{} + err := e.MakeContext(c). + MakeOrm(). + // Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, nil, "请求数据失败,请刷新") + return + } + + userId := user.GetUserId(c) + + if userId == 0 { + e.Error(500, nil, "请先登录") + return + } + + data := dto.TmMemberPlatformStatisticResp{} + + err = s.GetStatistic(userId, &data) + if err != nil { + e.Error(500, err, "获取数据失败") + return + } + + e.OK(data, "获取数据成功") +} diff --git a/app/admin/apis/tm_platform.go b/app/admin/apis/tm_platform.go new file mode 100644 index 0000000..9d5f295 --- /dev/null +++ b/app/admin/apis/tm_platform.go @@ -0,0 +1,222 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type TmPlatform struct { + api.Api +} + +// GetPage 获取翻译平台管理列表 +// @Summary 获取翻译平台管理列表 +// @Description 获取翻译平台管理列表 +// @Tags 翻译平台管理 +// @Param name query string false "平台名称" +// @Param showName query string false "展示名称" +// @Param apiBaseUrl query string false "平台接口地址" +// @Param code query string false "平台编码(字典 tm_platform)" +// @Param character query string false "字符数" +// @Param price query string false "单价" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.TmPlatform}} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-platform [get] +// @Security Bearer +func (e TmPlatform) GetPage(c *gin.Context) { + req := dto.TmPlatformGetPageReq{} + s := service.TmPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]models.TmPlatform, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取翻译平台管理失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取翻译平台管理 +// @Summary 获取翻译平台管理 +// @Description 获取翻译平台管理 +// @Tags 翻译平台管理 +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.TmPlatform} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-platform/{id} [get] +// @Security Bearer +func (e TmPlatform) Get(c *gin.Context) { + req := dto.TmPlatformGetReq{} + s := service.TmPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.TmPlatform + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取翻译平台管理失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(object, "查询成功") +} + +// Insert 创建翻译平台管理 +// @Summary 创建翻译平台管理 +// @Description 创建翻译平台管理 +// @Tags 翻译平台管理 +// @Accept application/json +// @Product application/json +// @Param data body dto.TmPlatformInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/tm-platform [post] +// @Security Bearer +func (e TmPlatform) Insert(c *gin.Context) { + req := dto.TmPlatformInsertReq{} + s := service.TmPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建翻译平台管理失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改翻译平台管理 +// @Summary 修改翻译平台管理 +// @Description 修改翻译平台管理 +// @Tags 翻译平台管理 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.TmPlatformUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/tm-platform/{id} [put] +// @Security Bearer +func (e TmPlatform) Update(c *gin.Context) { + req := dto.TmPlatformUpdateReq{} + s := service.TmPlatform{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改翻译平台管理失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "修改成功") +} + +// Delete 删除翻译平台管理 +// @Summary 删除翻译平台管理 +// @Description 删除翻译平台管理 +// @Tags 翻译平台管理 +// @Param data body dto.TmPlatformDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/tm-platform [delete] +// @Security Bearer +func (e TmPlatform) Delete(c *gin.Context) { + s := service.TmPlatform{} + req := dto.TmPlatformDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除翻译平台管理失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "删除成功") +} + +// List 翻译平台管理列表 +func (e TmPlatform) List(c *gin.Context) { + s := service.TmPlatform{} + + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + list := make([]dto.TmPlatformListResp, 0) + + err = s.GetList(&list) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取翻译平台管理列表失败")) + return + } + + e.OK(list, "") +} diff --git a/app/admin/apis/tm_platform_account.go b/app/admin/apis/tm_platform_account.go new file mode 100644 index 0000000..1444344 --- /dev/null +++ b/app/admin/apis/tm_platform_account.go @@ -0,0 +1,192 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type TmPlatformAccount struct { + api.Api +} + +// GetPage 获取翻译管理_平台账号列表 +// @Summary 获取翻译管理_平台账号列表 +// @Description 获取翻译管理_平台账号列表 +// @Tags 翻译管理_平台账号 +// @Param platformId query string false "平台主键" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.TmPlatformAccount}} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-platform-account [get] +// @Security Bearer +func (e TmPlatformAccount) GetPage(c *gin.Context) { + req := dto.TmPlatformAccountGetPageReq{} + s := service.TmPlatformAccount{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]models.TmPlatformAccount, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取翻译管理_平台账号失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取翻译管理_平台账号 +// @Summary 获取翻译管理_平台账号 +// @Description 获取翻译管理_平台账号 +// @Tags 翻译管理_平台账号 +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.TmPlatformAccount} "{"code": 200, "data": [...]}" +// @Router /api/v1/tm-platform-account/{id} [get] +// @Security Bearer +func (e TmPlatformAccount) Get(c *gin.Context) { + req := dto.TmPlatformAccountGetReq{} + s := service.TmPlatformAccount{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.TmPlatformAccount + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取翻译管理_平台账号失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(object, "查询成功") +} + +// Insert 创建翻译管理_平台账号 +// @Summary 创建翻译管理_平台账号 +// @Description 创建翻译管理_平台账号 +// @Tags 翻译管理_平台账号 +// @Accept application/json +// @Product application/json +// @Param data body dto.TmPlatformAccountInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/tm-platform-account [post] +// @Security Bearer +func (e TmPlatformAccount) Insert(c *gin.Context) { + req := dto.TmPlatformAccountInsertReq{} + s := service.TmPlatformAccount{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建翻译管理_平台账号失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改翻译管理_平台账号 +// @Summary 修改翻译管理_平台账号 +// @Description 修改翻译管理_平台账号 +// @Tags 翻译管理_平台账号 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.TmPlatformAccountUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/tm-platform-account/{id} [put] +// @Security Bearer +func (e TmPlatformAccount) Update(c *gin.Context) { + req := dto.TmPlatformAccountUpdateReq{} + s := service.TmPlatformAccount{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改翻译管理_平台账号失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "修改成功") +} + +// Delete 删除翻译管理_平台账号 +// @Summary 删除翻译管理_平台账号 +// @Description 删除翻译管理_平台账号 +// @Tags 翻译管理_平台账号 +// @Param data body dto.TmPlatformAccountDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/tm-platform-account [delete] +// @Security Bearer +func (e TmPlatformAccount) Delete(c *gin.Context) { + s := service.TmPlatformAccount{} + req := dto.TmPlatformAccountDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除翻译管理_平台账号失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK(req.GetId(), "删除成功") +} diff --git a/app/admin/apis/translate.go b/app/admin/apis/translate.go new file mode 100644 index 0000000..58c7677 --- /dev/null +++ b/app/admin/apis/translate.go @@ -0,0 +1,85 @@ +package apis + +import ( + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/statuscode" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" +) + +type Translate struct { + api.Api +} + +// 公开翻译接口 +func (e *Translate) Translate(c *gin.Context) { + req := dto.TranslateReq{} + s := service.TranslatorService{} + + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + + if err != nil { + e.Logger.Error(err) + e.Error(500, nil, "server error") + return + } + + if code := req.Validate(); code != statuscode.Success { + e.Error(code, nil, statuscode.ErrorMessage[code]) + return + } + + apiKey := c.GetString("apiKey") + result, code := s.TranslateJudge(&req, apiKey) + + if code != statuscode.Success { + e.Logger.Error(err) + e.Error(code, nil, statuscode.ErrorMessage[code]) + return + } + + e.OK(result, "success") +} + +// 获取个人翻译统计 +func (e *Translate) GetTranslateStatistic(c *gin.Context) { + req := dto.TranslateStatisticReq{} + s := service.TmMember{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.JSON). + MakeService(&s.Service). + Errors + + if err != nil { + e.Logger.Error(err) + e.Error(500, nil, "server error") + return + } + + userId := user.GetUserId(c) + + if userId == 0 { + e.Error(statuscode.Unauthorized, nil, "unauthorized") + return + } + + result := make([]dto.TranslateStatisticResp, 0) + error := s.GetTranslateStatistic(userId, &result) + + if error != nil { + e.Logger.Errorf("获取字符消耗统计数据失败 %v", error) + e.Error(500, nil, "server error") + return + } + + e.OK(result, "success") +} diff --git a/app/admin/consumer/exhausted_producer.go b/app/admin/consumer/exhausted_producer.go new file mode 100644 index 0000000..d989281 --- /dev/null +++ b/app/admin/consumer/exhausted_producer.go @@ -0,0 +1,51 @@ +package consumer + +import ( + "fmt" + "go-admin/app/admin/models" + commonDto "go-admin/common/dto" + "go-admin/common/mq" + "log" + + "github.com/bytedance/sonic" + amqp "github.com/rabbitmq/amqp091-go" + "gorm.io/gorm" +) + +const ( + EXHAUSTED_QUEUE = "account_exhausted_queue" +) + +// 消费者:监听 account_exhausted_queue,更新数据库账号状态为禁用 +func StartAccountExhaustedConsumer(db *gorm.DB, mqConn *amqp.Connection) error { + _, err := mq.MQ.DeclareQueue(EXHAUSTED_QUEUE) + if err != nil { + return fmt.Errorf("failed to declare a queue '%s': %w", EXHAUSTED_QUEUE, err) + } + + msgs, err := mq.MQ.Consume(EXHAUSTED_QUEUE) + if err != nil { + log.Fatalf("消费队列失败: %v", err) + } + + go func() { + for d := range msgs { + var msg commonDto.ExhaustedAccountMessage + if err := sonic.Unmarshal(d.Body, &msg); err != nil { + log.Printf("failed to parse exhausted message: %v", err) + continue + } + + err := db.Model(&models.TmPlatformAccount{}). + Where("id = ?", msg.Id). + Update("status", 2).Error + if err != nil { + log.Printf("failed to update account %d: %v", msg.Id, err) + } else { + log.Printf("account %d marked as exhausted.", msg.Id) + } + } + }() + + return nil +} diff --git a/app/admin/models/casbin_rule.go b/app/admin/models/casbin_rule.go new file mode 100644 index 0000000..d9013ee --- /dev/null +++ b/app/admin/models/casbin_rule.go @@ -0,0 +1,16 @@ +package models + +type CasbinRule struct { + ID uint `gorm:"primaryKey;autoIncrement"` + Ptype string `gorm:"size:512;uniqueIndex:unique_index"` + V0 string `gorm:"size:512;uniqueIndex:unique_index"` + V1 string `gorm:"size:512;uniqueIndex:unique_index"` + V2 string `gorm:"size:512;uniqueIndex:unique_index"` + V3 string `gorm:"size:512;uniqueIndex:unique_index"` + V4 string `gorm:"size:512;uniqueIndex:unique_index"` + V5 string `gorm:"size:512;uniqueIndex:unique_index"` +} + +func (CasbinRule) TableName() string { + return "sys_casbin_rule" +} diff --git a/app/admin/models/datascope.go b/app/admin/models/datascope.go new file mode 100644 index 0000000..8ccd047 --- /dev/null +++ b/app/admin/models/datascope.go @@ -0,0 +1,81 @@ +package models + +import ( + "errors" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "gorm.io/gorm" + + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/config" +) + +type DataPermission struct { + DataScope string + UserId int + DeptId int + RoleId int +} + +func (e *DataPermission) GetDataScope(tableName string, db *gorm.DB) (*gorm.DB, error) { + + if !config.ApplicationConfig.EnableDP { + usageStr := `数据权限已经为您` + pkg.Green(`关闭`) + `,如需开启请参考配置文件字段说明` + log.Debug("%s\n", usageStr) + return db, nil + } + user := new(SysUser) + role := new(SysRole) + err := db.Find(user, e.UserId).Error + if err != nil { + return nil, errors.New("获取用户数据出错 msg:" + err.Error()) + } + err = db.Find(role, user.RoleId).Error + if err != nil { + return nil, errors.New("获取用户数据出错 msg:" + err.Error()) + } + if role.DataScope == "2" { + db = db.Where(tableName+".create_by in (select sys_user.user_id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ?)", user.RoleId) + } + if role.DataScope == "3" { + db = db.Where(tableName+".create_by in (SELECT user_id from sys_user where dept_id = ? )", user.DeptId) + } + if role.DataScope == "4" { + db = db.Where(tableName+".create_by in (SELECT user_id from sys_user where sys_user.dept_id in(select dept_id from sys_dept where dept_path like ? ))", "%"+pkg.IntToString(user.DeptId)+"%") + } + if role.DataScope == "5" || role.DataScope == "" { + db = db.Where(tableName+".create_by = ?", e.UserId) + } + + return db, nil +} + +//func DataScopes(tableName string, userId int) func(db *gorm.DB) *gorm.DB { +// return func(db *gorm.DB) *gorm.DB { +// user := new(SysUser) +// role := new(SysRole) +// user.UserId = userId +// err := db.Find(user, userId).Error +// if err != nil { +// db.Error = errors.New("获取用户数据出错 msg:" + err.Error()) +// return db +// } +// err = db.Find(role, user.RoleId).Error +// if err != nil { +// db.Error = errors.New("获取用户数据出错 msg:" + err.Error()) +// return db +// } +// if role.DataScope == "2" { +// return db.Where(tableName+".create_by in (select sys_user.user_id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ?)", user.RoleId) +// } +// if role.DataScope == "3" { +// return db.Where(tableName+".create_by in (SELECT user_id from sys_user where dept_id = ? )", user.DeptId) +// } +// if role.DataScope == "4" { +// return db.Where(tableName+".create_by in (SELECT user_id from sys_user where sys_user.dept_id in(select dept_id from sys_dept where dept_path like ? ))", "%"+pkg.IntToString(user.DeptId)+"%") +// } +// if role.DataScope == "5" || role.DataScope == "" { +// return db.Where(tableName+".create_by = ?", userId) +// } +// return db +// } +//} diff --git a/app/admin/models/initdb.go b/app/admin/models/initdb.go new file mode 100644 index 0000000..cdec260 --- /dev/null +++ b/app/admin/models/initdb.go @@ -0,0 +1,55 @@ +package models + +import ( + "fmt" + "go-admin/common/global" + "gorm.io/gorm" + "io/ioutil" + "log" + "strings" +) + +func InitDb(db *gorm.DB) (err error) { + filePath := "config/db.sql" + err = ExecSql(db, filePath) + if global.Driver == "postgres" { + filePath = "config/pg.sql" + err = ExecSql(db, filePath) + } + return err +} + +func ExecSql(db *gorm.DB, filePath string) error { + sql, err := Ioutil(filePath) + if err != nil { + fmt.Println("数据库基础数据初始化脚本读取失败!原因:", err.Error()) + return err + } + sqlList := strings.Split(sql, ";") + for i := 0; i < len(sqlList)-1; i++ { + if strings.Contains(sqlList[i], "--") { + fmt.Println(sqlList[i]) + continue + } + sql := strings.Replace(sqlList[i]+";", "\n", "", -1) + sql = strings.TrimSpace(sql) + if err = db.Exec(sql).Error; err != nil { + log.Printf("error sql: %s", sql) + if !strings.Contains(err.Error(), "Query was empty") { + return err + } + } + } + return nil +} + +func Ioutil(filePath string) (string, error) { + if contents, err := ioutil.ReadFile(filePath); err == nil { + //因为contents是[]byte类型,直接转换成string类型后会多一行空格,需要使用strings.Replace替换换行符 + result := strings.Replace(string(contents), "\n", "", 1) + fmt.Println("Use ioutil.ReadFile to read a file:", result) + return result, nil + } else { + return "", err + } +} diff --git a/app/admin/models/model.go b/app/admin/models/model.go new file mode 100644 index 0000000..4a1c439 --- /dev/null +++ b/app/admin/models/model.go @@ -0,0 +1,11 @@ +package models + +import ( + "time" +) + +type BaseModel struct { + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt *time.Time `json:"deletedAt"` +} diff --git a/app/admin/models/sys_api.go b/app/admin/models/sys_api.go new file mode 100644 index 0000000..0b78e49 --- /dev/null +++ b/app/admin/models/sys_api.go @@ -0,0 +1,91 @@ +package models + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "regexp" + "strings" + + "github.com/bitly/go-simplejson" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/runtime" + "github.com/go-admin-team/go-admin-core/storage" + + "go-admin/common/models" +) + +type SysApi struct { + Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"` + Handle string `json:"handle" gorm:"size:128;comment:handle"` + Title string `json:"title" gorm:"size:128;comment:标题"` + Path string `json:"path" gorm:"size:128;comment:地址"` + Action string `json:"action" gorm:"size:16;comment:请求类型"` + Type string `json:"type" gorm:"size:16;comment:接口类型"` + models.ModelTime + models.ControlBy +} + +func (*SysApi) TableName() string { + return "sys_api" +} + +func (e *SysApi) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysApi) GetId() interface{} { + return e.Id +} + +func SaveSysApi(message storage.Messager) (err error) { + var rb []byte + rb, err = json.Marshal(message.GetValues()) + if err != nil { + err = fmt.Errorf("json Marshal error, %v", err.Error()) + return err + } + + var l runtime.Routers + err = json.Unmarshal(rb, &l) + if err != nil { + err = fmt.Errorf("json Unmarshal error, %s", err.Error()) + return err + } + dbList := sdk.Runtime.GetDb() + for _, d := range dbList { + for _, v := range l.List { + if v.HttpMethod != "HEAD" || + strings.Contains(v.RelativePath, "/swagger/") || + strings.Contains(v.RelativePath, "/static/") || + strings.Contains(v.RelativePath, "/form-generator/") || + strings.Contains(v.RelativePath, "/sys/tables") { + + // 根据接口方法注释里的@Summary填充接口名称,适用于代码生成器 + // 可在此处增加配置路径前缀的if判断,只对代码生成的自建应用进行定向的接口名称填充 + jsonFile, _ := ioutil.ReadFile("docs/swagger.json") + jsonData, _ := simplejson.NewFromReader(bytes.NewReader(jsonFile)) + urlPath := v.RelativePath + idPatten := "(.*)/:(\\w+)" // 正则替换,把:id换成{id} + reg, _ := regexp.Compile(idPatten) + if reg.MatchString(urlPath) { + urlPath = reg.ReplaceAllString(v.RelativePath, "${1}/{${2}}") // 把:id换成{id} + } + apiTitle, _ := jsonData.Get("paths").Get(urlPath).Get(strings.ToLower(v.HttpMethod)).Get("summary").String() + + err := d.Debug().Where(SysApi{Path: v.RelativePath, Action: v.HttpMethod}). + Attrs(SysApi{Handle: v.Handler, Title: apiTitle}). + FirstOrCreate(&SysApi{}). + //Update("handle", v.Handler). + Error + if err != nil { + err := fmt.Errorf("Models SaveSysApi error: %s \r\n ", err.Error()) + return err + } + } + } + } + return nil +} diff --git a/app/admin/models/sys_config.go b/app/admin/models/sys_config.go new file mode 100644 index 0000000..2024bbb --- /dev/null +++ b/app/admin/models/sys_config.go @@ -0,0 +1,30 @@ +package models + +import ( + "go-admin/common/models" +) + +type SysConfig struct { + models.Model + ConfigName string `json:"configName" gorm:"size:128;comment:ConfigName"` // + ConfigKey string `json:"configKey" gorm:"size:128;comment:ConfigKey"` // + ConfigValue string `json:"configValue" gorm:"size:255;comment:ConfigValue"` // + ConfigType string `json:"configType" gorm:"size:64;comment:ConfigType"` + IsFrontend string `json:"isFrontend" gorm:"size:64;comment:是否前台"` // + Remark string `json:"remark" gorm:"size:128;comment:Remark"` // + models.ControlBy + models.ModelTime +} + +func (*SysConfig) TableName() string { + return "sys_config" +} + +func (e *SysConfig) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysConfig) GetId() interface{} { + return e.Id +} diff --git a/app/admin/models/sys_dept.go b/app/admin/models/sys_dept.go new file mode 100644 index 0000000..e4400de --- /dev/null +++ b/app/admin/models/sys_dept.go @@ -0,0 +1,33 @@ +package models + +import "go-admin/common/models" + +type SysDept struct { + DeptId int `json:"deptId" gorm:"primaryKey;autoIncrement;"` //部门编码 + ParentId int `json:"parentId" gorm:""` //上级部门 + DeptPath string `json:"deptPath" gorm:"size:255;"` // + DeptName string `json:"deptName" gorm:"size:128;"` //部门名称 + Sort int `json:"sort" gorm:"size:4;"` //排序 + Leader string `json:"leader" gorm:"size:128;"` //负责人 + Phone string `json:"phone" gorm:"size:11;"` //手机 + Email string `json:"email" gorm:"size:64;"` //邮箱 + Status int `json:"status" gorm:"size:4;"` //状态 + models.ControlBy + models.ModelTime + DataScope string `json:"dataScope" gorm:"-"` + Params string `json:"params" gorm:"-"` + Children []SysDept `json:"children" gorm:"-"` +} + +func (*SysDept) TableName() string { + return "sys_dept" +} + +func (e *SysDept) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysDept) GetId() interface{} { + return e.DeptId +} diff --git a/app/admin/models/sys_dict_data.go b/app/admin/models/sys_dict_data.go new file mode 100644 index 0000000..15abf89 --- /dev/null +++ b/app/admin/models/sys_dict_data.go @@ -0,0 +1,34 @@ +package models + +import ( + "go-admin/common/models" +) + +type SysDictData struct { + DictCode int `json:"dictCode" gorm:"primaryKey;column:dict_code;autoIncrement;comment:主键编码"` + DictSort int `json:"dictSort" gorm:"size:20;comment:DictSort"` + DictLabel string `json:"dictLabel" gorm:"size:128;comment:DictLabel"` + DictValue string `json:"dictValue" gorm:"size:255;comment:DictValue"` + DictType string `json:"dictType" gorm:"size:64;comment:DictType"` + CssClass string `json:"cssClass" gorm:"size:128;comment:CssClass"` + ListClass string `json:"listClass" gorm:"size:128;comment:ListClass"` + IsDefault string `json:"isDefault" gorm:"size:8;comment:IsDefault"` + Status int `json:"status" gorm:"size:4;comment:Status"` + Default string `json:"default" gorm:"size:8;comment:Default"` + Remark string `json:"remark" gorm:"size:255;comment:Remark"` + models.ControlBy + models.ModelTime +} + +func (*SysDictData) TableName() string { + return "sys_dict_data" +} + +func (e *SysDictData) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysDictData) GetId() interface{} { + return e.DictCode +} diff --git a/app/admin/models/sys_dict_type.go b/app/admin/models/sys_dict_type.go new file mode 100644 index 0000000..49f7ebe --- /dev/null +++ b/app/admin/models/sys_dict_type.go @@ -0,0 +1,28 @@ +package models + +import ( + "go-admin/common/models" +) + +type SysDictType struct { + ID int `json:"id" gorm:"primaryKey;column:dict_id;autoIncrement;comment:主键编码"` + DictName string `json:"dictName" gorm:"size:128;comment:DictName"` + DictType string `json:"dictType" gorm:"size:128;comment:DictType"` + Status int `json:"status" gorm:"size:4;comment:Status"` + Remark string `json:"remark" gorm:"size:255;comment:Remark"` + models.ControlBy + models.ModelTime +} + +func (*SysDictType) TableName() string { + return "sys_dict_type" +} + +func (e *SysDictType) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysDictType) GetId() interface{} { + return e.ID +} diff --git a/app/admin/models/sys_login_log.go b/app/admin/models/sys_login_log.go new file mode 100644 index 0000000..98873e8 --- /dev/null +++ b/app/admin/models/sys_login_log.go @@ -0,0 +1,72 @@ +package models + +import ( + "encoding/json" + "errors" + "time" + + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/storage" + + "go-admin/common/models" +) + +type SysLoginLog struct { + models.Model + Username string `json:"username" gorm:"size:128;comment:用户名"` + Status string `json:"status" gorm:"size:4;comment:状态"` + Ipaddr string `json:"ipaddr" gorm:"size:255;comment:ip地址"` + LoginLocation string `json:"loginLocation" gorm:"size:255;comment:归属地"` + Browser string `json:"browser" gorm:"size:255;comment:浏览器"` + Os string `json:"os" gorm:"size:255;comment:系统"` + Platform string `json:"platform" gorm:"size:255;comment:固件"` + LoginTime time.Time `json:"loginTime" gorm:"comment:登录时间"` + Remark string `json:"remark" gorm:"size:255;comment:备注"` + Msg string `json:"msg" gorm:"size:255;comment:信息"` + CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"` + UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"` + models.ControlBy +} + +func (*SysLoginLog) TableName() string { + return "sys_login_log" +} + +func (e *SysLoginLog) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysLoginLog) GetId() interface{} { + return e.Id +} + +// SaveLoginLog 从队列中获取登录日志 +func SaveLoginLog(message storage.Messager) (err error) { + //准备db + db := sdk.Runtime.GetDbByKey(message.GetPrefix()) + if db == nil { + err = errors.New("db not exist") + log.Errorf("host[%s]'s %s", message.GetPrefix(), err.Error()) + return err + } + var rb []byte + rb, err = json.Marshal(message.GetValues()) + if err != nil { + log.Errorf("json Marshal error, %s", err.Error()) + return err + } + var l SysLoginLog + err = json.Unmarshal(rb, &l) + if err != nil { + log.Errorf("json Unmarshal error, %s", err.Error()) + return err + } + err = db.Create(&l).Error + if err != nil { + log.Errorf("db create error, %s", err.Error()) + return err + } + return nil +} diff --git a/app/admin/models/sys_menu.go b/app/admin/models/sys_menu.go new file mode 100644 index 0000000..ea7e669 --- /dev/null +++ b/app/admin/models/sys_menu.go @@ -0,0 +1,50 @@ +package models + +import "go-admin/common/models" + +type SysMenu struct { + MenuId int `json:"menuId" gorm:"primaryKey;autoIncrement"` + MenuName string `json:"menuName" gorm:"size:128;"` + Title string `json:"title" gorm:"size:128;"` + Icon string `json:"icon" gorm:"size:128;"` + Path string `json:"path" gorm:"size:128;"` + Paths string `json:"paths" gorm:"size:128;"` + MenuType string `json:"menuType" gorm:"size:1;"` + Action string `json:"action" gorm:"size:16;"` + Permission string `json:"permission" gorm:"size:255;"` + ParentId int `json:"parentId" gorm:"size:11;"` + NoCache bool `json:"noCache" gorm:"size:8;"` + Breadcrumb string `json:"breadcrumb" gorm:"size:255;"` + Component string `json:"component" gorm:"size:255;"` + Sort int `json:"sort" gorm:"size:4;"` + Visible string `json:"visible" gorm:"size:1;"` + IsFrame string `json:"isFrame" gorm:"size:1;DEFAULT:0;"` + SysApi []SysApi `json:"sysApi" gorm:"many2many:sys_menu_api_rule"` + Apis []int `json:"apis" gorm:"-"` + DataScope string `json:"dataScope" gorm:"-"` + Params string `json:"params" gorm:"-"` + RoleId int `gorm:"-"` + Children []SysMenu `json:"children,omitempty" gorm:"-"` + IsSelect bool `json:"is_select" gorm:"-"` + models.ControlBy + models.ModelTime +} + +type SysMenuSlice []SysMenu + +func (x SysMenuSlice) Len() int { return len(x) } +func (x SysMenuSlice) Less(i, j int) bool { return x[i].Sort < x[j].Sort } +func (x SysMenuSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (*SysMenu) TableName() string { + return "sys_menu" +} + +func (e *SysMenu) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysMenu) GetId() interface{} { + return e.MenuId +} diff --git a/app/admin/models/sys_opera_log.go b/app/admin/models/sys_opera_log.go new file mode 100644 index 0000000..e29a54d --- /dev/null +++ b/app/admin/models/sys_opera_log.go @@ -0,0 +1,88 @@ +package models + +import ( + "encoding/json" + "errors" + "time" + + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/storage" + + "go-admin/common/models" +) + +type SysOperaLog struct { + models.Model + Title string `json:"title" gorm:"size:255;comment:操作模块"` + BusinessType string `json:"businessType" gorm:"size:128;comment:操作类型"` + BusinessTypes string `json:"businessTypes" gorm:"size:128;comment:BusinessTypes"` + Method string `json:"method" gorm:"size:128;comment:函数"` + RequestMethod string `json:"requestMethod" gorm:"size:128;comment:请求方式 GET POST PUT DELETE"` + OperatorType string `json:"operatorType" gorm:"size:128;comment:操作类型"` + OperName string `json:"operName" gorm:"size:128;comment:操作者"` + DeptName string `json:"deptName" gorm:"size:128;comment:部门名称"` + OperUrl string `json:"operUrl" gorm:"size:255;comment:访问地址"` + OperIp string `json:"operIp" gorm:"size:128;comment:客户端ip"` + OperLocation string `json:"operLocation" gorm:"size:128;comment:访问位置"` + OperParam string `json:"operParam" gorm:"text;comment:请求参数"` + Status string `json:"status" gorm:"size:4;comment:操作状态 1:正常 2:关闭"` + OperTime time.Time `json:"operTime" gorm:"comment:操作时间"` + JsonResult string `json:"jsonResult" gorm:"size:255;comment:返回数据"` + Remark string `json:"remark" gorm:"size:255;comment:备注"` + LatencyTime string `json:"latencyTime" gorm:"size:128;comment:耗时"` + UserAgent string `json:"userAgent" gorm:"size:255;comment:ua"` + CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"` + UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"` + models.ControlBy +} + +func (*SysOperaLog) TableName() string { + return "sys_opera_log" +} + +func (e *SysOperaLog) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysOperaLog) GetId() interface{} { + return e.Id +} + +// SaveOperaLog 从队列中获取操作日志 +func SaveOperaLog(message storage.Messager) (err error) { + //准备db + db := sdk.Runtime.GetDbByKey(message.GetPrefix()) + if db == nil { + err = errors.New("db not exist") + log.Errorf("host[%s]'s %s", message.GetPrefix(), err.Error()) + // Log writing to the database ignores error + return nil + } + var rb []byte + rb, err = json.Marshal(message.GetValues()) + if err != nil { + log.Errorf("json Marshal error, %s", err.Error()) + // Log writing to the database ignores error + return nil + } + var l SysOperaLog + err = json.Unmarshal(rb, &l) + if err != nil { + log.Errorf("json Unmarshal error, %s", err.Error()) + // Log writing to the database ignores error + return nil + } + // 超出100个字符返回值截断 + if len(l.JsonResult) > 100 { + l.JsonResult = l.JsonResult[:100] + } + err = db.Create(&l).Error + if err != nil { + log.Errorf("db create error, %s", err.Error()) + // Log writing to the database ignores error + return nil + } + return nil +} diff --git a/app/admin/models/sys_post.go b/app/admin/models/sys_post.go new file mode 100644 index 0000000..705318a --- /dev/null +++ b/app/admin/models/sys_post.go @@ -0,0 +1,30 @@ +package models + +import "go-admin/common/models" + +type SysPost struct { + PostId int `gorm:"primaryKey;autoIncrement" json:"postId"` //岗位编号 + PostName string `gorm:"size:128;" json:"postName"` //岗位名称 + PostCode string `gorm:"size:128;" json:"postCode"` //岗位代码 + Sort int `gorm:"size:4;" json:"sort"` //岗位排序 + Status int `gorm:"size:4;" json:"status"` //状态 + Remark string `gorm:"size:255;" json:"remark"` //描述 + models.ControlBy + models.ModelTime + + DataScope string `gorm:"-" json:"dataScope"` + Params string `gorm:"-" json:"params"` +} + +func (*SysPost) TableName() string { + return "sys_post" +} + +func (e *SysPost) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysPost) GetId() interface{} { + return e.PostId +} diff --git a/app/admin/models/sys_role.go b/app/admin/models/sys_role.go new file mode 100644 index 0000000..d23fb17 --- /dev/null +++ b/app/admin/models/sys_role.go @@ -0,0 +1,35 @@ +package models + +import "go-admin/common/models" + +type SysRole struct { + RoleId int `json:"roleId" gorm:"primaryKey;autoIncrement"` // 角色编码 + RoleName string `json:"roleName" gorm:"size:128;"` // 角色名称 + Status string `json:"status" gorm:"size:4;"` // 状态 1禁用 2正常 + RoleKey string `json:"roleKey" gorm:"size:128;"` //角色代码 + RoleSort int `json:"roleSort" gorm:""` //角色排序 + Flag string `json:"flag" gorm:"size:128;"` // + Remark string `json:"remark" gorm:"size:255;"` //备注 + Admin bool `json:"admin" gorm:"size:4;"` + DataScope string `json:"dataScope" gorm:"size:128;"` + Params string `json:"params" gorm:"-"` + MenuIds []int `json:"menuIds" gorm:"-"` + DeptIds []int `json:"deptIds" gorm:"-"` + SysDept []SysDept `json:"sysDept" gorm:"many2many:sys_role_dept;foreignKey:RoleId;joinForeignKey:role_id;references:DeptId;joinReferences:dept_id;"` + SysMenu *[]SysMenu `json:"sysMenu" gorm:"many2many:sys_role_menu;foreignKey:RoleId;joinForeignKey:role_id;references:MenuId;joinReferences:menu_id;"` + models.ControlBy + models.ModelTime +} + +func (*SysRole) TableName() string { + return "sys_role" +} + +func (e *SysRole) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysRole) GetId() interface{} { + return e.RoleId +} diff --git a/app/admin/models/sys_user.go b/app/admin/models/sys_user.go new file mode 100644 index 0000000..eab2cad --- /dev/null +++ b/app/admin/models/sys_user.go @@ -0,0 +1,77 @@ +package models + +import ( + "go-admin/common/models" + "golang.org/x/crypto/bcrypt" + "gorm.io/gorm" +) + +type SysUser struct { + UserId int `gorm:"primaryKey;autoIncrement;comment:编码" json:"userId"` + Username string `json:"username" gorm:"size:64;comment:用户名"` + Password string `json:"-" gorm:"size:128;comment:密码"` + NickName string `json:"nickName" gorm:"size:128;comment:昵称"` + Phone string `json:"phone" gorm:"size:11;comment:手机号"` + RoleId int `json:"roleId" gorm:"size:20;comment:角色ID"` + Salt string `json:"-" gorm:"size:255;comment:加盐"` + Avatar string `json:"avatar" gorm:"size:255;comment:头像"` + Sex string `json:"sex" gorm:"size:255;comment:性别"` + Email string `json:"email" gorm:"size:128;comment:邮箱"` + DeptId int `json:"deptId" gorm:"size:20;comment:部门"` + PostId int `json:"postId" gorm:"size:20;comment:岗位"` + Remark string `json:"remark" gorm:"size:255;comment:备注"` + Status string `json:"status" gorm:"size:4;comment:状态"` + DeptIds []int `json:"deptIds" gorm:"-"` + PostIds []int `json:"postIds" gorm:"-"` + RoleIds []int `json:"roleIds" gorm:"-"` + Dept *SysDept `json:"dept"` + models.ControlBy + models.ModelTime +} + +func (*SysUser) TableName() string { + return "sys_user" +} + +func (e *SysUser) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysUser) GetId() interface{} { + return e.UserId +} + +// Encrypt 加密 +func (e *SysUser) Encrypt() (err error) { + if e.Password == "" { + return + } + + var hash []byte + if hash, err = bcrypt.GenerateFromPassword([]byte(e.Password), bcrypt.DefaultCost); err != nil { + return + } else { + e.Password = string(hash) + return + } +} + +func (e *SysUser) BeforeCreate(_ *gorm.DB) error { + return e.Encrypt() +} + +func (e *SysUser) BeforeUpdate(_ *gorm.DB) error { + var err error + if e.Password != "" { + err = e.Encrypt() + } + return err +} + +func (e *SysUser) AfterFind(_ *gorm.DB) error { + e.DeptIds = []int{e.DeptId} + e.PostIds = []int{e.PostId} + e.RoleIds = []int{e.RoleId} + return nil +} diff --git a/app/admin/models/tm_member.go b/app/admin/models/tm_member.go new file mode 100644 index 0000000..6d4b542 --- /dev/null +++ b/app/admin/models/tm_member.go @@ -0,0 +1,36 @@ +package models + +import ( + "go-admin/common/models" +) + +type TmMember struct { + models.Model + + UserId int `json:"userId" gorm:"type:int;comment:用户ID"` + NickName string `json:"nickName" gorm:"type:varchar(30);comment:用户昵称"` + AreaCode string `json:"areaCode" gorm:"type:varchar(10);comment:区号"` + Mobile string `json:"mobile" gorm:"type:varchar(20);comment:手机号"` + Email string `json:"email" gorm:"type:varchar(255);comment:邮箱号"` + Password string `json:"password" gorm:"type:varchar(255);comment:密码"` + Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"` + ApiKey string `json:"apiKey" gorm:"type:varchar(20);comment:apiKey"` + TotalChars int `json:"totalChars" gorm:"type:int;comment:总字数"` + RemainChars int `json:"remainChars" gorm:"type:int;comment:剩余字数"` + UserStatus int `json:"userStatus" gorm:"-"` + models.ModelTime + models.ControlBy +} + +func (TmMember) TableName() string { + return "tm_member" +} + +func (e *TmMember) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *TmMember) GetId() interface{} { + return e.Id +} diff --git a/app/admin/models/tm_member_daily_usage.go b/app/admin/models/tm_member_daily_usage.go new file mode 100644 index 0000000..a763d1f --- /dev/null +++ b/app/admin/models/tm_member_daily_usage.go @@ -0,0 +1,31 @@ +package models + +import ( + "go-admin/common/models" + "time" +) + +type TmMemberDailyUsage struct { + models.Model + + MemberId int `json:"memberId" gorm:"type:bigint;comment:用户id"` + PlatformId int `json:"platformId" gorm:"type:bigint;comment:平台id"` + UseChars int `json:"useChars" gorm:"type:bigint;comment:使用字符数"` + RemainChars int `json:"remainChars" gorm:"type:bigint;comment:剩余字符数"` + Date time.Time `json:"date" gorm:"type:date;comment:日期"` + models.ModelTime + models.ControlBy +} + +func (TmMemberDailyUsage) TableName() string { + return "tm_member_daily_usage" +} + +func (e *TmMemberDailyUsage) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *TmMemberDailyUsage) GetId() interface{} { + return e.Id +} diff --git a/app/admin/models/tm_member_platform.go b/app/admin/models/tm_member_platform.go new file mode 100644 index 0000000..7ccee49 --- /dev/null +++ b/app/admin/models/tm_member_platform.go @@ -0,0 +1,31 @@ +package models + +import ( + "go-admin/common/models" +) + +type TmMemberPlatform struct { + models.Model + + MemberId int `json:"memberId" gorm:"type:bigint;comment:用户id"` + RemainingCharacter int `json:"remainingCharacter" gorm:"type:bigint;comment:剩余字符数"` + TotalCharacter int `json:"totalCharacter" gorm:"type:bigint;comment:总字符数"` + PlatformId int `json:"platformId" gorm:"type:bigint;comment:平台id"` + PlatformKey string `json:"platformKey" gorm:"type:varchar(50);comment:平台key"` + Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"` + models.ModelTime + models.ControlBy +} + +func (TmMemberPlatform) TableName() string { + return "tm_member_platform" +} + +func (e *TmMemberPlatform) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *TmMemberPlatform) GetId() interface{} { + return e.Id +} diff --git a/app/admin/models/tm_platform.go b/app/admin/models/tm_platform.go new file mode 100644 index 0000000..f4ae86f --- /dev/null +++ b/app/admin/models/tm_platform.go @@ -0,0 +1,34 @@ +package models + +import ( + "go-admin/common/models" + + "github.com/shopspring/decimal" +) + +type TmPlatform struct { + models.Model + + Name string `json:"name" gorm:"type:varchar(20);comment:平台名称"` + ShowName string `json:"showName" gorm:"type:varchar(20);comment:展示名称"` + ApiBaseUrl string `json:"apiBaseUrl" gorm:"type:varchar(500);comment:平台接口地址"` + Description string `json:"description" gorm:"type:varchar(255);comment:描述"` + Code string `json:"code" gorm:"type:varchar(20);comment:平台编码(字典 tm_platform)"` + Character string `json:"character" gorm:"type:int;comment:字符数"` + Price decimal.Decimal `json:"price" gorm:"type:decimal(10,2);comment:单价"` + models.ModelTime + models.ControlBy +} + +func (TmPlatform) TableName() string { + return "tm_platform" +} + +func (e *TmPlatform) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *TmPlatform) GetId() interface{} { + return e.Id +} diff --git a/app/admin/models/tm_platform_account.go b/app/admin/models/tm_platform_account.go new file mode 100644 index 0000000..0d26a26 --- /dev/null +++ b/app/admin/models/tm_platform_account.go @@ -0,0 +1,32 @@ +package models + +import ( + "go-admin/common/models" +) + +type TmPlatformAccount struct { + models.Model + + PlatformId int `json:"platformId" gorm:"type:bigint;comment:平台主键"` + PlatformKey string `json:"platformKey" gorm:"type:varchar(30);comment:平台key"` + ApiKey string `json:"apiKey" gorm:"type:varchar(500);comment:api_key"` + ApiSecret string `json:"apiSecret" gorm:"type:varchar(255);comment:api密钥"` + QpsLimit int `json:"qpsLimit" gorm:"type:int;comment:qps限制"` + RemainChars int `json:"remainChars" gorm:"type:int;comment:剩余字符"` + Status int `json:"status" gorm:"type:int;comment:状态 1-启用 2-禁用"` + models.ModelTime + models.ControlBy +} + +func (TmPlatformAccount) TableName() string { + return "tm_platform_account" +} + +func (e *TmPlatformAccount) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *TmPlatformAccount) GetId() interface{} { + return e.Id +} diff --git a/app/admin/models/tm_recharge_log.go b/app/admin/models/tm_recharge_log.go new file mode 100644 index 0000000..051db0b --- /dev/null +++ b/app/admin/models/tm_recharge_log.go @@ -0,0 +1,27 @@ +package models + +import "go-admin/common/models" + +type TmRechargeLog struct { + models.Model + + UserId int `json:"userId" gorm:"column:user_id;type:bigint;not null;comment:用户id"` + MemberId int `json:"memberId" gorm:"column:member_id;type:bigint;not null;comment:翻译用户id"` + Status int `json:"status" gorm:"column:status;type:tinyint;not null;comment:状态 1-正常 2-作废"` + TotalChars int `json:"totalChars" gorm:"column:total_chars;type:bigint;not null;comment:充值字符数"` + models.ModelTime + models.ControlBy +} + +func (TmRechargeLog) TableName() string { + return "tm_recharge_log" +} + +func (e *TmRechargeLog) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *TmRechargeLog) GetId() interface{} { + return e.Id +} diff --git a/app/admin/router/init_router.go b/app/admin/router/init_router.go new file mode 100644 index 0000000..61fb978 --- /dev/null +++ b/app/admin/router/init_router.go @@ -0,0 +1,40 @@ +package router + +import ( + "os" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + common "go-admin/common/middleware" +) + +// InitRouter 路由初始化,不要怀疑,这里用到了 +func InitRouter() { + var r *gin.Engine + h := sdk.Runtime.GetEngine() + if h == nil { + log.Fatal("not found engine...") + os.Exit(-1) + } + switch h.(type) { + case *gin.Engine: + r = h.(*gin.Engine) + default: + log.Fatal("not support other engine") + os.Exit(-1) + } + + // the jwt middleware + authMiddleware, err := common.AuthInit() + if err != nil { + log.Fatalf("JWT Init Error, %s", err.Error()) + } + + // 注册系统路由 + InitSysRouter(r, authMiddleware) + + // 注册业务路由 + // TODO: 这里可存放业务路由,里边并无实际路由只有演示代码 + InitExamplesRouter(r, authMiddleware) +} diff --git a/app/admin/router/router.go b/app/admin/router/router.go new file mode 100644 index 0000000..a5aebbe --- /dev/null +++ b/app/admin/router/router.go @@ -0,0 +1,54 @@ +package router + +import ( + "github.com/gin-gonic/gin" + _ "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" +) + +var ( + routerNoCheckRole = make([]func(*gin.RouterGroup), 0) + routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0) + routerApp = make([]func(*gin.RouterGroup), 0) +) + +func InitExamplesRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine { + + // 无需认证的路由 + examplesNoCheckRoleRouter(r) + + //对外api + examplesAppRouter(r) + + // 需要认证的路由 + examplesCheckRoleRouter(r, authMiddleware) + + return r +} + +// 对外api +func examplesAppRouter(r *gin.Engine) { + v1 := r.Group("/open-api/v1") + for _, f := range routerApp { + f(v1) + } +} + +// 无需认证的路由示例 +func examplesNoCheckRoleRouter(r *gin.Engine) { + // 可根据业务需求来设置接口版本 + v1 := r.Group("/api/v1") + for _, f := range routerNoCheckRole { + f(v1) + } +} + +// 需要认证的路由示例 +func examplesCheckRoleRouter(r *gin.Engine, authMiddleware *jwtauth.GinJWTMiddleware) { + // 可根据业务需求来设置接口版本 + v1 := r.Group("/api/v1") + for _, f := range routerCheckRole { + f(v1, authMiddleware) + } +} diff --git a/app/admin/router/sys_api.go b/app/admin/router/sys_api.go new file mode 100644 index 0000000..8272df3 --- /dev/null +++ b/app/admin/router/sys_api.go @@ -0,0 +1,24 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysApiRouter) +} + +// registerSysApiRouter +func registerSysApiRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysApi{} + r := v1.Group("/sys-api").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.PUT("/:id", api.Update) + } +} diff --git a/app/admin/router/sys_config.go b/app/admin/router/sys_config.go new file mode 100644 index 0000000..2dabd08 --- /dev/null +++ b/app/admin/router/sys_config.go @@ -0,0 +1,43 @@ +package router + +import ( + "go-admin/app/admin/apis" + "go-admin/common/middleware" + + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysConfigRouter) +} + +// 需认证的路由代码 +func registerSysConfigRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysConfig{} + r := v1.Group("/config").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.POST("", api.Insert) + r.PUT("/:id", api.Update) + r.DELETE("", api.Delete) + } + + r1 := v1.Group("/configKey").Use(authMiddleware.MiddlewareFunc()) + { + r1.GET("/:configKey", api.GetSysConfigByKEYForService) + } + + r2 := v1.Group("/app-config") + { + r2.GET("", api.Get2SysApp) + } + + r3 := v1.Group("/set-config").Use(authMiddleware.MiddlewareFunc()) + { + r3.PUT("", api.Update2Set) + r3.GET("", api.Get2Set) + } + +} diff --git a/app/admin/router/sys_dept.go b/app/admin/router/sys_dept.go new file mode 100644 index 0000000..f939374 --- /dev/null +++ b/app/admin/router/sys_dept.go @@ -0,0 +1,32 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysDeptRouter) +} + +// 需认证的路由代码 +func registerSysDeptRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysDept{} + + r := v1.Group("/dept").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.POST("", api.Insert) + r.PUT("/:id", api.Update) + r.DELETE("", api.Delete) + } + + r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc()) + { + r1.GET("/deptTree", api.Get2Tree) + } + +} \ No newline at end of file diff --git a/app/admin/router/sys_dict.go b/app/admin/router/sys_dict.go new file mode 100644 index 0000000..ae9e0c4 --- /dev/null +++ b/app/admin/router/sys_dict.go @@ -0,0 +1,37 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerDictRouter) +} + +func registerDictRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + dictApi := apis.SysDictType{} + dataApi := apis.SysDictData{} + dicts := v1.Group("/dict").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + + dicts.GET("/data", dataApi.GetPage) + dicts.GET("/data/:dictCode", dataApi.Get) + dicts.POST("/data", dataApi.Insert) + dicts.PUT("/data/:dictCode", dataApi.Update) + dicts.DELETE("/data", dataApi.Delete) + + dicts.GET("/type-option-select", dictApi.GetAll) + dicts.GET("/type", dictApi.GetPage) + dicts.GET("/type/:id", dictApi.Get) + dicts.POST("/type", dictApi.Insert) + dicts.PUT("/type/:id", dictApi.Update) + dicts.DELETE("/type", dictApi.Delete) + } + opSelect := v1.Group("/dict-data").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + opSelect.GET("/option-select", dataApi.GetAll) + } +} diff --git a/app/admin/router/sys_login_log.go b/app/admin/router/sys_login_log.go new file mode 100644 index 0000000..61b4e83 --- /dev/null +++ b/app/admin/router/sys_login_log.go @@ -0,0 +1,24 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysLoginLogRouter) +} + +// 需认证的路由代码 +func registerSysLoginLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysLoginLog{} + + r := v1.Group("/sys-login-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/app/admin/router/sys_menu.go b/app/admin/router/sys_menu.go new file mode 100644 index 0000000..b5cad5a --- /dev/null +++ b/app/admin/router/sys_menu.go @@ -0,0 +1,33 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysMenuRouter) +} + +// 需认证的路由代码 +func registerSysMenuRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysMenu{} + + r := v1.Group("/menu").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.POST("", api.Insert) + r.PUT("/:id", api.Update) + r.DELETE("", api.Delete) + } + + r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc()) + { + r1.GET("/menurole", api.GetMenuRole) + //r1.GET("/menuids", api.GetMenuIDS) + } + +} \ No newline at end of file diff --git a/app/admin/router/sys_opera_log.go b/app/admin/router/sys_opera_log.go new file mode 100644 index 0000000..d24d54f --- /dev/null +++ b/app/admin/router/sys_opera_log.go @@ -0,0 +1,23 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysOperaLogRouter) +} + +// 需认证的路由代码 +func registerSysOperaLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysOperaLog{} + r := v1.Group("/sys-opera-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/app/admin/router/sys_post.go b/app/admin/router/sys_post.go new file mode 100644 index 0000000..e299a5d --- /dev/null +++ b/app/admin/router/sys_post.go @@ -0,0 +1,25 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSyPostRouter) +} + +// 需认证的路由代码 +func registerSyPostRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysPost{} + r := v1.Group("/post").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.POST("", api.Insert) + r.PUT("/:id", api.Update) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/app/admin/router/sys_role.go b/app/admin/router/sys_role.go new file mode 100644 index 0000000..5bfdd2a --- /dev/null +++ b/app/admin/router/sys_role.go @@ -0,0 +1,31 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysRoleRouter) +} + +// 需认证的路由代码 +func registerSysRoleRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysRole{} + r := v1.Group("/role").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.POST("", api.Insert) + r.PUT("/:id", api.Update) + r.DELETE("", api.Delete) + } + r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc()) + { + r1.PUT("/role-status", api.Update2Status) + r1.PUT("/roledatascope", api.Update2DataScope) + } +} diff --git a/app/admin/router/sys_router.go b/app/admin/router/sys_router.go new file mode 100644 index 0000000..b713e4b --- /dev/null +++ b/app/admin/router/sys_router.go @@ -0,0 +1,88 @@ +package router + +import ( + "go-admin/app/admin/apis" + "mime" + + "github.com/go-admin-team/go-admin-core/sdk/config" + + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "github.com/go-admin-team/go-admin-core/sdk/pkg/ws" + ginSwagger "github.com/swaggo/gin-swagger" + + swaggerfiles "github.com/swaggo/files" + + "go-admin/common/middleware" + "go-admin/common/middleware/handler" + _ "go-admin/docs/admin" +) + +func InitSysRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.RouterGroup { + g := r.Group("") + sysBaseRouter(g) + // 静态文件 + sysStaticFileRouter(g) + // swagger;注意:生产环境可以注释掉 + if config.ApplicationConfig.Mode != "prod" { + sysSwaggerRouter(g) + } + // 需要认证 + sysCheckRoleRouterInit(g, authMiddleware) + return g +} + +func sysBaseRouter(r *gin.RouterGroup) { + + go ws.WebsocketManager.Start() + go ws.WebsocketManager.SendService() + go ws.WebsocketManager.SendAllService() + + if config.ApplicationConfig.Mode != "prod" { + r.GET("/", apis.GoAdmin) + } + r.GET("/info", handler.Ping) +} + +func sysStaticFileRouter(r *gin.RouterGroup) { + err := mime.AddExtensionType(".js", "application/javascript") + if err != nil { + return + } + r.Static("/static", "./static") + if config.ApplicationConfig.Mode != "prod" { + r.Static("/form-generator", "./static/form-generator") + } +} + +func sysSwaggerRouter(r *gin.RouterGroup) { + r.GET("/swagger/admin/*any", ginSwagger.WrapHandler(swaggerfiles.NewHandler(), ginSwagger.InstanceName("admin"))) +} + +func sysCheckRoleRouterInit(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + wss := r.Group("").Use(authMiddleware.MiddlewareFunc()) + { + wss.GET("/ws/:id/:channel", ws.WebsocketManager.WsClient) + wss.GET("/wslogout/:id/:channel", ws.WebsocketManager.UnWsClient) + } + + v1 := r.Group("/api/v1") + { + v1.POST("/login", authMiddleware.LoginHandler) + // Refresh time can be longer than token timeout + v1.GET("/refresh_token", authMiddleware.RefreshHandler) + } + registerBaseRouter(v1, authMiddleware) +} + +func registerBaseRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysMenu{} + api2 := apis.SysDept{} + v1auth := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + v1auth.GET("/roleMenuTreeselect/:roleId", api.GetMenuTreeSelect) + //v1.GET("/menuTreeselect", api.GetMenuTreeSelect) + v1auth.GET("/roleDeptTreeselect/:roleId", api2.GetDeptTreeRoleSelect) + v1auth.POST("/logout", handler.LogOut) + } +} diff --git a/app/admin/router/sys_user.go b/app/admin/router/sys_user.go new file mode 100644 index 0000000..4a545a6 --- /dev/null +++ b/app/admin/router/sys_user.go @@ -0,0 +1,39 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/common/actions" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysUserRouter) +} + +// 需认证的路由代码 +func registerSysUserRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SysUser{} + r := v1.Group("/sys-user").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()).Use(actions.PermissionAction()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.POST("", api.Insert) + r.PUT("", api.Update) + r.DELETE("", api.Delete) + } + + user := v1.Group("/user").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()).Use(actions.PermissionAction()) + { + user.GET("/profile", api.GetProfile) + user.POST("/avatar", api.InsetAvatar) + user.PUT("/pwd/set", api.UpdatePwd) + user.PUT("/pwd/reset", api.ResetPwd) + user.PUT("/status", api.UpdateStatus) + } + v1auth := v1.Group("").Use(authMiddleware.MiddlewareFunc()) + { + v1auth.GET("/getinfo", api.GetInfo) + } +} \ No newline at end of file diff --git a/app/admin/router/tm_member.go b/app/admin/router/tm_member.go new file mode 100644 index 0000000..64721d5 --- /dev/null +++ b/app/admin/router/tm_member.go @@ -0,0 +1,36 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/actions" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerTmMemberRouter) +} + +// registerTmMemberRouter +func registerTmMemberRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.TmMember{} + r := v1.Group("/tm-member").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + + r.POST("recharge", actions.PermissionAction(), api.Recharge) //字符充值 + r.PUT("status", actions.PermissionAction(), api.ChangeStatus) //状态变更 + } + + r2 := v1.Group("/tm-member").Use(authMiddleware.MiddlewareFunc()) + { + r2.GET("/api-key", api.GetMyApiKey) + r2.GET("platforms", api.GetPlatforms) + } +} diff --git a/app/admin/router/tm_member_daily_usage.go b/app/admin/router/tm_member_daily_usage.go new file mode 100644 index 0000000..479100d --- /dev/null +++ b/app/admin/router/tm_member_daily_usage.go @@ -0,0 +1,27 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/middleware" + "go-admin/common/actions" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerTmMemberDailyUsageRouter) +} + +// registerTmMemberDailyUsageRouter +func registerTmMemberDailyUsageRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.TmMemberDailyUsage{} + r := v1.Group("/tm-member-daily-usage").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/app/admin/router/tm_member_platform.go b/app/admin/router/tm_member_platform.go new file mode 100644 index 0000000..e430789 --- /dev/null +++ b/app/admin/router/tm_member_platform.go @@ -0,0 +1,32 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/actions" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerTmMemberPlatformRouter) +} + +// registerTmMemberPlatformRouter +func registerTmMemberPlatformRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.TmMemberPlatform{} + r := v1.Group("/tm-member-platform").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + } + + f2 := v1.Group("/tm-member-platform").Use(authMiddleware.MiddlewareFunc()) + { + f2.GET("statistics", api.GetStatistic) + } +} diff --git a/app/admin/router/tm_platform.go b/app/admin/router/tm_platform.go new file mode 100644 index 0000000..1bc2cb7 --- /dev/null +++ b/app/admin/router/tm_platform.go @@ -0,0 +1,32 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/actions" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerTmPlatformRouter) +} + +// registerTmPlatformRouter +func registerTmPlatformRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.TmPlatform{} + r := v1.Group("/tm-platform").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + } + + r1 := v1.Group("/tm-platform") + { + r1.GET("list", api.List) + } +} diff --git a/app/admin/router/tm_platform_account.go b/app/admin/router/tm_platform_account.go new file mode 100644 index 0000000..99489b9 --- /dev/null +++ b/app/admin/router/tm_platform_account.go @@ -0,0 +1,27 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/middleware" + "go-admin/common/actions" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerTmPlatformAccountRouter) +} + +// registerTmPlatformAccountRouter +func registerTmPlatformAccountRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.TmPlatformAccount{} + r := v1.Group("/tm-platform-account").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/app/admin/router/translate_router.go b/app/admin/router/translate_router.go new file mode 100644 index 0000000..dcef383 --- /dev/null +++ b/app/admin/router/translate_router.go @@ -0,0 +1,32 @@ +package router + +import ( + "go-admin/app/admin/apis" + "go-admin/common/middleware" + + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerTranslateRouter) + routerApp = append(routerApp, registerTmPlatformAppRouter) +} + +// registerTmPlatformRouter +func registerTranslateRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.Translate{} + r := v1.Group("/translate").Use(authMiddleware.MiddlewareFunc()) + { + r.GET("/datastatistics", api.GetTranslateStatistic) + } +} + +func registerTmPlatformAppRouter(v1 *gin.RouterGroup) { + api := apis.Translate{} + + r := v1.Group("translate", middleware.FrontedAuth) + { + r.POST("", api.Translate) + } +} diff --git a/app/admin/service/dto/sys_api.go b/app/admin/service/dto/sys_api.go new file mode 100644 index 0000000..d26034e --- /dev/null +++ b/app/admin/service/dto/sys_api.go @@ -0,0 +1,95 @@ +package dto + +import ( + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" +) + +// SysApiGetPageReq 功能列表请求参数 +type SysApiGetPageReq struct { + dto.Pagination `search:"-"` + Title string `form:"title" search:"type:contains;column:title;table:sys_api" comment:"标题"` + Path string `form:"path" search:"type:contains;column:path;table:sys_api" comment:"地址"` + Action string `form:"action" search:"type:exact;column:action;table:sys_api" comment:"请求方式"` + ParentId string `form:"parentId" search:"type:exact;column:parent_id;table:sys_api" comment:"按钮id"` + Type string `form:"type" search:"-" comment:"类型"` + SysApiOrder +} + +type SysApiOrder struct { + TitleOrder string `search:"type:order;column:title;table:sys_api" form:"titleOrder"` + PathOrder string `search:"type:order;column:path;table:sys_api" form:"pathOrder"` + CreatedAtOrder string `search:"type:order;column:created_at;table:sys_api" form:"createdAtOrder"` +} + +func (m *SysApiGetPageReq) GetNeedSearch() interface{} { + return *m +} + +// SysApiInsertReq 功能创建请求参数 +type SysApiInsertReq struct { + Id int `json:"-" comment:"编码"` // 编码 + Handle string `json:"handle" comment:"handle"` + Title string `json:"title" comment:"标题"` + Path string `json:"path" comment:"地址"` + Type string `json:"type" comment:""` + Action string `json:"action" comment:"类型"` + common.ControlBy +} + +func (s *SysApiInsertReq) Generate(model *models.SysApi) { + model.Handle = s.Handle + model.Title = s.Title + model.Path = s.Path + model.Type = s.Type + model.Action = s.Action +} + +func (s *SysApiInsertReq) GetId() interface{} { + return s.Id +} + +// SysApiUpdateReq 功能更新请求参数 +type SysApiUpdateReq struct { + Id int `uri:"id" comment:"编码"` // 编码 + Handle string `json:"handle" comment:"handle"` + Title string `json:"title" comment:"标题"` + Path string `json:"path" comment:"地址"` + Type string `json:"type" comment:""` + Action string `json:"action" comment:"类型"` + common.ControlBy +} + +func (s *SysApiUpdateReq) Generate(model *models.SysApi) { + if s.Id != 0 { + model.Id = s.Id + } + model.Handle = s.Handle + model.Title = s.Title + model.Path = s.Path + model.Type = s.Type + model.Action = s.Action +} + +func (s *SysApiUpdateReq) GetId() interface{} { + return s.Id +} + +// SysApiGetReq 功能获取请求参数 +type SysApiGetReq struct { + Id int `uri:"id"` +} + +func (s *SysApiGetReq) GetId() interface{} { + return s.Id +} + +// SysApiDeleteReq 功能删除请求参数 +type SysApiDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *SysApiDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/sys_config.go b/app/admin/service/dto/sys_config.go new file mode 100644 index 0000000..06f7467 --- /dev/null +++ b/app/admin/service/dto/sys_config.go @@ -0,0 +1,112 @@ +package dto + +import ( + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" +) + +// SysConfigGetPageReq 列表或者搜索使用结构体 +type SysConfigGetPageReq struct { + dto.Pagination `search:"-"` + ConfigName string `form:"configName" search:"type:contains;column:config_name;table:sys_config"` + ConfigKey string `form:"configKey" search:"type:contains;column:config_key;table:sys_config"` + ConfigType string `form:"configType" search:"type:exact;column:config_type;table:sys_config"` + IsFrontend string `form:"isFrontend" search:"type:exact;column:is_frontend;table:sys_config"` + SysConfigOrder +} + +type SysConfigOrder struct { + IdOrder string `search:"type:order;column:id;table:sys_config" form:"idOrder"` + ConfigNameOrder string `search:"type:order;column:config_name;table:sys_config" form:"configNameOrder"` + ConfigKeyOrder string `search:"type:order;column:config_key;table:sys_config" form:"configKeyOrder"` + ConfigTypeOrder string `search:"type:order;column:config_type;table:sys_config" form:"configTypeOrder"` + CreatedAtOrder string `search:"type:order;column:created_at;table:sys_config" form:"createdAtOrder"` +} + +func (m *SysConfigGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysConfigGetToSysAppReq struct { + IsFrontend string `form:"isFrontend" search:"type:exact;column:is_frontend;table:sys_config"` +} + +func (m *SysConfigGetToSysAppReq) GetNeedSearch() interface{} { + return *m +} + +// SysConfigControl 增、改使用的结构体 +type SysConfigControl struct { + Id int `uri:"Id" comment:"编码"` // 编码 + ConfigName string `json:"configName" comment:""` + ConfigKey string `uri:"configKey" json:"configKey" comment:""` + ConfigValue string `json:"configValue" comment:""` + ConfigType string `json:"configType" comment:""` + IsFrontend string `json:"isFrontend"` + Remark string `json:"remark" comment:""` + common.ControlBy +} + +// Generate 结构体数据转化 从 SysConfigControl 至 system.SysConfig 对应的模型 +func (s *SysConfigControl) Generate(model *models.SysConfig) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.ConfigName = s.ConfigName + model.ConfigKey = s.ConfigKey + model.ConfigValue = s.ConfigValue + model.ConfigType = s.ConfigType + model.IsFrontend = s.IsFrontend + model.Remark = s.Remark + +} + +// GetId 获取数据对应的ID +func (s *SysConfigControl) GetId() interface{} { + return s.Id +} + +// GetSetSysConfigReq 增、改使用的结构体 +type GetSetSysConfigReq struct { + ConfigKey string `json:"configKey" comment:""` + ConfigValue string `json:"configValue" comment:""` +} + +// Generate 结构体数据转化 从 SysConfigControl 至 system.SysConfig 对应的模型 +func (s *GetSetSysConfigReq) Generate(model *models.SysConfig) { + model.ConfigValue = s.ConfigValue +} + +type UpdateSetSysConfigReq map[string]string + +// SysConfigByKeyReq 根据Key获取配置 +type SysConfigByKeyReq struct { + ConfigKey string `uri:"configKey" search:"type:contains;column:config_key;table:sys_config"` +} + +func (m *SysConfigByKeyReq) GetNeedSearch() interface{} { + return *m +} + +type GetSysConfigByKEYForServiceResp struct { + ConfigKey string `json:"configKey" comment:""` + ConfigValue string `json:"configValue" comment:""` +} + +type SysConfigGetReq struct { + Id int `uri:"id"` +} + +func (s *SysConfigGetReq) GetId() interface{} { + return s.Id +} + +type SysConfigDeleteReq struct { + Ids []int `json:"ids"` + common.ControlBy +} + +func (s *SysConfigDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/sys_dept.go b/app/admin/service/dto/sys_dept.go new file mode 100644 index 0000000..345a550 --- /dev/null +++ b/app/admin/service/dto/sys_dept.go @@ -0,0 +1,110 @@ +package dto + +import ( + "go-admin/app/admin/models" + common "go-admin/common/models" +) + +// SysDeptGetPageReq 列表或者搜索使用结构体 +type SysDeptGetPageReq struct { + DeptId int `form:"deptId" search:"type:exact;column:dept_id;table:sys_dept" comment:"id"` //id + ParentId int `form:"parentId" search:"type:exact;column:parent_id;table:sys_dept" comment:"上级部门"` //上级部门 + DeptPath string `form:"deptPath" search:"type:exact;column:dept_path;table:sys_dept" comment:""` //路径 + DeptName string `form:"deptName" search:"type:exact;column:dept_name;table:sys_dept" comment:"部门名称"` //部门名称 + Sort int `form:"sort" search:"type:exact;column:sort;table:sys_dept" comment:"排序"` //排序 + Leader string `form:"leader" search:"type:exact;column:leader;table:sys_dept" comment:"负责人"` //负责人 + Phone string `form:"phone" search:"type:exact;column:phone;table:sys_dept" comment:"手机"` //手机 + Email string `form:"email" search:"type:exact;column:email;table:sys_dept" comment:"邮箱"` //邮箱 + Status string `form:"status" search:"type:exact;column:status;table:sys_dept" comment:"状态"` //状态 +} + +func (m *SysDeptGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysDeptInsertReq struct { + DeptId int `uri:"id" comment:"编码"` // 编码 + ParentId int `json:"parentId" comment:"上级部门" vd:"?"` //上级部门 + DeptPath string `json:"deptPath" comment:""` //路径 + DeptName string `json:"deptName" comment:"部门名称" vd:"len($)>0"` //部门名称 + Sort int `json:"sort" comment:"排序" vd:"?"` //排序 + Leader string `json:"leader" comment:"负责人" vd:"@:len($)>0; msg:'leader不能为空'"` //负责人 + Phone string `json:"phone" comment:"手机" vd:"?"` //手机 + Email string `json:"email" comment:"邮箱" vd:"?"` //邮箱 + Status int `json:"status" comment:"状态" vd:"$>0"` //状态 + common.ControlBy +} + +func (s *SysDeptInsertReq) Generate(model *models.SysDept) { + if s.DeptId != 0 { + model.DeptId = s.DeptId + } + model.DeptName = s.DeptName + model.ParentId = s.ParentId + model.DeptPath = s.DeptPath + model.Sort = s.Sort + model.Leader = s.Leader + model.Phone = s.Phone + model.Email = s.Email + model.Status = s.Status +} + +// GetId 获取数据对应的ID +func (s *SysDeptInsertReq) GetId() interface{} { + return s.DeptId +} + +type SysDeptUpdateReq struct { + DeptId int `uri:"id" comment:"编码"` // 编码 + ParentId int `json:"parentId" comment:"上级部门" vd:"?"` //上级部门 + DeptPath string `json:"deptPath" comment:""` //路径 + DeptName string `json:"deptName" comment:"部门名称" vd:"len($)>0"` //部门名称 + Sort int `json:"sort" comment:"排序" vd:"?"` //排序 + Leader string `json:"leader" comment:"负责人" vd:"@:len($)>0; msg:'leader不能为空'"` //负责人 + Phone string `json:"phone" comment:"手机" vd:"?"` //手机 + Email string `json:"email" comment:"邮箱" vd:"?"` //邮箱 + Status int `json:"status" comment:"状态" vd:"$>0"` //状态 + common.ControlBy +} + +// Generate 结构体数据转化 从 SysDeptControl 至 SysDept 对应的模型 +func (s *SysDeptUpdateReq) Generate(model *models.SysDept) { + if s.DeptId != 0 { + model.DeptId = s.DeptId + } + model.DeptName = s.DeptName + model.ParentId = s.ParentId + model.DeptPath = s.DeptPath + model.Sort = s.Sort + model.Leader = s.Leader + model.Phone = s.Phone + model.Email = s.Email + model.Status = s.Status +} + +// GetId 获取数据对应的ID +func (s *SysDeptUpdateReq) GetId() interface{} { + return s.DeptId +} + +type SysDeptGetReq struct { + Id int `uri:"id"` +} + +func (s *SysDeptGetReq) GetId() interface{} { + return s.Id +} + +type SysDeptDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *SysDeptDeleteReq) GetId() interface{} { + return s.Ids +} + +type DeptLabel struct { + Id int `gorm:"-" json:"id"` + Label string `gorm:"-" json:"label"` + Children []DeptLabel `gorm:"-" json:"children"` +} diff --git a/app/admin/service/dto/sys_dict_data.go b/app/admin/service/dto/sys_dict_data.go new file mode 100644 index 0000000..6c659ff --- /dev/null +++ b/app/admin/service/dto/sys_dict_data.go @@ -0,0 +1,122 @@ +package dto + +import ( + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" +) + +type SysDictDataGetPageReq struct { + dto.Pagination `search:"-"` + Id int `form:"id" search:"type:exact;column:dict_code;table:sys_dict_data" comment:""` + DictLabel string `form:"dictLabel" search:"type:contains;column:dict_label;table:sys_dict_data" comment:""` + DictValue string `form:"dictValue" search:"type:contains;column:dict_value;table:sys_dict_data" comment:""` + DictType string `form:"dictType" search:"type:contains;column:dict_type;table:sys_dict_data" comment:""` + Status string `form:"status" search:"type:exact;column:status;table:sys_dict_data" comment:""` +} + +func (m *SysDictDataGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysDictDataGetAllResp struct { + DictLabel string `json:"label"` + DictValue string `json:"value"` +} + +type SysDictDataInsertReq struct { + Id int `json:"-" comment:""` + DictSort int `json:"dictSort" comment:""` + DictLabel string `json:"dictLabel" comment:""` + DictValue string `json:"dictValue" comment:""` + DictType string `json:"dictType" comment:""` + CssClass string `json:"cssClass" comment:""` + ListClass string `json:"listClass" comment:""` + IsDefault string `json:"isDefault" comment:""` + Status int `json:"status" comment:""` + Default string `json:"default" comment:""` + Remark string `json:"remark" comment:""` + common.ControlBy +} + +func (s *SysDictDataInsertReq) Generate(model *models.SysDictData) { + model.DictCode = s.Id + model.DictSort = s.DictSort + model.DictLabel = s.DictLabel + model.DictValue = s.DictValue + model.DictType = s.DictType + model.CssClass = s.CssClass + model.ListClass = s.ListClass + model.IsDefault = s.IsDefault + model.Status = s.Status + model.Default = s.Default + model.Remark = s.Remark +} + +func (s *SysDictDataInsertReq) GetId() interface{} { + return s.Id +} + +type SysDictDataDetail struct { + Id int `json:"id"` + DictSort int `json:"dictSort"` + DictLabel string `json:"dictLabel"` + DictValue string `json:"dictValue"` + DictType string `json:"dictType"` + CssClass string `json:"cssClass"` + ListClass string `json:"listClass"` + IsDefault string `json:"isDefault"` + Status int `json:"status"` + Default string `json:"default"` + Remark string `json:"remark"` +} + +type SysDictDataUpdateReq struct { + Id int `uri:"dictCode" comment:""` + DictSort int `json:"dictSort" comment:""` + DictLabel string `json:"dictLabel" comment:""` + DictValue string `json:"dictValue" comment:""` + DictType string `json:"dictType" comment:""` + CssClass string `json:"cssClass" comment:""` + ListClass string `json:"listClass" comment:""` + IsDefault string `json:"isDefault" comment:""` + Status int `json:"status" comment:""` + Default string `json:"default" comment:""` + Remark string `json:"remark" comment:""` + common.ControlBy +} + +func (s *SysDictDataUpdateReq) Generate(model *models.SysDictData) { + model.DictCode = s.Id + model.DictSort = s.DictSort + model.DictLabel = s.DictLabel + model.DictValue = s.DictValue + model.DictType = s.DictType + model.CssClass = s.CssClass + model.ListClass = s.ListClass + model.IsDefault = s.IsDefault + model.Status = s.Status + model.Default = s.Default + model.Remark = s.Remark +} + +func (s *SysDictDataUpdateReq) GetId() interface{} { + return s.Id +} + +type SysDictDataGetReq struct { + Id int `uri:"dictCode"` +} + +func (s *SysDictDataGetReq) GetId() interface{} { + return s.Id +} + +type SysDictDataDeleteReq struct { + Ids []int `json:"ids"` + common.ControlBy `json:"-"` +} + +func (s *SysDictDataDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/sys_dict_type.go b/app/admin/service/dto/sys_dict_type.go new file mode 100644 index 0000000..4812d7e --- /dev/null +++ b/app/admin/service/dto/sys_dict_type.go @@ -0,0 +1,100 @@ +package dto + +import ( + "go-admin/app/admin/models" + + "go-admin/common/dto" + common "go-admin/common/models" +) + +type SysDictTypeGetPageReq struct { + dto.Pagination `search:"-"` + DictId []int `form:"dictId" search:"type:in;column:dict_id;table:sys_dict_type"` + DictName string `form:"dictName" search:"type:icontains;column:dict_name;table:sys_dict_type"` + DictType string `form:"dictType" search:"type:icontains;column:dict_type;table:sys_dict_type"` + Status int `form:"status" search:"type:exact;column:status;table:sys_dict_type"` +} + +type SysDictTypeOrder struct { + DictIdOrder string `search:"type:order;column:dict_id;table:sys_dict_type" form:"dictIdOrder"` +} + +func (m *SysDictTypeGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysDictTypeInsertReq struct { + Id int `uri:"id"` + DictName string `json:"dictName"` + DictType string `json:"dictType"` + Status int `json:"status"` + Remark string `json:"remark"` + common.ControlBy +} + +func (s *SysDictTypeInsertReq) Generate(model *models.SysDictType) { + if s.Id != 0 { + model.ID = s.Id + } + model.DictName = s.DictName + model.DictType = s.DictType + model.Status = s.Status + model.Remark = s.Remark + +} + +func (s *SysDictTypeInsertReq) GetId() interface{} { + return s.Id +} + +// 缓存数据 +type SysDictDetailResp struct { + Id int `json:"id"` + DictName string `json:"dictName"` + DictType string `json:"dictType"` + Status int `json:"status"` + Remark string `json:"remark"` + //datas + Datas []SysDictDataDetail `json:"datas"` +} + +type SysDictTypeUpdateReq struct { + Id int `uri:"id"` + DictName string `json:"dictName"` + DictType string `json:"dictType"` + Status int `json:"status"` + Remark string `json:"remark"` + common.ControlBy +} + +func (s *SysDictTypeUpdateReq) Generate(model *models.SysDictType) { + if s.Id != 0 { + model.ID = s.Id + } + model.DictName = s.DictName + model.DictType = s.DictType + model.Status = s.Status + model.Remark = s.Remark + +} + +func (s *SysDictTypeUpdateReq) GetId() interface{} { + return s.Id +} + +type SysDictTypeGetReq struct { + Id int `uri:"id"` +} + +func (s *SysDictTypeGetReq) GetId() interface{} { + return s.Id +} + +type SysDictTypeDeleteReq struct { + Ids []int `json:"ids"` + common.ControlBy +} + +func (s *SysDictTypeDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/sys_login_log.go b/app/admin/service/dto/sys_login_log.go new file mode 100644 index 0000000..42a6e45 --- /dev/null +++ b/app/admin/service/dto/sys_login_log.go @@ -0,0 +1,57 @@ +package dto + +import ( + "time" + + "go-admin/common/dto" +) + +type SysLoginLogGetPageReq struct { + dto.Pagination `search:"-"` + Username string `form:"username" search:"type:exact;column:username;table:sys_login_log" comment:"用户名"` + Status string `form:"status" search:"type:exact;column:status;table:sys_login_log" comment:"状态"` + Ipaddr string `form:"ipaddr" search:"type:exact;column:ipaddr;table:sys_login_log" comment:"ip地址"` + LoginLocation string `form:"loginLocation" search:"type:exact;column:login_location;table:sys_login_log" comment:"归属地"` + BeginTime string `form:"beginTime" search:"type:gte;column:ctime;table:sys_login_log" comment:"创建时间"` + EndTime string `form:"endTime" search:"type:lte;column:ctime;table:sys_login_log" comment:"创建时间"` + SysLoginLogOrder +} + +type SysLoginLogOrder struct { + CreatedAtOrder string `search:"type:order;column:created_at;table:sys_login_log" form:"createdAtOrder"` +} + +func (m *SysLoginLogGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysLoginLogControl struct { + ID int `uri:"Id" comment:"主键"` // 主键 + Username string `json:"username" comment:"用户名"` + Status string `json:"status" comment:"状态"` + Ipaddr string `json:"ipaddr" comment:"ip地址"` + LoginLocation string `json:"loginLocation" comment:"归属地"` + Browser string `json:"browser" comment:"浏览器"` + Os string `json:"os" comment:"系统"` + Platform string `json:"platform" comment:"固件"` + LoginTime time.Time `json:"loginTime" comment:"登录时间"` + Remark string `json:"remark" comment:"备注"` + Msg string `json:"msg" comment:"信息"` +} + +type SysLoginLogGetReq struct { + Id int `uri:"id"` +} + +func (s *SysLoginLogGetReq) GetId() interface{} { + return s.Id +} + +// SysLoginLogDeleteReq 功能删除请求参数 +type SysLoginLogDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *SysLoginLogDeleteReq) GetId() interface{} { + return s.Ids +} \ No newline at end of file diff --git a/app/admin/service/dto/sys_menu.go b/app/admin/service/dto/sys_menu.go new file mode 100644 index 0000000..67f4674 --- /dev/null +++ b/app/admin/service/dto/sys_menu.go @@ -0,0 +1,159 @@ +package dto + +import ( + "go-admin/app/admin/models" + common "go-admin/common/models" + + "go-admin/common/dto" +) + +// SysMenuGetPageReq 列表或者搜索使用结构体 +type SysMenuGetPageReq struct { + dto.Pagination `search:"-"` + Title string `form:"title" search:"type:contains;column:title;table:sys_menu" comment:"菜单名称"` // 菜单名称 + Visible int `form:"visible" search:"type:exact;column:visible;table:sys_menu" comment:"显示状态"` // 显示状态 +} + +func (m *SysMenuGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysMenuInsertReq struct { + MenuId int `uri:"id" comment:"编码"` // 编码 + MenuName string `form:"menuName" comment:"菜单name"` //菜单name + Title string `form:"title" comment:"显示名称"` //显示名称 + Icon string `form:"icon" comment:"图标"` //图标 + Path string `form:"path" comment:"路径"` //路径 + Paths string `form:"paths" comment:"id路径"` //id路径 + MenuType string `form:"menuType" comment:"菜单类型"` //菜单类型 + SysApi []models.SysApi `form:"sysApi"` + Apis []int `form:"apis"` + Action string `form:"action" comment:"请求方式"` //请求方式 + Permission string `form:"permission" comment:"权限编码"` //权限编码 + ParentId int `form:"parentId" comment:"上级菜单"` //上级菜单 + NoCache bool `form:"noCache" comment:"是否缓存"` //是否缓存 + Breadcrumb string `form:"breadcrumb" comment:"是否面包屑"` //是否面包屑 + Component string `form:"component" comment:"组件"` //组件 + Sort int `form:"sort" comment:"排序"` //排序 + Visible string `form:"visible" comment:"是否显示"` //是否显示 + IsFrame string `form:"isFrame" comment:"是否frame"` //是否frame + common.ControlBy +} + +func (s *SysMenuInsertReq) Generate(model *models.SysMenu) { + if s.MenuId != 0 { + model.MenuId = s.MenuId + } + model.MenuName = s.MenuName + model.Title = s.Title + model.Icon = s.Icon + model.Path = s.Path + model.Paths = s.Paths + model.MenuType = s.MenuType + model.Action = s.Action + model.SysApi = s.SysApi + model.Permission = s.Permission + model.ParentId = s.ParentId + model.NoCache = s.NoCache + model.Breadcrumb = s.Breadcrumb + model.Component = s.Component + model.Sort = s.Sort + model.Visible = s.Visible + model.IsFrame = s.IsFrame + if s.CreateBy != 0 { + model.CreateBy = s.CreateBy + } + if s.UpdateBy != 0 { + model.UpdateBy = s.UpdateBy + } +} + +func (s *SysMenuInsertReq) GetId() interface{} { + return s.MenuId +} + +type SysMenuUpdateReq struct { + MenuId int `uri:"id" comment:"编码"` // 编码 + MenuName string `form:"menuName" comment:"菜单name"` //菜单name + Title string `form:"title" comment:"显示名称"` //显示名称 + Icon string `form:"icon" comment:"图标"` //图标 + Path string `form:"path" comment:"路径"` //路径 + Paths string `form:"paths" comment:"id路径"` //id路径 + MenuType string `form:"menuType" comment:"菜单类型"` //菜单类型 + SysApi []models.SysApi `form:"sysApi"` + Apis []int `form:"apis"` + Action string `form:"action" comment:"请求方式"` //请求方式 + Permission string `form:"permission" comment:"权限编码"` //权限编码 + ParentId int `form:"parentId" comment:"上级菜单"` //上级菜单 + NoCache bool `form:"noCache" comment:"是否缓存"` //是否缓存 + Breadcrumb string `form:"breadcrumb" comment:"是否面包屑"` //是否面包屑 + Component string `form:"component" comment:"组件"` //组件 + Sort int `form:"sort" comment:"排序"` //排序 + Visible string `form:"visible" comment:"是否显示"` //是否显示 + IsFrame string `form:"isFrame" comment:"是否frame"` //是否frame + common.ControlBy +} + +func (s *SysMenuUpdateReq) Generate(model *models.SysMenu) { + if s.MenuId != 0 { + model.MenuId = s.MenuId + } + model.MenuName = s.MenuName + model.Title = s.Title + model.Icon = s.Icon + model.Path = s.Path + model.Paths = s.Paths + model.MenuType = s.MenuType + model.Action = s.Action + model.SysApi = s.SysApi + model.Permission = s.Permission + model.ParentId = s.ParentId + model.NoCache = s.NoCache + model.Breadcrumb = s.Breadcrumb + model.Component = s.Component + model.Sort = s.Sort + model.Visible = s.Visible + model.IsFrame = s.IsFrame + if s.CreateBy != 0 { + model.CreateBy = s.CreateBy + } + if s.UpdateBy != 0 { + model.UpdateBy = s.UpdateBy + } +} + +func (s *SysMenuUpdateReq) GetId() interface{} { + return s.MenuId +} + +type SysMenuGetReq struct { + Id int `uri:"id"` +} + +func (s *SysMenuGetReq) GetId() interface{} { + return s.Id +} + +type SysMenuDeleteReq struct { + Ids []int `json:"ids"` + common.ControlBy +} + +func (s *SysMenuDeleteReq) GetId() interface{} { + return s.Ids +} + +type MenuLabel struct { + Id int `json:"id,omitempty" gorm:"-"` + Label string `json:"label,omitempty" gorm:"-"` + Children []MenuLabel `json:"children,omitempty" gorm:"-"` +} + +type MenuRole struct { + models.SysMenu + IsSelect bool `json:"is_select" gorm:"-"` +} + +type SelectRole struct { + RoleId int `uri:"roleId"` +} diff --git a/app/admin/service/dto/sys_opera_log.go b/app/admin/service/dto/sys_opera_log.go new file mode 100644 index 0000000..5df36eb --- /dev/null +++ b/app/admin/service/dto/sys_opera_log.go @@ -0,0 +1,102 @@ +package dto + +import ( + "time" + + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" +) + +const ( + OperaStatusEnabel = "1" // 状态-正常 + OperaStatusDisable = "2" // 状态-关闭 +) + +type SysOperaLogGetPageReq struct { + dto.Pagination `search:"-"` + Title string `form:"title" search:"type:contains;column:title;table:sys_opera_log" comment:"操作模块"` + Method string `form:"method" search:"type:contains;column:method;table:sys_opera_log" comment:"函数"` + RequestMethod string `form:"requestMethod" search:"type:contains;column:request_method;table:sys_opera_log" comment:"请求方式: GET POST PUT DELETE"` + OperUrl string `form:"operUrl" search:"type:contains;column:oper_url;table:sys_opera_log" comment:"访问地址"` + OperIp string `form:"operIp" search:"type:exact;column:oper_ip;table:sys_opera_log" comment:"客户端ip"` + Status int `form:"status" search:"type:exact;column:status;table:sys_opera_log" comment:"状态 1:正常 2:关闭"` + BeginTime string `form:"beginTime" search:"type:gte;column:created_at;table:sys_opera_log" comment:"创建时间"` + EndTime string `form:"endTime" search:"type:lte;column:created_at;table:sys_opera_log" comment:"更新时间"` + SysOperaLogOrder +} + +type SysOperaLogOrder struct { + CreatedAtOrder string `search:"type:order;column:created_at;table:sys_opera_log" form:"createdAtOrder"` +} + +func (m *SysOperaLogGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysOperaLogControl struct { + ID int `uri:"Id" comment:"编码"` // 编码 + Title string `json:"title" comment:"操作模块"` + BusinessType string `json:"businessType" comment:"操作类型"` + BusinessTypes string `json:"businessTypes" comment:""` + Method string `json:"method" comment:"函数"` + RequestMethod string `json:"requestMethod" comment:"请求方式"` + OperatorType string `json:"operatorType" comment:"操作类型"` + OperName string `json:"operName" comment:"操作者"` + DeptName string `json:"deptName" comment:"部门名称"` + OperUrl string `json:"operUrl" comment:"访问地址"` + OperIp string `json:"operIp" comment:"客户端ip"` + OperLocation string `json:"operLocation" comment:"访问位置"` + OperParam string `json:"operParam" comment:"请求参数"` + Status string `json:"status" comment:"操作状态"` + OperTime time.Time `json:"operTime" comment:"操作时间"` + JsonResult string `json:"jsonResult" comment:"返回数据"` + Remark string `json:"remark" comment:"备注"` + LatencyTime string `json:"latencyTime" comment:"耗时"` + UserAgent string `json:"userAgent" comment:"ua"` +} + +func (s *SysOperaLogControl) Generate() (*models.SysOperaLog, error) { + return &models.SysOperaLog{ + Model: common.Model{Id: s.ID}, + Title: s.Title, + BusinessType: s.BusinessType, + BusinessTypes: s.BusinessTypes, + Method: s.Method, + RequestMethod: s.RequestMethod, + OperatorType: s.OperatorType, + OperName: s.OperName, + DeptName: s.DeptName, + OperUrl: s.OperUrl, + OperIp: s.OperIp, + OperLocation: s.OperLocation, + OperParam: s.OperParam, + Status: s.Status, + OperTime: s.OperTime, + JsonResult: s.JsonResult, + Remark: s.Remark, + LatencyTime: s.LatencyTime, + UserAgent: s.UserAgent, + }, nil +} + +func (s *SysOperaLogControl) GetId() interface{} { + return s.ID +} + +type SysOperaLogGetReq struct { + Id int `uri:"id"` +} + +func (s *SysOperaLogGetReq) GetId() interface{} { + return s.Id +} + +// SysOperaLogDeleteReq 功能删除请求参数 +type SysOperaLogDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *SysOperaLogDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/sys_post.go b/app/admin/service/dto/sys_post.go new file mode 100644 index 0000000..2b432a7 --- /dev/null +++ b/app/admin/service/dto/sys_post.go @@ -0,0 +1,111 @@ +package dto + +import ( + "go-admin/app/admin/models" + common "go-admin/common/models" + + "go-admin/common/dto" +) + +// SysPostPageReq 列表或者搜索使用结构体 +type SysPostPageReq struct { + dto.Pagination `search:"-"` + PostId int `form:"postId" search:"type:exact;column:post_id;table:sys_post" comment:"id"` // id + PostName string `form:"postName" search:"type:contains;column:post_name;table:sys_post" comment:"名称"` // 名称 + PostCode string `form:"postCode" search:"type:contains;column:post_code;table:sys_post" comment:"编码"` // 编码 + Sort int `form:"sort" search:"type:exact;column:sort;table:sys_post" comment:"排序"` // 排序 + Status int `form:"status" search:"type:exact;column:status;table:sys_post" comment:"状态"` // 状态 + Remark string `form:"remark" search:"type:exact;column:remark;table:sys_post" comment:"备注"` // 备注 +} + +func (m *SysPostPageReq) GetNeedSearch() interface{} { + return *m +} + +// SysPostInsertReq 增使用的结构体 +type SysPostInsertReq struct { + PostId int `uri:"id" comment:"id"` + PostName string `form:"postName" comment:"名称"` + PostCode string `form:"postCode" comment:"编码"` + Sort int `form:"sort" comment:"排序"` + Status int `form:"status" comment:"状态"` + Remark string `form:"remark" comment:"备注"` + common.ControlBy +} + +func (s *SysPostInsertReq) Generate(model *models.SysPost) { + model.PostName = s.PostName + model.PostCode = s.PostCode + model.Sort = s.Sort + model.Status = s.Status + model.Remark = s.Remark + if s.ControlBy.UpdateBy != 0 { + model.UpdateBy = s.UpdateBy + } + if s.ControlBy.CreateBy != 0 { + model.CreateBy = s.CreateBy + } +} + +// GetId 获取数据对应的ID +func (s *SysPostInsertReq) GetId() interface{} { + return s.PostId +} + +// SysPostUpdateReq 改使用的结构体 +type SysPostUpdateReq struct { + PostId int `uri:"id" comment:"id"` + PostName string `form:"postName" comment:"名称"` + PostCode string `form:"postCode" comment:"编码"` + Sort int `form:"sort" comment:"排序"` + Status int `form:"status" comment:"状态"` + Remark string `form:"remark" comment:"备注"` + common.ControlBy +} + +func (s *SysPostUpdateReq) Generate(model *models.SysPost) { + model.PostId = s.PostId + model.PostName = s.PostName + model.PostCode = s.PostCode + model.Sort = s.Sort + model.Status = s.Status + model.Remark = s.Remark + if s.ControlBy.UpdateBy != 0 { + model.UpdateBy = s.UpdateBy + } + if s.ControlBy.CreateBy != 0 { + model.CreateBy = s.CreateBy + } +} + +func (s *SysPostUpdateReq) GetId() interface{} { + return s.PostId +} + +// SysPostGetReq 获取单个的结构体 +type SysPostGetReq struct { + Id int `uri:"id"` +} + +func (s *SysPostGetReq) GetId() interface{} { + return s.Id +} + +// SysPostDeleteReq 删除的结构体 +type SysPostDeleteReq struct { + Ids []int `json:"ids"` + common.ControlBy +} + +func (s *SysPostDeleteReq) Generate(model *models.SysPost) { + if s.ControlBy.UpdateBy != 0 { + model.UpdateBy = s.UpdateBy + } + if s.ControlBy.CreateBy != 0 { + model.CreateBy = s.CreateBy + } +} + +func (s *SysPostDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/sys_role.go b/app/admin/service/dto/sys_role.go new file mode 100644 index 0000000..789b85e --- /dev/null +++ b/app/admin/service/dto/sys_role.go @@ -0,0 +1,164 @@ +package dto + +import ( + "go-admin/app/admin/models" + common "go-admin/common/models" + + "go-admin/common/dto" +) + +type SysRoleGetPageReq struct { + dto.Pagination `search:"-"` + + RoleId int `form:"roleId" search:"type:exact;column:role_id;table:sys_role" comment:"角色编码"` // 角色编码 + RoleName string `form:"roleName" search:"type:exact;column:role_name;table:sys_role" comment:"角色名称"` // 角色名称 + Status string `form:"status" search:"type:exact;column:status;table:sys_role" comment:"状态"` // 状态 + RoleKey string `form:"roleKey" search:"type:exact;column:role_key;table:sys_role" comment:"角色代码"` // 角色代码 + RoleSort int `form:"roleSort" search:"type:exact;column:role_sort;table:sys_role" comment:"角色排序"` // 角色排序 + Flag string `form:"flag" search:"type:exact;column:flag;table:sys_role" comment:"标记"` // 标记 + Remark string `form:"remark" search:"type:exact;column:remark;table:sys_role" comment:"备注"` // 备注 + Admin bool `form:"admin" search:"type:exact;column:admin;table:sys_role" comment:"是否管理员"` + DataScope string `form:"dataScope" search:"type:exact;column:data_scope;table:sys_role" comment:"是否管理员"` +} + +type SysRoleOrder struct { + RoleIdOrder string `search:"type:order;column:role_id;table:sys_role" form:"roleIdOrder"` + RoleNameOrder string `search:"type:order;column:role_name;table:sys_role" form:"roleNameOrder"` + RoleSortOrder string `search:"type:order;column:role_sort;table:sys_role" form:"usernameOrder"` + StatusOrder string `search:"type:order;column:status;table:sys_role" form:"statusOrder"` + CreatedAtOrder string `search:"type:order;column:created_at;table:sys_role" form:"createdAtOrder"` +} + +func (m *SysRoleGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SysRoleInsertReq struct { + RoleId int `uri:"id" comment:"角色编码"` // 角色编码 + RoleName string `form:"roleName" comment:"角色名称"` // 角色名称 + Status string `form:"status" comment:"状态"` // 状态 1禁用 2正常 + RoleKey string `form:"roleKey" comment:"角色代码"` // 角色代码 + RoleSort int `form:"roleSort" comment:"角色排序"` // 角色排序 + Flag string `form:"flag" comment:"标记"` // 标记 + Remark string `form:"remark" comment:"备注"` // 备注 + Admin bool `form:"admin" comment:"是否管理员"` + DataScope string `form:"dataScope"` + SysMenu []models.SysMenu `form:"sysMenu"` + MenuIds []int `form:"menuIds"` + SysDept []models.SysDept `form:"sysDept"` + DeptIds []int `form:"deptIds"` + common.ControlBy +} + +func (s *SysRoleInsertReq) Generate(model *models.SysRole) { + if s.RoleId != 0 { + model.RoleId = s.RoleId + } + model.RoleName = s.RoleName + model.Status = s.Status + model.RoleKey = s.RoleKey + model.RoleSort = s.RoleSort + model.Flag = s.Flag + model.Remark = s.Remark + model.Admin = s.Admin + model.DataScope = s.DataScope + model.SysMenu = &s.SysMenu + model.SysDept = s.SysDept +} + +func (s *SysRoleInsertReq) GetId() interface{} { + return s.RoleId +} + +type SysRoleUpdateReq struct { + RoleId int `uri:"id" comment:"角色编码"` // 角色编码 + RoleName string `form:"roleName" comment:"角色名称"` // 角色名称 + Status string `form:"status" comment:"状态"` // 状态 + RoleKey string `form:"roleKey" comment:"角色代码"` // 角色代码 + RoleSort int `form:"roleSort" comment:"角色排序"` // 角色排序 + Flag string `form:"flag" comment:"标记"` // 标记 + Remark string `form:"remark" comment:"备注"` // 备注 + Admin bool `form:"admin" comment:"是否管理员"` + DataScope string `form:"dataScope"` + SysMenu []models.SysMenu `form:"sysMenu"` + MenuIds []int `form:"menuIds"` + SysDept []models.SysDept `form:"sysDept"` + DeptIds []int `form:"deptIds"` + common.ControlBy +} + +func (s *SysRoleUpdateReq) Generate(model *models.SysRole) { + if s.RoleId != 0 { + model.RoleId = s.RoleId + } + model.RoleName = s.RoleName + model.Status = s.Status + model.RoleKey = s.RoleKey + model.RoleSort = s.RoleSort + model.Flag = s.Flag + model.Remark = s.Remark + model.Admin = s.Admin + model.DataScope = s.DataScope + model.SysMenu = &s.SysMenu + model.SysDept = s.SysDept +} + +func (s *SysRoleUpdateReq) GetId() interface{} { + return s.RoleId +} + +type UpdateStatusReq struct { + RoleId int `form:"roleId" comment:"角色编码"` // 角色编码 + Status string `form:"status" comment:"状态"` // 状态 + common.ControlBy +} + +func (s *UpdateStatusReq) Generate(model *models.SysRole) { + if s.RoleId != 0 { + model.RoleId = s.RoleId + } + model.Status = s.Status +} + +func (s *UpdateStatusReq) GetId() interface{} { + return s.RoleId +} + +type SysRoleByName struct { + RoleName string `form:"role"` // 角色编码 +} + +type SysRoleGetReq struct { + Id int `uri:"id"` +} + +func (s *SysRoleGetReq) GetId() interface{} { + return s.Id +} + +type SysRoleDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *SysRoleDeleteReq) GetId() interface{} { + return s.Ids +} + +// RoleDataScopeReq 角色数据权限修改 +type RoleDataScopeReq struct { + RoleId int `json:"roleId" binding:"required"` + DataScope string `json:"dataScope" binding:"required"` + DeptIds []int `json:"deptIds"` +} + +func (s *RoleDataScopeReq) Generate(model *models.SysRole) { + if s.RoleId != 0 { + model.RoleId = s.RoleId + } + model.DataScope = s.DataScope + model.DeptIds = s.DeptIds +} + +type DeptIdList struct { + DeptId int `json:"DeptId"` +} diff --git a/app/admin/service/dto/sys_user.go b/app/admin/service/dto/sys_user.go new file mode 100644 index 0000000..ebb72bc --- /dev/null +++ b/app/admin/service/dto/sys_user.go @@ -0,0 +1,189 @@ +package dto + +import ( + "go-admin/app/admin/models" + + "go-admin/common/dto" + common "go-admin/common/models" +) + +type SysUserGetPageReq struct { + dto.Pagination `search:"-"` + UserId int `form:"userId" search:"type:exact;column:user_id;table:sys_user" comment:"用户ID"` + Username string `form:"username" search:"type:contains;column:username;table:sys_user" comment:"用户名"` + NickName string `form:"nickName" search:"type:contains;column:nick_name;table:sys_user" comment:"昵称"` + Phone string `form:"phone" search:"type:contains;column:phone;table:sys_user" comment:"手机号"` + RoleId string `form:"roleId" search:"type:exact;column:role_id;table:sys_user" comment:"角色ID"` + Sex string `form:"sex" search:"type:exact;column:sex;table:sys_user" comment:"性别"` + Email string `form:"email" search:"type:contains;column:email;table:sys_user" comment:"邮箱"` + PostId string `form:"postId" search:"type:exact;column:post_id;table:sys_user" comment:"岗位"` + Status string `form:"status" search:"type:exact;column:status;table:sys_user" comment:"状态"` + DeptJoin `search:"type:left;on:dept_id:dept_id;table:sys_user;join:sys_dept"` + SysUserOrder +} + +type SysUserOrder struct { + UserIdOrder string `search:"type:order;column:user_id;table:sys_user" form:"userIdOrder"` + UsernameOrder string `search:"type:order;column:username;table:sys_user" form:"usernameOrder"` + StatusOrder string `search:"type:order;column:status;table:sys_user" form:"statusOrder"` + CreatedAtOrder string `search:"type:order;column:created_at;table:sys_user" form:"createdAtOrder"` +} + +type DeptJoin struct { + DeptId string `search:"type:contains;column:dept_path;table:sys_dept" form:"deptId"` +} + +func (m *SysUserGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type ResetSysUserPwdReq struct { + UserId int `json:"userId" comment:"用户ID" vd:"$>0"` // 用户ID + Password string `json:"password" comment:"密码" vd:"len($)>0"` + common.ControlBy +} + +func (s *ResetSysUserPwdReq) GetId() interface{} { + return s.UserId +} + +func (s *ResetSysUserPwdReq) Generate(model *models.SysUser) { + if s.UserId != 0 { + model.UserId = s.UserId + } + model.Password = s.Password +} + +type UpdateSysUserAvatarReq struct { + UserId int `json:"userId" comment:"用户ID" vd:"len($)>0"` // 用户ID + Avatar string `json:"avatar" comment:"头像" vd:"len($)>0"` + common.ControlBy +} + +func (s *UpdateSysUserAvatarReq) GetId() interface{} { + return s.UserId +} + +func (s *UpdateSysUserAvatarReq) Generate(model *models.SysUser) { + if s.UserId != 0 { + model.UserId = s.UserId + } + model.Avatar = s.Avatar +} + +type UpdateSysUserStatusReq struct { + UserId int `json:"userId" comment:"用户ID" vd:"$>0"` // 用户ID + Status string `json:"status" comment:"状态" vd:"len($)>0"` + common.ControlBy +} + +func (s *UpdateSysUserStatusReq) GetId() interface{} { + return s.UserId +} + +func (s *UpdateSysUserStatusReq) Generate(model *models.SysUser) { + if s.UserId != 0 { + model.UserId = s.UserId + } + model.Status = s.Status +} + +type SysUserInsertReq struct { + UserId int `json:"userId" comment:"用户ID"` // 用户ID + Username string `json:"username" comment:"用户名" vd:"len($)>0"` + Password string `json:"password" comment:"密码"` + NickName string `json:"nickName" comment:"昵称" vd:"len($)>0"` + Phone string `json:"phone" comment:"手机号" ` + RoleId int `json:"roleId" comment:"角色ID" vd:"$>0"` + Avatar string `json:"avatar" comment:"头像"` + Sex string `json:"sex" comment:"性别"` + Email string `json:"email" comment:"邮箱" ` //vd:"len($)>0,email" + DeptId int `json:"deptId" comment:"部门" vd:"$>0"` + PostId int `json:"postId" comment:"岗位"` + Remark string `json:"remark" comment:"备注"` + Status string `json:"status" comment:"状态" vd:"len($)>0" default:"1"` + common.ControlBy +} + +func (s *SysUserInsertReq) Generate(model *models.SysUser) { + if s.UserId != 0 { + model.UserId = s.UserId + } + model.Username = s.Username + model.Password = s.Password + model.NickName = s.NickName + model.Phone = s.Phone + model.RoleId = s.RoleId + model.Avatar = s.Avatar + model.Sex = s.Sex + model.Email = s.Email + model.DeptId = s.DeptId + model.PostId = s.PostId + model.Remark = s.Remark + model.Status = s.Status + model.CreateBy = s.CreateBy +} + +func (s *SysUserInsertReq) GetId() interface{} { + return s.UserId +} + +type SysUserUpdateReq struct { + UserId int `json:"userId" comment:"用户ID"` // 用户ID + Username string `json:"username" comment:"用户名" vd:"len($)>0"` + NickName string `json:"nickName" comment:"昵称" vd:"len($)>0"` + Phone string `json:"phone" comment:"手机号" vd:"len($)>0"` + RoleId int `json:"roleId" comment:"角色ID" vd:"$>0"` + Avatar string `json:"avatar" comment:"头像"` + Sex string `json:"sex" comment:"性别"` + Email string `json:"email" comment:"邮箱" vd:"len($)>0,email"` + DeptId int `json:"deptId" comment:"部门" vd:"$>0"` + PostId int `json:"postId" comment:"岗位"` + Remark string `json:"remark" comment:"备注"` + Status string `json:"status" comment:"状态" default:"1"` + common.ControlBy +} + +func (s *SysUserUpdateReq) Generate(model *models.SysUser) { + if s.UserId != 0 { + model.UserId = s.UserId + } + model.Username = s.Username + model.NickName = s.NickName + model.Phone = s.Phone + model.RoleId = s.RoleId + model.Avatar = s.Avatar + model.Sex = s.Sex + model.Email = s.Email + model.DeptId = s.DeptId + model.PostId = s.PostId + model.Remark = s.Remark + model.Status = s.Status +} + +func (s *SysUserUpdateReq) GetId() interface{} { + return s.UserId +} + +type SysUserById struct { + dto.ObjectById + common.ControlBy +} + +func (s *SysUserById) GetId() interface{} { + if len(s.Ids) > 0 { + s.Ids = append(s.Ids, s.Id) + return s.Ids + } + return s.Id +} + +func (s *SysUserById) GenerateM() (common.ActiveRecord, error) { + return &models.SysUser{}, nil +} + +// PassWord 密码 +type PassWord struct { + NewPassword string `json:"newPassword" vd:"len($)>0"` + OldPassword string `json:"oldPassword" vd:"len($)>0"` +} diff --git a/app/admin/service/dto/tm_member.go b/app/admin/service/dto/tm_member.go new file mode 100644 index 0000000..0504c38 --- /dev/null +++ b/app/admin/service/dto/tm_member.go @@ -0,0 +1,193 @@ +package dto + +import ( + "errors" + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" + "time" +) + +type TmMemberGetPageReq struct { + dto.Pagination `search:"-"` + NickName string `form:"nickName" search:"type:contains;column:nick_name;table:tm_member" comment:"用户昵称"` + Mobile string `form:"mobile" search:"type:contains;column:mobile;table:tm_member" comment:"手机号"` + Email string `form:"email" search:"type:contains;column:email;table:tm_member" comment:"邮箱号"` + Status string `form:"status" search:"type:exact;column:status;table:tm_member" comment:"状态 1-启用 2-禁用"` + TmMemberOrder +} + +type TmMemberOrder struct { + Id string `form:"idOrder" search:"type:order;column:id;table:tm_member"` + NickName string `form:"nickNameOrder" search:"type:order;column:nick_name;table:tm_member"` + AreaCode string `form:"areaCodeOrder" search:"type:order;column:area_code;table:tm_member"` + Mobile string `form:"mobileOrder" search:"type:order;column:mobile;table:tm_member"` + Email string `form:"emailOrder" search:"type:order;column:email;table:tm_member"` + Password string `form:"passwordOrder" search:"type:order;column:password;table:tm_member"` + Status string `form:"statusOrder" search:"type:order;column:status;table:tm_member"` + ApiKey string `form:"apiKeyOrder" search:"type:order;column:api_key;table:tm_member"` + CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:tm_member"` + UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:tm_member"` + DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:tm_member"` + CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:tm_member"` + UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:tm_member"` +} + +func (m *TmMemberGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type TmMemberInsertReq struct { + Id int `json:"-" comment:"主键Id"` // 主键Id + UserId int `json:"userId" comment:"用户ID"` + NickName string `json:"nickName" comment:"用户昵称"` + AreaCode string `json:"areaCode" comment:"区号"` + Mobile string `json:"mobile" comment:"手机号"` + Email string `json:"email" comment:"邮箱号"` + Password string `json:"password" comment:"密码"` + Status int `json:"status" comment:"状态 1-启用 2-禁用"` + ApiKey string `json:"apiKey" comment:"apiKey"` + common.ControlBy +} + +func (s *TmMemberInsertReq) Generate(model *models.TmMember) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.NickName = s.NickName + model.UserId = s.UserId + model.AreaCode = s.AreaCode + model.Mobile = s.Mobile + model.Email = s.Email + model.Password = s.Password + model.Status = s.Status + model.ApiKey = s.ApiKey + model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 +} + +func (s *TmMemberInsertReq) GetId() interface{} { + return s.Id +} + +type TmMemberUpdateReq struct { + Id int `uri:"id" comment:"主键Id"` // 主键Id + UserId int `json:"userId" comment:"用户ID"` + NickName string `json:"nickName" comment:"用户昵称"` + AreaCode string `json:"areaCode" comment:"区号"` + Mobile string `json:"mobile" comment:"手机号"` + Email string `json:"email" comment:"邮箱号"` + Password string `json:"password" comment:"密码"` + Status int `json:"status" comment:"状态 1-启用 2-禁用"` + ApiKey string `json:"apiKey" comment:"apiKey"` + common.ControlBy +} + +func (s *TmMemberUpdateReq) Generate(model *models.TmMember) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.UserId = s.UserId + model.NickName = s.NickName + model.AreaCode = s.AreaCode + model.Mobile = s.Mobile + model.Email = s.Email + model.Password = s.Password + model.Status = s.Status + model.ApiKey = s.ApiKey + model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 +} + +func (s *TmMemberUpdateReq) GetId() interface{} { + return s.Id +} + +// TmMemberGetReq 功能获取请求参数 +type TmMemberGetReq struct { + Id int `uri:"id"` +} + +func (s *TmMemberGetReq) GetId() interface{} { + return s.Id +} + +// TmMemberDeleteReq 功能删除请求参数 +type TmMemberDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *TmMemberDeleteReq) GetId() interface{} { + return s.Ids +} + +type TmMemberResp struct { + Id int `json:"id"` + UserId int `json:"userId"` + NickName string `json:"nickName"` + UserStatus int `json:"userStatus"` + Status int `json:"status"` + ApiKey string `json:"apiKey"` + TotalChars int `json:"totalChars"` + RemainChars int `json:"remainChars"` + CreatedAt time.Time `json:"createdAt"` + Platforms []TmMemberPlatformResp `json:"platforms"` +} + +type TmMemberPlatformResp struct { + Name string `json:"name"` + RemainChars int `json:"remainChars"` +} + +type TmMemberRechargeReq struct { + Id int `uri:"id" comment:"主键Id"` // 主键Id + PlatformId int `json:"platformId" comment:"平台ID"` + PlatformCode string `json:"platformCode" comment:"平台编码"` + TotalChars int `json:"totalChars" comment:"总字数(万)"` +} + +func (e *TmMemberRechargeReq) Validate() error { + if e.Id <= 0 { + return errors.New("id不能为空") + } + + if e.TotalChars <= 0 { + return errors.New("充值字符数不能小于等于0") + } + + return nil +} + +type TmMemberChangeStatusReq struct { + Id int `uri:"id" comment:"主键Id"` // 主键Id + Status int `json:"status" comment:"状态 1-启用 2-禁用"` +} + +func (e *TmMemberChangeStatusReq) Validate() error { + if e.Id <= 0 { + return errors.New("id不能为空") + } + + if e.Status < 1 || e.Status > 2 { + return errors.New("状态超出范围") + } + + return nil +} + +type TmMemberPlatformFrontedResp struct { + Id int `json:"id"` + Name string `json:"name"` + RemainChars int `json:"remainChars"` + TotalChars int `json:"totalChars"` + Price int `json:"price"` + ApiKey string `json:"apiKey"` +} + +type TmMemberSyncInsertReq struct { + UserId int `json:"userId" comment:"用户ID"` + NickName string `json:"nickName" comment:"用户昵称"` + PlatformId int `json:"platformId" comment:"平台ID"` + PlatformKey string `json:"platformKey" comment:"平台Key"` + Mobile string `json:"mobile" comment:"手机号"` + Email string `json:"email" comment:"邮箱号"` + CreateBy int `json:"createBy" comment:"创建者"` +} diff --git a/app/admin/service/dto/tm_member_daily_usage.go b/app/admin/service/dto/tm_member_daily_usage.go new file mode 100644 index 0000000..49d8dbd --- /dev/null +++ b/app/admin/service/dto/tm_member_daily_usage.go @@ -0,0 +1,101 @@ +package dto + +import ( + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" + "time" +) + +type TmMemberDailyUsageGetPageReq struct { + dto.Pagination `search:"-"` + TmMemberDailyUsageOrder +} + +type TmMemberDailyUsageOrder struct { + Id string `form:"idOrder" search:"type:order;column:id;table:tm_member_daily_usage"` + MemberId string `form:"memberIdOrder" search:"type:order;column:member_id;table:tm_member_daily_usage"` + PlatformId string `form:"platformIdOrder" search:"type:order;column:platform_id;table:tm_member_daily_usage"` + UseChars string `form:"useCharsOrder" search:"type:order;column:use_chars;table:tm_member_daily_usage"` + RemainChars string `form:"remainCharsOrder" search:"type:order;column:remain_chars;table:tm_member_daily_usage"` + Date string `form:"dateOrder" search:"type:order;column:date;table:tm_member_daily_usage"` + CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:tm_member_daily_usage"` + UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:tm_member_daily_usage"` + DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:tm_member_daily_usage"` + CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:tm_member_daily_usage"` + UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:tm_member_daily_usage"` +} + +func (m *TmMemberDailyUsageGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type TmMemberDailyUsageInsertReq struct { + Id int `json:"-" comment:"主键"` // 主键 + MemberId int `json:"memberId" comment:"用户id"` + PlatformId int `json:"platformId" comment:"平台id"` + UseChars int `json:"useChars" comment:"使用字符数"` + RemainChars int `json:"remainChars" comment:"剩余字符数"` + Date time.Time `json:"date" comment:"日期"` + common.ControlBy +} + +func (s *TmMemberDailyUsageInsertReq) Generate(model *models.TmMemberDailyUsage) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.MemberId = s.MemberId + model.PlatformId = s.PlatformId + model.UseChars = s.UseChars + model.RemainChars = s.RemainChars + model.Date = s.Date + model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 +} + +func (s *TmMemberDailyUsageInsertReq) GetId() interface{} { + return s.Id +} + +type TmMemberDailyUsageUpdateReq struct { + Id int `uri:"id" comment:"主键"` // 主键 + MemberId int `json:"memberId" comment:"用户id"` + PlatformId int `json:"platformId" comment:"平台id"` + UseChars int `json:"useChars" comment:"使用字符数"` + RemainChars int `json:"remainChars" comment:"剩余字符数"` + Date time.Time `json:"date" comment:"日期"` + common.ControlBy +} + +func (s *TmMemberDailyUsageUpdateReq) Generate(model *models.TmMemberDailyUsage) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.MemberId = s.MemberId + model.PlatformId = s.PlatformId + model.UseChars = s.UseChars + model.RemainChars = s.RemainChars + model.Date = s.Date + model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 +} + +func (s *TmMemberDailyUsageUpdateReq) GetId() interface{} { + return s.Id +} + +// TmMemberDailyUsageGetReq 功能获取请求参数 +type TmMemberDailyUsageGetReq struct { + Id int `uri:"id"` +} + +func (s *TmMemberDailyUsageGetReq) GetId() interface{} { + return s.Id +} + +// TmMemberDailyUsageDeleteReq 功能删除请求参数 +type TmMemberDailyUsageDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *TmMemberDailyUsageDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/tm_member_platform.go b/app/admin/service/dto/tm_member_platform.go new file mode 100644 index 0000000..a51afe7 --- /dev/null +++ b/app/admin/service/dto/tm_member_platform.go @@ -0,0 +1,111 @@ +package dto + +import ( + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" +) + +type TmMemberPlatformGetPageReq struct { + dto.Pagination `search:"-"` + TmMemberPlatformOrder +} + +type TmMemberPlatformOrder struct { + Id string `form:"idOrder" search:"type:order;column:id;table:tm_member_platform"` + MemberId string `form:"memberIdOrder" search:"type:order;column:member_id;table:tm_member_platform"` + RemainingCharacter string `form:"remainingCharacterOrder" search:"type:order;column:remaining_character;table:tm_member_platform"` + TotalCharacter string `form:"totalCharacterOrder" search:"type:order;column:total_character;table:tm_member_platform"` + PlatformId string `form:"platformIdOrder" search:"type:order;column:platform_id;table:tm_member_platform"` + Status string `form:"statusOrder" search:"type:order;column:status;table:tm_member_platform"` + CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:tm_member_platform"` + UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:tm_member_platform"` + DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:tm_member_platform"` + CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:tm_member_platform"` + UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:tm_member_platform"` +} + +func (m *TmMemberPlatformGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type TmMemberPlatformInsertReq struct { + Id int `json:"-" comment:"主键id"` // 主键id + MemberId int `json:"memberId" comment:"用户id"` + RemainingCharacter int `json:"remainingCharacter" comment:"剩余字符数"` + TotalCharacter int `json:"totalCharacter" comment:"总字符数"` + PlatformId int `json:"platformId" comment:"平台id"` + Status int `json:"status" comment:"状态 1-启用 2-禁用"` + common.ControlBy +} + +func (s *TmMemberPlatformInsertReq) Generate(model *models.TmMemberPlatform) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.MemberId = s.MemberId + model.RemainingCharacter = s.RemainingCharacter + model.TotalCharacter = s.TotalCharacter + model.PlatformId = s.PlatformId + model.Status = s.Status + model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 +} + +func (s *TmMemberPlatformInsertReq) GetId() interface{} { + return s.Id +} + +type TmMemberPlatformUpdateReq struct { + Id int `uri:"id" comment:"主键id"` // 主键id + MemberId int `json:"memberId" comment:"用户id"` + RemainingCharacter int `json:"remainingCharacter" comment:"剩余字符数"` + TotalCharacter int `json:"totalCharacter" comment:"总字符数"` + PlatformId int `json:"platformId" comment:"平台id"` + Status int `json:"status" comment:"状态 1-启用 2-禁用"` + common.ControlBy +} + +func (s *TmMemberPlatformUpdateReq) Generate(model *models.TmMemberPlatform) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.MemberId = s.MemberId + model.RemainingCharacter = s.RemainingCharacter + model.TotalCharacter = s.TotalCharacter + model.PlatformId = s.PlatformId + model.Status = s.Status + model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 +} + +func (s *TmMemberPlatformUpdateReq) GetId() interface{} { + return s.Id +} + +// TmMemberPlatformGetReq 功能获取请求参数 +type TmMemberPlatformGetReq struct { + Id int `uri:"id"` +} + +func (s *TmMemberPlatformGetReq) GetId() interface{} { + return s.Id +} + +// TmMemberPlatformDeleteReq 功能删除请求参数 +type TmMemberPlatformDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *TmMemberPlatformDeleteReq) GetId() interface{} { + return s.Ids +} + +type TmMemberPlatformStatisticResp struct { + XAxis []string `json:"xAxis"` + Data []TmMemberPlatformStatisticItemResp `json:"data"` +} + +type TmMemberPlatformStatisticItemResp struct { + PlatformName string `json:"platformName"` + PlatformId int `json:"platformId"` + Data []int `json:"data" comment:"数据"` +} diff --git a/app/admin/service/dto/tm_platform.go b/app/admin/service/dto/tm_platform.go new file mode 100644 index 0000000..fb40885 --- /dev/null +++ b/app/admin/service/dto/tm_platform.go @@ -0,0 +1,125 @@ +package dto + +import ( + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" + + "github.com/shopspring/decimal" +) + +type TmPlatformGetPageReq struct { + dto.Pagination `search:"-"` + Name string `form:"name" search:"type:contains;column:name;table:tm_platform" comment:"平台名称"` + ShowName string `form:"showName" search:"type:contains;column:show_name;table:tm_platform" comment:"展示名称"` + ApiBaseUrl string `form:"apiBaseUrl" search:"type:exact;column:api_base_url;table:tm_platform" comment:"平台接口地址"` + Code string `form:"code" search:"type:exact;column:code;table:tm_platform" comment:"平台编码(字典 tm_platform)"` + Character string `form:"character" search:"type:exact;column:character;table:tm_platform" comment:"字符数"` + Price string `form:"price" search:"type:exact;column:price;table:tm_platform" comment:"单价"` + TmPlatformOrder +} + +type TmPlatformOrder struct { + Id string `form:"idOrder" search:"type:order;column:id;table:tm_platform"` + Name string `form:"nameOrder" search:"type:order;column:name;table:tm_platform"` + ShowName string `form:"showNameOrder" search:"type:order;column:show_name;table:tm_platform"` + ApiBaseUrl string `form:"apiBaseUrlOrder" search:"type:order;column:api_base_url;table:tm_platform"` + Description string `form:"descriptionOrder" search:"type:order;column:description;table:tm_platform"` + Code string `form:"codeOrder" search:"type:order;column:code;table:tm_platform"` + Character string `form:"characterOrder" search:"type:order;column:character;table:tm_platform"` + Price string `form:"priceOrder" search:"type:order;column:price;table:tm_platform"` + CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:tm_platform"` + UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:tm_platform"` + DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:tm_platform"` + CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:tm_platform"` + UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:tm_platform"` +} + +func (m *TmPlatformGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type TmPlatformInsertReq struct { + Id int `json:"-" comment:"平台id"` // 平台id + Name string `json:"name" comment:"平台名称"` + ShowName string `json:"showName" comment:"展示名称"` + ApiBaseUrl string `json:"apiBaseUrl" comment:"平台接口地址"` + Description string `json:"description" comment:"描述"` + Code string `json:"code" comment:"平台编码(字典 tm_platform)"` + Character string `json:"character" comment:"字符数"` + Price decimal.Decimal `json:"price" comment:"单价"` + common.ControlBy +} + +func (s *TmPlatformInsertReq) Generate(model *models.TmPlatform) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.Name = s.Name + model.ShowName = s.ShowName + model.ApiBaseUrl = s.ApiBaseUrl + model.Description = s.Description + model.Code = s.Code + model.Character = s.Character + model.Price = s.Price + model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 +} + +func (s *TmPlatformInsertReq) GetId() interface{} { + return s.Id +} + +type TmPlatformListResp struct { + Id int `json:"id"` + ShowName string `json:"showName"` + Code string `json:"code"` + Price decimal.Decimal `json:"price"` +} + +type TmPlatformUpdateReq struct { + Id int `uri:"id" comment:"平台id"` // 平台id + Name string `json:"name" comment:"平台名称"` + ShowName string `json:"showName" comment:"展示名称"` + ApiBaseUrl string `json:"apiBaseUrl" comment:"平台接口地址"` + Description string `json:"description" comment:"描述"` + Code string `json:"code" comment:"平台编码(字典 tm_platform)"` + Character string `json:"character" comment:"字符数"` + Price decimal.Decimal `json:"price" comment:"单价"` + common.ControlBy +} + +func (s *TmPlatformUpdateReq) Generate(model *models.TmPlatform) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.Name = s.Name + model.ShowName = s.ShowName + model.ApiBaseUrl = s.ApiBaseUrl + model.Description = s.Description + model.Code = s.Code + model.Character = s.Character + model.Price = s.Price + model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 +} + +func (s *TmPlatformUpdateReq) GetId() interface{} { + return s.Id +} + +// TmPlatformGetReq 功能获取请求参数 +type TmPlatformGetReq struct { + Id int `uri:"id"` +} + +func (s *TmPlatformGetReq) GetId() interface{} { + return s.Id +} + +// TmPlatformDeleteReq 功能删除请求参数 +type TmPlatformDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *TmPlatformDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/tm_platform_account.go b/app/admin/service/dto/tm_platform_account.go new file mode 100644 index 0000000..a131860 --- /dev/null +++ b/app/admin/service/dto/tm_platform_account.go @@ -0,0 +1,97 @@ +package dto + +import ( + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" +) + +type TmPlatformAccountGetPageReq struct { + dto.Pagination `search:"-"` + PlatformId string `form:"platformId" search:"type:exact;column:platform_id;table:tm_platform_account" comment:"平台主键"` + TmPlatformAccountOrder +} + +type TmPlatformAccountOrder struct { + Id string `form:"idOrder" search:"type:order;column:id;table:tm_platform_account"` + PlatformId string `form:"platformIdOrder" search:"type:order;column:platform_id;table:tm_platform_account"` + ApiKey string `form:"apiKeyOrder" search:"type:order;column:api_key;table:tm_platform_account"` + ApiSecret string `form:"apiSecretOrder" search:"type:order;column:api_secret;table:tm_platform_account"` + QpsLimit string `form:"qpsLimitOrder" search:"type:order;column:qps_limit;table:tm_platform_account"` + CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:tm_platform_account"` + UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:tm_platform_account"` + DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:tm_platform_account"` + CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:tm_platform_account"` + UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:tm_platform_account"` +} + +func (m *TmPlatformAccountGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type TmPlatformAccountInsertReq struct { + Id int `json:"-" comment:"主键id"` // 主键id + PlatformId int `json:"platformId" comment:"平台主键"` + ApiKey string `json:"apiKey" comment:"api_key"` + ApiSecret string `json:"apiSecret" comment:"api密钥"` + QpsLimit int `json:"qpsLimit" comment:"qps限制"` + common.ControlBy +} + +func (s *TmPlatformAccountInsertReq) Generate(model *models.TmPlatformAccount) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.PlatformId = s.PlatformId + model.ApiKey = s.ApiKey + model.ApiSecret = s.ApiSecret + model.QpsLimit = s.QpsLimit + model.Status = 1 + model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 +} + +func (s *TmPlatformAccountInsertReq) GetId() interface{} { + return s.Id +} + +type TmPlatformAccountUpdateReq struct { + Id int `uri:"id" comment:"主键id"` // 主键id + PlatformId int `json:"platformId" comment:"平台主键"` + ApiKey string `json:"apiKey" comment:"api_key"` + ApiSecret string `json:"apiSecret" comment:"api密钥"` + QpsLimit int `json:"qpsLimit" comment:"qps限制"` + common.ControlBy +} + +func (s *TmPlatformAccountUpdateReq) Generate(model *models.TmPlatformAccount) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.PlatformId = s.PlatformId + model.ApiKey = s.ApiKey + model.ApiSecret = s.ApiSecret + model.QpsLimit = s.QpsLimit + model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 +} + +func (s *TmPlatformAccountUpdateReq) GetId() interface{} { + return s.Id +} + +// TmPlatformAccountGetReq 功能获取请求参数 +type TmPlatformAccountGetReq struct { + Id int `uri:"id"` +} + +func (s *TmPlatformAccountGetReq) GetId() interface{} { + return s.Id +} + +// TmPlatformAccountDeleteReq 功能删除请求参数 +type TmPlatformAccountDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *TmPlatformAccountDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/translate.go b/app/admin/service/dto/translate.go new file mode 100644 index 0000000..a139a36 --- /dev/null +++ b/app/admin/service/dto/translate.go @@ -0,0 +1,68 @@ +package dto + +import "go-admin/common/statuscode" + +// TranslateResult 翻译结果 +type TranslateResult struct { + TranslatedText string `json:"translatedText" comment:"翻译后的文本"` + SourceLanguage string `json:"sourceLanguage" comment:"源语言"` + TargetLanguage string `json:"targetLanguage" comment:"目标语言"` +} + +type DeepseekTranslateRequest struct { + Model string `json:"model"` + Messages []Message `json:"messages"` + Stream bool `json:"stream"` +} + +type Message struct { + Role string `json:"role"` + Content string `json:"content"` +} + +type DeepSeekResponse struct { + Choices []struct { + Message Message `json:"message"` + } `json:"choices"` +} + +//翻译请求 +type TranslateReq struct { + Text string `json:"text"` + SourceLang string `json:"sourceLang"` + TargetLang string `json:"targetLang"` + Platform string `json:"platform"` +} + +func (e *TranslateReq) Validate() int { + if e.Text == "" { + return statuscode.InvalidParams + } + + if e.Platform == "" { + return statuscode.InvalidParams + } + + if e.TargetLang == "" { + return statuscode.InvalidParams + } + + if e.SourceLang == "" { + e.SourceLang = "auto" + } + + return statuscode.Success +} + +type TranslateStatisticReq struct { +} + +type TranslateStatisticResp struct { + TotalCount int `json:"y" comment:"总字符数"` + Date string `json:"x" comment:"日期"` +} + +type TranslateUserInfoResp struct { + UserApiKey string `json:"userApiKey" comment:"用户API Key"` + RemainChars int `json:"remainChars" comment:"剩余可翻译字符数"` +} diff --git a/app/admin/service/sys_api.go b/app/admin/service/sys_api.go new file mode 100644 index 0000000..cb4d895 --- /dev/null +++ b/app/admin/service/sys_api.go @@ -0,0 +1,123 @@ +package service + +import ( + "errors" + "fmt" + + "github.com/go-admin-team/go-admin-core/sdk/runtime" + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" + "go-admin/common/global" +) + +type SysApi struct { + service.Service +} + +// GetPage 获取SysApi列表 +func (e *SysApi) GetPage(c *dto.SysApiGetPageReq, p *actions.DataPermission, list *[]models.SysApi, count *int64) error { + var err error + var data models.SysApi + + orm := e.Orm.Debug().Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ) + if c.Type != "" { + qType := c.Type + if qType == "暂无" { + qType = "" + } + if global.Driver == "postgres" { + orm = orm.Where("type = ?", qType) + } else { + orm = orm.Where("`type` = ?", qType) + } + + } + err = orm.Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("Service GetSysApiPage error:%s", err) + return err + } + return nil +} + +// Get 获取SysApi对象with id +func (e *SysApi) Get(d *dto.SysApiGetReq, p *actions.DataPermission, model *models.SysApi) *SysApi { + var data models.SysApi + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetSysApi error:%s", err) + _ = e.AddError(err) + return e + } + if err != nil { + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + return e + } + return e +} + +// Update 修改SysApi对象 +func (e *SysApi) Update(c *dto.SysApiUpdateReq, p *actions.DataPermission) error { + var model = models.SysApi{} + db := e.Orm.Debug().First(&model, c.GetId()) + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + c.Generate(&model) + db = e.Orm.Save(&model) + if err := db.Error; err != nil { + e.Log.Errorf("Service UpdateSysApi error:%s", err) + return err + } + + return nil +} + +// Remove 删除SysApi +func (e *SysApi) Remove(d *dto.SysApiDeleteReq, p *actions.DataPermission) error { + var data models.SysApi + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveSysApi error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} + +// CheckStorageSysApi 创建SysApi对象 +func (e *SysApi) CheckStorageSysApi(c *[]runtime.Router) error { + for _, v := range *c { + err := e.Orm.Debug().Where(models.SysApi{Path: v.RelativePath, Action: v.HttpMethod}). + Attrs(models.SysApi{Handle: v.Handler}). + FirstOrCreate(&models.SysApi{}).Error + if err != nil { + err := fmt.Errorf("Service CheckStorageSysApi error: %s \r\n ", err.Error()) + return err + } + } + return nil +} diff --git a/app/admin/service/sys_config.go b/app/admin/service/sys_config.go new file mode 100644 index 0000000..341e8f2 --- /dev/null +++ b/app/admin/service/sys_config.go @@ -0,0 +1,251 @@ +package service + +import ( + "errors" + "fmt" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" + rediskey "go-admin/common/redis_key" + "go-admin/utils/redishelper" + + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" +) + +type SysConfig struct { + service.Service +} + +// GetPage 获取SysConfig列表 +func (e *SysConfig) GetPage(c *dto.SysConfigGetPageReq, list *[]models.SysConfig, count *int64) error { + err := e.Orm. + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("Service GetSysConfigPage error:%s", err) + return err + } + return nil +} + +// Get 获取SysConfig对象 +func (e *SysConfig) Get(d *dto.SysConfigGetReq, model *models.SysConfig) error { + err := e.Orm.First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetSysConfigPage error:%s", err) + return err + } + if err != nil { + e.Log.Errorf("Service GetSysConfig error:%s", err) + return err + } + return nil +} + +// Insert 创建SysConfig对象 +func (e *SysConfig) Insert(c *dto.SysConfigControl) error { + var err error + var data models.SysConfig + c.Generate(&data) + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("Service InsertSysConfig error:%s", err) + return err + } + + e.saveCache(data) + return nil +} + +// Update 修改SysConfig对象 +func (e *SysConfig) Update(c *dto.SysConfigControl) error { + var err error + var model = models.SysConfig{} + e.Orm.First(&model, c.GetId()) + c.Generate(&model) + db := e.Orm.Save(&model) + err = db.Error + if err != nil { + e.Log.Errorf("Service UpdateSysConfig error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + + } + + e.saveCache(model) + return nil +} + +// SetSysConfig 修改SysConfig对象 +func (e *SysConfig) SetSysConfig(c *[]dto.GetSetSysConfigReq) error { + var err error + for _, req := range *c { + var model = models.SysConfig{} + e.Orm.Where("config_key = ?", req.ConfigKey).First(&model) + if model.Id != 0 { + req.Generate(&model) + db := e.Orm.Save(&model) + err = db.Error + if err != nil { + e.Log.Errorf("Service SetSysConfig error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + + e.saveCache(model) + } + } + return nil +} + +func (e *SysConfig) GetForSet(c *[]dto.GetSetSysConfigReq) error { + var err error + var data models.SysConfig + + err = e.Orm.Model(&data). + Find(c).Error + if err != nil { + e.Log.Errorf("Service GetSysConfigPage error:%s", err) + return err + } + return nil +} + +func (e *SysConfig) UpdateForSet(c *[]dto.GetSetSysConfigReq) error { + m := *c + for _, req := range m { + var data models.SysConfig + if err := e.Orm.Where("config_key = ?", req.ConfigKey). + First(&data).Error; err != nil { + e.Log.Errorf("Service GetSysConfigPage error:%s", err) + return err + } + if data.ConfigValue != req.ConfigValue { + data.ConfigValue = req.ConfigValue + + if err := e.Orm.Save(&data).Error; err != nil { + e.Log.Errorf("Service GetSysConfigPage error:%s", err) + return err + } + + e.saveCache(data) + } + + } + + return nil +} + +// 更新缓存 +// 新数据 +func (e *SysConfig) saveCache(entity models.SysConfig) error { + key := fmt.Sprintf(rediskey.SYS_CONFIG_KEY, entity.ConfigKey) + val, err := sonic.MarshalString(entity) + + if err != nil || val == "" { + return errors.New("更新配置缓存 缓存序列化失败") + } + + redishelper.DefaultRedis.SetString(key, string(val)) + + return nil +} + +// Remove 删除SysConfig +func (e *SysConfig) Remove(d *dto.SysConfigDeleteReq) error { + var err error + var data models.SysConfig + + db := e.Orm.Delete(&data, d.Ids) + if err = db.Error; err != nil { + err = db.Error + e.Log.Errorf("Service RemoveSysConfig error:%s", err) + return err + } + if db.RowsAffected == 0 { + err = errors.New("无权删除该数据") + return err + } + + key := fmt.Sprintf(rediskey.SYS_CONFIG_KEY, data.ConfigKey) + redishelper.DefaultRedis.DeleteString(key) + return nil +} + +// GetWithKey 根据Key获取SysConfig +func (e *SysConfig) GetWithKey(c *dto.SysConfigByKeyReq, resp *dto.GetSysConfigByKEYForServiceResp) error { + var err error + var data models.SysConfig + key := fmt.Sprintf(rediskey.SYS_CONFIG_KEY, c.ConfigKey) + val, _ := redishelper.DefaultRedis.GetString(key) + + if val != "" { + err = sonic.UnmarshalString(val, &data) + if err != nil { + e.Log.Errorf("At Service GetSysConfigByKEY Error:%s", err) + return err + } + + } + + if data.Id == 0 { + err = e.Orm.Table(data.TableName()).Where("config_key = ?", c.ConfigKey).First(resp).Error + if err != nil { + e.Log.Errorf("At Service GetSysConfigByKEY Error:%s", err) + return err + } + } + + resp.ConfigKey = data.ConfigKey + resp.ConfigValue = data.ConfigValue + + return nil +} + +func (e *SysConfig) GetWithKeyList(c *dto.SysConfigGetToSysAppReq, list *[]models.SysConfig) error { + var err error + err = e.Orm. + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + ). + Find(list).Error + if err != nil { + e.Log.Errorf("Service GetSysConfigByKey error:%s", err) + return err + } + return nil +} + +// 初始化配置缓存 +func (e *SysConfig) InitCache() error { + var list []models.SysConfig + + if err := e.Orm.Find(&list).Error; err != nil { + return err + } + + for _, entity := range list { + key := fmt.Sprintf(rediskey.SYS_CONFIG_KEY, entity.ConfigKey) + val, err := sonic.MarshalString(entity) + + if err != nil || val == "" { + return errors.New("初始化配置缓存 缓存序列化失败") + } + + redishelper.DefaultRedis.SetString(key, string(val)) + } + + return nil +} diff --git a/app/admin/service/sys_dept.go b/app/admin/service/sys_dept.go new file mode 100644 index 0000000..fd43d5c --- /dev/null +++ b/app/admin/service/sys_dept.go @@ -0,0 +1,295 @@ +package service + +import ( + "errors" + "go-admin/app/admin/models" + + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + + "gorm.io/gorm" + + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" + + "github.com/go-admin-team/go-admin-core/sdk/service" +) + +type SysDept struct { + service.Service +} + +// GetPage 获取SysDept列表 +//func (e *SysDept) GetPage(c *dto.SysDeptGetPageReq, list *[]models.SysDept) error { +// var err error +// var data models.SysDept +// +// err = e.Orm.Model(&data). +// Scopes( +// cDto.MakeCondition(c.GetNeedSearch()), +// ). +// Find(list).Error +// if err != nil { +// e.Log.Errorf("db error:%s", err) +// return err +// } +// return nil +//} + +// Get 获取SysDept对象 +func (e *SysDept) Get(d *dto.SysDeptGetReq, model *models.SysDept) error { + var err error + var data models.SysDept + + db := e.Orm.Model(&data). + First(model, d.GetId()) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error:%s", err) + return err + } + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建SysDept对象 +func (e *SysDept) Insert(c *dto.SysDeptInsertReq) error { + var err error + var data models.SysDept + c.Generate(&data) + tx := e.Orm.Debug().Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + err = tx.Create(&data).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + deptPath := pkg.IntToString(data.DeptId) + "/" + if data.ParentId != 0 { + var deptP models.SysDept + tx.First(&deptP, data.ParentId) + deptPath = deptP.DeptPath + deptPath + } else { + deptPath = "/0/" + deptPath + } + var mp = map[string]string{} + mp["dept_path"] = deptPath + if err := tx.Model(&data).Update("dept_path", deptPath).Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Update 修改SysDept对象 +func (e *SysDept) Update(c *dto.SysDeptUpdateReq) error { + var err error + var model = models.SysDept{} + tx := e.Orm.Debug().Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + tx.First(&model, c.GetId()) + c.Generate(&model) + + deptPath := pkg.IntToString(model.DeptId) + "/" + if model.ParentId != 0 { + var deptP models.SysDept + tx.First(&deptP, model.ParentId) + deptPath = deptP.DeptPath + deptPath + } else { + deptPath = "/0/" + deptPath + } + model.DeptPath = deptPath + db := tx.Save(&model) + if err = db.Error; err != nil { + e.Log.Errorf("UpdateSysDept error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// Remove 删除SysDept +func (e *SysDept) Remove(d *dto.SysDeptDeleteReq) error { + var err error + var data models.SysDept + + db := e.Orm.Model(&data).Delete(&data, d.GetId()) + if err = db.Error; err != nil { + err = db.Error + e.Log.Errorf("Delete error: %s", err) + return err + } + if db.RowsAffected == 0 { + err = errors.New("无权删除该数据") + return err + } + return nil +} + +// GetSysDeptList 获取组织数据 +func (e *SysDept) getList(c *dto.SysDeptGetPageReq, list *[]models.SysDept) error { + var err error + var data models.SysDept + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + ). + Find(list).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// SetDeptTree 设置组织数据 +func (e *SysDept) SetDeptTree(c *dto.SysDeptGetPageReq) (m []dto.DeptLabel, err error) { + var list []models.SysDept + err = e.getList(c, &list) + + m = make([]dto.DeptLabel, 0) + for i := 0; i < len(list); i++ { + if list[i].ParentId != 0 { + continue + } + e := dto.DeptLabel{} + e.Id = list[i].DeptId + e.Label = list[i].DeptName + deptsInfo := deptTreeCall(&list, e) + + m = append(m, deptsInfo) + } + return +} + +// Call 递归构造组织数据 +func deptTreeCall(deptList *[]models.SysDept, dept dto.DeptLabel) dto.DeptLabel { + list := *deptList + min := make([]dto.DeptLabel, 0) + for j := 0; j < len(list); j++ { + if dept.Id != list[j].ParentId { + continue + } + mi := dto.DeptLabel{Id: list[j].DeptId, Label: list[j].DeptName, Children: []dto.DeptLabel{}} + ms := deptTreeCall(deptList, mi) + min = append(min, ms) + } + dept.Children = min + return dept +} + +// SetDeptPage 设置dept页面数据 +func (e *SysDept) SetDeptPage(c *dto.SysDeptGetPageReq) (m []models.SysDept, err error) { + var list []models.SysDept + err = e.getList(c, &list) + for i := 0; i < len(list); i++ { + if list[i].ParentId != 0 { + continue + } + info := e.deptPageCall(&list, list[i]) + m = append(m, info) + } + return +} + +func (e *SysDept) deptPageCall(deptlist *[]models.SysDept, menu models.SysDept) models.SysDept { + list := *deptlist + min := make([]models.SysDept, 0) + for j := 0; j < len(list); j++ { + if menu.DeptId != list[j].ParentId { + continue + } + mi := models.SysDept{} + mi.DeptId = list[j].DeptId + mi.ParentId = list[j].ParentId + mi.DeptPath = list[j].DeptPath + mi.DeptName = list[j].DeptName + mi.Sort = list[j].Sort + mi.Leader = list[j].Leader + mi.Phone = list[j].Phone + mi.Email = list[j].Email + mi.Status = list[j].Status + mi.CreatedAt = list[j].CreatedAt + mi.Children = []models.SysDept{} + ms := e.deptPageCall(deptlist, mi) + min = append(min, ms) + } + menu.Children = min + return menu +} + +// GetWithRoleId 获取角色的部门ID集合 +func (e *SysDept) GetWithRoleId(roleId int) ([]int, error) { + deptIds := make([]int, 0) + deptList := make([]dto.DeptIdList, 0) + if err := e.Orm.Table("sys_role_dept"). + Select("sys_role_dept.dept_id"). + Joins("LEFT JOIN sys_dept on sys_dept.dept_id=sys_role_dept.dept_id"). + Where("role_id = ? ", roleId). + Where(" sys_role_dept.dept_id not in(select sys_dept.parent_id from sys_role_dept LEFT JOIN sys_dept on sys_dept.dept_id=sys_role_dept.dept_id where role_id =? )", roleId). + Find(&deptList).Error; err != nil { + return nil, err + } + for i := 0; i < len(deptList); i++ { + deptIds = append(deptIds, deptList[i].DeptId) + } + return deptIds, nil +} + +func (e *SysDept) SetDeptLabel() (m []dto.DeptLabel, err error) { + list := make([]models.SysDept, 0) + err = e.Orm.Find(&list).Error + if err != nil { + log.Error("find dept list error, %s", err.Error()) + return + } + m = make([]dto.DeptLabel, 0) + var item dto.DeptLabel + for i := range list { + if list[i].ParentId != 0 { + continue + } + item = dto.DeptLabel{} + item.Id = list[i].DeptId + item.Label = list[i].DeptName + deptInfo := deptLabelCall(&list, item) + m = append(m, deptInfo) + } + return +} + +// deptLabelCall +func deptLabelCall(deptList *[]models.SysDept, dept dto.DeptLabel) dto.DeptLabel { + list := *deptList + var mi dto.DeptLabel + min := make([]dto.DeptLabel, 0) + for j := 0; j < len(list); j++ { + if dept.Id != list[j].ParentId { + continue + } + mi = dto.DeptLabel{Id: list[j].DeptId, Label: list[j].DeptName, Children: []dto.DeptLabel{}} + ms := deptLabelCall(deptList, mi) + min = append(min, ms) + } + dept.Children = min + return dept +} diff --git a/app/admin/service/sys_dict_data.go b/app/admin/service/sys_dict_data.go new file mode 100644 index 0000000..0f76012 --- /dev/null +++ b/app/admin/service/sys_dict_data.go @@ -0,0 +1,139 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" +) + +type SysDictData struct { + service.Service +} + +// GetPage 获取列表 +func (e *SysDictData) GetPage(c *dto.SysDictDataGetPageReq, list *[]models.SysDictData, count *int64) error { + var err error + var data models.SysDictData + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} + +// Get 获取对象 +func (e *SysDictData) Get(d *dto.SysDictDataGetReq, model *models.SysDictData) error { + var err error + var data models.SysDictData + + db := e.Orm.Model(&data). + First(model, d.GetId()) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error: %s", err) + return err + } + if err = db.Error; err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} + +// Insert 创建对象 +func (e *SysDictData) Insert(c *dto.SysDictDataInsertReq) error { + var err error + var data = new(models.SysDictData) + c.Generate(data) + err = e.Orm.Create(data).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + + e.saveCache(data) + + return nil +} + +func (e *SysDictData) saveCache(data *models.SysDictData) { + var dictType models.SysDictType + e.Orm.Model(dictType).Where("dict_type = ?", data.DictType).Find(&dictType) + + if dictType.ID > 0 { + dictService := SysDictType{Service: e.Service} + dictService.SaveDataCache(&dictType) + } +} + +// Update 修改对象 +func (e *SysDictData) Update(c *dto.SysDictDataUpdateReq) error { + var err error + var model = models.SysDictData{} + e.Orm.First(&model, c.GetId()) + c.Generate(&model) + db := e.Orm.Save(model) + if err = db.Error; err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + + } + + e.saveCache(&model) + + return nil +} + +// Remove 删除 +func (e *SysDictData) Remove(c *dto.SysDictDataDeleteReq) error { + var err error + var data models.SysDictData + + db := e.Orm.Delete(&data, c.GetId()) + if err = db.Error; err != nil { + err = db.Error + e.Log.Errorf("Delete error: %s", err) + return err + } + if db.RowsAffected == 0 { + err = errors.New("无权删除该数据") + return err + } + + e.saveCache(&data) + return nil +} + +// GetAll 获取所有 +func (e *SysDictData) GetAll(c *dto.SysDictDataGetPageReq, list *[]models.SysDictData) error { + var err error + var data models.SysDictData + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + ). + Find(list).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} diff --git a/app/admin/service/sys_dict_type.go b/app/admin/service/sys_dict_type.go new file mode 100644 index 0000000..1571911 --- /dev/null +++ b/app/admin/service/sys_dict_type.go @@ -0,0 +1,216 @@ +package service + +import ( + "errors" + "fmt" + + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/sdk/service" + "github.com/jinzhu/copier" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" + rediskey "go-admin/common/redis_key" + "go-admin/utils/redishelper" +) + +type SysDictType struct { + service.Service +} + +// GetPage 获取列表 +func (e *SysDictType) GetPage(c *dto.SysDictTypeGetPageReq, list *[]models.SysDictType, count *int64) error { + var err error + var data models.SysDictType + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} + +// Get 获取对象 +func (e *SysDictType) Get(d *dto.SysDictTypeGetReq, model *models.SysDictType) error { + var err error + + db := e.Orm.First(model, d.GetId()) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error: %s", err) + return err + } + if err = db.Error; err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} + +// Insert 创建对象 +func (e *SysDictType) Insert(c *dto.SysDictTypeInsertReq) error { + var err error + var data models.SysDictType + c.Generate(&data) + var count int64 + e.Orm.Model(&data).Where("dict_type = ?", data.DictType).Count(&count) + if count > 0 { + return errors.New(fmt.Sprintf("当前字典类型[%s]已经存在!", data.DictType)) + } + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + + e.saveCache(&data) + return nil +} + +// Update 修改对象 +func (e *SysDictType) Update(c *dto.SysDictTypeUpdateReq) error { + var err error + var model = models.SysDictType{} + e.Orm.First(&model, c.GetId()) + c.Generate(&model) + db := e.Orm.Save(&model) + if err = db.Error; err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + + } + + e.saveCache(&model) + return nil +} + +func (e *SysDictType) saveCache(data *models.SysDictType) error { + key := fmt.Sprintf(rediskey.SysDictKey, data.DictType) + + val, _ := sonic.MarshalString(data) + + if val != "" { + redishelper.DefaultRedis.SetString(key, val) + } + + e.SaveDataCache(data) + + return nil +} + +// 保存字典数据缓存 +func (e *SysDictType) SaveDataCache(data *models.SysDictType) error { + cacheData := dto.SysDictDetailResp{} + copier.Copy(&cacheData, data) + dataListKey := fmt.Sprintf(rediskey.SysDictDataList, data.DictType) + datas := make([]models.SysDictData, 0) + cacheDatas := []dto.SysDictDataDetail{} + + e.Orm.Model(&models.SysDictData{}).Where("dict_type = ?", data.DictType).Find(&datas) + + copier.Copy(&cacheDatas, datas) + cacheData.Datas = cacheDatas + listVal, _ := sonic.MarshalString(cacheData) + if listVal != "" { + redishelper.DefaultRedis.SetString(dataListKey, listVal) + } + + return nil +} + +// Remove 删除 +func (e *SysDictType) Remove(d *dto.SysDictTypeDeleteReq) error { + var err error + var data models.SysDictType + var datas []models.SysDictType + e.Orm.Model(data).Where("id in ?", d.Ids).Select("dict_type").Find(&datas) + + db := e.Orm.Delete(&data, d.GetId()) + if err = db.Error; err != nil { + err = db.Error + e.Log.Errorf("Delete error: %s", err) + return err + } + if db.RowsAffected == 0 { + err = errors.New("无权删除该数据") + return err + } + + for _, item := range datas { + key := fmt.Sprintf(rediskey.SysDictKey, item.DictType) + listKey := fmt.Sprintf(rediskey.SysDictDataList, item.DictType) + redishelper.DefaultRedis.DeleteString(key) + redishelper.DefaultRedis.DeleteString(listKey) + } + + return nil +} + +// 初始化字典数据 +func (e *SysDictType) InitDict() error { + var dicts []models.SysDictType + var datas []models.SysDictData + if err := e.Orm.Model(&models.SysDictType{}).Find(&dicts).Error; err != nil { + return err + } + + if err := e.Orm.Model(&models.SysDictData{}).Find(&datas).Error; err != nil { + return err + } + + for _, item := range dicts { + key := fmt.Sprintf(rediskey.SysDictKey, item.DictType) + listKey := fmt.Sprintf(rediskey.SysDictDataList, item.DictType) + cacheData := dto.SysDictDetailResp{} + copier.Copy(&cacheData, item) + dataList := make([]models.SysDictData, 0) + for _, dataItem := range datas { + if dataItem.DictType == item.DictType { + dataList = append(dataList, dataItem) + } + } + cacheDatas := []dto.SysDictDataDetail{} + copier.Copy(&cacheDatas, dataList) + cacheData.Datas = cacheDatas + listVal, _ := sonic.MarshalString(cacheData) + val, _ := sonic.MarshalString(item) + if listVal != "" { + redishelper.DefaultRedis.SetString(listKey, listVal) + } + if val != "" { + redishelper.DefaultRedis.SetString(key, val) + } + } + + return nil +} + +// GetAll 获取所有 +func (e *SysDictType) GetAll(c *dto.SysDictTypeGetPageReq, list *[]models.SysDictType) error { + var err error + var data models.SysDictType + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + ). + Find(list).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} diff --git a/app/admin/service/sys_login_log.go b/app/admin/service/sys_login_log.go new file mode 100644 index 0000000..985feb3 --- /dev/null +++ b/app/admin/service/sys_login_log.go @@ -0,0 +1,70 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" +) + +type SysLoginLog struct { + service.Service +} + +// GetPage 获取SysLoginLog列表 +func (e *SysLoginLog) GetPage(c *dto.SysLoginLogGetPageReq, list *[]models.SysLoginLog, count *int64) error { + var err error + var data models.SysLoginLog + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Get 获取SysLoginLog对象 +func (e *SysLoginLog) Get(d *dto.SysLoginLogGetReq, model *models.SysLoginLog) error { + var err error + db := e.Orm.First(model, d.GetId()) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error:%s", err) + return err + } + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Remove 删除SysLoginLog +func (e *SysLoginLog) Remove(c *dto.SysLoginLogDeleteReq) error { + var err error + var data models.SysLoginLog + + db := e.Orm.Delete(&data, c.GetId()) + if err = db.Error; err != nil { + err = db.Error + e.Log.Errorf("Delete error: %s", err) + return err + } + if db.RowsAffected == 0 { + err = errors.New("无权删除该数据") + return err + } + return nil +} diff --git a/app/admin/service/sys_menu.go b/app/admin/service/sys_menu.go new file mode 100644 index 0000000..3d6aab7 --- /dev/null +++ b/app/admin/service/sys_menu.go @@ -0,0 +1,423 @@ +package service + +import ( + "fmt" + "sort" + "strings" + + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/pkg/errors" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" + cModels "go-admin/common/models" + + "github.com/go-admin-team/go-admin-core/sdk/service" +) + +type SysMenu struct { + service.Service +} + +// GetPage 获取SysMenu列表 +func (e *SysMenu) GetPage(c *dto.SysMenuGetPageReq, menus *[]models.SysMenu) *SysMenu { + var menu = make([]models.SysMenu, 0) + err := e.getPage(c, &menu).Error + if err != nil { + _ = e.AddError(err) + return e + } + for i := 0; i < len(menu); i++ { + if menu[i].ParentId != 0 { + continue + } + menusInfo := menuCall(&menu, menu[i]) + *menus = append(*menus, menusInfo) + } + return e +} + +// getPage 菜单分页列表 +func (e *SysMenu) getPage(c *dto.SysMenuGetPageReq, list *[]models.SysMenu) *SysMenu { + var err error + var data models.SysMenu + + err = e.Orm.Model(&data). + Scopes( + cDto.OrderDest("sort", false), + cDto.MakeCondition(c.GetNeedSearch()), + ).Preload("SysApi"). + Find(list).Error + if err != nil { + e.Log.Errorf("getSysMenuPage error:%s", err) + _ = e.AddError(err) + return e + } + return e +} + +// Get 获取SysMenu对象 +func (e *SysMenu) Get(d *dto.SysMenuGetReq, model *models.SysMenu) *SysMenu { + var err error + var data models.SysMenu + + db := e.Orm.Model(&data).Preload("SysApi"). + First(model, d.GetId()) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("GetSysMenu error:%s", err) + _ = e.AddError(err) + return e + } + if err != nil { + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + return e + } + apis := make([]int, 0) + for _, v := range model.SysApi { + apis = append(apis, v.Id) + } + model.Apis = apis + return e +} + +// Insert 创建SysMenu对象 +func (e *SysMenu) Insert(c *dto.SysMenuInsertReq) *SysMenu { + var err error + var data models.SysMenu + c.Generate(&data) + tx := e.Orm.Debug().Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + err = tx.Where("id in ?", c.Apis).Find(&data.SysApi).Error + if err != nil { + tx.Rollback() + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + } + err = tx.Create(&data).Error + if err != nil { + tx.Rollback() + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + } + c.MenuId = data.MenuId + err = e.initPaths(tx, &data) + if err != nil { + tx.Rollback() + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + } + tx.Commit() + return e +} + +func (e *SysMenu) initPaths(tx *gorm.DB, menu *models.SysMenu) error { + var err error + var data models.SysMenu + parentMenu := new(models.SysMenu) + if menu.ParentId != 0 { + err = tx.Model(&data).First(parentMenu, menu.ParentId).Error + if err != nil { + return err + } + if parentMenu.Paths == "" { + err = errors.New("父级paths异常,请尝试对当前节点父级菜单进行更新操作!") + return err + } + menu.Paths = parentMenu.Paths + "/" + pkg.IntToString(menu.MenuId) + } else { + menu.Paths = "/0/" + pkg.IntToString(menu.MenuId) + } + err = tx.Model(&data).Where("menu_id = ?", menu.MenuId).Update("paths", menu.Paths).Error + return err +} + +// Update 修改SysMenu对象 +func (e *SysMenu) Update(c *dto.SysMenuUpdateReq) *SysMenu { + var err error + tx := e.Orm.Debug().Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + var alist = make([]models.SysApi, 0) + var model = models.SysMenu{} + tx.Preload("SysApi").First(&model, c.GetId()) + oldPath := model.Paths + tx.Where("id in ?", c.Apis).Find(&alist) + err = tx.Model(&model).Association("SysApi").Delete(model.SysApi) + if err != nil { + e.Log.Errorf("delete policy error:%s", err) + _ = e.AddError(err) + return e + } + c.Generate(&model) + model.SysApi = alist + db := tx.Model(&model).Session(&gorm.Session{FullSaveAssociations: true}).Debug().Save(&model) + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + return e + } + if db.RowsAffected == 0 { + _ = e.AddError(errors.New("无权更新该数据")) + return e + } + var menuList []models.SysMenu + tx.Where("paths like ?", oldPath+"%").Find(&menuList) + for _, v := range menuList { + v.Paths = strings.Replace(v.Paths, oldPath, model.Paths, 1) + tx.Model(&v).Update("paths", v.Paths) + } + return e +} + +// Remove 删除SysMenu +func (e *SysMenu) Remove(d *dto.SysMenuDeleteReq) *SysMenu { + var err error + var data models.SysMenu + + db := e.Orm.Model(&data).Delete(&data, d.Ids) + if err = db.Error; err != nil { + err = db.Error + e.Log.Errorf("Delete error: %s", err) + _ = e.AddError(err) + } + if db.RowsAffected == 0 { + err = errors.New("无权删除该数据") + _ = e.AddError(err) + } + return e +} + +// GetList 获取菜单数据 +func (e *SysMenu) GetList(c *dto.SysMenuGetPageReq, list *[]models.SysMenu) error { + var err error + var data models.SysMenu + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + ). + Find(list).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// SetLabel 修改角色中 设置菜单基础数据 +func (e *SysMenu) SetLabel() (m []dto.MenuLabel, err error) { + var list []models.SysMenu + err = e.GetList(&dto.SysMenuGetPageReq{}, &list) + + m = make([]dto.MenuLabel, 0) + for i := 0; i < len(list); i++ { + if list[i].ParentId != 0 { + continue + } + e := dto.MenuLabel{} + e.Id = list[i].MenuId + e.Label = list[i].Title + deptsInfo := menuLabelCall(&list, e) + + m = append(m, deptsInfo) + } + return +} + +// GetSysMenuByRoleName 左侧菜单 +func (e *SysMenu) GetSysMenuByRoleName(roleName ...string) ([]models.SysMenu, error) { + var MenuList []models.SysMenu + var role models.SysRole + var err error + admin := false + for _, s := range roleName { + if s == "admin" { + admin = true + } + } + + if len(roleName) > 0 && admin { + var data []models.SysMenu + err = e.Orm.Where(" menu_type in ('M','C')"). + Order("sort"). + Find(&data). + Error + MenuList = data + } else { + err = e.Orm.Model(&role).Preload("SysMenu", func(db *gorm.DB) *gorm.DB { + return db.Where(" menu_type in ('M','C')").Order("sort") + }).Where("role_name in ?", roleName).Find(&role). + Error + MenuList = *role.SysMenu + } + + if err != nil { + e.Log.Errorf("db error:%s", err) + } + return MenuList, err +} + +// menuLabelCall 递归构造组织数据 +func menuLabelCall(eList *[]models.SysMenu, dept dto.MenuLabel) dto.MenuLabel { + list := *eList + + min := make([]dto.MenuLabel, 0) + for j := 0; j < len(list); j++ { + + if dept.Id != list[j].ParentId { + continue + } + mi := dto.MenuLabel{} + mi.Id = list[j].MenuId + mi.Label = list[j].Title + mi.Children = []dto.MenuLabel{} + if list[j].MenuType != "F" { + ms := menuLabelCall(eList, mi) + min = append(min, ms) + } else { + min = append(min, mi) + } + } + if len(min) > 0 { + dept.Children = min + } else { + dept.Children = nil + } + return dept +} + +// menuCall 构建菜单树 +func menuCall(menuList *[]models.SysMenu, menu models.SysMenu) models.SysMenu { + list := *menuList + + min := make([]models.SysMenu, 0) + for j := 0; j < len(list); j++ { + + if menu.MenuId != list[j].ParentId { + continue + } + mi := models.SysMenu{} + mi.MenuId = list[j].MenuId + mi.MenuName = list[j].MenuName + mi.Title = list[j].Title + mi.Icon = list[j].Icon + mi.Path = list[j].Path + mi.MenuType = list[j].MenuType + mi.Action = list[j].Action + mi.Permission = list[j].Permission + mi.ParentId = list[j].ParentId + mi.NoCache = list[j].NoCache + mi.Breadcrumb = list[j].Breadcrumb + mi.Component = list[j].Component + mi.Sort = list[j].Sort + mi.Visible = list[j].Visible + mi.CreatedAt = list[j].CreatedAt + mi.SysApi = list[j].SysApi + mi.Children = []models.SysMenu{} + + if mi.MenuType != cModels.Button { + ms := menuCall(menuList, mi) + min = append(min, ms) + } else { + min = append(min, mi) + } + } + menu.Children = min + return menu +} + +func menuDistinct(menuList []models.SysMenu) (result []models.SysMenu) { + distinctMap := make(map[int]struct{}, len(menuList)) + for _, menu := range menuList { + if _, ok := distinctMap[menu.MenuId]; !ok { + distinctMap[menu.MenuId] = struct{}{} + result = append(result, menu) + } + } + return result +} + +func recursiveSetMenu(orm *gorm.DB, mIds []int, menus *[]models.SysMenu) error { + if len(mIds) == 0 || menus == nil { + return nil + } + var subMenus []models.SysMenu + err := orm.Where(fmt.Sprintf(" menu_type in ('%s', '%s', '%s') and menu_id in ?", + cModels.Directory, cModels.Menu, cModels.Button), mIds).Order("sort").Find(&subMenus).Error + if err != nil { + return err + } + + subIds := make([]int, 0) + for _, menu := range subMenus { + if menu.ParentId != 0 { + subIds = append(subIds, menu.ParentId) + } + if menu.MenuType != cModels.Button { + *menus = append(*menus, menu) + } + } + return recursiveSetMenu(orm, subIds, menus) +} + +// SetMenuRole 获取左侧菜单树使用 +func (e *SysMenu) SetMenuRole(roleName string) (m []models.SysMenu, err error) { + menus, err := e.getByRoleName(roleName) + m = make([]models.SysMenu, 0) + for i := 0; i < len(menus); i++ { + if menus[i].ParentId != 0 { + continue + } + menusInfo := menuCall(&menus, menus[i]) + m = append(m, menusInfo) + } + return +} + +func (e *SysMenu) getByRoleName(roleName string) ([]models.SysMenu, error) { + var role models.SysRole + var err error + data := make([]models.SysMenu, 0) + + if roleName == "admin" { + err = e.Orm.Where(" menu_type in ('M','C') and deleted_at is null"). + Order("sort"). + Find(&data). + Error + err = errors.WithStack(err) + } else { + role.RoleKey = roleName + err = e.Orm.Model(&role).Where("role_key = ? ", roleName).Preload("SysMenu").First(&role).Error + + if role.SysMenu != nil { + mIds := make([]int, 0) + for _, menu := range *role.SysMenu { + mIds = append(mIds, menu.MenuId) + } + if err := recursiveSetMenu(e.Orm, mIds, &data); err != nil { + return nil, err + } + + data = menuDistinct(data) + } + } + + sort.Sort(models.SysMenuSlice(data)) + return data, err +} diff --git a/app/admin/service/sys_opera_log.go b/app/admin/service/sys_opera_log.go new file mode 100644 index 0000000..c94b82c --- /dev/null +++ b/app/admin/service/sys_opera_log.go @@ -0,0 +1,83 @@ +package service + +import ( + "errors" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" +) + +type SysOperaLog struct { + service.Service +} + +// GetPage 获取SysOperaLog列表 +func (e *SysOperaLog) GetPage(c *dto.SysOperaLogGetPageReq, list *[]models.SysOperaLog, count *int64) error { + var err error + var data models.SysOperaLog + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("Service GetSysOperaLogPage error:%s", err.Error()) + return err + } + return nil +} + +// Get 获取SysOperaLog对象 +func (e *SysOperaLog) Get(d *dto.SysOperaLogGetReq, model *models.SysOperaLog) error { + var data models.SysOperaLog + + err := e.Orm.Model(&data). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetSysOperaLog error:%s", err.Error()) + return err + } + if err != nil { + e.Log.Errorf("Service GetSysOperaLog error:%s", err.Error()) + return err + } + return nil +} + +// Insert 创建SysOperaLog对象 +func (e *SysOperaLog) Insert(model *models.SysOperaLog) error { + var err error + var data models.SysOperaLog + + err = e.Orm.Model(&data). + Create(model).Error + if err != nil { + e.Log.Errorf("Service InsertSysOperaLog error:%s", err.Error()) + return err + } + return nil +} + +// Remove 删除SysOperaLog +func (e *SysOperaLog) Remove(d *dto.SysOperaLogDeleteReq) error { + var err error + var data models.SysOperaLog + + db := e.Orm.Model(&data).Delete(&data, d.GetId()) + if err = db.Error; err != nil { + e.Log.Errorf("Service RemoveSysOperaLog error:%s", err.Error()) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} diff --git a/app/admin/service/sys_post.go b/app/admin/service/sys_post.go new file mode 100644 index 0000000..51956f4 --- /dev/null +++ b/app/admin/service/sys_post.go @@ -0,0 +1,105 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" +) + +type SysPost struct { + service.Service +} + +// GetPage 获取SysPost列表 +func (e *SysPost) GetPage(c *dto.SysPostPageReq, list *[]models.SysPost, count *int64) error { + var err error + var data models.SysPost + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("db error:%s \r", err) + return err + } + return nil +} + +// Get 获取SysPost对象 +func (e *SysPost) Get(d *dto.SysPostGetReq, model *models.SysPost) error { + var err error + var data models.SysPost + + db := e.Orm.Model(&data). + First(model, d.GetId()) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error:%s", err) + return err + } + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建SysPost对象 +func (e *SysPost) Insert(c *dto.SysPostInsertReq) error { + var err error + var data models.SysPost + c.Generate(&data) + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Update 修改SysPost对象 +func (e *SysPost) Update(c *dto.SysPostUpdateReq) error { + var err error + var model = models.SysPost{} + e.Orm.First(&model, c.GetId()) + c.Generate(&model) + + db := e.Orm.Save(&model) + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + + } + return nil +} + +// Remove 删除SysPost +func (e *SysPost) Remove(d *dto.SysPostDeleteReq) error { + var err error + var data models.SysPost + + db := e.Orm.Model(&data).Delete(&data, d.GetId()) + if err = db.Error; err != nil { + err = db.Error + e.Log.Errorf("Delete error: %s", err) + return err + } + if db.RowsAffected == 0 { + err = errors.New("无权删除该数据") + return err + } + return nil +} \ No newline at end of file diff --git a/app/admin/service/sys_role.go b/app/admin/service/sys_role.go new file mode 100644 index 0000000..f1fee74 --- /dev/null +++ b/app/admin/service/sys_role.go @@ -0,0 +1,352 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/config" + "gorm.io/gorm/clause" + + "github.com/casbin/casbin/v2" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + cDto "go-admin/common/dto" +) + +type SysRole struct { + service.Service +} + +// GetPage 获取SysRole列表 +func (e *SysRole) GetPage(c *dto.SysRoleGetPageReq, list *[]models.SysRole, count *int64) error { + var err error + var data models.SysRole + + err = e.Orm.Model(&data).Preload("SysMenu"). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Get 获取SysRole对象 +func (e *SysRole) Get(d *dto.SysRoleGetReq, model *models.SysRole) error { + var err error + db := e.Orm.First(model, d.GetId()) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error:%s", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + model.MenuIds, err = e.GetRoleMenuId(model.RoleId) + if err != nil { + e.Log.Errorf("get menuIds error, %s", err.Error()) + return err + } + return nil +} + +// Insert 创建SysRole对象 +func (e *SysRole) Insert(c *dto.SysRoleInsertReq, cb *casbin.SyncedEnforcer) error { + var err error + var data models.SysRole + var dataMenu []models.SysMenu + err = e.Orm.Preload("SysApi").Where("menu_id in ?", c.MenuIds).Find(&dataMenu).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + c.SysMenu = dataMenu + c.Generate(&data) + tx := e.Orm + if config.DatabaseConfig.Driver != "sqlite3" { + tx := e.Orm.Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + } + var count int64 + err = tx.Model(&data).Where("role_key = ?", c.RoleKey).Count(&count).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + + if count > 0 { + err = errors.New("roleKey已存在,需更换在提交!") + e.Log.Errorf("db error:%s", err) + return err + } + + err = tx.Create(&data).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + + mp := make(map[string]interface{}, 0) + polices := make([][]string, 0) + for _, menu := range dataMenu { + for _, api := range menu.SysApi { + if mp[data.RoleKey+"-"+api.Path+"-"+api.Action] != "" { + mp[data.RoleKey+"-"+api.Path+"-"+api.Action] = "" + polices = append(polices, []string{data.RoleKey, api.Path, api.Action}) + } + } + } + + if len(polices) <= 0 { + return nil + } + + // 写入 sys_casbin_rule 权限表里 当前角色数据的记录 + _, err = cb.AddNamedPolicies("p", polices) + if err != nil { + return err + } + + return nil +} + +// Update 修改SysRole对象 +func (e *SysRole) Update(c *dto.SysRoleUpdateReq, cb *casbin.SyncedEnforcer) error { + var err error + tx := e.Orm + if config.DatabaseConfig.Driver != "sqlite3" { + tx := e.Orm.Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + } + var model = models.SysRole{} + var mlist = make([]models.SysMenu, 0) + tx.Preload("SysMenu").First(&model, c.GetId()) + tx.Preload("SysApi").Where("menu_id in ?", c.MenuIds).Find(&mlist) + err = tx.Model(&model).Association("SysMenu").Delete(model.SysMenu) + if err != nil { + e.Log.Errorf("delete policy error:%s", err) + return err + } + c.Generate(&model) + model.SysMenu = &mlist + // 更新关联的数据,使用 FullSaveAssociations 模式 + db := tx.Session(&gorm.Session{FullSaveAssociations: true}).Debug().Save(&model) + + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + + // 清除 sys_casbin_rule 权限表里 当前角色的所有记录 + _, err = cb.RemoveFilteredPolicy(0, model.RoleKey) + if err != nil { + e.Log.Errorf("delete policy error:%s", err) + return err + } + mp := make(map[string]interface{}, 0) + polices := make([][]string, 0) + for _, menu := range mlist { + for _, api := range menu.SysApi { + if mp[model.RoleKey+"-"+api.Path+"-"+api.Action] != "" { + mp[model.RoleKey+"-"+api.Path+"-"+api.Action] = "" + //_, err = cb.AddNamedPolicy("p", model.RoleKey, api.Path, api.Action) + polices = append(polices, []string{model.RoleKey, api.Path, api.Action}) + } + } + } + if len(polices) <= 0 { + return nil + } + + // 写入 sys_casbin_rule 权限表里 当前角色数据的记录 + _, err = cb.AddNamedPolicies("p", polices) + if err != nil { + return err + } + return nil +} + +// Remove 删除SysRole +func (e *SysRole) Remove(c *dto.SysRoleDeleteReq, cb *casbin.SyncedEnforcer) error { + var err error + tx := e.Orm + if config.DatabaseConfig.Driver != "sqlite3" { + tx := e.Orm.Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + } + var model = models.SysRole{} + tx.Preload("SysMenu").Preload("SysDept").First(&model, c.GetId()) + //删除 SysRole 时,同时删除角色所有 关联其它表 记录 (SysMenu 和 SysMenu) + db := tx.Select(clause.Associations).Delete(&model) + + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + + // 清除 sys_casbin_rule 权限表里 当前角色的所有记录 + _, _ = cb.RemoveFilteredPolicy(0, model.RoleKey) + + return nil +} + +// GetRoleMenuId 获取角色对应的菜单ids +func (e *SysRole) GetRoleMenuId(roleId int) ([]int, error) { + menuIds := make([]int, 0) + model := models.SysRole{} + model.RoleId = roleId + if err := e.Orm.Model(&model).Preload("SysMenu").First(&model).Error; err != nil { + return nil, err + } + l := *model.SysMenu + for i := 0; i < len(l); i++ { + menuIds = append(menuIds, l[i].MenuId) + } + return menuIds, nil +} + +func (e *SysRole) UpdateDataScope(c *dto.RoleDataScopeReq) *SysRole { + var err error + tx := e.Orm + if config.DatabaseConfig.Driver != "sqlite3" { + tx := e.Orm.Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + } + var dlist = make([]models.SysDept, 0) + var model = models.SysRole{} + tx.Preload("SysDept").First(&model, c.RoleId) + tx.Where("dept_id in ?", c.DeptIds).Find(&dlist) + // 删除SysRole 和 SysDept 的关联关系 + err = tx.Model(&model).Association("SysDept").Delete(model.SysDept) + if err != nil { + e.Log.Errorf("delete SysDept error:%s", err) + _ = e.AddError(err) + return e + } + c.Generate(&model) + model.SysDept = dlist + // 更新关联的数据,使用 FullSaveAssociations 模式 + db := tx.Model(&model).Session(&gorm.Session{FullSaveAssociations: true}).Debug().Save(&model) + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + return e + } + if db.RowsAffected == 0 { + _ = e.AddError(errors.New("无权更新该数据")) + return e + } + return e +} + +// UpdateStatus 修改SysRole对象status +func (e *SysRole) UpdateStatus(c *dto.UpdateStatusReq) error { + var err error + tx := e.Orm + if config.DatabaseConfig.Driver != "sqlite3" { + tx := e.Orm.Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + } + var model = models.SysRole{} + tx.First(&model, c.GetId()) + c.Generate(&model) + // 更新关联的数据,使用 FullSaveAssociations 模式 + db := tx.Session(&gorm.Session{FullSaveAssociations: true}).Debug().Save(&model) + if err = db.Error; err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// GetWithName 获取SysRole对象 +func (e *SysRole) GetWithName(d *dto.SysRoleByName, model *models.SysRole) *SysRole { + var err error + db := e.Orm.Where("role_name = ?", d.RoleName).First(model) + err = db.Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + return e + } + if err != nil { + e.Log.Errorf("db error:%s", err) + _ = e.AddError(err) + return e + } + model.MenuIds, err = e.GetRoleMenuId(model.RoleId) + if err != nil { + e.Log.Errorf("get menuIds error, %s", err.Error()) + _ = e.AddError(err) + return e + } + return e +} + +// GetById 获取SysRole对象 +func (e *SysRole) GetById(roleId int) ([]string, error) { + permissions := make([]string, 0) + model := models.SysRole{} + model.RoleId = roleId + if err := e.Orm.Model(&model).Preload("SysMenu").First(&model).Error; err != nil { + return nil, err + } + l := *model.SysMenu + for i := 0; i < len(l); i++ { + if l[i].Permission != "" { + permissions = append(permissions, l[i].Permission) + } + } + return permissions, nil +} diff --git a/app/admin/service/sys_role_menu.go b/app/admin/service/sys_role_menu.go new file mode 100644 index 0000000..9d5d38b --- /dev/null +++ b/app/admin/service/sys_role_menu.go @@ -0,0 +1,110 @@ +package service + +import ( + "github.com/go-admin-team/go-admin-core/sdk/service" +) + +// SysRoleMenu 即将弃用结构体 +type SysRoleMenu struct { + service.Service +} + +//func (e *SysRoleMenu) ReloadRule(tx *gorm.DB, roleId int, menuId []int) (err error) { +// var role models.SysRole +// +// msgID := e.MsgID +// +// menu := make([]models.Menu, 0) +// roleMenu := make([]models.RoleMenu, len(menuId)) +// casbinRule := make([]models.CasbinRule, 0) +// //先删除所有的 +// err = e.DeleteRoleMenu(tx, roleId) +// if err != nil { +// return +// } +// +// // 在事务中做一些数据库操作(从这一点使用'tx',而不是'db') +// err = tx.Where("role_id = ?", roleId).First(&role).Error +// if err != nil { +// log.Errorf("msgID[%s] get role error, %s", msgID, err.Error()) +// return +// } +// err = tx.Where("menu_id in (?)", menuId). +// //Select("path, action, menu_id, menu_type"). +// Find(&menu).Error +// if err != nil { +// log.Errorf("msgID[%s] get menu error, %s", msgID, err.Error()) +// return +// } +// for i := range menu { +// roleMenu[i] = models.RoleMenu{ +// RoleId: role.RoleId, +// MenuId: menu[i].MenuId, +// RoleName: role.RoleKey, +// } +// if menu[i].MenuType == "A" { +// casbinRule = append(casbinRule, models.CasbinRule{ +// PType: "p", +// V0: role.RoleKey, +// V1: menu[i].Path, +// V2: menu[i].Action, +// }) +// } +// } +// err = tx.Create(&roleMenu).Error +// if err != nil { +// log.Errorf("msgID[%s] batch create role's menu error, %s", msgID, err.Error()) +// return +// } +// if len(casbinRule) > 0 { +// err = tx.Create(&casbinRule).Error +// if err != nil { +// log.Errorf("msgID[%s] batch create casbin rule error, %s", msgID, err.Error()) +// return +// } +// } +// +// return +//} + +//func (e *SysRoleMenu) DeleteRoleMenu(tx *gorm.DB, roleId int) (err error) { +// msgID := e.MsgID +// err = tx.Where("role_id = ?", roleId). +// Delete(&models.SysRoleDept{}).Error +// if err != nil { +// log.Errorf("msgID[%s] delete role's dept error, %s", msgID, err.Error()) +// return +// } +// err = tx.Where("role_id = ?", roleId). +// Delete(&models.RoleMenu{}).Error +// if err != nil { +// log.Errorf("msgID[%s] delete role's menu error, %s", msgID, err.Error()) +// return +// } +// var role models.SysRole +// err = tx.Where("role_id = ?", roleId). +// First(&role).Error +// if err != nil { +// log.Errorf("msgID[%s] get role error, %s", msgID, err.Error()) +// return +// } +// err = tx.Where("v0 = ?", role.RoleKey). +// Delete(&models.CasbinRule{}).Error +// if err != nil { +// log.Errorf("msgID[%s] delete casbin rule error, %s", msgID, err.Error()) +// return +// } +// return +//} +// +//func (e *SysRoleMenu) GetIDS(tx *gorm.DB, roleName string) ([]models.MenuPath, error) { +// var r []models.MenuPath +// table := tx.Select("sys_menu.path").Table("sys_role_menu") +// table = table.Joins("left join sys_role on sys_role.role_id=sys_role_menu.role_id") +// table = table.Joins("left join sys_menu on sys_menu.id=sys_role_menu.menu_id") +// table = table.Where("sys_role.role_name = ? and sys_menu.type=1", roleName) +// if err := table.Find(&r).Error; err != nil { +// return nil, err +// } +// return r, nil +//} \ No newline at end of file diff --git a/app/admin/service/sys_user.go b/app/admin/service/sys_user.go new file mode 100644 index 0000000..9cf9d71 --- /dev/null +++ b/app/admin/service/sys_user.go @@ -0,0 +1,338 @@ +package service + +import ( + "errors" + "fmt" + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/utils/redishelper" + + "github.com/bytedance/sonic" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/common/actions" + cDto "go-admin/common/dto" + rediskey "go-admin/common/redis_key" +) + +type SysUser struct { + service.Service +} + +func (e SysUser) GetByIds(userIds []int) ([]models.SysUser, error) { + result := make([]models.SysUser, 0) + + if err := e.Orm.Model(models.SysUser{}).Where("user_id in ?", userIds).Find(&result).Error; err != nil { + return nil, err + } + + return result, nil +} + +// GetPage 获取SysUser列表 +func (e *SysUser) GetPage(c *dto.SysUserGetPageReq, p *actions.DataPermission, list *[]models.SysUser, count *int64) error { + var err error + var data models.SysUser + + err = e.Orm.Debug().Preload("Dept"). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} + +// Get 获取SysUser对象 +func (e *SysUser) Get(d *dto.SysUserById, p *actions.DataPermission, model *models.SysUser) error { + var data models.SysUser + + err := e.Orm.Model(&data).Debug(). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error: %s", err) + return err + } + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} + +// Insert 创建SysUser对象 +func (e *SysUser) Insert(c *dto.SysUserInsertReq) error { + var err error + var data models.SysUser + var role models.SysRole + var i int64 + e.Orm.Model(role).Where("role_id = ?", c.RoleId).Find(&role) + + if role.RoleId == 0 { + err = errors.New("角色不存在") + } + + err = e.Orm.Model(&data).Where("username = ?", c.Username).Count(&i).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + if i > 0 { + err := errors.New("用户名已存在!") + e.Log.Errorf("db error: %s", err) + return err + } + c.Generate(&data) + + memberService := TmMember{} + memberData := models.TmMember{} + + err = e.Orm.Transaction(func(tx *gorm.DB) error { + if err1 := tx.Create(&data).Error; err1 != nil { + return err1 + } + + //普通用户需要新增 用户翻译信息表 + if role.RoleKey == "normal_member" { + memberService.Orm = tx + memberService.Log = e.Log + memberReq := dto.TmMemberSyncInsertReq{ + UserId: data.UserId, + NickName: data.NickName, + Mobile: data.Phone, + Email: data.Email, + } + err1 := memberService.SyncInsert(&memberReq, &memberData) + if err1 != nil { + return err1 + } + } + + return nil + }) + + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + + key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, memberData.ApiKey) + val, _ := sonic.MarshalString(memberData) + + if val != "" { + redishelper.DefaultRedis.SetString(key, val) + } + + return nil +} + +// Update 修改SysUser对象 +func (e *SysUser) Update(c *dto.SysUserUpdateReq, p *actions.DataPermission) error { + var err error + var model models.SysUser + db := e.Orm.Scopes( + actions.Permission(model.TableName(), p), + ).First(&model, c.GetId()) + if err = db.Error; err != nil { + e.Log.Errorf("Service UpdateSysUser error: %s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + + } + c.Generate(&model) + update := e.Orm.Model(&model).Where("user_id = ?", &model.UserId).Omit("password", "salt").Updates(&model) + if err = update.Error; err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + if update.RowsAffected == 0 { + err = errors.New("update userinfo error") + log.Warnf("db update error") + return err + } + return nil +} + +// UpdateAvatar 更新用户头像 +func (e *SysUser) UpdateAvatar(c *dto.UpdateSysUserAvatarReq, p *actions.DataPermission) error { + var err error + var model models.SysUser + db := e.Orm.Scopes( + actions.Permission(model.TableName(), p), + ).First(&model, c.GetId()) + if err = db.Error; err != nil { + e.Log.Errorf("Service UpdateSysUser error: %s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + + } + err = e.Orm.Table(model.TableName()).Where("user_id =? ", c.UserId).Updates(c).Error + if err != nil { + e.Log.Errorf("Service UpdateSysUser error: %s", err) + return err + } + return nil +} + +// UpdateStatus 更新用户状态 +func (e *SysUser) UpdateStatus(c *dto.UpdateSysUserStatusReq, p *actions.DataPermission) error { + var err error + var model models.SysUser + db := e.Orm.Scopes( + actions.Permission(model.TableName(), p), + ).First(&model, c.GetId()) + if err = db.Error; err != nil { + e.Log.Errorf("Service UpdateSysUser error: %s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + + } + err = e.Orm.Table(model.TableName()).Where("user_id =? ", c.UserId).Updates(c).Error + if err != nil { + e.Log.Errorf("Service UpdateSysUser error: %s", err) + return err + } + return nil +} + +// ResetPwd 重置用户密码 +func (e *SysUser) ResetPwd(c *dto.ResetSysUserPwdReq, p *actions.DataPermission) error { + var err error + var model models.SysUser + db := e.Orm.Scopes( + actions.Permission(model.TableName(), p), + ).First(&model, c.GetId()) + if err = db.Error; err != nil { + e.Log.Errorf("At Service ResetSysUserPwd error: %s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + c.Generate(&model) + err = e.Orm.Omit("username", "nick_name", "phone", "role_id", "avatar", "sex").Save(&model).Error + if err != nil { + e.Log.Errorf("At Service ResetSysUserPwd error: %s", err) + return err + } + return nil +} + +// Remove 删除SysUser +func (e *SysUser) Remove(c *dto.SysUserById, p *actions.DataPermission) error { + var err error + var data models.SysUser + + memberService := TmMember{} + + err = e.Orm.Transaction(func(tx *gorm.DB) error { + db := tx.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, c.GetId()) + + if err = db.Error; err != nil { + e.Log.Errorf("Error found in RemoveSysUser : %s", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + + memberService.Orm = tx + memberService.Log = e.Log + + if err := memberService.RemoveByUserIds(c.Ids); err != nil { + e.Log.Errorf("删除翻译账户失败:", err) + return err + } + + return nil + }) + + return err +} + +// UpdatePwd 修改SysUser对象密码 +func (e *SysUser) UpdatePwd(id int, oldPassword, newPassword string, p *actions.DataPermission) error { + var err error + + if newPassword == "" { + return nil + } + c := &models.SysUser{} + + err = e.Orm.Model(c). + Scopes( + actions.Permission(c.TableName(), p), + ).Select("UserId", "Password", "Salt"). + First(c, id).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return errors.New("无权更新该数据") + } + e.Log.Errorf("db error: %s", err) + return err + } + var ok bool + ok, err = pkg.CompareHashAndPassword(c.Password, oldPassword) + if err != nil { + e.Log.Errorf("CompareHashAndPassword error, %s", err.Error()) + return err + } + if !ok { + err = errors.New("incorrect Password") + e.Log.Warnf("user[%d] %s", id, err.Error()) + return err + } + c.Password = newPassword + db := e.Orm.Model(c).Where("user_id = ?", id). + Select("Password", "Salt"). + Updates(c) + if err = db.Error; err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + if db.RowsAffected == 0 { + err = errors.New("set password error") + log.Warnf("db update error") + return err + } + return nil +} + +func (e *SysUser) GetProfile(c *dto.SysUserById, user *models.SysUser, roles *[]models.SysRole, posts *[]models.SysPost) error { + err := e.Orm.Preload("Dept").First(user, c.GetId()).Error + if err != nil { + return err + } + err = e.Orm.Find(roles, user.RoleId).Error + if err != nil { + return err + } + err = e.Orm.Find(posts, user.PostIds).Error + if err != nil { + return err + } + + return nil +} diff --git a/app/admin/service/tm_member.go b/app/admin/service/tm_member.go new file mode 100644 index 0000000..ef66454 --- /dev/null +++ b/app/admin/service/tm_member.go @@ -0,0 +1,680 @@ +package service + +import ( + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/sdk/service" + "github.com/go-redis/redis/v8" + "github.com/jinzhu/copier" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" + rediskey "go-admin/common/redis_key" + "go-admin/utils/redishelper" + "go-admin/utils/utility" +) + +type TmMember struct { + service.Service +} + +func (e TmMember) GetUserPlatforms(userId int, resp *[]dto.TmMemberPlatformFrontedResp) error { + var datas []models.TmMemberPlatform + var memberAccount models.TmMember + + if err := e.Orm.Model(&memberAccount). + Find(&memberAccount).Error; err != nil { + return err + } + + err := e.Orm.Model(&models.TmMemberPlatform{}). + Where(" member_id=?", memberAccount.Id). + Find(&datas).Error + if err != nil { + return err + } + + platformService := TmPlatform{Service: e.Service} + + for _, item := range datas { + dataItem := dto.TmMemberPlatformFrontedResp{} + copier.Copy(&dataItem, &item) + platform, _ := platformService.GetByKey(item.PlatformKey) + + dataItem.ApiKey = memberAccount.ApiKey + dataItem.Name = platform.ShowName + dataItem.Price = int(platform.Price.IntPart()) + dataItem.RemainChars, _ = e.GetRemainCount(item.PlatformKey, dataItem.ApiKey) + + *resp = append(*resp, dataItem) + } + + return nil +} + +// GetPage 获取TmMember列表 +func (e *TmMember) GetPage(c *dto.TmMemberGetPageReq, p *actions.DataPermission, list *[]dto.TmMemberResp, count *int64) error { + var err error + var data models.TmMember + var datas []models.TmMember + + err = e.Orm.Model(&data). + Joins("join sys_user on sys_user.user_id = tm_member.user_id "). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Select("tm_member.id,tm_member.api_key,tm_member.total_chars,tm_member.remain_chars,tm_member.status,tm_member.created_at,sys_user.status as userStatus,sys_user.nick_name,sys_user.user_id"). + Find(&datas).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("TmMemberService GetPage error:%s \r\n", err) + return err + } + + userIds := []int{} + + for _, item := range datas { + if !utility.ContainsInt(userIds, item.UserId) { + userIds = append(userIds, item.UserId) + } + } + + platformService := TmPlatform{Service: e.Service} + userService := SysUser{Service: e.Service} + users, _ := userService.GetByIds(userIds) + activeList, _ := platformService.GetActiveList() + + for _, item := range datas { + dataItem := dto.TmMemberResp{} + copier.Copy(&dataItem, &item) + + // count, _ := e.GetRemainCount(,dataItem.ApiKey) + dataItem.ApiKey = utility.DesensitizeGeneric(dataItem.ApiKey, 2, 2, '*') + // dataItem.RemainChars = count + + for _, user := range users { + if user.UserId == item.UserId { + dataItem.UserStatus, _ = strconv.Atoi(user.Status) + } + } + + for _, platform := range activeList { + platformItem := dto.TmMemberPlatformResp{} + platformItem.Name = platform.Name + platformItem.RemainChars, _ = e.GetRemainCount(platform.Code, item.ApiKey) + + dataItem.Platforms = append(dataItem.Platforms, platformItem) + } + + *list = append(*list, dataItem) + } + + return nil +} + +// Get 获取TmMember对象 +func (e *TmMember) Get(d *dto.TmMemberGetReq, p *actions.DataPermission, model *models.TmMember) error { + var data models.TmMember + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetTmMember error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建TmMember对象 +func (e *TmMember) Insert(c *dto.TmMemberInsertReq, data *models.TmMember) error { + var err error + c.Generate(data) + + apiKey, err := utility.GenerateBase62Key(32) + + if err != nil { + return errors.New("生成apiKey失败") + } + + data.ApiKey = apiKey + data.RemainChars = 10000 + data.TotalChars = 10000 + + err = e.Orm.Create(data).Error + if err != nil { + e.Log.Errorf("TmMemberService Insert error:%s \r\n", err) + return err + } + + return nil +} + +// SaveCache 保存缓存 +func (e *TmMember) SaveCache(data *models.TmMember) error { + key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, data.ApiKey) + val, err := sonic.MarshalString(data) + if err != nil { + return err + } + + redishelper.DefaultRedis.SetString(key, val) + + return nil +} + +// SaveAllCache 保存所有缓存 +func (e *TmMember) SaveAllCache() error { + var list []models.TmMember + if err := e.Orm.Model(&models.TmMember{}). + Joins("join sys_user on sys_user.user_id = tm_member.user_id"). + Find(&list).Error; err != nil { + return err + } + for _, item := range list { + key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, item.ApiKey) + // remainKey := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, item.ApiKey) + val, err := sonic.MarshalString(item) + if err != nil { + return err + } + redishelper.DefaultRedis.SetString(key, val) + // redishelper.DefaultRedis.SetString(remainKey, strconv.Itoa(item.RemainChars)) + } + return nil +} + +// Update 修改TmMember对象 +func (e *TmMember) Update(c *dto.TmMemberUpdateReq, p *actions.DataPermission) error { + var err error + var data = models.TmMember{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("TmMemberService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// Remove 删除TmMember +func (e *TmMember) Remove(d *dto.TmMemberDeleteReq, p *actions.DataPermission) error { + var data models.TmMember + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveTmMember error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} + +func (e *TmMember) RemoveByUserIds(userIds []int) error { + data := make([]models.TmMember, 0) + if err := e.Orm.Model(&data).Where("user_id in ?", userIds).Find(&data).Error; err != nil { + return err + } + if err := e.Orm.Model(models.TmMember{}).Delete(&models.TmMember{}, "user_id in ?", userIds).Error; err != nil { + return err + } + + for _, item := range data { + key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, item.ApiKey) + remainKey := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, item.ApiKey, "*") + scanKeys, _ := redishelper.DefaultRedis.ScanKeys(remainKey) + + redishelper.DefaultRedis.DeleteString(key) + for _, s := range scanKeys { + redishelper.DefaultRedis.DeleteString(s) + } + } + + return nil +} + +// SyncMemberRemain 同步剩余字符 +func (e *TmMember) SyncMemberRemain() error { + scanKeys, err := redishelper.DefaultRedis.ScanKeys(fmt.Sprintf("%s*", rediskey.TM_MEMBER_REMAIN_COUNT_PURE)) + + if err != nil { + return err + } + + members := e.getCacheMembers() + datas := make([]models.TmMemberPlatform, 0) + + for _, key := range scanKeys { + items := strings.Split(key, ":") + apiKey := items[len(items)-2] + platform := items[len(items)-1] + val, err := redishelper.DefaultRedis.GetString(key) + remainCount, err1 := strconv.Atoi(val) + + if err != nil || err1 != nil { + e.Log.Errorf("TmMemberService SyncMemberRemain GetString error:%s \r\n err1:%s \r\n", err, err1) + continue + } + + if member := members[apiKey]; member.Id > 0 { + item := models.TmMemberPlatform{} + item.Id = member.Id + item.RemainingCharacter = remainCount + item.PlatformKey = platform + datas = append(datas, item) + } + } + + arrayData := utility.SplitSlice(datas, 1000) + for _, dataBatch := range arrayData { + + // 遍历当前批次的所有记录,为每条记录单独执行 UPDATE + for _, record := range dataBatch { + stmt := ` + UPDATE tm_member_platform + SET + remaining_character = ?, + updated_at = NOW() + WHERE platform_key = ? AND member_id = ?; + ` + args := []interface{}{ + record.RemainingCharacter, + record.PlatformKey, + record.Id, + } + + // 执行单个 UPDATE 语句 + if err := e.Orm.Exec(stmt, args...).Error; err != nil { + // 记录错误,但继续处理批次中的其他记录 + e.Log.Errorf("TmMemberService SyncMemberRemain single Exec for PlatformKey %s, MemberID %d error: %s \r\n", record.PlatformKey, record.Id, err) + } + } + } + + return nil +} + +// SyncMemberDailyUsage 同步每日使用字符 +func (e *TmMember) SyncMemberDailyUsage() error { + key := fmt.Sprintf("%s:%s*", rediskey.TM_MEMBER_DAILY_COUNT_PURE, time.Now().AddDate(0, 0, -1).Format("20060102")) + todayKey := fmt.Sprintf("%s:%s*", rediskey.TM_MEMBER_DAILY_COUNT_PURE, time.Now().Format("20060102")) + dailys := make([]models.TmMemberDailyUsage, 0) + + members := e.getCacheMembers() + + keys, err := redishelper.DefaultRedis.ScanKeys(key) + + if err != nil { + e.Log.Errorf("TmMemberService SyncMemberDailyUsage ScanKeys error:%s \r\n", err) + return err + } + + todayKeys, err := redishelper.DefaultRedis.ScanKeys(todayKey) + if err != nil { + e.Log.Errorf("TmMemberService SyncMemberDailyUsage ScanKeys error:%s \r\n", err) + return err + } + + e.loadSyncData(keys, &members, &dailys) + e.loadSyncData(todayKeys, &members, &dailys) + + arrayData := utility.SplitSlice(dailys, 1000) + for _, dataBatch := range arrayData { + // 构建批量插入 SQL + var ( + valueStrings []string // 存储 ?, ?, ?, ? 这样的占位符字符串 + valueArgs []interface{} // 存储所有参数值 + ) + + // 循环当前批次的数据,构建 SQL 片段和参数 + for _, record := range dataBatch { + // 为每一条记录添加 VALUES (?, ?, ?, ?) 部分 + valueStrings = append(valueStrings, "(?, ?,?, ?)") + // 按照 SQL 语句中字段的顺序添加参数 + valueArgs = append(valueArgs, record.MemberId) + valueArgs = append(valueArgs, record.PlatformId) + valueArgs = append(valueArgs, record.Date) // time.Time 会被 SQL 驱动正确处理为 DATE 类型 + valueArgs = append(valueArgs, record.UseChars) + } + + // 拼接完整的 SQL 语句 + // 核心的 INSERT ... ON DUPLICATE KEY UPDATE 部分 + stmt := fmt.Sprintf(` + INSERT INTO tm_member_daily_usage (member_id,platform_id, date, use_chars) + VALUES %s + ON DUPLICATE KEY UPDATE use_chars = VALUES(use_chars), updated_at = NOW(); + `, strings.Join(valueStrings, ",")) // 用逗号连接所有的 VALUES 部分 + + // 执行批量 SQL + if execErr := e.Orm.Exec(stmt, valueArgs...).Error; execErr != nil { + e.Log.Errorf("TmMemberService SyncMemberDailyUsage Exec error:%s \r\n", execErr) + } + } + + return nil +} + +// 获取缓存memebr +func (e *TmMember) getCacheMembers() map[string]models.TmMember { + memberVals, _ := redishelper.DefaultRedis.GetAllKeysAndValues(fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, "*")) + members := map[string]models.TmMember{} + for _, val := range memberVals { + var member models.TmMember + err := sonic.UnmarshalString(val, &member) + if err != nil { + e.Log.Errorf("TmMemberService SyncMemberDailyUsage UnmarshalString error:%s \r\n", err) + continue + } + members[member.ApiKey] = member + } + return members +} + +// 加载同步数据 +func (e *TmMember) loadSyncData(keys []string, members *map[string]models.TmMember, dailys *[]models.TmMemberDailyUsage) { + platformService := TmPlatform{Service: e.Service} + + for _, key := range keys { + items := strings.Split(key, ":") + apiKey := items[len(items)-2] + platform := items[len(items)-1] + + if apiKey == "" { + continue + } + + platformEntity, _ := platformService.GetByKey(platform) + + if platformEntity.Id <= 0 { + e.Log.Error("TmMemberService SyncMemberDailyUsage platform not found", platform) + continue + } + + keyVal, _ := redishelper.DefaultRedis.GetString(key) + count, err := strconv.Atoi(keyVal) + + if err != nil { + e.Log.Errorf("TmMemberService SyncMemberDailyUsage GetString error:%s \r\n", err) + continue + } + + if member := (*members)[apiKey]; member.Id > 0 { + date, err := time.Parse("20060102", items[1]) + + if err != nil { + e.Log.Errorf("同步每日使用字符 日期转换失败 Parse error:%s \r\n", err) + continue + } + *dailys = append(*dailys, models.TmMemberDailyUsage{ + MemberId: (*members)[apiKey].Id, + UseChars: count, + Date: date, + PlatformId: platformEntity.Id, + }) + } + } +} + +// func (e *TmMember) GetMyApiKey(userId int) (dto.TranslateUserInfoResp, error) { +// var data models.TmMember +// resp := dto.TranslateUserInfoResp{} +// if err := e.Orm.Model(&data).Where("user_id = ?", userId).First(&data).Error; err != nil { +// e.Log.Errorf("TmMemberService GetMyApiKey error:%s \r\n", err) +// return resp, nil +// } + +// var err error +// resp.UserApiKey = data.ApiKey +// resp.RemainChars, err = e.GetRemainCount(data.ApiKey) + +// if err != nil { +// e.Log.Errorf("转换类型失败,error:%v", err) +// } +// return resp, nil +// } + +// GetTranslateStatistic 获取翻译统计 +func (e *TmMember) GetTranslateStatistic(userId int, list *[]dto.TranslateStatisticResp) error { + endDate := time.Now().Format("2006-01-02") + startDate := time.Now().AddDate(0, 0, -14).Format("2006-01-02") + var datas []models.TmMemberDailyUsage + if err := e.Orm.Model(&models.TmMemberDailyUsage{}). + Joins("join tm_member on tm_member.id = tm_member_daily_usage.member_id"). + Where("tm_member.user_id = ? and date >= ? and date <= ?", userId, startDate, endDate).Find(&datas).Error; err != nil { + e.Log.Errorf("个人翻译统计 获取统计数据失败 error:%s \r\n", err) + return err + } + + usageMap := make(map[string]int) + for _, usage := range datas { + // 如果同一天有多条记录(例如来自不同平台),则累加其字符数 + usageMap[usage.Date.Format("2006-01-02")] += int(usage.UseChars) + } + + resultList := make([]dto.TranslateStatisticResp, 0, 15) + currentDate := time.Now().AddDate(0, 0, -14) // 从15天前的日期开始 + for i := 0; i < 15; i++ { + dateStr := currentDate.Format("2006-01-02") + // 从 map 中获取当天的总字符数,如果 map 中没有,则默认为0 + totalChars := usageMap[dateStr] + + // 将数据添加到结果列表中 + resultList = append(resultList, dto.TranslateStatisticResp{ + TotalCount: totalChars, + Date: dateStr, + }) + // 移动到下一天 + currentDate = currentDate.AddDate(0, 0, 1) + } + + // 将生成的列表赋值给传入的指针,以便调用者获取结果 + *list = resultList + + return nil +} + +// 字符数充值 +func (e *TmMember) Recharge(req *dto.TmMemberRechargeReq, p *actions.DataPermission, userId int) error { + data := models.TmMember{} + if err := e.GetById(req.Id, &data); err != nil { + return err + } + + record := models.TmRechargeLog{} + record.UserId = data.UserId + record.MemberId = data.Id + record.CreateBy = userId + record.CreatedAt = time.Now() + record.TotalChars = req.TotalChars * 10000 + + if err := e.IncrBy(req.PlatformCode, data.ApiKey, record.TotalChars); err != nil { + e.Log.Errorf("TmMemberService Recharge IncrBy error:%s \r\n", err) + return errors.New("充值失败") + } + + if err := e.Orm.Model(record).Create(&record).Error; err != nil { + if err2 := e.DecrBy(req.PlatformCode, data.ApiKey, record.TotalChars); err2 != nil { + e.Log.Errorf("充值失败 缓存重置失败 error:%s \r\n", err2) + } + + e.Log.Errorf("TmMemberService Recharge Create error:%s \r\n", err) + return errors.New("充值失败") + } + + return nil +} + +// 获取可用字符数 +func (e *TmMember) GetRemainCount(platformKey, apiKey string) (int, error) { + key := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, apiKey, platformKey) + val, err := redishelper.DefaultRedis.GetString(key) + result := 0 + + if err != nil && !errors.Is(err, redis.Nil) { + return 0, err + } + + if val != "" { + result, err = strconv.Atoi(val) + if err != nil { + return 0, err + } + } + + if result == 0 { + var data models.TmMember + + if err := e.Orm.Model(&data).Where("api_key = ?", apiKey).First(&data).Error; err != nil { + return 0, err + } + + result = data.RemainChars + redishelper.DefaultRedis.SetString(key, strconv.Itoa(result)) + } + + return result, nil +} + +// 增加字符 +func (e *TmMember) IncrBy(platformKey, apiKey string, totalChars int) error { + remainCountKey := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, apiKey, platformKey) + + return redishelper.DefaultRedis.IncrBy(remainCountKey, int64(totalChars)).Err() +} + +// 扣除字符 +func (e *TmMember) DecrBy(platformKey, apiKey string, totalChars int) error { + remainCountKey := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, apiKey, platformKey) + + return redishelper.DefaultRedis.DecrBy(remainCountKey, int64(totalChars)).Err() +} + +// 根据id获取数据 +func (e *TmMember) GetById(id int, data *models.TmMember) error { + if err := e.Orm.Model(data).Where("id = ?", id).First(data).Error; err != nil { + return err + } + return nil +} + +// 修改翻译用户状态 +func (e TmMember) ChangeStatus(req *dto.TmMemberChangeStatusReq, p *actions.DataPermission) error { + var err error + var data = models.TmMember{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).Where("id = ?", req.Id).First(&data) + + db := e.Orm.Model(data).Update("status", req.Status) + if err = db.Error; err != nil { + e.Log.Errorf("TmMemberService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + + data.Status = req.Status + val, _ := sonic.MarshalString(data) + + if val != "" { + key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, data.ApiKey) + redishelper.DefaultRedis.SetString(key, val) + } + + return nil +} + +// 根据api key获取数据 +func (e *TmMember) GetByKey(apiKey string) (models.TmMember, error) { + key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, apiKey) + val, _ := redishelper.DefaultRedis.GetString(key) + result := models.TmMember{} + + if val != "" { + sonic.UnmarshalString(val, &result) + } + + if result.Id == 0 { + if err := e.Orm.Model(&result).Where("api_key = ?", apiKey).First(&result).Error; err != nil { + return result, err + } + } + + return result, nil +} + +// 同步插入数据 +func (e *TmMember) SyncInsert(req *dto.TmMemberSyncInsertReq, entity *models.TmMember) error { + platformService := TmPlatform{Service: e.Service} + activePlatforms, _ := platformService.GetActiveList() + TmMemberPlatforms := make([]models.TmMemberPlatform, 0) + + copier.Copy(entity, req) + + apiKey, err := utility.GenerateBase62Key(32) + + if err != nil { + return errors.New("生成apiKey失败") + } + + entity.ApiKey = apiKey + entity.CreatedAt = time.Now() + entity.Status = 1 + + if err := e.Orm.Save(entity).Error; err != nil { + return err + } + + for _, platform := range activePlatforms { + item := models.TmMemberPlatform{ + MemberId: entity.Id, + PlatformId: platform.Id, + PlatformKey: platform.Code, + Status: 1, + TotalCharacter: 10000, + RemainingCharacter: 10000, + } + + TmMemberPlatforms = append(TmMemberPlatforms, item) + } + + if err := e.Orm.Save(&TmMemberPlatforms).Error; err != nil { + return err + } + + for _, platform := range TmMemberPlatforms { + e.IncrBy(platform.PlatformKey, entity.ApiKey, platform.RemainingCharacter) + } + + return nil +} diff --git a/app/admin/service/tm_member_daily_usage.go b/app/admin/service/tm_member_daily_usage.go new file mode 100644 index 0000000..1009f54 --- /dev/null +++ b/app/admin/service/tm_member_daily_usage.go @@ -0,0 +1,180 @@ +package service + +import ( + "errors" + "time" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" +) + +type TmMemberDailyUsage struct { + service.Service +} + +// GetPage 获取TmMemberDailyUsage列表 +func (e *TmMemberDailyUsage) GetPage(c *dto.TmMemberDailyUsageGetPageReq, p *actions.DataPermission, list *[]models.TmMemberDailyUsage, count *int64) error { + var err error + var data models.TmMemberDailyUsage + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("TmMemberDailyUsageService GetPage error:%s \r\n", err) + return err + } + return nil +} + +// Get 获取TmMemberDailyUsage对象 +func (e *TmMemberDailyUsage) Get(d *dto.TmMemberDailyUsageGetReq, p *actions.DataPermission, model *models.TmMemberDailyUsage) error { + var data models.TmMemberDailyUsage + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetTmMemberDailyUsage error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建TmMemberDailyUsage对象 +func (e *TmMemberDailyUsage) Insert(c *dto.TmMemberDailyUsageInsertReq) error { + var err error + var data models.TmMemberDailyUsage + c.Generate(&data) + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("TmMemberDailyUsageService Insert error:%s \r\n", err) + return err + } + return nil +} + +// Update 修改TmMemberDailyUsage对象 +func (e *TmMemberDailyUsage) Update(c *dto.TmMemberDailyUsageUpdateReq, p *actions.DataPermission) error { + var err error + var data = models.TmMemberDailyUsage{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("TmMemberDailyUsageService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// Remove 删除TmMemberDailyUsage +func (e *TmMemberDailyUsage) Remove(d *dto.TmMemberDailyUsageDeleteReq, p *actions.DataPermission) error { + var data models.TmMemberDailyUsage + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveTmMemberDailyUsage error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} + +// 获取字符消耗折线图 +func (e *TmMemberDailyUsage) GetStatistic(userId int, resp *dto.TmMemberPlatformStatisticResp) error { + startTime := time.Now().AddDate(0, 0, -14).Format("2006-01-02") + endTime := time.Now().Format("2006-01-02") + var datas []models.TmMemberDailyUsage + platformService := TmPlatform{Service: e.Service} + activeList, _ := platformService.GetActiveList() + respDatas := []dto.TmMemberPlatformStatisticItemResp{} + defaultData := []int{} + + for i := 0; i <= 14; i++ { + date := time.Now().AddDate(0, 0, i-14).Format("2006-01-02") + + resp.XAxis = append(resp.XAxis, date) + defaultData = append(defaultData, 0) + } + + if err := e.Orm.Model(models.TmMemberDailyUsage{}). + Joins("JOIN tm_member on tm_member.id=tm_member_daily_usage.member_id"). + Where("tm_member_daily_usage.date >= ? and tm_member_daily_usage.date <= ?", startTime, endTime).Find(&datas).Error; err != nil { + e.Log.Error("获取折线图数据失败", err) + return nil + } + + if len(activeList) == 0 { + return nil + } else { + for _, platform := range activeList { + data := []int{} + for i := 0; i <= 14; i++ { + date := time.Now().AddDate(0, 0, i-14).Format("2006-01-02") + count := 0 + for _, item := range datas { + if item.Date.Format("2006-01-02") == date && item.PlatformId == platform.Id { + count += item.UseChars + } + } + data = append(data, count) + } + respDatas = append(respDatas, dto.TmMemberPlatformStatisticItemResp{ + PlatformName: platform.ShowName, + PlatformId: platform.Id, + Data: data, + }) + } + } + + //添加默认数据 + for _, item := range activeList { + add := true + for _, respItem := range respDatas { + if item.Id == respItem.PlatformId { + add = false + break + } + } + + if add { + respDatas = append(respDatas, dto.TmMemberPlatformStatisticItemResp{ + PlatformName: item.ShowName, + PlatformId: item.Id, + Data: defaultData, + }) + } + } + + resp.Data = respDatas + return nil +} diff --git a/app/admin/service/tm_member_platform.go b/app/admin/service/tm_member_platform.go new file mode 100644 index 0000000..f17c7bf --- /dev/null +++ b/app/admin/service/tm_member_platform.go @@ -0,0 +1,109 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" +) + +type TmMemberPlatform struct { + service.Service +} + +// GetPage 获取TmMemberPlatform列表 +func (e *TmMemberPlatform) GetPage(c *dto.TmMemberPlatformGetPageReq, p *actions.DataPermission, list *[]models.TmMemberPlatform, count *int64) error { + var err error + var data models.TmMemberPlatform + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("TmMemberPlatformService GetPage error:%s \r\n", err) + return err + } + return nil +} + +// Get 获取TmMemberPlatform对象 +func (e *TmMemberPlatform) Get(d *dto.TmMemberPlatformGetReq, p *actions.DataPermission, model *models.TmMemberPlatform) error { + var data models.TmMemberPlatform + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetTmMemberPlatform error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建TmMemberPlatform对象 +func (e *TmMemberPlatform) Insert(c *dto.TmMemberPlatformInsertReq) error { + var err error + var data models.TmMemberPlatform + c.Generate(&data) + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("TmMemberPlatformService Insert error:%s \r\n", err) + return err + } + return nil +} + +// Update 修改TmMemberPlatform对象 +func (e *TmMemberPlatform) Update(c *dto.TmMemberPlatformUpdateReq, p *actions.DataPermission) error { + var err error + var data = models.TmMemberPlatform{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("TmMemberPlatformService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// Remove 删除TmMemberPlatform +func (e *TmMemberPlatform) Remove(d *dto.TmMemberPlatformDeleteReq, p *actions.DataPermission) error { + var data models.TmMemberPlatform + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveTmMemberPlatform error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} diff --git a/app/admin/service/tm_platform.go b/app/admin/service/tm_platform.go new file mode 100644 index 0000000..2b421cc --- /dev/null +++ b/app/admin/service/tm_platform.go @@ -0,0 +1,236 @@ +package service + +import ( + "errors" + "fmt" + + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/sdk/service" + "github.com/go-redis/redis/v8" + "github.com/jinzhu/copier" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" + rediskey "go-admin/common/redis_key" + "go-admin/utils/redishelper" +) + +type TmPlatform struct { + service.Service +} + +// GetPage 获取TmPlatform列表 +func (e *TmPlatform) GetPage(c *dto.TmPlatformGetPageReq, p *actions.DataPermission, list *[]models.TmPlatform, count *int64) error { + var err error + var data models.TmPlatform + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("TmPlatformService GetPage error:%s \r\n", err) + return err + } + return nil +} + +// Get 获取TmPlatform对象 +func (e *TmPlatform) Get(d *dto.TmPlatformGetReq, p *actions.DataPermission, model *models.TmPlatform) error { + var data models.TmPlatform + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetTmPlatform error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建TmPlatform对象 +func (e *TmPlatform) Insert(c *dto.TmPlatformInsertReq) error { + var err error + var data models.TmPlatform + var count int64 + c.Generate(&data) + e.Orm.Model(data).Where("code = ?", c.Code).Count(&count) + + if count > 0 { + return errors.New("平台编码已存在") + } + + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("TmPlatformService Insert error:%s \r\n", err) + return err + } + + e.saveCache(&data) + return nil +} + +// Update 修改TmPlatform对象 +func (e *TmPlatform) Update(c *dto.TmPlatformUpdateReq, p *actions.DataPermission) error { + var err error + var data = models.TmPlatform{} + var count int64 + + e.Orm.Model(data).Where("code = ? and id <> ? ", c.Code, c.Id).Count(&count) + + if count > 0 { + return errors.New("平台编码已存在") + } + + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("TmPlatformService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + + e.saveCache(&data) + return nil +} + +// Remove 删除TmPlatform +func (e *TmPlatform) Remove(d *dto.TmPlatformDeleteReq, p *actions.DataPermission) error { + var data models.TmPlatform + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveTmPlatform error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + + key := fmt.Sprintf(rediskey.TM_PLATFORM_KEY, data.Code) + redishelper.DefaultRedis.DeleteString(key) + return nil +} + +func (e *TmPlatform) saveCache(data *models.TmPlatform) { + key := fmt.Sprintf(rediskey.TM_PLATFORM_KEY, data.Code) + val, _ := sonic.MarshalString(data) + + if val != "" { + redishelper.DefaultRedis.SetString(key, val) + } + + e.SaveListCache(false) +} + +// 保存json数据到redis缓存 +// init 是否是初始化 +func (e *TmPlatform) SaveListCache(init bool) []models.TmPlatform { + var list []models.TmPlatform + e.Orm.Find(&list) + items := make([]string, 0) + dataMap := make(map[string]string, 0) + + for _, listItem := range list { + if listItem.Id != 0 { + val, _ := sonic.MarshalString(listItem) + items = append(items, val) + dataMap[fmt.Sprintf(rediskey.TM_PLATFORM_KEY, listItem.Code)] = val + } + } + + for key, val := range dataMap { + redishelper.DefaultRedis.SetString(key, val) + } + + redishelper.DefaultRedis.SetListCache(rediskey.TM_PLATFORM_LIST_KEY, 0, items...) + + return list +} + +func (e *TmPlatform) GetList(datas *[]dto.TmPlatformListResp) error { + listKey := fmt.Sprintf(rediskey.TM_PLATFORM_LIST_KEY) + vals, _ := redishelper.DefaultRedis.GetAllList(listKey) + + if len(vals) == 0 { + for _, val := range vals { + item := dto.TmPlatformListResp{} + sonic.UnmarshalString(val, &item) + + if item.Id != 0 { + *datas = append(*datas, item) + } + } + } + + if len(*datas) == 0 { + entitys := e.SaveListCache(false) + + for _, entity := range entitys { + item := dto.TmPlatformListResp{} + copier.Copy(&item, &entity) + + if item.Id != 0 { + *datas = append(*datas, item) + } + } + } + + return nil +} + +// 根据key 获取翻译平台信息 +func (e *TmPlatform) GetByKey(code string) (*models.TmPlatform, error) { + key := fmt.Sprintf(rediskey.TM_PLATFORM_KEY, code) + val, err := redishelper.DefaultRedis.GetString(key) + result := models.TmPlatform{} + if err != nil && !errors.Is(err, redis.Nil) { + return nil, err + } + + if val != "" { + err = sonic.UnmarshalString(val, &result) + if err != nil { + return nil, err + } + } + + if result.Id == 0 { + e.Orm.Model(&result).Where("code = ?", code).Find(&result) + } + return &result, nil +} + +func (e *TmPlatform) GetActiveList() ([]models.TmPlatform, error) { + var list []models.TmPlatform + err := e.Orm.Model(&models.TmPlatform{}).Find(&list).Error + if err != nil { + e.Log.Errorf("db error:%s", err) + return nil, err + } + return list, nil +} diff --git a/app/admin/service/tm_platform_account.go b/app/admin/service/tm_platform_account.go new file mode 100644 index 0000000..45b0567 --- /dev/null +++ b/app/admin/service/tm_platform_account.go @@ -0,0 +1,218 @@ +package service + +import ( + "errors" + "fmt" + "strconv" + + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" + rediskey "go-admin/common/redis_key" + "go-admin/utils/redishelper" +) + +type TmPlatformAccount struct { + service.Service +} + +// GetPage 获取TmPlatformAccount列表 +func (e *TmPlatformAccount) GetPage(c *dto.TmPlatformAccountGetPageReq, p *actions.DataPermission, list *[]models.TmPlatformAccount, count *int64) error { + var err error + var data models.TmPlatformAccount + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("TmPlatformAccountService GetPage error:%s \r\n", err) + return err + } + return nil +} + +// Get 获取TmPlatformAccount对象 +func (e *TmPlatformAccount) Get(d *dto.TmPlatformAccountGetReq, p *actions.DataPermission, model *models.TmPlatformAccount) error { + var data models.TmPlatformAccount + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetTmPlatformAccount error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建TmPlatformAccount对象 +func (e *TmPlatformAccount) Insert(c *dto.TmPlatformAccountInsertReq) error { + var err error + var data models.TmPlatformAccount + platform := models.TmPlatform{} + + if err := e.Orm.Model(platform).Where("id = ?", c.PlatformId).First(&platform).Error; err != nil { + return err + } + + c.Generate(&data) + data.PlatformKey = platform.Code + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("TmPlatformAccountService Insert error:%s \r\n", err) + return err + } + + e.SaveCache(data.PlatformKey, false) + return nil +} + +// Update 修改TmPlatformAccount对象 +func (e *TmPlatformAccount) Update(c *dto.TmPlatformAccountUpdateReq, p *actions.DataPermission) error { + var err error + var data = models.TmPlatformAccount{} + platform := models.TmPlatform{} + + if err := e.Orm.Model(platform).Where("id = ?", c.PlatformId).First(&platform).Error; err != nil { + return err + } + + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + data.PlatformKey = platform.Code + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("TmPlatformAccountService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + + e.SaveCache(data.PlatformKey, false) + return nil +} + +// Remove 删除TmPlatformAccount +func (e *TmPlatformAccount) Remove(d *dto.TmPlatformAccountDeleteReq, p *actions.DataPermission) error { + var data models.TmPlatformAccount + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveTmPlatformAccount error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + + redishelper.DefaultRedis.DeleteString(fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, data.PlatformKey)) + return nil +} + +// 保存缓存 +func (e *TmPlatformAccount) SaveCache(platformKey string, cacheAll bool) { + var list []models.TmPlatformAccount + cacheList := map[string][]string{} + e.Orm.Model(&models.TmPlatformAccount{}).Where("status =1").Find(&list) + platformService := TmPlatform{} + + for _, item := range list { + if cacheAll || (item.Status == 1 && item.PlatformKey == platformKey) { + platform, err := platformService.GetByKey(item.PlatformKey) + + if platform == nil || platform.Id == 0 { + e.Log.Errorf("获取翻译平台消息失败 %v", err) + return + } + + val, _ := sonic.MarshalString(item) + configs := map[string]interface{}{} + configs[item.PlatformKey] = map[string]interface{}{ + "apiKey": item.ApiKey, + "apiSecret": item.ApiSecret, + "endpoint": platform.ApiBaseUrl, + } + cfg := TranslatorServiceConfig{ + DefaultProvider: item.PlatformKey, + ProviderConfigs: configs, + } + translator, err := NewTranslatorService(&cfg) + + if err != nil { + continue + } + + if val != "" { + cacheList[item.PlatformKey] = append(cacheList[item.PlatformKey], val) + } + + remainKey := fmt.Sprintf(rediskey.TM_PLATEFORM_ACCOUNT_REMAIN_KEY, item.PlatformKey, item.ApiKey) + remainCount, err := translator.providers[item.PlatformKey].GetRemainCount() + + if err != nil { + continue + } + + redishelper.DefaultRedis.SetString(remainKey, strconv.Itoa(remainCount)) + + } + } + + for platformKey, item := range cacheList { + key := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, platformKey) + + if cacheAll { + redishelper.DefaultRedis.SetListCache(key, 0, item...) + } else { + redishelper.DefaultRedis.RPushList(key, item...) + } + } +} + +// 获取平台账号剩余字符数 +func (e *TmPlatformAccount) GetRemainCount(platformCode string, accountApiKey string) (int, error) { + key := fmt.Sprintf(rediskey.TM_PLATEFORM_ACCOUNT_REMAIN_KEY, platformCode, accountApiKey) + val, err := redishelper.DefaultRedis.GetString(key) + + if err != nil { + return 0, err + } + + return strconv.Atoi(val) +} + +// 扣除api剩余字符 +func (e *TmPlatformAccount) DecrRemainBy(platformCode string, accountApiKey string, count int) error { + key := fmt.Sprintf(rediskey.TM_PLATEFORM_ACCOUNT_REMAIN_KEY, platformCode, accountApiKey) + + if err := redishelper.DefaultRedis.DecrBy(key, int64(count)).Err(); err != nil { + e.Log.Errorf("翻译平台扣除字符失败 key: %s err:%v", key, err) + return err + } + + return nil +} diff --git a/app/admin/service/translator_deepl.go b/app/admin/service/translator_deepl.go new file mode 100644 index 0000000..ade3570 --- /dev/null +++ b/app/admin/service/translator_deepl.go @@ -0,0 +1,109 @@ +package service + +import ( + "fmt" + "go-admin/app/admin/service/dto" + "go-admin/utils/httphelper" + "strings" + "time" +) + +type DeeplTranslatorConfig struct { + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` + Endpoint string `json:"endpoint"` +} + +// deepl 或deepl pro 翻译器 +type DeeplTranslator struct { + config *DeeplTranslatorConfig + client *httphelper.HTTPClient +} + +type deeplTranslationResponse struct { + Translations []struct { + DetectedSourceLanguage string `json:"detected_source_language"` + Text string `json:"text"` + } `json:"translations"` +} + +// 定义 Deepl 获取使用量 API 的响应结构 +type deeplUsageResponse struct { + CharacterCount int `json:"character_count"` + CharacterLimit int `json:"character_limit"` + TeamCharacterLimit int `json:"team_character_limit,omitempty"` // for Team accounts +} + +// 初始化适配器实例 +func NewDeeplTranslator(config *DeeplTranslatorConfig) *DeeplTranslator { + defaultHeaders := map[string]string{ + "Content-Type": "application/json", + } + + httpClient := httphelper.NewHTTPClient( + 15*time.Second, + config.Endpoint, + defaultHeaders, + ) + + return &DeeplTranslator{ + config: config, + client: httpClient, + } +} + +// deepl 翻译函数 +func (e *DeeplTranslator) Translate(text string, sourceLang, targetLang string) (*dto.TranslateResult, error) { + result := dto.TranslateResult{} + requestBody := map[string]interface{}{ + "text": []string{text}, + "target_lang": targetLang, + } + headers := map[string]string{ + "Authorization": fmt.Sprintf("DeepL-Auth-Key %s", e.config.ApiKey), + "Content-Type": "application/json", + } + if sourceLang != "" || strings.ToLower(sourceLang) == "auto" { + requestBody["source_lang"] = "" + } + + var responseData deeplTranslationResponse + + // Deepl API 翻译通常是 POST 请求到 /v2/translate + err := e.client.Post("/v2/translate", requestBody, headers, &responseData) + if err != nil { + return &result, fmt.Errorf("deepl translate request failed: %w", err) + } + + if len(responseData.Translations) > 0 { + result.TranslatedText = responseData.Translations[0].Text + result.SourceLanguage = sourceLang + result.TargetLanguage = targetLang + } + return &result, nil +} + +func (e *DeeplTranslator) GetRemainCount() (int, error) { + path := "/v2/usage" + headers := map[string]string{ + "Authorization": fmt.Sprintf("DeepL-Auth-Key %s", e.config.ApiKey), + "Content-Type": "application/json", + } + + var responseData deeplUsageResponse + err := e.client.Get(path, headers, &responseData) // GET 请求通常没有请求体 + if err != nil { + return 0, fmt.Errorf("deepl usage request failed: %w", err) + } + + // 返回剩余字符数 (假设 DeepL 返回已用字符数和限制,我们需要计算剩余) + // 根据 DeepL 文档,它通常返回 character_count 和 character_limit + remain := responseData.CharacterLimit - responseData.CharacterCount + + return remain, nil +} + +// 获取适配器名称 +func (e *DeeplTranslator) GetPlatform() string { + return "deepl" +} diff --git a/app/admin/service/translator_deepseek.go b/app/admin/service/translator_deepseek.go new file mode 100644 index 0000000..f6b11be --- /dev/null +++ b/app/admin/service/translator_deepseek.go @@ -0,0 +1,107 @@ +package service + +import ( + "bytes" + "encoding/json" + "fmt" + "go-admin/app/admin/service/dto" + "go-admin/utils/httphelper" + "io/ioutil" + "net/http" + "time" +) + +type DeepseekTranslatorConfig struct { + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` + Endpoint string `json:"endpoint"` +} + +type DeepSeekTranslator struct { + config *DeepseekTranslatorConfig + client *httphelper.HTTPClient +} + +// 初始化适配器实例 +func NewDeepseekTranslator(config *DeepseekTranslatorConfig) *DeepSeekTranslator { + defaultHeaders := map[string]string{ + "Content-Type": "application/json", + } + + httpClient := httphelper.NewHTTPClient( + 15*time.Second, + config.Endpoint, + defaultHeaders, + ) + + return &DeepSeekTranslator{ + config: config, + client: httpClient, + } +} + +// 翻译 +func (e *DeepSeekTranslator) Translate(text string, source string, target string) (*dto.TranslateResult, error) { + // TODO: 实现Deepseek API调用 + result := dto.TranslateResult{} + reqBody := dto.DeepseekTranslateRequest{ + Model: "deepseek-v3-fast", // v3 fast模型 + Stream: false, + Messages: []dto.Message{ + {Role: "system", Content: fmt.Sprintf("你是翻译大师,请只将用户输入从%s翻译为%s,仅返回翻译后的文本", source, target)}, + {Role: "user", Content: text}, + }, + } + + data, err := json.Marshal(reqBody) + if err != nil { + return &result, err + } + + req, err := http.NewRequest("POST", e.config.Endpoint, bytes.NewBuffer(data)) + if err != nil { + return &result, err + } + + req.Header.Set("Authorization", "Bearer "+e.config.ApiKey) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Do(req) + if err != nil { + return &result, err + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode != 200 { + return &result, fmt.Errorf("DeepSeek error: %s", string(body)) + } + + var dsResp dto.DeepSeekResponse + err = json.Unmarshal(body, &dsResp) + if err != nil { + return &result, err + } + + if len(dsResp.Choices) == 0 { + return &result, fmt.Errorf("no translation result from DeepSeek") + } + + result.TranslatedText = dsResp.Choices[0].Message.Content + result.SourceLanguage = source + result.TargetLanguage = target + + return &result, nil +} + +func (e *DeepSeekTranslator) GetRemainCount() (int, error) { + // TODO: 实现Deepseek API调用 + + return 0, nil +} + +// 返回服务商 +func (e *DeepSeekTranslator) GetPlatform() string { + return "deepseek" +} diff --git a/app/admin/service/translator_deepseek_test.go b/app/admin/service/translator_deepseek_test.go new file mode 100644 index 0000000..3c8e839 --- /dev/null +++ b/app/admin/service/translator_deepseek_test.go @@ -0,0 +1,33 @@ +package service + +import ( + "fmt" + "testing" +) + +func TestDeepSeekTranslator(t *testing.T) { + config := TranslatorServiceConfig{ + DefaultProvider: "deepseek", + ProviderConfigs: map[string]interface{}{ + "deepseek": map[string]interface{}{ + "apiKey": "sk-KlaHS7PtYhuBNLpAG7iNAjs0YQ8JH7plqJxv4dLCwW16xV8x", + "endpoint": "https://api.just2chat.cn/v1/chat/completions", + }, + }, + } + + service, err := NewTranslatorService(&config) + + if err != nil { + fmt.Sprintln("报错:", err) + return + } + + result, err := service.providers["deepseek"].Translate("我想翻译内容", "zh", "fr") + + if err != nil { + fmt.Sprintln("报错:", err) + return + } + fmt.Println(result) +} diff --git a/app/admin/service/translator_google.go b/app/admin/service/translator_google.go new file mode 100644 index 0000000..3fb66a0 --- /dev/null +++ b/app/admin/service/translator_google.go @@ -0,0 +1,51 @@ +package service + +import ( + "go-admin/app/admin/service/dto" + "go-admin/utils/httphelper" + "time" +) + +type GoogleTranslator struct { + config *GoogleTranslatorConfig + client *httphelper.HTTPClient +} + +type GoogleTranslatorConfig struct { + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` + Endpoint string `json:"endpoint"` +} + +func NewGoogleTranslator(config *GoogleTranslatorConfig) *GoogleTranslator { + defaultHeaders := map[string]string{ + "Content-Type": "application/json", + } + + httpClient := httphelper.NewHTTPClient( + 15*time.Second, + config.Endpoint, + defaultHeaders, + ) + + return &GoogleTranslator{ + config: config, + client: httpClient, + } +} + +// 翻译 +func (t *GoogleTranslator) Translate(text string, sourceLang, targetLang string) (*dto.TranslateResult, error) { + return &dto.TranslateResult{}, nil +} + +func (t *GoogleTranslator) GetRemainCount() (int, error) { + //todo 实现获取剩余调用次数 + + return 0, nil +} + +// 获取服务商 +func (t *GoogleTranslator) GetPlatform() string { + return "google" +} diff --git a/app/admin/service/translator_interface.go b/app/admin/service/translator_interface.go new file mode 100644 index 0000000..536b033 --- /dev/null +++ b/app/admin/service/translator_interface.go @@ -0,0 +1,20 @@ +package service + +import "go-admin/app/admin/service/dto" + +//翻译接口 +type Translator interface { + // Translate 执行翻译操作 + // ctx: 上下文,用于超时、取消等控制 + // text: 待翻译的文本 + // sourceLang: 源语言(ISO 639-1 标准,如 "en", "zh") + // targetLang: 目标语言(ISO 639-1 标准) + // 返回 TranslationResult 和错误 + Translate(text, from, to string) (*dto.TranslateResult, error) + + //获取剩余字符数 + GetRemainCount() (int, error) + + // GetServiceName 返回服务商名称 + GetPlatform() string +} diff --git a/app/admin/service/translator_service.go b/app/admin/service/translator_service.go new file mode 100644 index 0000000..b0ced86 --- /dev/null +++ b/app/admin/service/translator_service.go @@ -0,0 +1,277 @@ +package service + +import ( + "encoding/json" + "fmt" + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/mq" + rediskey "go-admin/common/redis_key" + "go-admin/common/statuscode" + "go-admin/utils/redishelper" + "time" + "unicode/utf8" + + commonDto "go-admin/common/dto" + + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/service" + "github.com/pkg/errors" +) + +type TranslatorServiceConfig struct { + DefaultProvider string // 默认翻译服务商 + ProviderConfigs map[string]interface{} // 各个服务商的具体配置 +} + +type TranslatorService struct { + service.Service + config *TranslatorServiceConfig + providers map[string]Translator // 注册的翻译服务商适配器 + // cache cache.Cache // 缓存服务 +} + +type TranslatorToolService struct { + service.Service +} + +// NewTranslatorService 创建翻译服务实例 +func NewTranslatorService(cfg *TranslatorServiceConfig) (*TranslatorService, error) { + svc := &TranslatorService{ + config: cfg, + // cache: c, + providers: make(map[string]Translator), + } + + // 根据配置初始化并注册翻译服务商适配器 + for providerName, providerCfg := range cfg.ProviderConfigs { + var newAdapter Translator + switch providerName { + case "google": + googleCfgBytes, _ := json.Marshal(providerCfg) // 假设配置是map[string]interface{},需要转换 + var googleCfg GoogleTranslatorConfig + if err := json.Unmarshal(googleCfgBytes, &googleCfg); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal config for GoogleTranslate") + } + newAdapter = NewGoogleTranslator(&googleCfg) + // case "BaiduTranslate": + // // newAdapter = adapter.NewBaiduTranslator(...) + case "deepseek": + deepseekCfgBytes, _ := json.Marshal(providerCfg) // 假设配置是map[string]interface{},需要转换 + var deepseekCfg DeepseekTranslatorConfig + if err := json.Unmarshal(deepseekCfgBytes, &deepseekCfg); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal config for DeepseekTranslator") + } + newAdapter = NewDeepseekTranslator(&deepseekCfg) + case "deepl", "deepl_free": + deeplCfgBytes, _ := json.Marshal(providerCfg) // 假设配置是map[string]interface{},需要转换 + var deeplCfg DeeplTranslatorConfig + if err := json.Unmarshal(deeplCfgBytes, &deeplCfg); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal config for DeepLTranslator") + } + newAdapter = NewDeeplTranslator(&deeplCfg) + default: + return nil, errors.Errorf("unsupported translation provider: %s", providerName) + } + svc.RegisterProvider(providerName, newAdapter) + } + + if len(svc.providers) == 0 { + return nil, errors.New("no translation providers registered") + } + + return svc, nil +} + +// RegisterProvider 注册翻译服务商适配器 +func (s *TranslatorService) RegisterProvider(name string, provider Translator) { + // s.providerMutex.Lock() + // defer s.providerMutex.Unlock() + s.providers[name] = provider + logger.Infof("Registered translation provider: %s", name) +} + +// 翻译校验 +// return statusCode +func (s *TranslatorService) TranslateJudge(req *dto.TranslateReq, apiKey string) (result *dto.TranslateResult, respCode int) { + tmMemberService := TmMember{Service: s.Service} + tmPlatformAccount := TmPlatformAccount{Service: s.Service} + memberInfo, err1 := tmMemberService.GetByKey(apiKey) + + if err1 != nil { + s.Log.Errorf("获取用户信息失败:%v", err1) + respCode = statuscode.ServerError + return + } + + if memberInfo.Status == 2 { + respCode = statuscode.ApiUnauthorized + return + } + + remainCount, _ := tmMemberService.GetRemainCount(req.Platform, apiKey) + count := utf8.RuneCountInString(req.Text) + respCode = statuscode.Success + + if remainCount < count { + respCode = statuscode.InSufficRemainChar + return + } + + Translator, code := s.GetTranslator(req.Platform) + + if code != statuscode.Success { + respCode = code + return + } + + result, err := Translator.providers[req.Platform].Translate(req.Text, req.SourceLang, req.TargetLang) + + if err == nil { + err2 := tmMemberService.DecrBy(req.Platform, apiKey, count) + + if err2 != nil { + s.Log.Errorf("翻译计数失败:%v", err2) + respCode = statuscode.ServerError + return + } + + platformConfigInterface := Translator.config.ProviderConfigs[req.Platform] + + // 尝试将 interface{} 断言为 map[string]interface{} + if mapData, ok := platformConfigInterface.(map[string]interface{}); !ok { + tmPlatformAccount.DecrRemainBy(req.Platform, mapData["apiKey"].(string), count) + } + + date := time.Now().Format("20060102") + redishelper.DefaultRedis.IncrBy(fmt.Sprintf(rediskey.TM_MEMBER_DAILY_COUNT, date, apiKey, req.Platform), int64(count)) + //每日统计保留三天 + redishelper.DefaultRedis.Expire(fmt.Sprintf(rediskey.TM_MEMBER_DAILY_COUNT, date, apiKey, req.Platform), 3*24*time.Hour) + } else { + code = statuscode.ServerError + } + + return +} + +func (s *TranslatorService) GetTranslator(platform string) (translator *TranslatorService, code int) { + platformKey := fmt.Sprintf(rediskey.TM_PLATFORM_KEY, platform) + platformVal, _ := redishelper.DefaultRedis.GetString(platformKey) + + if platformVal == "" { + code = statuscode.PlatformNotSupport + return + } + + var platformEntity models.TmPlatform + account, err := s.GetNextAccount(platform) + + if err != nil { + s.Log.Errorf("获取翻译api失败:%v", err) + } + + sonic.UnmarshalString(platformVal, &platformEntity) + + if account.Id == 0 || account.Status == 2 { + code = statuscode.TransactionNotAvailable + return + } + + configs := map[string]interface{}{} + configs[platform] = map[string]interface{}{ + "apiKey": account.ApiKey, + "apiSecret": account.ApiSecret, + "endpoint": platformEntity.ApiBaseUrl, + } + cfg := TranslatorServiceConfig{ + DefaultProvider: platform, + ProviderConfigs: configs, + } + + switch platform { + case "deepl", "deepl_free", "deepseek": + translator, err = NewTranslatorService(&cfg) + + if err != nil { + s.Log.Errorf("failed to create translator service: %s", err) + code = statuscode.ServerError + return + } + + code = statuscode.Success + return + default: + code = statuscode.PlatformNotSupport + return + } +} + +// 从 Redis List 顺序取出一个账号,使用后放回队尾,模拟轮询 +func (s *TranslatorService) GetNextAccount(platformCode string) (*models.TmPlatformAccount, error) { + var val string + var err error + var remain int + key := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, platformCode) + + retries := []time.Duration{100 * time.Millisecond, 200 * time.Millisecond, 300 * time.Millisecond} + + defer func() { + if val != "" { + if remain > 0 { + // 放回队尾,继续轮询机制 + if err := redishelper.DefaultRedis.RPushList(key, val); err != nil { + s.Log.Errorf("failed to push account back to queue: %v", err) + } + } + } + }() + + // 尝试从 Redis 队列中弹出账号 ID,带重试机制 + for _, delay := range retries { + val, err = redishelper.DefaultRedis.LPopList(key) + if err == nil { + // 成功获取到值,跳出重试循环 + break + } + + time.Sleep(delay) + } + + // 如果所有重试都失败了,并且不是因为队列为空 + if err != nil { + return nil, errors.New("failed to get account from queue after multiple retries: " + err.Error()) + } + + accountService := TmPlatformAccount{Service: s.Service} + account := models.TmPlatformAccount{} + sonic.UnmarshalString(val, &account) + + switch platformCode { + case "deepseek": + remain = 999999 + default: + remain, _ = accountService.GetRemainCount(platformCode, account.ApiKey) + } + + // 如果剩余字符数 <= 0,跳过该账号,不放回队列,并更新数据库状态 + if remain <= 0 { + event := commonDto.ExhaustedAccountMessage{ + Id: account.Id, + Platform: platformCode, + } + payload, _ := sonic.Marshal(event) + err = mq.MQ.Publish( // default exchange + "account_exhausted_queue", + payload, + ) + + if err != nil { + s.Log.Errorf("发送账号耗尽通知失败:%v", err) + } + + return nil, errors.New("account exhausted and removed from queue") + } + + return &account, nil +} diff --git a/app/jobs/apis/sys_job.go b/app/jobs/apis/sys_job.go new file mode 100644 index 0000000..296138d --- /dev/null +++ b/app/jobs/apis/sys_job.go @@ -0,0 +1,69 @@ +package apis + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/api" + + "go-admin/app/jobs/service" + "go-admin/common/dto" +) + +type SysJob struct { + api.Api +} + +// RemoveJobForService 调用service实现 +func (e SysJob) RemoveJobForService(c *gin.Context) { + v := dto.GeneralDelDto{} + s := service.SysJob{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&v). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + return + } + + s.Cron = sdk.Runtime.GetCrontabKey(c.Request.Host) + err = s.RemoveJob(&v) + if err != nil { + e.Logger.Errorf("RemoveJob error, %s", err.Error()) + e.Error(500, err, "") + return + } + e.OK(nil, s.Msg) +} + +// StartJobForService 启动job service实现 +func (e SysJob) StartJobForService(c *gin.Context) { + e.MakeContext(c) + log := e.GetLogger() + db, err := e.GetOrm() + if err != nil { + log.Error(err) + return + } + var v dto.GeneralGetDto + err = c.BindUri(&v) + if err != nil { + log.Warnf("参数验证错误, error: %s", err) + e.Error(http.StatusUnprocessableEntity, err, "参数验证失败") + return + } + s := service.SysJob{} + s.Orm = db + s.Log = log + s.Cron = sdk.Runtime.GetCrontabKey(c.Request.Host) + err = s.StartJob(&v) + if err != nil { + log.Errorf("GetCrontabKey error, %s", err.Error()) + e.Error(500, err, err.Error()) + return + } + e.OK(nil, s.Msg) +} diff --git a/app/jobs/examples.go b/app/jobs/examples.go new file mode 100644 index 0000000..d42e1db --- /dev/null +++ b/app/jobs/examples.go @@ -0,0 +1,42 @@ +package jobs + +import ( + "fmt" + "time" +) + +// InitJob +// 需要将定义的struct 添加到字典中; +// 字典 key 可以配置到 自动任务 调用目标 中; +func InitJob() { + jobList = map[string]JobExec{ + "ExamplesOne": ExamplesOne{}, + "DailyJob": DailyJob{}, + "RemainCharJob": RemainCharJob{}, + // ... + } +} + +// ExamplesOne +// 新添加的job 必须按照以下格式定义,并实现Exec函数 +type ExamplesOne struct { +} + +func (t ExamplesOne) Exec(arg interface{}) error { + str := time.Now().Format(timeFormat) + " [INFO] JobCore ExamplesOne exec success" + // TODO: 这里需要注意 Examples 传入参数是 string 所以 arg.(string);请根据对应的类型进行转化; + switch arg.(type) { + + case string: + if arg.(string) != "" { + fmt.Println("string", arg.(string)) + fmt.Println(str, arg.(string)) + } else { + fmt.Println("arg is nil") + fmt.Println(str, "arg is nil") + } + break + } + + return nil +} diff --git a/app/jobs/jobbase.go b/app/jobs/jobbase.go new file mode 100644 index 0000000..5993b3c --- /dev/null +++ b/app/jobs/jobbase.go @@ -0,0 +1,203 @@ +package jobs + +import ( + "fmt" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + models2 "go-admin/app/jobs/models" + "gorm.io/gorm" + "time" + + "github.com/robfig/cron/v3" + + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/cronjob" +) + +var timeFormat = "2006-01-02 15:04:05" +var retryCount = 3 + +var jobList map[string]JobExec + +//var lock sync.Mutex + +type JobCore struct { + InvokeTarget string + Name string + JobId int + EntryId int + CronExpression string + Args string +} + +// HttpJob 任务类型 http +type HttpJob struct { + JobCore +} + +type ExecJob struct { + JobCore +} + +func (e *ExecJob) Run() { + startTime := time.Now() + var obj = jobList[e.InvokeTarget] + if obj == nil { + log.Warn("[Job] ExecJob Run job nil") + return + } + err := CallExec(obj.(JobExec), e.Args) + if err != nil { + // 如果失败暂停一段时间重试 + fmt.Println(time.Now().Format(timeFormat), " [ERROR] mission failed! ", err) + } + // 结束时间 + endTime := time.Now() + + // 执行时间 + latencyTime := endTime.Sub(startTime) + //TODO: 待完善部分 + //str := time.Now().Format(timeFormat) + " [INFO] JobCore " + string(e.EntryId) + "exec success , spend :" + latencyTime.String() + //ws.SendAll(str) + log.Info("[Job] JobCore %s exec success , spend :%v", e.Name, latencyTime) + return +} + +// Run http 任务接口 +func (h *HttpJob) Run() { + + startTime := time.Now() + var count = 0 + var err error + var str string + /* 循环 */ +LOOP: + if count < retryCount { + /* 跳过迭代 */ + str, err = pkg.Get(h.InvokeTarget) + if err != nil { + // 如果失败暂停一段时间重试 + fmt.Println(time.Now().Format(timeFormat), " [ERROR] mission failed! ", err) + fmt.Printf(time.Now().Format(timeFormat)+" [INFO] Retry after the task fails %d seconds! %s \n", (count+1)*5, str) + time.Sleep(time.Duration(count+1) * 5 * time.Second) + count = count + 1 + goto LOOP + } + } + // 结束时间 + endTime := time.Now() + + // 执行时间 + latencyTime := endTime.Sub(startTime) + //TODO: 待完善部分 + + log.Infof("[Job] JobCore %s exec success , spend :%v", h.Name, latencyTime) + return +} + +// Setup 初始化 +func Setup(dbs map[string]*gorm.DB) { + + fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore Starting...") + + for k, db := range dbs { + sdk.Runtime.SetCrontab(k, cronjob.NewWithSeconds()) + setup(k, db) + } +} + +func setup(key string, db *gorm.DB) { + crontab := sdk.Runtime.GetCrontabKey(key) + sysJob := models2.SysJob{} + jobList := make([]models2.SysJob, 0) + err := sysJob.GetList(db, &jobList) + if err != nil { + fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore init error", err) + } + if len(jobList) == 0 { + fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore total:0") + } + + _, err = sysJob.RemoveAllEntryID(db) + if err != nil { + fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore remove entry_id error", err) + } + + for i := 0; i < len(jobList); i++ { + if jobList[i].JobType == 1 { + j := &HttpJob{} + j.InvokeTarget = jobList[i].InvokeTarget + j.CronExpression = jobList[i].CronExpression + j.JobId = jobList[i].JobId + j.Name = jobList[i].JobName + + sysJob.EntryId, err = AddJob(crontab, j) + } else if jobList[i].JobType == 2 { + j := &ExecJob{} + j.InvokeTarget = jobList[i].InvokeTarget + j.CronExpression = jobList[i].CronExpression + j.JobId = jobList[i].JobId + j.Name = jobList[i].JobName + j.Args = jobList[i].Args + sysJob.EntryId, err = AddJob(crontab, j) + } + err = sysJob.Update(db, jobList[i].JobId) + } + + // 其中任务 + crontab.Start() + fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore start success.") + // 关闭任务 + defer crontab.Stop() + select {} +} + +// AddJob 添加任务 AddJob(invokeTarget string, jobId int, jobName string, cronExpression string) +func AddJob(c *cron.Cron, job Job) (int, error) { + if job == nil { + fmt.Println("unknown") + return 0, nil + } + return job.addJob(c) +} + +func (h *HttpJob) addJob(c *cron.Cron) (int, error) { + id, err := c.AddJob(h.CronExpression, h) + if err != nil { + fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore AddJob error", err) + return 0, err + } + EntryId := int(id) + return EntryId, nil +} + +func (e *ExecJob) addJob(c *cron.Cron) (int, error) { + id, err := c.AddJob(e.CronExpression, e) + if err != nil { + fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore AddJob error", err) + return 0, err + } + EntryId := int(id) + return EntryId, nil +} + +// Remove 移除任务 +func Remove(c *cron.Cron, entryID int) chan bool { + ch := make(chan bool) + go func() { + c.Remove(cron.EntryID(entryID)) + fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore Remove success ,info entryID :", entryID) + ch <- true + }() + return ch +} + +// 任务停止 +//func Stop() chan bool { +// ch := make(chan bool) +// go func() { +// global.GADMCron.Stop() +// ch <- true +// }() +// return ch +//} diff --git a/app/jobs/models/sys_job.go b/app/jobs/models/sys_job.go new file mode 100644 index 0000000..a8cc6bf --- /dev/null +++ b/app/jobs/models/sys_job.go @@ -0,0 +1,61 @@ +package models + +import ( + "go-admin/common/models" + "gorm.io/gorm" +) + +type SysJob struct { + JobId int `json:"jobId" gorm:"primaryKey;autoIncrement"` // 编码 + JobName string `json:"jobName" gorm:"size:255;"` // 名称 + JobGroup string `json:"jobGroup" gorm:"size:255;"` // 任务分组 + JobType int `json:"jobType" gorm:"size:1;"` // 任务类型 + CronExpression string `json:"cronExpression" gorm:"size:255;"` // cron表达式 + InvokeTarget string `json:"invokeTarget" gorm:"size:255;"` // 调用目标 + Args string `json:"args" gorm:"size:255;"` // 目标参数 + MisfirePolicy int `json:"misfirePolicy" gorm:"size:255;"` // 执行策略 + Concurrent int `json:"concurrent" gorm:"size:1;"` // 是否并发 + Status int `json:"status" gorm:"size:1;"` // 状态 + EntryId int `json:"entry_id" gorm:"size:11;"` // job启动时返回的id + models.ControlBy + models.ModelTime + + DataScope string `json:"dataScope" gorm:"-"` +} + +func (*SysJob) TableName() string { + return "sys_job" +} + +func (e *SysJob) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SysJob) GetId() interface{} { + return e.JobId +} + +func (e *SysJob) SetCreateBy(createBy int) { + e.CreateBy = createBy +} + +func (e *SysJob) SetUpdateBy(updateBy int) { + e.UpdateBy = updateBy +} + +func (e *SysJob) GetList(tx *gorm.DB, list interface{}) (err error) { + return tx.Table(e.TableName()).Where("status = ?", 2).Find(list).Error +} + +// Update 更新SysJob +func (e *SysJob) Update(tx *gorm.DB, id interface{}) (err error) { + return tx.Table(e.TableName()).Where(id).Updates(&e).Error +} + +func (e *SysJob) RemoveAllEntryID(tx *gorm.DB) (update SysJob, err error) { + if err = tx.Table(e.TableName()).Where("entry_id > ?", 0).Update("entry_id", 0).Error; err != nil { + return + } + return +} diff --git a/app/jobs/router/int_router.go b/app/jobs/router/int_router.go new file mode 100644 index 0000000..ab65faa --- /dev/null +++ b/app/jobs/router/int_router.go @@ -0,0 +1,36 @@ +package router + +import ( + //"github.com/go-admin-team/go-admin-core/sdk/pkg" + "os" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + common "go-admin/common/middleware" +) + +// InitRouter 路由初始化,不要怀疑,这里用到了 +func InitRouter() { + var r *gin.Engine + h := sdk.Runtime.GetEngine() + if h == nil { + log.Fatal("not found engine...") + os.Exit(-1) + } + switch h.(type) { + case *gin.Engine: + r = h.(*gin.Engine) + default: + log.Fatal("not support other engine") + os.Exit(-1) + } + + authMiddleware, err := common.AuthInit() + if err != nil { + log.Fatalf("JWT Init Error, %s", err.Error()) + } + + // 注册业务路由 + initRouter(r, authMiddleware) +} diff --git a/app/jobs/router/router.go b/app/jobs/router/router.go new file mode 100644 index 0000000..8c893a2 --- /dev/null +++ b/app/jobs/router/router.go @@ -0,0 +1,42 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" +) + +var ( + routerNoCheckRole = make([]func(*gin.RouterGroup), 0) + routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0) +) + +// initRouter 路由示例 +func initRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine { + + // 无需认证的路由 + noCheckRoleRouter(r) + // 需要认证的路由 + checkRoleRouter(r, authMiddleware) + + return r +} + +// noCheckRoleRouter 无需认证的路由示例 +func noCheckRoleRouter(r *gin.Engine) { + // 可根据业务需求来设置接口版本 + v1 := r.Group("/api/v1") + + for _, f := range routerNoCheckRole { + f(v1) + } +} + +// checkRoleRouter 需要认证的路由示例 +func checkRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) { + // 可根据业务需求来设置接口版本 + v1 := r.Group("/api/v1") + + for _, f := range routerCheckRole { + f(v1, authMiddleware) + } +} diff --git a/app/jobs/router/sys_job.go b/app/jobs/router/sys_job.go new file mode 100644 index 0000000..89723d4 --- /dev/null +++ b/app/jobs/router/sys_job.go @@ -0,0 +1,38 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/jobs/apis" + models2 "go-admin/app/jobs/models" + dto2 "go-admin/app/jobs/service/dto" + "go-admin/common/actions" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysJobRouter) +} + +// 需认证的路由代码 +func registerSysJobRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + + r := v1.Group("/sysjob").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + sysJob := &models2.SysJob{} + r.GET("", actions.PermissionAction(), actions.IndexAction(sysJob, new(dto2.SysJobSearch), func() interface{} { + list := make([]models2.SysJob, 0) + return &list + })) + r.GET("/:id", actions.PermissionAction(), actions.ViewAction(new(dto2.SysJobById), func() interface{} { + return &dto2.SysJobItem{} + })) + r.POST("", actions.CreateAction(new(dto2.SysJobControl))) + r.PUT("", actions.PermissionAction(), actions.UpdateAction(new(dto2.SysJobControl))) + r.DELETE("", actions.PermissionAction(), actions.DeleteAction(new(dto2.SysJobById))) + } + sysJob := apis.SysJob{} + + v1.GET("/job/remove/:id", sysJob.RemoveJobForService) + v1.GET("/job/start/:id", sysJob.StartJobForService) +} diff --git a/app/jobs/service/dto/sys_job.go b/app/jobs/service/dto/sys_job.go new file mode 100644 index 0000000..c66bcbd --- /dev/null +++ b/app/jobs/service/dto/sys_job.go @@ -0,0 +1,108 @@ +package dto + +import ( + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "go-admin/app/jobs/models" + + "go-admin/common/dto" + common "go-admin/common/models" +) + +type SysJobSearch struct { + dto.Pagination `search:"-"` + JobId int `form:"jobId" search:"type:exact;column:job_id;table:sys_job"` + JobName string `form:"jobName" search:"type:icontains;column:job_name;table:sys_job"` + JobGroup string `form:"jobGroup" search:"type:exact;column:job_group;table:sys_job"` + CronExpression string `form:"cronExpression" search:"type:exact;column:cron_expression;table:sys_job"` + InvokeTarget string `form:"invokeTarget" search:"type:exact;column:invoke_target;table:sys_job"` + Status int `form:"status" search:"type:exact;column:status;table:sys_job"` +} + +func (m *SysJobSearch) GetNeedSearch() interface{} { + return *m +} + +func (m *SysJobSearch) Bind(ctx *gin.Context) error { + log := api.GetRequestLogger(ctx) + err := ctx.ShouldBind(m) + if err != nil { + log.Errorf("Bind error: %s", err) + } + return err +} + +func (m *SysJobSearch) Generate() dto.Index { + o := *m + return &o +} + +type SysJobControl struct { + JobId int `json:"jobId"` + JobName string `json:"jobName" validate:"required"` // 名称 + JobGroup string `json:"jobGroup"` // 任务分组 + JobType int `json:"jobType"` // 任务类型 + CronExpression string `json:"cronExpression"` // cron表达式 + InvokeTarget string `json:"invokeTarget"` // 调用目标 + Args string `json:"args"` // 目标参数 + MisfirePolicy int `json:"misfirePolicy"` // 执行策略 + Concurrent int `json:"concurrent"` // 是否并发 + Status int `json:"status"` // 状态 + EntryId int `json:"entryId"` // job启动时返回的id +} + +func (s *SysJobControl) Bind(ctx *gin.Context) error { + return ctx.ShouldBind(s) +} + +func (s *SysJobControl) Generate() dto.Control { + cp := *s + return &cp +} + +func (s *SysJobControl) GenerateM() (common.ActiveRecord, error) { + return &models.SysJob{ + JobId: s.JobId, + JobName: s.JobName, + JobGroup: s.JobGroup, + JobType: s.JobType, + CronExpression: s.CronExpression, + InvokeTarget: s.InvokeTarget, + Args: s.Args, + MisfirePolicy: s.MisfirePolicy, + Concurrent: s.Concurrent, + Status: s.Status, + EntryId: s.EntryId, + }, nil +} + +func (s *SysJobControl) GetId() interface{} { + return s.JobId +} + +type SysJobById struct { + dto.ObjectById +} + +func (s *SysJobById) Generate() dto.Control { + cp := *s + return &cp +} + +func (s *SysJobById) GenerateM() (common.ActiveRecord, error) { + return &models.SysJob{}, nil +} + +type SysJobItem struct { + JobId int `json:"jobId"` + JobName string `json:"jobName" validate:"required"` // 名称 + JobGroup string `json:"jobGroup"` // 任务分组 + JobType int `json:"jobType"` // 任务类型 + CronExpression string `json:"cronExpression"` // cron表达式 + InvokeTarget string `json:"invokeTarget"` // 调用目标 + Args string `json:"args"` // 目标参数 + MisfirePolicy int `json:"misfirePolicy"` // 执行策略 + Concurrent int `json:"concurrent"` // 是否并发 + Status int `json:"status"` // 状态 + EntryId int `json:"entryId"` // job启动时返回的id +} diff --git a/app/jobs/service/sys_job.go b/app/jobs/service/sys_job.go new file mode 100644 index 0000000..a1ab810 --- /dev/null +++ b/app/jobs/service/sys_job.go @@ -0,0 +1,93 @@ +package service + +import ( + "errors" + "time" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "github.com/robfig/cron/v3" + + "go-admin/app/jobs" + "go-admin/app/jobs/models" + "go-admin/common/dto" +) + +type SysJob struct { + service.Service + Cron *cron.Cron +} + +// RemoveJob 删除job +func (e *SysJob) RemoveJob(c *dto.GeneralDelDto) error { + var err error + var data models.SysJob + err = e.Orm.Table(data.TableName()).First(&data, c.Id).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + cn := jobs.Remove(e.Cron, data.EntryId) + + select { + case res := <-cn: + if res { + err = e.Orm.Table(data.TableName()).Where("entry_id = ?", data.EntryId).Update("entry_id", 0).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + } + return err + } + case <-time.After(time.Second * 1): + e.Msg = "操作超时!" + return nil + } + return nil +} + +// StartJob 启动任务 +func (e *SysJob) StartJob(c *dto.GeneralGetDto) error { + var data models.SysJob + var err error + err = e.Orm.Table(data.TableName()).First(&data, c.Id).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + + if data.Status == 1 { + err = errors.New("当前Job是关闭状态不能被启动,请先启用。") + return err + } + + if data.JobType == 1 { + var j = &jobs.HttpJob{} + j.InvokeTarget = data.InvokeTarget + j.CronExpression = data.CronExpression + j.JobId = data.JobId + j.Name = data.JobName + data.EntryId, err = jobs.AddJob(e.Cron, j) + if err != nil { + e.Log.Errorf("jobs AddJob[HttpJob] error: %s", err) + } + } else { + var j = &jobs.ExecJob{} + j.InvokeTarget = data.InvokeTarget + j.CronExpression = data.CronExpression + j.JobId = data.JobId + j.Name = data.JobName + j.Args = data.Args + data.EntryId, err = jobs.AddJob(e.Cron, j) + if err != nil { + e.Log.Errorf("jobs AddJob[ExecJob] error: %s", err) + } + } + if err != nil { + return err + } + + err = e.Orm.Table(data.TableName()).Where(c.Id).Updates(&data).Error + if err != nil { + e.Log.Errorf("db error: %s", err) + } + return err +} diff --git a/app/jobs/translate.go b/app/jobs/translate.go new file mode 100644 index 0000000..2b861ca --- /dev/null +++ b/app/jobs/translate.go @@ -0,0 +1,42 @@ +package jobs + +import ( + "go-admin/app/admin/service" + + "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + "gorm.io/gorm" +) + +type DailyJob struct{} + +type RemainCharJob struct{} + +// 剩余字符统计 +func (t RemainCharJob) Exec(arg interface{}) error { + memberService := service.TmMember{} + memberService.Orm = GetDb() + memberService.Log = logger.NewHelper(logger.DefaultLogger) + + return memberService.SyncMemberRemain() +} + +// 每日使用字符量统计 +func (t DailyJob) Exec(arg interface{}) error { + //TODO: 实现每日使用字符量统计逻辑 + memberService := service.TmMember{} + memberService.Orm = GetDb() + memberService.Log = logger.NewHelper(logger.DefaultLogger) + + return memberService.SyncMemberDailyUsage() +} + +func GetDb() *gorm.DB { + dbs := sdk.Runtime.GetDb() + + for _, db := range dbs { + return db + } + + return nil +} diff --git a/app/jobs/translate_test.go b/app/jobs/translate_test.go new file mode 100644 index 0000000..831d173 --- /dev/null +++ b/app/jobs/translate_test.go @@ -0,0 +1,38 @@ +package jobs + +import ( + "go-admin/utils/redishelper" + "testing" + + "github.com/go-admin-team/go-admin-core/sdk" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +func TestTranslate(t *testing.T) { + dsn := "root:123456@tcp(127.0.0.1:3306)/aggregate_translate?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" + db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + sdk.Runtime.SetDb("default", db) + + redishelper.InitDefaultRedis("127.0.0.1:6379", "", 1) + redishelper.InitLockRedisConn("127.0.0.1:6379", "", "1") + job := DailyJob{} + + if err := job.Exec(nil); err != nil { + t.Error(err) + } +} + +func TestRemainTranslate(t *testing.T) { + dsn := "root:123456@tcp(127.0.0.1:3306)/aggregate_translate?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" + db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + sdk.Runtime.SetDb("default", db) + + redishelper.InitDefaultRedis("127.0.0.1:6379", "", 1) + redishelper.InitLockRedisConn("127.0.0.1:6379", "", "1") + job := RemainCharJob{} + + if err := job.Exec(nil); err != nil { + t.Error(err) + } +} diff --git a/app/jobs/type.go b/app/jobs/type.go new file mode 100644 index 0000000..1b5c30b --- /dev/null +++ b/app/jobs/type.go @@ -0,0 +1,16 @@ +package jobs + +import "github.com/robfig/cron/v3" + +type Job interface { + Run() + addJob(*cron.Cron) (int, error) +} + +type JobExec interface { + Exec(arg interface{}) error +} + +func CallExec(e JobExec, arg interface{}) error { + return e.Exec(arg) +} diff --git a/app/other/apis/file.go b/app/other/apis/file.go new file mode 100644 index 0000000..e0d77f4 --- /dev/null +++ b/app/other/apis/file.go @@ -0,0 +1,204 @@ +package apis + +import ( + "encoding/base64" + "errors" + "fmt" + "io/ioutil" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/utils" + "github.com/google/uuid" + + "go-admin/common/file_store" +) + +type FileResponse struct { + Size int64 `json:"size"` + Path string `json:"path"` + FullPath string `json:"full_path"` + Name string `json:"name"` + Type string `json:"type"` +} + +const path = "static/uploadfile/" + +type File struct { + api.Api +} + +// UploadFile 上传图片 +// @Summary 上传图片 +// @Description 获取JSON +// @Tags 公共接口 +// @Accept multipart/form-data +// @Param type query string true "type" (1:单图,2:多图, 3:base64图片) +// @Param file formData file true "file" +// @Success 200 {string} string "{"code": 200, "message": "添加成功"}" +// @Success 200 {string} string "{"code": -1, "message": "添加失败"}" +// @Router /api/v1/public/uploadFile [post] +// @Security Bearer +func (e File) UploadFile(c *gin.Context) { + e.MakeContext(c) + tag, _ := c.GetPostForm("type") + urlPrefix := fmt.Sprintf("%s://%s/", "http", c.Request.Host) + var fileResponse FileResponse + + switch tag { + case "1": // 单图 + var done bool + fileResponse, done = e.singleFile(c, fileResponse, urlPrefix) + if done { + return + } + e.OK(fileResponse, "上传成功") + return + case "2": // 多图 + multipartFile := e.multipleFile(c, urlPrefix) + e.OK(multipartFile, "上传成功") + return + case "3": // base64 + fileResponse = e.baseImg(c, fileResponse, urlPrefix) + e.OK(fileResponse, "上传成功") + default: + var done bool + fileResponse, done = e.singleFile(c, fileResponse, urlPrefix) + if done { + return + } + e.OK(fileResponse, "上传成功") + return + } + +} + +func (e File) baseImg(c *gin.Context, fileResponse FileResponse, urlPerfix string) FileResponse { + files, _ := c.GetPostForm("file") + file2list := strings.Split(files, ",") + ddd, _ := base64.StdEncoding.DecodeString(file2list[1]) + guid := uuid.New().String() + fileName := guid + ".jpg" + err := utils.IsNotExistMkDir(path) + if err != nil { + e.Error(500, errors.New(""), "初始化文件路径失败") + } + base64File := path + fileName + _ = ioutil.WriteFile(base64File, ddd, 0666) + typeStr := strings.Replace(strings.Replace(file2list[0], "data:", "", -1), ";base64", "", -1) + fileResponse = FileResponse{ + Size: pkg.GetFileSize(base64File), + Path: base64File, + FullPath: urlPerfix + base64File, + Name: "", + Type: typeStr, + } + source, _ := c.GetPostForm("source") + err = thirdUpload(source, fileName, base64File) + if err != nil { + e.Error(200, errors.New(""), "上传第三方失败") + return fileResponse + } + if source != "1" { + fileResponse.Path = "/static/uploadfile/" + fileName + fileResponse.FullPath = "/static/uploadfile/" + fileName + } + return fileResponse +} + +func (e File) multipleFile(c *gin.Context, urlPerfix string) []FileResponse { + files := c.Request.MultipartForm.File["file"] + source, _ := c.GetPostForm("source") + var multipartFile []FileResponse + for _, f := range files { + guid := uuid.New().String() + fileName := guid + utils.GetExt(f.Filename) + + err := utils.IsNotExistMkDir(path) + if err != nil { + e.Error(500, errors.New(""), "初始化文件路径失败") + } + multipartFileName := path + fileName + err1 := c.SaveUploadedFile(f, multipartFileName) + fileType, _ := utils.GetType(multipartFileName) + if err1 == nil { + err := thirdUpload(source, fileName, multipartFileName) + if err != nil { + e.Error(500, errors.New(""), "上传第三方失败") + } else { + fileResponse := FileResponse{ + Size: pkg.GetFileSize(multipartFileName), + Path: multipartFileName, + FullPath: urlPerfix + multipartFileName, + Name: f.Filename, + Type: fileType, + } + if source != "1" { + fileResponse.Path = "/static/uploadfile/" + fileName + fileResponse.FullPath = "/static/uploadfile/" + fileName + } + multipartFile = append(multipartFile, fileResponse) + } + } + } + return multipartFile +} + +func (e File) singleFile(c *gin.Context, fileResponse FileResponse, urlPerfix string) (FileResponse, bool) { + files, err := c.FormFile("file") + + if err != nil { + e.Error(200, errors.New(""), "图片不能为空") + return FileResponse{}, true + } + // 上传文件至指定目录 + guid := uuid.New().String() + + fileName := guid + utils.GetExt(files.Filename) + + err = utils.IsNotExistMkDir(path) + if err != nil { + e.Error(500, errors.New(""), "初始化文件路径失败") + } + singleFile := path + fileName + _ = c.SaveUploadedFile(files, singleFile) + fileType, _ := utils.GetType(singleFile) + fileResponse = FileResponse{ + Size: pkg.GetFileSize(singleFile), + Path: singleFile, + FullPath: urlPerfix + singleFile, + Name: files.Filename, + Type: fileType, + } + //source, _ := c.GetPostForm("source") + //err = thirdUpload(source, fileName, singleFile) + //if err != nil { + // e.Error(200, errors.New(""), "上传第三方失败") + // return FileResponse{}, true + //} + fileResponse.Path = "/static/uploadfile/" + fileName + fileResponse.FullPath = "/static/uploadfile/" + fileName + return fileResponse, false +} + +func thirdUpload(source string, name string, path string) error { + switch source { + case "2": + return ossUpload("img/"+name, path) + case "3": + return qiniuUpload("img/"+name, path) + } + return nil +} + +func ossUpload(name string, path string) error { + oss := file_store.ALiYunOSS{} + return oss.UpLoad(name, path) +} + +func qiniuUpload(name string, path string) error { + oss := file_store.ALiYunOSS{} + return oss.UpLoad(name, path) +} diff --git a/app/other/apis/sys_server_monitor.go b/app/other/apis/sys_server_monitor.go new file mode 100644 index 0000000..c9aee1d --- /dev/null +++ b/app/other/apis/sys_server_monitor.go @@ -0,0 +1,186 @@ +package apis + +import ( + "fmt" + "github.com/shirou/gopsutil/v3/net" + "runtime" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/v3/host" + "github.com/shirou/gopsutil/v3/mem" +) + +const ( + B = 1 + KB = 1024 * B + MB = 1024 * KB + GB = 1024 * MB +) + +var ( + //Version string + //expectDiskFsTypes = []string{ + // "apfs", "ext4", "ext3", "ext2", "f2fs", "reiserfs", "jfs", "btrfs", + // "fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs", "fuse.rclone", + //} + excludeNetInterfaces = []string{ + "lo", "tun", "docker", "veth", "br-", "vmbr", "vnet", "kube", + } + //getMacDiskNo = regexp.MustCompile(`\/dev\/disk(\d)s.*`) +) + +var ( + netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdateNetStats uint64 + cachedBootTime time.Time +) + +type ServerMonitor struct { + api.Api +} + +// GetHourDiffer 获取相差时间 +func GetHourDiffer(startTime, endTime string) int64 { + var hour int64 + t1, err := time.ParseInLocation("2006-01-02 15:04:05", startTime, time.Local) + t2, err := time.ParseInLocation("2006-01-02 15:04:05", endTime, time.Local) + if err == nil && t1.Before(t2) { + diff := t2.Unix() - t1.Unix() // + hour = diff / 3600 + return hour + } else { + return hour + } +} + +// ServerInfo 获取系统信息 +// @Summary 系统信息 +// @Description 获取JSON +// @Tags 系统信息 +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/server-monitor [get] +// @Security Bearer +func (e ServerMonitor) ServerInfo(c *gin.Context) { + e.Context = c + + sysInfo, err := host.Info() + osDic := make(map[string]interface{}, 0) + osDic["goOs"] = runtime.GOOS + osDic["arch"] = runtime.GOARCH + osDic["mem"] = runtime.MemProfileRate + osDic["compiler"] = runtime.Compiler + osDic["version"] = runtime.Version() + osDic["numGoroutine"] = runtime.NumGoroutine() + osDic["ip"] = pkg.GetLocaHonst() + osDic["projectDir"] = pkg.GetCurrentPath() + osDic["hostName"] = sysInfo.Hostname + osDic["time"] = time.Now().Format("2006-01-02 15:04:05") + + memory, _ := mem.VirtualMemory() + memDic := make(map[string]interface{}, 0) + memDic["used"] = memory.Used / MB + memDic["total"] = memory.Total / MB + + fmt.Println("mem", int(memory.Total/memory.Used*100)) + memDic["percent"] = pkg.Round(memory.UsedPercent, 2) + + swapDic := make(map[string]interface{}, 0) + swapDic["used"] = memory.SwapTotal - memory.SwapFree + swapDic["total"] = memory.SwapTotal + + cpuDic := make(map[string]interface{}, 0) + cpuDic["cpuInfo"], _ = cpu.Info() + percent, _ := cpu.Percent(0, false) + cpuDic["percent"] = pkg.Round(percent[0], 2) + cpuDic["cpuNum"], _ = cpu.Counts(false) + + //服务器磁盘信息 + disklist := make([]disk.UsageStat, 0) + //所有分区 + var diskTotal, diskUsed, diskUsedPercent float64 + diskInfo, err := disk.Partitions(true) + if err == nil { + for _, p := range diskInfo { + diskDetail, err := disk.Usage(p.Mountpoint) + if err == nil { + diskDetail.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", diskDetail.UsedPercent), 64) + diskDetail.Total = diskDetail.Total / 1024 / 1024 + diskDetail.Used = diskDetail.Used / 1024 / 1024 + diskDetail.Free = diskDetail.Free / 1024 / 1024 + disklist = append(disklist, *diskDetail) + + } + } + } + + d, _ := disk.Usage("/") + + diskTotal = float64(d.Total / GB) + diskUsed = float64(d.Used / GB) + diskUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", d.UsedPercent), 64) + + diskDic := make(map[string]interface{}, 0) + diskDic["total"] = diskTotal + diskDic["used"] = diskUsed + diskDic["percent"] = diskUsedPercent + + bootTime, _ := host.BootTime() + cachedBootTime = time.Unix(int64(bootTime), 0) + + TrackNetworkSpeed() + netDic := make(map[string]interface{}, 0) + netDic["in"] = pkg.Round(float64(netInSpeed/KB), 2) + netDic["out"] = pkg.Round(float64(netOutSpeed/KB), 2) + e.Custom(gin.H{ + "code": 200, + "os": osDic, + "mem": memDic, + "cpu": cpuDic, + "disk": diskDic, + "net": netDic, + "swap": swapDic, + "location": "Aliyun", + "bootTime": GetHourDiffer(cachedBootTime.Format("2006-01-02 15:04:05"), time.Now().Format("2006-01-02 15:04:05")), + }) +} + +func TrackNetworkSpeed() { + var innerNetInTransfer, innerNetOutTransfer uint64 + nc, err := net.IOCounters(true) + if err == nil { + for _, v := range nc { + if isListContainsStr(excludeNetInterfaces, v.Name) { + continue + } + innerNetInTransfer += v.BytesRecv + innerNetOutTransfer += v.BytesSent + } + now := uint64(time.Now().Unix()) + diff := now - lastUpdateNetStats + if diff > 0 { + netInSpeed = (innerNetInTransfer - netInTransfer) / diff + fmt.Println("netInSpeed", netInSpeed) + netOutSpeed = (innerNetOutTransfer - netOutTransfer) / diff + fmt.Println("netOutSpeed", netOutSpeed) + } + netInTransfer = innerNetInTransfer + netOutTransfer = innerNetOutTransfer + lastUpdateNetStats = now + } +} + +func isListContainsStr(list []string, str string) bool { + for i := 0; i < len(list); i++ { + if strings.Contains(str, list[i]) { + return true + } + } + return false +} diff --git a/app/other/apis/tools/db_columns.go b/app/other/apis/tools/db_columns.go new file mode 100644 index 0000000..e0b8390 --- /dev/null +++ b/app/other/apis/tools/db_columns.go @@ -0,0 +1,52 @@ +package tools + +import ( + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/other/models/tools" +) + +// GetDBColumnList 分页列表数据 +// @Summary 分页列表数据 / page list data +// @Description 数据库表列分页列表 / database table column page list +// @Tags 工具 / 生成工具 +// @Param tableName query string false "tableName / 数据表名称" +// @Param pageSize query int false "pageSize / 页条数" +// @Param pageIndex query int false "pageIndex / 页码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/db/columns/page [get] +func (e Gen) GetDBColumnList(c *gin.Context) { + e.Context = c + log := e.GetLogger() + var data tools.DBColumns + var err error + var pageSize = 10 + var pageIndex = 1 + + if size := c.Request.FormValue("pageSize"); size != "" { + pageSize, err = pkg.StringToInt(size) + } + + if index := c.Request.FormValue("pageIndex"); index != "" { + pageIndex, err = pkg.StringToInt(index) + } + + db, err := pkg.GetOrm(c) + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + data.TableName = c.Request.FormValue("tableName") + pkg.Assert(data.TableName == "", "table name cannot be empty!", 500) + result, count, err := data.GetPage(db, pageSize, pageIndex) + if err != nil { + log.Errorf("GetPage error, %s", err.Error()) + e.Error(500, err, "") + return + } + e.PageOK(result, count, pageIndex, pageSize, "查询成功") +} diff --git a/app/other/apis/tools/db_tables.go b/app/other/apis/tools/db_tables.go new file mode 100644 index 0000000..d1ec3c4 --- /dev/null +++ b/app/other/apis/tools/db_tables.go @@ -0,0 +1,60 @@ +package tools + +import ( + "errors" + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/other/models/tools" +) + +// GetDBTableList 分页列表数据 +// @Summary 分页列表数据 / page list data +// @Description 数据库表分页列表 / database table page list +// @Tags 工具 / 生成工具 +// @Param tableName query string false "tableName / 数据表名称" +// @Param pageSize query int false "pageSize / 页条数" +// @Param pageIndex query int false "pageIndex / 页码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/db/tables/page [get] +func (e Gen) GetDBTableList(c *gin.Context) { + //var res response.Response + var data tools.DBTables + var err error + var pageSize = 10 + var pageIndex = 1 + e.Context = c + log := e.GetLogger() + if config.DatabaseConfig.Driver == "sqlite3" || config.DatabaseConfig.Driver == "postgres" { + err = errors.New("对不起,sqlite3 或 postgres 不支持代码生成!") + log.Warn(err) + e.Error(403, err, "") + return + } + + if size := c.Request.FormValue("pageSize"); size != "" { + pageSize, err = pkg.StringToInt(size) + } + + if index := c.Request.FormValue("pageIndex"); index != "" { + pageIndex, err = pkg.StringToInt(index) + } + + db, err := pkg.GetOrm(c) + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + data.TableName = c.Request.FormValue("tableName") + result, count, err := data.GetPage(db, pageSize, pageIndex) + if err != nil { + log.Errorf("GetPage error, %s", err.Error()) + e.Error(500, err, "") + return + } + e.PageOK(result, count, pageIndex, pageSize, "查询成功") +} diff --git a/app/other/apis/tools/gen.go b/app/other/apis/tools/gen.go new file mode 100644 index 0000000..e9baafc --- /dev/null +++ b/app/other/apis/tools/gen.go @@ -0,0 +1,410 @@ +package tools + +import ( + "bytes" + "fmt" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "strconv" + "strings" + "text/template" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + + "go-admin/app/other/models/tools" +) + +type Gen struct { + api.Api +} + +func (e Gen) Preview(c *gin.Context) { + e.Context = c + log := e.GetLogger() + table := tools.SysTables{} + id, err := pkg.StringToInt(c.Param("tableId")) + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("tableId接收失败!错误详情:%s", err.Error())) + return + } + table.TableId = id + t1, err := template.ParseFiles("template/v4/model.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("model模版读取失败!错误详情:%s", err.Error())) + return + } + t2, err := template.ParseFiles("template/v4/no_actions/apis.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("api模版读取失败!错误详情:%s", err.Error())) + return + } + t3, err := template.ParseFiles("template/v4/js.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("js模版读取失败!错误详情:%s", err.Error())) + return + } + t4, err := template.ParseFiles("template/v4/vue.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("vue模版读取失败!错误详情:%s", err.Error())) + return + } + t5, err := template.ParseFiles("template/v4/no_actions/router_check_role.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("路由模版读取失败!错误详情:%s", err.Error())) + return + } + t6, err := template.ParseFiles("template/v4/dto.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("dto模版读取失败!错误详情:%s", err.Error())) + return + } + t7, err := template.ParseFiles("template/v4/no_actions/service.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("service模版读取失败!错误详情:%s", err.Error())) + return + } + + db, err := pkg.GetOrm(c) + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, fmt.Sprintf("数据库链接获取失败!错误详情:%s", err.Error())) + return + } + + tab, _ := table.Get(db,false) + var b1 bytes.Buffer + err = t1.Execute(&b1, tab) + var b2 bytes.Buffer + err = t2.Execute(&b2, tab) + var b3 bytes.Buffer + err = t3.Execute(&b3, tab) + var b4 bytes.Buffer + err = t4.Execute(&b4, tab) + var b5 bytes.Buffer + err = t5.Execute(&b5, tab) + var b6 bytes.Buffer + err = t6.Execute(&b6, tab) + var b7 bytes.Buffer + err = t7.Execute(&b7, tab) + + mp := make(map[string]interface{}) + mp["template/model.go.template"] = b1.String() + mp["template/api.go.template"] = b2.String() + mp["template/js.go.template"] = b3.String() + mp["template/vue.go.template"] = b4.String() + mp["template/router.go.template"] = b5.String() + mp["template/dto.go.template"] = b6.String() + mp["template/service.go.template"] = b7.String() + e.OK(mp, "") +} + +func (e Gen) GenCode(c *gin.Context) { + e.Context = c + log := e.GetLogger() + table := tools.SysTables{} + id, err := pkg.StringToInt(c.Param("tableId")) + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("tableId参数接收失败!错误详情:%s", err.Error())) + return + } + + db, err := pkg.GetOrm(c) + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, fmt.Sprintf("数据库链接获取失败!错误详情:%s", err.Error())) + return + } + + table.TableId = id + tab, _ := table.Get(db,false) + + e.NOActionsGen(c, tab) + + e.OK("", "Code generated successfully!") +} + +func (e Gen) GenApiToFile(c *gin.Context) { + e.Context = c + log := e.GetLogger() + table := tools.SysTables{} + id, err := pkg.StringToInt(c.Param("tableId")) + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("tableId参数获取失败!错误详情:%s", err.Error())) + return + } + + db, err := pkg.GetOrm(c) + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, fmt.Sprintf("数据库链接获取失败!错误详情:%s", err.Error())) + return + } + + table.TableId = id + tab, _ := table.Get(db,false) + e.genApiToFile(c, tab) + + e.OK("", "Code generated successfully!") +} + +func (e Gen) NOActionsGen(c *gin.Context, tab tools.SysTables) { + e.Context = c + log := e.GetLogger() + tab.MLTBName = strings.Replace(tab.TBName, "_", "-", -1) + + basePath := "template/v4/" + routerFile := basePath + "no_actions/router_check_role.go.template" + + if tab.IsAuth == 2 { + routerFile = basePath + "no_actions/router_no_check_role.go.template" + } + + t1, err := template.ParseFiles(basePath + "model.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("model模版读取失败!错误详情:%s", err.Error())) + return + } + t2, err := template.ParseFiles(basePath + "no_actions/apis.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("api模版读取失败!错误详情:%s", err.Error())) + return + } + t3, err := template.ParseFiles(routerFile) + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("路由模版失败!错误详情:%s", err.Error())) + return + } + t4, err := template.ParseFiles(basePath + "js.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("js模版解析失败!错误详情:%s", err.Error())) + return + } + t5, err := template.ParseFiles(basePath + "vue.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("vue模版解析失败!错误详情:%s", err.Error())) + return + } + t6, err := template.ParseFiles(basePath + "dto.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("dto模版解析失败失败!错误详情:%s", err.Error())) + return + } + t7, err := template.ParseFiles(basePath + "no_actions/service.go.template") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("service模版失败!错误详情:%s", err.Error())) + return + } + + _ = pkg.PathCreate("./app/" + tab.PackageName + "/apis/") + _ = pkg.PathCreate("./app/" + tab.PackageName + "/models/") + _ = pkg.PathCreate("./app/" + tab.PackageName + "/router/") + _ = pkg.PathCreate("./app/" + tab.PackageName + "/service/dto/") + _ = pkg.PathCreate(config.GenConfig.FrontPath + "/api/" + tab.PackageName + "/") + err = pkg.PathCreate(config.GenConfig.FrontPath + "/views/" + tab.PackageName + "/" + tab.MLTBName + "/") + if err != nil { + log.Error(err) + e.Error(500, err, fmt.Sprintf("views目录创建失败!错误详情:%s", err.Error())) + return + } + + var b1 bytes.Buffer + err = t1.Execute(&b1, tab) + var b2 bytes.Buffer + err = t2.Execute(&b2, tab) + var b3 bytes.Buffer + err = t3.Execute(&b3, tab) + var b4 bytes.Buffer + err = t4.Execute(&b4, tab) + var b5 bytes.Buffer + err = t5.Execute(&b5, tab) + var b6 bytes.Buffer + err = t6.Execute(&b6, tab) + var b7 bytes.Buffer + err = t7.Execute(&b7, tab) + pkg.FileCreate(b1, "./app/"+tab.PackageName+"/models/"+tab.TBName+".go") + pkg.FileCreate(b2, "./app/"+tab.PackageName+"/apis/"+tab.TBName+".go") + pkg.FileCreate(b3, "./app/"+tab.PackageName+"/router/"+tab.TBName+".go") + pkg.FileCreate(b4, config.GenConfig.FrontPath+"/api/"+tab.PackageName+"/"+tab.MLTBName+".js") + pkg.FileCreate(b5, config.GenConfig.FrontPath+"/views/"+tab.PackageName+"/"+tab.MLTBName+"/index.vue") + pkg.FileCreate(b6, "./app/"+tab.PackageName+"/service/dto/"+tab.TBName+".go") + pkg.FileCreate(b7, "./app/"+tab.PackageName+"/service/"+tab.TBName+".go") + +} + +func (e Gen) genApiToFile(c *gin.Context, tab tools.SysTables) { + err := e.MakeContext(c). + MakeOrm(). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + basePath := "template/" + + t1, err := template.ParseFiles(basePath + "api_migrate.template") + if err != nil { + e.Logger.Error(err) + e.Error(500, err, fmt.Sprintf("数据迁移模版解析失败!错误详情:%s", err.Error())) + return + } + i := strconv.FormatInt(time.Now().UnixNano()/1e6, 10) + var b1 bytes.Buffer + err = t1.Execute(&b1, struct { + tools.SysTables + GenerateTime string + }{tab, i}) + + pkg.FileCreate(b1, "./cmd/migrate/migration/version-local/"+i+"_migrate.go") + +} + +func (e Gen) GenMenuAndApi(c *gin.Context) { + s := service.SysMenu{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + table := tools.SysTables{} + id, err := pkg.StringToInt(c.Param("tableId")) + if err != nil { + e.Logger.Error(err) + e.Error(500, err, fmt.Sprintf("tableId参数解析失败!错误详情:%s", err.Error())) + return + } + + table.TableId = id + tab, _ := table.Get(e.Orm,true) + tab.MLTBName = strings.Replace(tab.TBName, "_", "-", -1) + + Mmenu := dto.SysMenuInsertReq{} + Mmenu.Title = tab.TableComment + Mmenu.Icon = "pass" + Mmenu.Path = "/" + tab.MLTBName + Mmenu.MenuType = "M" + Mmenu.Action = "无" + Mmenu.ParentId = 0 + Mmenu.NoCache = false + Mmenu.Component = "Layout" + Mmenu.Sort = 0 + Mmenu.Visible = "0" + Mmenu.IsFrame = "0" + Mmenu.CreateBy = 1 + s.Insert(&Mmenu) + + Cmenu := dto.SysMenuInsertReq{} + Cmenu.MenuName = tab.ClassName + "Manage" + Cmenu.Title = tab.TableComment + Cmenu.Icon = "pass" + Cmenu.Path = "/" + tab.PackageName + "/" + tab.MLTBName + Cmenu.MenuType = "C" + Cmenu.Action = "无" + Cmenu.Permission = tab.PackageName + ":" + tab.BusinessName + ":list" + Cmenu.ParentId = Mmenu.MenuId + Cmenu.NoCache = false + Cmenu.Component = "/" + tab.PackageName + "/" + tab.MLTBName + "/index" + Cmenu.Sort = 0 + Cmenu.Visible = "0" + Cmenu.IsFrame = "0" + Cmenu.CreateBy = 1 + Cmenu.UpdateBy = 1 + s.Insert(&Cmenu) + + MList := dto.SysMenuInsertReq{} + MList.MenuName = "" + MList.Title = "分页获取" + tab.TableComment + MList.Icon = "" + MList.Path = tab.TBName + MList.MenuType = "F" + MList.Action = "无" + MList.Permission = tab.PackageName + ":" + tab.BusinessName + ":query" + MList.ParentId = Cmenu.MenuId + MList.NoCache = false + MList.Sort = 0 + MList.Visible = "0" + MList.IsFrame = "0" + MList.CreateBy = 1 + MList.UpdateBy = 1 + s.Insert(&MList) + + MCreate := dto.SysMenuInsertReq{} + MCreate.MenuName = "" + MCreate.Title = "创建" + tab.TableComment + MCreate.Icon = "" + MCreate.Path = tab.TBName + MCreate.MenuType = "F" + MCreate.Action = "无" + MCreate.Permission = tab.PackageName + ":" + tab.BusinessName + ":add" + MCreate.ParentId = Cmenu.MenuId + MCreate.NoCache = false + MCreate.Sort = 0 + MCreate.Visible = "0" + MCreate.IsFrame = "0" + MCreate.CreateBy = 1 + MCreate.UpdateBy = 1 + s.Insert(&MCreate) + + MUpdate := dto.SysMenuInsertReq{} + MUpdate.MenuName = "" + MUpdate.Title = "修改" + tab.TableComment + MUpdate.Icon = "" + MUpdate.Path = tab.TBName + MUpdate.MenuType = "F" + MUpdate.Action = "无" + MUpdate.Permission = tab.PackageName + ":" + tab.BusinessName + ":edit" + MUpdate.ParentId = Cmenu.MenuId + MUpdate.NoCache = false + MUpdate.Sort = 0 + MUpdate.Visible = "0" + MUpdate.IsFrame = "0" + MUpdate.CreateBy = 1 + MUpdate.UpdateBy = 1 + s.Insert(&MUpdate) + + MDelete := dto.SysMenuInsertReq{} + MDelete.MenuName = "" + MDelete.Title = "删除" + tab.TableComment + MDelete.Icon = "" + MDelete.Path = tab.TBName + MDelete.MenuType = "F" + MDelete.Action = "无" + MDelete.Permission = tab.PackageName + ":" + tab.BusinessName + ":remove" + MDelete.ParentId = Cmenu.MenuId + MDelete.NoCache = false + MDelete.Sort = 0 + MDelete.Visible = "0" + MDelete.IsFrame = "0" + MDelete.CreateBy = 1 + MDelete.UpdateBy = 1 + s.Insert(&MDelete) + + e.OK("", "数据生成成功!") +} diff --git a/app/other/apis/tools/sys_tables.go b/app/other/apis/tools/sys_tables.go new file mode 100644 index 0000000..ea7dee7 --- /dev/null +++ b/app/other/apis/tools/sys_tables.go @@ -0,0 +1,361 @@ +package tools + +import ( + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "gorm.io/gorm" + + "go-admin/app/other/models/tools" +) + +type SysTable struct { + api.Api +} + +// GetPage 分页列表数据 +// @Summary 分页列表数据 +// @Description 生成表分页列表 +// @Tags 工具 / 生成工具 +// @Param tableName query string false "tableName / 数据表名称" +// @Param pageSize query int false "pageSize / 页条数" +// @Param pageIndex query int false "pageIndex / 页码" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys/tables/page [get] +func (e SysTable) GetPage(c *gin.Context) { + e.Context = c + log := e.GetLogger() + var data tools.SysTables + var err error + var pageSize = 10 + var pageIndex = 1 + + if size := c.Request.FormValue("pageSize"); size != "" { + pageSize, err = pkg.StringToInt(size) + } + + if index := c.Request.FormValue("pageIndex"); index != "" { + pageIndex, err = pkg.StringToInt(index) + } + + db, err := e.GetOrm() + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + data.TBName = c.Request.FormValue("tableName") + data.TableComment = c.Request.FormValue("tableComment") + result, count, err := data.GetPage(db, pageSize, pageIndex) + if err != nil { + log.Errorf("GetPage error, %s", err.Error()) + e.Error(500, err, "") + return + } + e.PageOK(result, count, pageIndex, pageSize, "查询成功") +} + +// Get +// @Summary 获取配置 +// @Description 获取JSON +// @Tags 工具 / 生成工具 +// @Param configKey path int true "configKey" +// @Success 200 {object} response.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/sys/tables/info/{tableId} [get] +// @Security Bearer +func (e SysTable) Get(c *gin.Context) { + e.Context = c + log := e.GetLogger() + db, err := e.GetOrm() + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + var data tools.SysTables + data.TableId, _ = pkg.StringToInt(c.Param("tableId")) + result, err := data.Get(db,true) + if err != nil { + log.Errorf("Get error, %s", err.Error()) + e.Error(500, err, "") + return + } + + mp := make(map[string]interface{}) + mp["list"] = result.Columns + mp["info"] = result + e.OK(mp, "") +} + +func (e SysTable) GetSysTablesInfo(c *gin.Context) { + e.Context = c + log := e.GetLogger() + db, err := e.GetOrm() + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + var data tools.SysTables + if c.Request.FormValue("tableName") != "" { + data.TBName = c.Request.FormValue("tableName") + } + result, err := data.Get(db,true) + if err != nil { + log.Errorf("Get error, %s", err.Error()) + e.Error(500, err, "抱歉未找到相关信息") + return + } + + mp := make(map[string]interface{}) + mp["list"] = result.Columns + mp["info"] = result + e.OK(mp, "") + //res.Data = mp + //c.JSON(http.StatusOK, res.ReturnOK()) +} + +func (e SysTable) GetSysTablesTree(c *gin.Context) { + e.Context = c + log := e.GetLogger() + db, err := e.GetOrm() + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + var data tools.SysTables + result, err := data.GetTree(db) + if err != nil { + log.Errorf("GetTree error, %s", err.Error()) + e.Error(500, err, "抱歉未找到相关信息") + return + } + + e.OK(result, "") +} + +// Insert +// @Summary 添加表结构 +// @Description 添加表结构 +// @Tags 工具 / 生成工具 +// @Accept application/json +// @Product application/json +// @Param tables query string false "tableName / 数据表名称" +// @Success 200 {string} string "{"code": 200, "message": "添加成功"}" +// @Success 200 {string} string "{"code": -1, "message": "添加失败"}" +// @Router /api/v1/sys/tables/info [post] +// @Security Bearer +func (e SysTable) Insert(c *gin.Context) { + e.Context = c + log := e.GetLogger() + db, err := e.GetOrm() + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + tablesList := strings.Split(c.Request.FormValue("tables"), ",") + for i := 0; i < len(tablesList); i++ { + + data, err := genTableInit(db, tablesList, i, c) + if err != nil { + log.Errorf("genTableInit error, %s", err.Error()) + e.Error(500, err, "") + return + } + + _, err = data.Create(db) + if err != nil { + log.Errorf("Create error, %s", err.Error()) + e.Error(500, err, "") + return + } + } + e.OK(nil, "添加成功") + +} + +func genTableInit(tx *gorm.DB, tablesList []string, i int, c *gin.Context) (tools.SysTables, error) { + var data tools.SysTables + var dbTable tools.DBTables + var dbColumn tools.DBColumns + data.TBName = tablesList[i] + data.CreateBy = 0 + + dbTable.TableName = data.TBName + dbtable, err := dbTable.Get(tx) + if err != nil { + return data, err + } + + dbColumn.TableName = data.TBName + tablenamelist := strings.Split(dbColumn.TableName, "_") + for i := 0; i < len(tablenamelist); i++ { + strStart := string([]byte(tablenamelist[i])[:1]) + strend := string([]byte(tablenamelist[i])[1:]) + // 大驼峰表名 结构体使用 + data.ClassName += strings.ToUpper(strStart) + strend + // 小驼峰表名 js函数名和权限标识使用 + if i == 0 { + data.BusinessName += strings.ToLower(strStart) + strend + } else { + data.BusinessName += strings.ToUpper(strStart) + strend + } + //data.PackageName += strings.ToLower(strStart) + strings.ToLower(strend) + //data.ModuleName += strings.ToLower(strStart) + strings.ToLower(strend) + } + //data.ModuleFrontName = strings.ReplaceAll(data.ModuleName, "_", "-") + data.PackageName = "admin" + data.TplCategory = "crud" + data.Crud = true + // 中横线表名称,接口路径、前端文件夹名称和js名称使用 + data.ModuleName = strings.Replace(data.TBName, "_", "-", -1) + dbcolumn, err := dbColumn.GetList(tx) + data.CreateBy = 0 + data.TableComment = dbtable.TableComment + if dbtable.TableComment == "" { + data.TableComment = data.ClassName + } + + data.FunctionName = data.TableComment + //data.BusinessName = data.ModuleName + data.IsLogicalDelete = "1" + data.LogicalDelete = true + data.LogicalDeleteColumn = "is_del" + data.IsActions = 2 + data.IsDataScope = 1 + data.IsAuth = 1 + + data.FunctionAuthor = "wenjianzhang" + for i := 0; i < len(dbcolumn); i++ { + var column tools.SysColumns + column.ColumnComment = dbcolumn[i].ColumnComment + column.ColumnName = dbcolumn[i].ColumnName + column.ColumnType = dbcolumn[i].ColumnType + column.Sort = i + 1 + column.Insert = true + column.IsInsert = "1" + column.QueryType = "EQ" + column.IsPk = "0" + + namelist := strings.Split(dbcolumn[i].ColumnName, "_") + for i := 0; i < len(namelist); i++ { + strStart := string([]byte(namelist[i])[:1]) + strend := string([]byte(namelist[i])[1:]) + column.GoField += strings.ToUpper(strStart) + strend + if i == 0 { + column.JsonField = strings.ToLower(strStart) + strend + } else { + column.JsonField += strings.ToUpper(strStart) + strend + } + } + if strings.Contains(dbcolumn[i].ColumnKey, "PR") { + column.IsPk = "1" + column.Pk = true + data.PkColumn = dbcolumn[i].ColumnName + //column.GoField = strings.ToUpper(column.GoField) + //column.JsonField = strings.ToUpper(column.JsonField) + data.PkGoField = column.GoField + data.PkJsonField = column.JsonField + } + column.IsRequired = "0" + if strings.Contains(dbcolumn[i].IsNullable, "NO") { + column.IsRequired = "1" + column.Required = true + } + + if strings.Contains(dbcolumn[i].ColumnType, "int") { + if strings.Contains(dbcolumn[i].ColumnKey, "PR") { + column.GoType = "int" + } else { + column.GoType = "string" + } + column.HtmlType = "input" + } else if strings.Contains(dbcolumn[i].ColumnType, "timestamp") { + column.GoType = "time.Time" + column.HtmlType = "datetime" + } else if strings.Contains(dbcolumn[i].ColumnType, "datetime") { + column.GoType = "time.Time" + column.HtmlType = "datetime" + } else { + column.GoType = "string" + column.HtmlType = "input" + } + + data.Columns = append(data.Columns, column) + } + return data, err +} + +// Update +// @Summary 修改表结构 +// @Description 修改表结构 +// @Tags 工具 / 生成工具 +// @Accept application/json +// @Product application/json +// @Param data body tools.SysTables true "body" +// @Success 200 {string} string "{"code": 200, "message": "添加成功"}" +// @Success 200 {string} string "{"code": -1, "message": "添加失败"}" +// @Router /api/v1/sys/tables/info [put] +// @Security Bearer +func (e SysTable) Update(c *gin.Context) { + var data tools.SysTables + err := c.Bind(&data) + pkg.HasError(err, "数据解析失败", 500) + + e.Context = c + log := e.GetLogger() + db, err := e.GetOrm() + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + data.UpdateBy = 0 + result, err := data.Update(db) + if err != nil { + log.Errorf("Update error, %s", err.Error()) + e.Error(500, err, "") + return + } + e.OK(result, "修改成功") +} + +// Delete +// @Summary 删除表结构 +// @Description 删除表结构 +// @Tags 工具 / 生成工具 +// @Param tableId path int true "tableId" +// @Success 200 {string} string "{"code": 200, "message": "删除成功"}" +// @Success 200 {string} string "{"code": -1, "message": "删除失败"}" +// @Router /api/v1/sys/tables/info/{tableId} [delete] +func (e SysTable) Delete(c *gin.Context) { + e.Context = c + log := e.GetLogger() + db, err := e.GetOrm() + if err != nil { + log.Errorf("get db connection error, %s", err.Error()) + e.Error(500, err, "数据库连接获取失败") + return + } + + var data tools.SysTables + IDS := pkg.IdsStrToIdsIntGroup("tableId", c) + _, err = data.BatchDelete(db, IDS) + if err != nil { + log.Errorf("BatchDelete error, %s", err.Error()) + e.Error(500, err, "删除失败") + return + } + e.OK(nil, "删除成功") +} diff --git a/app/other/models/tools/db_columns.go b/app/other/models/tools/db_columns.go new file mode 100644 index 0000000..46d9bc6 --- /dev/null +++ b/app/other/models/tools/db_columns.go @@ -0,0 +1,70 @@ +package tools + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "gorm.io/gorm" +) + +type DBColumns struct { + TableSchema string `gorm:"column:TABLE_SCHEMA" json:"tableSchema"` + TableName string `gorm:"column:TABLE_NAME" json:"tableName"` + ColumnName string `gorm:"column:COLUMN_NAME" json:"columnName"` + ColumnDefault string `gorm:"column:COLUMN_DEFAULT" json:"columnDefault"` + IsNullable string `gorm:"column:IS_NULLABLE" json:"isNullable"` + DataType string `gorm:"column:DATA_TYPE" json:"dataType"` + CharacterMaximumLength string `gorm:"column:CHARACTER_MAXIMUM_LENGTH" json:"characterMaximumLength"` + CharacterSetName string `gorm:"column:CHARACTER_SET_NAME" json:"characterSetName"` + ColumnType string `gorm:"column:COLUMN_TYPE" json:"columnType"` + ColumnKey string `gorm:"column:COLUMN_KEY" json:"columnKey"` + Extra string `gorm:"column:EXTRA" json:"extra"` + ColumnComment string `gorm:"column:COLUMN_COMMENT" json:"columnComment"` +} + +func (e *DBColumns) GetPage(tx *gorm.DB, pageSize int, pageIndex int) ([]DBColumns, int, error) { + var doc []DBColumns + var count int64 + table := new(gorm.DB) + + if config.DatabaseConfig.Driver == "mysql" { + table = tx.Table("information_schema.`COLUMNS`") + table = table.Where("table_schema= ? ", config.GenConfig.DBName) + + if e.TableName != "" { + return nil, 0, errors.New("table name cannot be empty!") + } + + table = table.Where("TABLE_NAME = ?", e.TableName) + } + + if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil { + return nil, 0, err + } + //table.Count(&count) + return doc, int(count), nil + +} + +func (e *DBColumns) GetList(tx *gorm.DB) ([]DBColumns, error) { + var doc []DBColumns + table := new(gorm.DB) + + if e.TableName == "" { + return nil, errors.New("table name cannot be empty!") + } + + if config.DatabaseConfig.Driver == "mysql" { + table = tx.Table("information_schema.columns") + table = table.Where("table_schema= ? ", config.GenConfig.DBName) + + table = table.Where("TABLE_NAME = ?", e.TableName).Order("ORDINAL_POSITION asc") + } else { + pkg.Assert(true, "目前只支持mysql数据库", 500) + } + if err := table.Find(&doc).Error; err != nil { + return doc, err + } + return doc, nil +} \ No newline at end of file diff --git a/app/other/models/tools/db_tables.go b/app/other/models/tools/db_tables.go new file mode 100644 index 0000000..77c4927 --- /dev/null +++ b/app/other/models/tools/db_tables.go @@ -0,0 +1,62 @@ +package tools + +import ( + "errors" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + + "gorm.io/gorm" + + config2 "github.com/go-admin-team/go-admin-core/sdk/config" +) + +type DBTables struct { + TableName string `gorm:"column:TABLE_NAME" json:"tableName"` + Engine string `gorm:"column:ENGINE" json:"engine"` + TableRows string `gorm:"column:TABLE_ROWS" json:"tableRows"` + TableCollation string `gorm:"column:TABLE_COLLATION" json:"tableCollation"` + CreateTime string `gorm:"column:CREATE_TIME" json:"createTime"` + UpdateTime string `gorm:"column:UPDATE_TIME" json:"updateTime"` + TableComment string `gorm:"column:TABLE_COMMENT" json:"tableComment"` +} + +func (e *DBTables) GetPage(tx *gorm.DB, pageSize int, pageIndex int) ([]DBTables, int, error) { + var doc []DBTables + table := new(gorm.DB) + var count int64 + + if config2.DatabaseConfig.Driver == "mysql" { + table = tx.Table("information_schema.tables") + table = table.Where("TABLE_NAME not in (select table_name from `" + config2.GenConfig.DBName + "`.sys_tables) ") + table = table.Where("table_schema= ? ", config2.GenConfig.DBName) + + if e.TableName != "" { + table = table.Where("TABLE_NAME = ?", e.TableName) + } + if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil { + return nil, 0, err + } + } else { + pkg.Assert(true, "目前只支持mysql数据库", 500) + } + + //table.Count(&count) + return doc, int(count), nil +} + +func (e *DBTables) Get(tx *gorm.DB) (DBTables, error) { + var doc DBTables + if config2.DatabaseConfig.Driver == "mysql" { + table := tx.Table("information_schema.tables") + table = table.Where("table_schema= ? ", config2.GenConfig.DBName) + if e.TableName == "" { + return doc, errors.New("table name cannot be empty!") + } + table = table.Where("TABLE_NAME = ?", e.TableName) + if err := table.First(&doc).Error; err != nil { + return doc, err + } + } else { + pkg.Assert(true, "目前只支持mysql数据库", 500) + } + return doc, nil +} diff --git a/app/other/models/tools/sys_columns.go b/app/other/models/tools/sys_columns.go new file mode 100644 index 0000000..f3adeb3 --- /dev/null +++ b/app/other/models/tools/sys_columns.go @@ -0,0 +1,100 @@ +package tools + +import ( + "go-admin/app/admin/models" + "gorm.io/gorm" +) + +type SysColumns struct { + ColumnId int `gorm:"primaryKey;autoIncrement" json:"columnId"` + TableId int `gorm:"" json:"tableId"` + ColumnName string `gorm:"size:128;" json:"columnName"` + ColumnComment string `gorm:"column:column_comment;size:128;" json:"columnComment"` + ColumnType string `gorm:"column:column_type;size:128;" json:"columnType"` + GoType string `gorm:"column:go_type;size:128;" json:"goType"` + GoField string `gorm:"column:go_field;size:128;" json:"goField"` + JsonField string `gorm:"column:json_field;size:128;" json:"jsonField"` + IsPk string `gorm:"column:is_pk;size:4;" json:"isPk"` + IsIncrement string `gorm:"column:is_increment;size:4;" json:"isIncrement"` + IsRequired string `gorm:"column:is_required;size:4;" json:"isRequired"` + IsInsert string `gorm:"column:is_insert;size:4;" json:"isInsert"` + IsEdit string `gorm:"column:is_edit;size:4;" json:"isEdit"` + IsList string `gorm:"column:is_list;size:4;" json:"isList"` + IsQuery string `gorm:"column:is_query;size:4;" json:"isQuery"` + QueryType string `gorm:"column:query_type;size:128;" json:"queryType"` + HtmlType string `gorm:"column:html_type;size:128;" json:"htmlType"` + DictType string `gorm:"column:dict_type;size:128;" json:"dictType"` + Sort int `gorm:"column:sort;" json:"sort"` + List string `gorm:"column:list;size:1;" json:"list"` + Pk bool `gorm:"column:pk;size:1;" json:"pk"` + Required bool `gorm:"column:required;size:1;" json:"required"` + SuperColumn bool `gorm:"column:super_column;size:1;" json:"superColumn"` + UsableColumn bool `gorm:"column:usable_column;size:1;" json:"usableColumn"` + Increment bool `gorm:"column:increment;size:1;" json:"increment"` + Insert bool `gorm:"column:insert;size:1;" json:"insert"` + Edit bool `gorm:"column:edit;size:1;" json:"edit"` + Query bool `gorm:"column:query;size:1;" json:"query"` + Remark string `gorm:"column:remark;size:255;" json:"remark"` + FkTableName string `gorm:"" json:"fkTableName"` + FkTableNameClass string `gorm:"" json:"fkTableNameClass"` + FkTableNamePackage string `gorm:"" json:"fkTableNamePackage"` + FkCol []SysColumns `gorm:"-" json:"fkCol"` + FkLabelId string `gorm:"" json:"fkLabelId"` + FkLabelName string `gorm:"size:255;" json:"fkLabelName"` + CreateBy int `gorm:"column:create_by;size:20;" json:"createBy"` + UpdateBy int `gorm:"column:update_By;size:20;" json:"updateBy"` + + models.BaseModel +} + +func (*SysColumns) TableName() string { + return "sys_columns" +} + +func (e *SysColumns) GetList(tx *gorm.DB, exclude bool) ([]SysColumns, error) { + var doc []SysColumns + table := tx.Table("sys_columns") + table = table.Where("table_id = ? ", e.TableId) + if exclude { + notIn := make([]string, 0, 6) + notIn = append(notIn, "id") + notIn = append(notIn, "create_by") + notIn = append(notIn, "update_by") + notIn = append(notIn, "created_at") + notIn = append(notIn, "updated_at") + notIn = append(notIn, "deleted_at") + table = table.Where(" column_name not in(?)", notIn) + } + + if err := table.Find(&doc).Error; err != nil { + return nil, err + } + return doc, nil +} + +func (e *SysColumns) Create(tx *gorm.DB) (SysColumns, error) { + var doc SysColumns + e.CreateBy = 0 + result := tx.Table("sys_columns").Create(&e) + if result.Error != nil { + err := result.Error + return doc, err + } + doc = *e + return doc, nil +} + +func (e *SysColumns) Update(tx *gorm.DB) (update SysColumns, err error) { + if err = tx.Table("sys_columns").First(&update, e.ColumnId).Error; err != nil { + return + } + + //参数1:是要修改的数据 + //参数2:是修改的数据 + e.UpdateBy = 0 + if err = tx.Table("sys_columns").Model(&update).Updates(&e).Error; err != nil { + return + } + + return +} diff --git a/app/other/models/tools/sys_tables.go b/app/other/models/tools/sys_tables.go new file mode 100644 index 0000000..91ded97 --- /dev/null +++ b/app/other/models/tools/sys_tables.go @@ -0,0 +1,238 @@ +package tools + +import ( + common "go-admin/common/models" + "strings" + + "gorm.io/gorm" + + "go-admin/app/admin/models" +) + +type SysTables struct { + TableId int `gorm:"primaryKey;autoIncrement" json:"tableId"` //表编码 + TBName string `gorm:"column:table_name;size:255;" json:"tableName"` //表名称 + MLTBName string `gorm:"-" json:"-"` //表名称 + TableComment string `gorm:"size:255;" json:"tableComment"` //表备注 + ClassName string `gorm:"size:255;" json:"className"` //类名 + TplCategory string `gorm:"size:255;" json:"tplCategory"` // + PackageName string `gorm:"size:255;" json:"packageName"` //包名 + ModuleName string `gorm:"size:255;" json:"moduleName"` //go文件名 + ModuleFrontName string `gorm:"size:255;comment:前端文件名;" json:"moduleFrontName"` //前端文件名 + BusinessName string `gorm:"size:255;" json:"businessName"` // + FunctionName string `gorm:"size:255;" json:"functionName"` //功能名称 + FunctionAuthor string `gorm:"size:255;" json:"functionAuthor"` //功能作者 + PkColumn string `gorm:"size:255;" json:"pkColumn"` + PkGoField string `gorm:"size:255;" json:"pkGoField"` + PkJsonField string `gorm:"size:255;" json:"pkJsonField"` + Options string `gorm:"size:255;" json:"options"` + TreeCode string `gorm:"size:255;" json:"treeCode"` + TreeParentCode string `gorm:"size:255;" json:"treeParentCode"` + TreeName string `gorm:"size:255;" json:"treeName"` + Tree bool `gorm:"size:1;default:0;" json:"tree"` + Crud bool `gorm:"size:1;default:1;" json:"crud"` + Remark string `gorm:"size:255;" json:"remark"` + IsDataScope int `gorm:"size:1;" json:"isDataScope"` + IsActions int `gorm:"size:1;" json:"isActions"` + IsAuth int `gorm:"size:1;" json:"isAuth"` + IsLogicalDelete string `gorm:"size:1;" json:"isLogicalDelete"` + LogicalDelete bool `gorm:"size:1;" json:"logicalDelete"` + LogicalDeleteColumn string `gorm:"size:128;" json:"logicalDeleteColumn"` + common.ModelTime + common.ControlBy + DataScope string `gorm:"-" json:"dataScope"` + Params Params `gorm:"-" json:"params"` + Columns []SysColumns `gorm:"-" json:"columns"` + + models.BaseModel +} + +func (*SysTables) TableName() string { + return "sys_tables" +} + +type Params struct { + TreeCode string `gorm:"-" json:"treeCode"` + TreeParentCode string `gorm:"-" json:"treeParentCode"` + TreeName string `gorm:"-" json:"treeName"` +} + +func (e *SysTables) GetPage(tx *gorm.DB, pageSize int, pageIndex int) ([]SysTables, int, error) { + var doc []SysTables + + table := tx.Table("sys_tables") + + if e.TBName != "" { + table = table.Where("table_name = ?", e.TBName) + } + if e.TableComment != "" { + table = table.Where("table_comment = ?", e.TableComment) + } + + var count int64 + + if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil { + return nil, 0, err + } + //table.Where("`deleted_at` IS NULL").Count(&count) + return doc, int(count), nil +} + +func (e *SysTables) Get(tx *gorm.DB, exclude bool) (SysTables, error) { + var doc SysTables + var err error + table := tx.Table("sys_tables") + + if e.TBName != "" { + table = table.Where("table_name = ?", e.TBName) + } + if e.TableId != 0 { + table = table.Where("table_id = ?", e.TableId) + } + if e.TableComment != "" { + table = table.Where("table_comment = ?", e.TableComment) + } + + if err := table.First(&doc).Error; err != nil { + return doc, err + } + var col SysColumns + col.TableId = doc.TableId + if doc.Columns, err = col.GetList(tx, exclude); err != nil { + return doc, err + } + + return doc, nil +} + +func (e *SysTables) GetTree(tx *gorm.DB) ([]SysTables, error) { + var doc []SysTables + var err error + table := tx.Table("sys_tables") + + if e.TBName != "" { + table = table.Where("table_name = ?", e.TBName) + } + if e.TableId != 0 { + table = table.Where("table_id = ?", e.TableId) + } + if e.TableComment != "" { + table = table.Where("table_comment = ?", e.TableComment) + } + + if err := table.Find(&doc).Error; err != nil { + return doc, err + } + for i := 0; i < len(doc); i++ { + var col SysColumns + //col.FkCol = append(col.FkCol, SysColumns{ColumnId: 0, ColumnName: "请选择"}) + col.TableId = doc[i].TableId + if doc[i].Columns, err = col.GetList(tx, false); err != nil { + return doc, err + } + + } + + return doc, nil +} + +func (e *SysTables) Create(tx *gorm.DB) (SysTables, error) { + var doc SysTables + e.CreateBy = 0 + result := tx.Table("sys_tables").Create(&e) + if result.Error != nil { + err := result.Error + return doc, err + } + doc = *e + for i := 0; i < len(e.Columns); i++ { + e.Columns[i].TableId = doc.TableId + + _, _ = e.Columns[i].Create(tx) + } + + return doc, nil +} + +func (e *SysTables) Update(tx *gorm.DB) (update SysTables, err error) { + //if err = orm.Eloquent.Table("sys_tables").First(&update, e.TableId).Error; err != nil { + // return + //} + + //参数1:是要修改的数据 + //参数2:是修改的数据 + e.UpdateBy = 0 + if err = tx.Table("sys_tables").Where("table_id = ?", e.TableId).Updates(&e).Error; err != nil { + return + } + + tableNames := make([]string, 0) + for i := range e.Columns { + if e.Columns[i].FkTableName != "" { + tableNames = append(tableNames, e.Columns[i].FkTableName) + } + } + + tables := make([]SysTables, 0) + tableMap := make(map[string]*SysTables) + if len(tableNames) > 0 { + if err = tx.Table("sys_tables").Where("table_name in (?)", tableNames).Find(&tables).Error; err != nil { + return + } + for i := range tables { + tableMap[tables[i].TBName] = &tables[i] + } + } + + for i := 0; i < len(e.Columns); i++ { + if e.Columns[i].FkTableName != "" { + t, ok := tableMap[e.Columns[i].FkTableName] + if ok { + e.Columns[i].FkTableNameClass = t.ClassName + t.MLTBName = strings.Replace(t.TBName, "_", "-", -1) + e.Columns[i].FkTableNamePackage = t.MLTBName + } else { + tableNameList := strings.Split(e.Columns[i].FkTableName, "_") + e.Columns[i].FkTableNameClass = "" + //e.Columns[i].FkTableNamePackage = "" + for a := 0; a < len(tableNameList); a++ { + strStart := string([]byte(tableNameList[a])[:1]) + strEnd := string([]byte(tableNameList[a])[1:]) + e.Columns[i].FkTableNameClass += strings.ToUpper(strStart) + strEnd + //e.Columns[i].FkTableNamePackage += strings.ToLower(strStart) + strings.ToLower(strEnd) + } + } + } + _, _ = e.Columns[i].Update(tx) + } + return +} + +func (e *SysTables) Delete(db *gorm.DB) (success bool, err error) { + tx := db.Begin() + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + if err = tx.Table("sys_tables").Delete(SysTables{}, "table_id = ?", e.TableId).Error; err != nil { + success = false + return + } + if err = tx.Table("sys_columns").Delete(SysColumns{}, "table_id = ?", e.TableId).Error; err != nil { + success = false + return + } + success = true + return +} + +func (e *SysTables) BatchDelete(tx *gorm.DB, id []int) (Result bool, err error) { + if err = tx.Unscoped().Table(e.TableName()).Where(" table_id in (?)", id).Delete(&SysColumns{}).Error; err != nil { + return + } + Result = true + return +} diff --git a/app/other/router/file.go b/app/other/router/file.go new file mode 100644 index 0000000..c3bd3ac --- /dev/null +++ b/app/other/router/file.go @@ -0,0 +1,20 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/other/apis" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerFileRouter) +} + +// 需认证的路由代码 +func registerFileRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + var api = apis.File{} + r := v1.Group("").Use(authMiddleware.MiddlewareFunc()) + { + r.POST("/public/uploadFile", api.UploadFile) + } +} diff --git a/app/other/router/gen_router.go b/app/other/router/gen_router.go new file mode 100644 index 0000000..c3c356b --- /dev/null +++ b/app/other/router/gen_router.go @@ -0,0 +1,56 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/admin/apis" + "go-admin/app/other/apis/tools" +) + +func init() { + routerCheckRole = append(routerCheckRole, sysNoCheckRoleRouter, registerDBRouter, registerSysTableRouter) +} + +func sysNoCheckRoleRouter(v1 *gin.RouterGroup ,authMiddleware *jwt.GinJWTMiddleware) { + r1 := v1.Group("") + { + sys := apis.System{} + r1.GET("/captcha", sys.GenerateCaptchaHandler) + } + + r := v1.Group("").Use(authMiddleware.MiddlewareFunc()) + { + gen := tools.Gen{} + r.GET("/gen/preview/:tableId", gen.Preview) + r.GET("/gen/toproject/:tableId", gen.GenCode) + r.GET("/gen/apitofile/:tableId", gen.GenApiToFile) + r.GET("/gen/todb/:tableId", gen.GenMenuAndApi) + sysTable := tools.SysTable{} + r.GET("/gen/tabletree", sysTable.GetSysTablesTree) + } +} + +func registerDBRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + db := v1.Group("/db").Use(authMiddleware.MiddlewareFunc()) + { + gen := tools.Gen{} + db.GET("/tables/page", gen.GetDBTableList) + db.GET("/columns/page", gen.GetDBColumnList) + } +} + +func registerSysTableRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + tables := v1.Group("/sys/tables") + { + sysTable := tools.SysTable{} + tables.Group("").Use(authMiddleware.MiddlewareFunc()).GET("/page", sysTable.GetPage) + tablesInfo := tables.Group("/info").Use(authMiddleware.MiddlewareFunc()) + { + tablesInfo.POST("", sysTable.Insert) + tablesInfo.PUT("", sysTable.Update) + tablesInfo.DELETE("/:tableId", sysTable.Delete) + tablesInfo.GET("/:tableId", sysTable.Get) + tablesInfo.GET("", sysTable.GetSysTablesInfo) + } + } +} \ No newline at end of file diff --git a/app/other/router/init_router.go b/app/other/router/init_router.go new file mode 100644 index 0000000..708f93e --- /dev/null +++ b/app/other/router/init_router.go @@ -0,0 +1,36 @@ +package router + +import ( + "os" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + common "go-admin/common/middleware" +) + +// InitRouter 路由初始化,不要怀疑,这里用到了 +func InitRouter() { + var r *gin.Engine + h := sdk.Runtime.GetEngine() + if h == nil { + log.Fatal("not found engine...") + os.Exit(-1) + } + switch h.(type) { + case *gin.Engine: + r = h.(*gin.Engine) + default: + log.Fatal("not support other engine") + os.Exit(-1) + } + // the jwt middleware + authMiddleware, err := common.AuthInit() + if err != nil { + log.Fatalf("JWT Init Error, %s", err.Error()) + } + + // 注册业务路由 + // TODO: 这里可存放业务路由,里边并无实际路由只有演示代码 + initRouter(r, authMiddleware) +} diff --git a/app/other/router/monitor.go b/app/other/router/monitor.go new file mode 100644 index 0000000..cdbe7ad --- /dev/null +++ b/app/other/router/monitor.go @@ -0,0 +1,23 @@ +package router + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/tools/transfer" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func init() { + routerNoCheckRole = append(routerNoCheckRole, registerMonitorRouter) +} + +// 需认证的路由代码 +func registerMonitorRouter(v1 *gin.RouterGroup) { + v1.GET("/metrics", transfer.Handler(promhttp.Handler())) + //健康检查 + v1.GET("/health", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + +} \ No newline at end of file diff --git a/app/other/router/router.go b/app/other/router/router.go new file mode 100644 index 0000000..8c893a2 --- /dev/null +++ b/app/other/router/router.go @@ -0,0 +1,42 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" +) + +var ( + routerNoCheckRole = make([]func(*gin.RouterGroup), 0) + routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0) +) + +// initRouter 路由示例 +func initRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine { + + // 无需认证的路由 + noCheckRoleRouter(r) + // 需要认证的路由 + checkRoleRouter(r, authMiddleware) + + return r +} + +// noCheckRoleRouter 无需认证的路由示例 +func noCheckRoleRouter(r *gin.Engine) { + // 可根据业务需求来设置接口版本 + v1 := r.Group("/api/v1") + + for _, f := range routerNoCheckRole { + f(v1) + } +} + +// checkRoleRouter 需要认证的路由示例 +func checkRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) { + // 可根据业务需求来设置接口版本 + v1 := r.Group("/api/v1") + + for _, f := range routerCheckRole { + f(v1, authMiddleware) + } +} diff --git a/app/other/router/sys_server_monitor.go b/app/other/router/sys_server_monitor.go new file mode 100644 index 0000000..ffa91a1 --- /dev/null +++ b/app/other/router/sys_server_monitor.go @@ -0,0 +1,21 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/app/other/apis" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSysServerMonitorRouter) +} + +// 需认证的路由代码 +func registerSysServerMonitorRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.ServerMonitor{} + r := v1.Group("/server-monitor").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", api.ServerInfo) + } +} diff --git a/app/other/service/dto/sys_tables.go b/app/other/service/dto/sys_tables.go new file mode 100644 index 0000000..2e8b923 --- /dev/null +++ b/app/other/service/dto/sys_tables.go @@ -0,0 +1,6 @@ +package dto + +type SysTableSearch struct { + TBName string `form:"tableName" search:"type:exact;column:table_name;table:table_name"` + TableComment string `form:"tableComment" search:"type:icontains;column:table_comment;table:table_comment"` +} diff --git a/cmd/api/jobs.go b/cmd/api/jobs.go new file mode 100644 index 0000000..e95caf8 --- /dev/null +++ b/cmd/api/jobs.go @@ -0,0 +1,8 @@ +package api + +import "go-admin/app/jobs/router" + +func init() { + //注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法 + AppRouters = append(AppRouters, router.InitRouter) +} diff --git a/cmd/api/other.go b/cmd/api/other.go new file mode 100644 index 0000000..4c291be --- /dev/null +++ b/cmd/api/other.go @@ -0,0 +1,8 @@ +package api + +import "go-admin/app/other/router" + +func init() { + //注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法 + AppRouters = append(AppRouters, router.InitRouter) +} diff --git a/cmd/api/server.go b/cmd/api/server.go new file mode 100644 index 0000000..20c81ce --- /dev/null +++ b/cmd/api/server.go @@ -0,0 +1,279 @@ +package api + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "os/signal" + "strconv" + "time" + + "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/runtime" + "gorm.io/gorm" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/config/source/file" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/spf13/cobra" + + "go-admin/app/admin/consumer" + "go-admin/app/admin/models" + "go-admin/app/admin/router" + "go-admin/app/admin/service" + "go-admin/app/jobs" + "go-admin/common/database" + "go-admin/common/global" + common "go-admin/common/middleware" + "go-admin/common/middleware/handler" + "go-admin/common/mq" + "go-admin/common/storage" + ext "go-admin/config" + "go-admin/utils/redishelper" +) + +var ( + configYml string + apiCheck bool + StartCmd = &cobra.Command{ + Use: "server", + Short: "Start API server", + Example: "go-admin server -c config/settings.yml", + SilenceUsage: true, + PreRun: func(cmd *cobra.Command, args []string) { + setup() + }, + RunE: func(cmd *cobra.Command, args []string) error { + return run() + }, + } +) + +var AppRouters = make([]func(), 0) + +func init() { + StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file") + StartCmd.PersistentFlags().BoolVarP(&apiCheck, "api", "a", false, "Start server with check api data") + + //注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法 + AppRouters = append(AppRouters, router.InitRouter) +} + +func setup() { + // 注入配置扩展项 + config.ExtendConfig = &ext.ExtConfig + //1. 读取配置 + config.Setup( + file.NewSource(file.WithPath(configYml)), + database.Setup, + storage.Setup, + ) + //注册监听函数 + queue := sdk.Runtime.GetMemoryQueue("") + queue.Register(global.LoginLog, models.SaveLoginLog) + queue.Register(global.OperateLog, models.SaveOperaLog) + queue.Register(global.ApiCheck, models.SaveSysApi) + go queue.Run() + + usageStr := `starting api server...` + log.Println(usageStr) +} + +func run() error { + if config.ApplicationConfig.Mode == pkg.ModeProd.String() { + gin.SetMode(gin.ReleaseMode) + } + initRouter() + + for _, f := range AppRouters { + f() + } + + srv := &http.Server{ + Addr: fmt.Sprintf("%s:%d", config.ApplicationConfig.Host, config.ApplicationConfig.Port), + Handler: sdk.Runtime.GetEngine(), + } + + var db *gorm.DB + dbs := sdk.Runtime.GetDb() + + for _, item := range dbs { + db = item + break + } + + //初始化redis链接 + initCommon() + + initBusinesses(db) + + //初始化消费者 + initConsumer(db) + + go func() { + jobs.InitJob() + jobs.Setup(sdk.Runtime.GetDb()) + + }() + + if apiCheck { + var routers = sdk.Runtime.GetRouter() + q := sdk.Runtime.GetMemoryQueue("") + mp := make(map[string]interface{}, 0) + mp["List"] = routers + message, err := sdk.Runtime.GetStreamMessage("", global.ApiCheck, mp) + if err != nil { + log.Printf("GetStreamMessage error, %s \n", err.Error()) + //日志报错错误,不中断请求 + } else { + err = q.Append(message) + if err != nil { + log.Printf("Append message error, %s \n", err.Error()) + } + } + } + + go func() { + // 服务连接 + if config.SslConfig.Enable { + if err := srv.ListenAndServeTLS(config.SslConfig.Pem, config.SslConfig.KeyStr); err != nil && err != http.ErrServerClosed { + log.Fatal("listen: ", err) + } + } else { + if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Fatal("listen: ", err) + } + } + }() + fmt.Println(pkg.Red(string(global.LogoContent))) + tip() + fmt.Println(pkg.Green("Server run at:")) + fmt.Printf("- Local: %s://localhost:%d/ \r\n", "http", config.ApplicationConfig.Port) + fmt.Printf("- Network: %s://%s:%d/ \r\n", pkg.GetLocaHonst(), "http", config.ApplicationConfig.Port) + fmt.Println(pkg.Green("Swagger run at:")) + fmt.Printf("- Local: http://localhost:%d/swagger/admin/index.html \r\n", config.ApplicationConfig.Port) + fmt.Printf("- Network: %s://%s:%d/swagger/admin/index.html \r\n", "http", pkg.GetLocaHonst(), config.ApplicationConfig.Port) + fmt.Printf("%s Enter Control + C Shutdown Server \r\n", pkg.GetCurrentTimeStr()) + // 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间) + quit := make(chan os.Signal, 1) + signal.Notify(quit, os.Interrupt) + <-quit + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + fmt.Printf("%s Shutdown Server ... \r\n", pkg.GetCurrentTimeStr()) + + if err := srv.Shutdown(ctx); err != nil { + log.Fatal("Server Shutdown:", err) + } + log.Println("Server exiting") + + return nil +} + +func initCommon() { + redishelper.InitDefaultRedis(config.CacheConfig.Redis.Addr, config.CacheConfig.Redis.Password, config.CacheConfig.Redis.DB) + + if err := redishelper.DefaultRedis.Ping(); err != nil { + fmt.Println("redis链接失败", err) + os.Exit(-1) + } + + redishelper.InitLockRedisConn(config.CacheConfig.Redis.Addr, config.CacheConfig.Redis.Password, strconv.Itoa(config.CacheConfig.Redis.DB)) + + fmt.Println(",", ext.ExtConfig) + url := fmt.Sprintf("amqp://%s:%s@%s/", ext.ExtConfig.Mq.Username, ext.ExtConfig.Mq.Pass, ext.ExtConfig.Mq.Addr) + _, err := mq.InitMQ(url) + + if err != nil { + fmt.Println("mq链接失败", err) + + os.Exit(-1) + } +} + +var Router runtime.Router + +func tip() { + usageStr := `欢迎使用 ` + pkg.Green(`go-admin `+global.Version) + ` 可以使用 ` + pkg.Red(`-h`) + ` 查看命令` + fmt.Printf("%s \n\n", usageStr) +} + +func initRouter() { + var r *gin.Engine + h := sdk.Runtime.GetEngine() + if h == nil { + h = gin.New() + sdk.Runtime.SetEngine(h) + } + switch h.(type) { + case *gin.Engine: + r = h.(*gin.Engine) + default: + log.Fatal("not support other engine") + //os.Exit(-1) + } + if config.SslConfig.Enable { + r.Use(handler.TlsHandler()) + } + //r.Use(middleware.Metrics()) + r.Use(common.Sentinel()). + Use(common.RequestId(pkg.TrafficKey)). + Use(api.SetRequestLogger) + + common.InitMiddleware(r) + +} + +// 初始化业务 +func initBusinesses(db *gorm.DB) { + + configService := service.SysConfig{} + configService.Orm = db + configService.Log = logger.NewHelper(logger.DefaultLogger) + dictService := service.SysDictType{} + dictService.Orm = db + dictService.Log = configService.Log + platformService := service.TmPlatform{} + platformService.Orm = db + platformService.Log = configService.Log + platformAccountService := service.TmPlatformAccount{} + platformAccountService.Orm = db + platformAccountService.Log = configService.Log + + memberService := service.TmMember{} + memberService.Orm = db + memberService.Log = configService.Log + + if err := configService.InitCache(); err != nil { + fmt.Println("init cache error :", err) + os.Exit(-1) + } + + if err := dictService.InitDict(); err != nil { + fmt.Println("init dict error :", err) + os.Exit(-1) + } + + platformService.SaveListCache(true) + platformAccountService.SaveCache("", true) + + if err := memberService.SaveAllCache(); err != nil { + fmt.Println("init member cache error :", err) + os.Exit(-1) + } +} + +// 初始化消费者 +func initConsumer(db *gorm.DB) { + if err := consumer.StartAccountExhaustedConsumer(db, mq.MQ.Conn); err != nil { + fmt.Println(err) + + os.Exit(-1) + } +} diff --git a/cmd/app/server.go b/cmd/app/server.go new file mode 100644 index 0000000..013ac38 --- /dev/null +++ b/cmd/app/server.go @@ -0,0 +1,90 @@ +package app + +import ( + "bytes" + "errors" + "fmt" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/utils" + "github.com/spf13/cobra" + "text/template" +) + +var ( + appName string + StartCmd = &cobra.Command{ + Use: "app", + Short: "Create a new app", + Long: "Use when you need to create a new app", + Example: "go-admin app -n admin", + Run: func(cmd *cobra.Command, args []string) { + run() + }, + } +) + +func init() { + StartCmd.PersistentFlags().StringVarP(&appName, "name", "n", "", "Start server with provided configuration file") +} + +func run() { + + fmt.Println(`start init`) + //1. 读取配置 + + fmt.Println(`generate migration file`) + _ = genFile() + +} + +func genFile() error { + if appName == "" { + return errors.New("arg `name` invalid :name is empty") + } + path := "app/" + appPath := path + appName + err := utils.IsNotExistMkDir(appPath) + if err != nil { + return err + } + apiPath := appPath + "/apis/" + err = utils.IsNotExistMkDir(apiPath) + if err != nil { + return err + } + modelsPath := appPath + "/models/" + err = utils.IsNotExistMkDir(modelsPath) + if err != nil { + return err + } + routerPath := appPath + "/router/" + err = utils.IsNotExistMkDir(routerPath) + if err != nil { + return err + } + servicePath := appPath + "/service/" + err = utils.IsNotExistMkDir(servicePath) + if err != nil { + return err + } + dtoPath := appPath + "/service/dto/" + err = utils.IsNotExistMkDir(dtoPath) + if err != nil { + return err + } + + t1, err := template.ParseFiles("template/cmd_api.template") + if err != nil { + return err + } + m := map[string]string{} + m["appName"] = appName + var b1 bytes.Buffer + err = t1.Execute(&b1, m) + pkg.FileCreate(b1, "./cmd/api/"+appName+".go") + t2, err := template.ParseFiles("template/router.template") + var b2 bytes.Buffer + err = t2.Execute(&b2, nil) + pkg.FileCreate(b2, appPath+"/router/router.go") + return nil +} diff --git a/cmd/cobra.go b/cmd/cobra.go new file mode 100644 index 0000000..d6030a9 --- /dev/null +++ b/cmd/cobra.go @@ -0,0 +1,57 @@ +package cmd + +import ( + "errors" + "fmt" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "go-admin/cmd/app" + "go-admin/common/global" + "os" + + "github.com/spf13/cobra" + + "go-admin/cmd/api" + "go-admin/cmd/config" + "go-admin/cmd/migrate" + "go-admin/cmd/version" +) + +var rootCmd = &cobra.Command{ + Use: "go-admin", + Short: "go-admin", + SilenceUsage: true, + Long: `go-admin`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + tip() + return errors.New(pkg.Red("requires at least one arg")) + } + return nil + }, + PersistentPreRunE: func(*cobra.Command, []string) error { return nil }, + Run: func(cmd *cobra.Command, args []string) { + tip() + }, +} + +func tip() { + usageStr := `欢迎使用 ` + pkg.Green(`go-admin `+global.Version) + ` 可以使用 ` + pkg.Red(`-h`) + ` 查看命令` + usageStr1 := `也可以参考 https://doc.go-admin.dev/guide/ksks 的相关内容` + fmt.Printf("%s\n", usageStr) + fmt.Printf("%s\n", usageStr1) +} + +func init() { + rootCmd.AddCommand(api.StartCmd) + rootCmd.AddCommand(migrate.StartCmd) + rootCmd.AddCommand(version.StartCmd) + rootCmd.AddCommand(config.StartCmd) + rootCmd.AddCommand(app.StartCmd) +} + +//Execute : apply commands +func Execute() { + if err := rootCmd.Execute(); err != nil { + os.Exit(-1) + } +} diff --git a/cmd/config/server.go b/cmd/config/server.go new file mode 100644 index 0000000..52ce85b --- /dev/null +++ b/cmd/config/server.go @@ -0,0 +1,63 @@ +package config + +import ( + "encoding/json" + "fmt" + + "github.com/go-admin-team/go-admin-core/config/source/file" + "github.com/spf13/cobra" + + "github.com/go-admin-team/go-admin-core/sdk/config" +) + +var ( + configYml string + StartCmd = &cobra.Command{ + Use: "config", + Short: "Get Application config info", + Example: "go-admin config -c config/settings.yml", + Run: func(cmd *cobra.Command, args []string) { + run() + }, + } +) + +func init() { + StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file") +} + +func run() { + config.Setup(file.NewSource(file.WithPath(configYml))) + + application, errs := json.MarshalIndent(config.ApplicationConfig, "", " ") //转换成JSON返回的是byte[] + if errs != nil { + fmt.Println(errs.Error()) + } + fmt.Println("application:", string(application)) + + jwt, errs := json.MarshalIndent(config.JwtConfig, "", " ") //转换成JSON返回的是byte[] + if errs != nil { + fmt.Println(errs.Error()) + } + fmt.Println("jwt:", string(jwt)) + + // todo 需要兼容 + database, errs := json.MarshalIndent(config.DatabasesConfig, "", " ") //转换成JSON返回的是byte[] + if errs != nil { + fmt.Println(errs.Error()) + } + fmt.Println("database:", string(database)) + + gen, errs := json.MarshalIndent(config.GenConfig, "", " ") //转换成JSON返回的是byte[] + if errs != nil { + fmt.Println(errs.Error()) + } + fmt.Println("gen:", string(gen)) + + loggerConfig, errs := json.MarshalIndent(config.LoggerConfig, "", " ") //转换成JSON返回的是byte[] + if errs != nil { + fmt.Println(errs.Error()) + } + fmt.Println("logger:", string(loggerConfig)) + +} diff --git a/cmd/migrate/migration/init.go b/cmd/migrate/migration/init.go new file mode 100644 index 0000000..739e6b4 --- /dev/null +++ b/cmd/migrate/migration/init.go @@ -0,0 +1,66 @@ +package migration + +import ( + "log" + "path/filepath" + "sort" + "sync" + + "gorm.io/gorm" +) + +var Migrate = &Migration{ + version: make(map[string]func(db *gorm.DB, version string) error), +} + +type Migration struct { + db *gorm.DB + version map[string]func(db *gorm.DB, version string) error + mutex sync.Mutex +} + +func (e *Migration) GetDb() *gorm.DB { + return e.db +} + +func (e *Migration) SetDb(db *gorm.DB) { + e.db = db +} + +func (e *Migration) SetVersion(k string, f func(db *gorm.DB, version string) error) { + e.mutex.Lock() + defer e.mutex.Unlock() + e.version[k] = f +} + +func (e *Migration) Migrate() { + versions := make([]string, 0) + for k := range e.version { + versions = append(versions, k) + } + if !sort.StringsAreSorted(versions) { + sort.Strings(versions) + } + var err error + var count int64 + for _, v := range versions { + err = e.db.Table("sys_migration").Where("version = ?", v).Count(&count).Error + if err != nil { + log.Fatalln(err) + } + if count > 0 { + log.Println(count) + count = 0 + continue + } + err = (e.version[v])(e.db.Debug(), v) + if err != nil { + log.Fatalln(err) + } + } +} + +func GetFilename(s string) string { + s = filepath.Base(s) + return s[:13] +} diff --git a/cmd/migrate/migration/models/by.go b/cmd/migrate/migration/models/by.go new file mode 100644 index 0000000..c9dd906 --- /dev/null +++ b/cmd/migrate/migration/models/by.go @@ -0,0 +1,22 @@ +package models + +import ( + "time" + + "gorm.io/gorm" +) + +type ControlBy struct { + CreateBy int `json:"createBy" gorm:"index;comment:创建者"` + UpdateBy int `json:"updateBy" gorm:"index;comment:更新者"` +} + +type Model struct { + Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"` +} + +type ModelTime struct { + CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"` + UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"` + DeletedAt gorm.DeletedAt `json:"-" gorm:"index;comment:删除时间"` +} diff --git a/cmd/migrate/migration/models/casbin_rule.go b/cmd/migrate/migration/models/casbin_rule.go new file mode 100644 index 0000000..bab7203 --- /dev/null +++ b/cmd/migrate/migration/models/casbin_rule.go @@ -0,0 +1,17 @@ +package models + +// CasbinRule sys_casbin_rule +type CasbinRule struct { + ID uint `gorm:"primaryKey;autoIncrement"` + Ptype string `gorm:"size:512;uniqueIndex:unique_index"` + V0 string `gorm:"size:512;uniqueIndex:unique_index"` + V1 string `gorm:"size:512;uniqueIndex:unique_index"` + V2 string `gorm:"size:512;uniqueIndex:unique_index"` + V3 string `gorm:"size:512;uniqueIndex:unique_index"` + V4 string `gorm:"size:512;uniqueIndex:unique_index"` + V5 string `gorm:"size:512;uniqueIndex:unique_index"` +} + +func (CasbinRule) TableName() string { + return "sys_casbin_rule" +} diff --git a/cmd/migrate/migration/models/initdb.go b/cmd/migrate/migration/models/initdb.go new file mode 100644 index 0000000..ba7f4ca --- /dev/null +++ b/cmd/migrate/migration/models/initdb.go @@ -0,0 +1,72 @@ +package models + +import ( + "fmt" + "go-admin/common/global" + "io/ioutil" + "log" + "strings" + + "gorm.io/gorm" +) + +func InitDb(db *gorm.DB) (err error) { + filePath := "config/db.sql" + if global.Driver == "postgres" { + filePath := "config/db.sql" + if err = ExecSql(db, filePath); err != nil { + return err + } + filePath = "config/pg.sql" + err = ExecSql(db, filePath) + } else if global.Driver == "mysql" { + filePath = "config/db-begin-mysql.sql" + if err = ExecSql(db, filePath); err != nil { + return err + } + filePath = "config/db.sql" + if err = ExecSql(db, filePath); err != nil { + return err + } + filePath = "config/db-end-mysql.sql" + err = ExecSql(db, filePath) + } else { + err = ExecSql(db, filePath) + } + return err +} + +func ExecSql(db *gorm.DB, filePath string) error { + sql, err := Ioutil(filePath) + if err != nil { + fmt.Println("数据库基础数据初始化脚本读取失败!原因:", err.Error()) + return err + } + sqlList := strings.Split(sql, ";") + for i := 0; i < len(sqlList)-1; i++ { + if strings.Contains(sqlList[i], "--") { + fmt.Println(sqlList[i]) + continue + } + sql := strings.Replace(sqlList[i]+";", "\n", "", -1) + sql = strings.TrimSpace(sql) + if err = db.Exec(sql).Error; err != nil { + log.Printf("error sql: %s", sql) + if !strings.Contains(err.Error(), "Query was empty") { + return err + } + } + } + return nil +} + +func Ioutil(filePath string) (string, error) { + if contents, err := ioutil.ReadFile(filePath); err == nil { + //因为contents是[]byte类型,直接转换成string类型后会多一行空格,需要使用strings.Replace替换换行符 + result := strings.Replace(string(contents), "\n", "", 1) + fmt.Println("Use ioutil.ReadFile to read a file:", result) + return result, nil + } else { + return "", err + } +} diff --git a/cmd/migrate/migration/models/model.go b/cmd/migrate/migration/models/model.go new file mode 100644 index 0000000..4a1c439 --- /dev/null +++ b/cmd/migrate/migration/models/model.go @@ -0,0 +1,11 @@ +package models + +import ( + "time" +) + +type BaseModel struct { + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt *time.Time `json:"deletedAt"` +} diff --git a/cmd/migrate/migration/models/role_dept.go b/cmd/migrate/migration/models/role_dept.go new file mode 100644 index 0000000..0aae705 --- /dev/null +++ b/cmd/migrate/migration/models/role_dept.go @@ -0,0 +1,10 @@ +package models + +type SysRoleDept struct { + RoleId int `gorm:"size:11;primaryKey"` + DeptId int `gorm:"size:11;primaryKey"` +} + +func (SysRoleDept) TableName() string { + return "sys_role_dept" +} diff --git a/cmd/migrate/migration/models/sys_api.go b/cmd/migrate/migration/models/sys_api.go new file mode 100644 index 0000000..8d75170 --- /dev/null +++ b/cmd/migrate/migration/models/sys_api.go @@ -0,0 +1,16 @@ +package models + +type SysApi struct { + Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"` + Handle string `json:"handle" gorm:"size:128;comment:handle"` + Title string `json:"title" gorm:"size:128;comment:标题"` + Path string `json:"path" gorm:"size:128;comment:地址"` + Type string `json:"type" gorm:"size:16;comment:接口类型"` + Action string `json:"action" gorm:"size:16;comment:请求类型"` + ModelTime + ControlBy +} + +func (SysApi) TableName() string { + return "sys_api" +} \ No newline at end of file diff --git a/cmd/migrate/migration/models/sys_columns.go b/cmd/migrate/migration/models/sys_columns.go new file mode 100644 index 0000000..2c8377e --- /dev/null +++ b/cmd/migrate/migration/models/sys_columns.go @@ -0,0 +1,44 @@ +package models + +type SysColumns struct { + ColumnId int `gorm:"primaryKey;autoIncrement" json:"columnId"` + TableId int `gorm:"" json:"tableId"` + ColumnName string `gorm:"size:128;" json:"columnName"` + ColumnComment string `gorm:"column:column_comment;size:128;" json:"columnComment"` + ColumnType string `gorm:"column:column_type;size:128;" json:"columnType"` + GoType string `gorm:"column:go_type;size:128;" json:"goType"` + GoField string `gorm:"column:go_field;size:128;" json:"goField"` + JsonField string `gorm:"column:json_field;size:128;" json:"jsonField"` + IsPk string `gorm:"column:is_pk;size:4;" json:"isPk"` + IsIncrement string `gorm:"column:is_increment;size:4;" json:"isIncrement"` + IsRequired string `gorm:"column:is_required;size:4;" json:"isRequired"` + IsInsert string `gorm:"column:is_insert;size:4;" json:"isInsert"` + IsEdit string `gorm:"column:is_edit;size:4;" json:"isEdit"` + IsList string `gorm:"column:is_list;size:4;" json:"isList"` + IsQuery string `gorm:"column:is_query;size:4;" json:"isQuery"` + QueryType string `gorm:"column:query_type;size:128;" json:"queryType"` + HtmlType string `gorm:"column:html_type;size:128;" json:"htmlType"` + DictType string `gorm:"column:dict_type;size:128;" json:"dictType"` + Sort int `gorm:"column:sort;" json:"sort"` + List string `gorm:"column:list;size:1;" json:"list"` + Pk bool `gorm:"column:pk;size:1;" json:"pk"` + Required bool `gorm:"column:required;size:1;" json:"required"` + SuperColumn bool `gorm:"column:super_column;size:1;" json:"superColumn"` + UsableColumn bool `gorm:"column:usable_column;size:1;" json:"usableColumn"` + Increment bool `gorm:"column:increment;size:1;" json:"increment"` + Insert bool `gorm:"column:insert;size:1;" json:"insert"` + Edit bool `gorm:"column:edit;size:1;" json:"edit"` + Query bool `gorm:"column:query;size:1;" json:"query"` + Remark string `gorm:"column:remark;size:255;" json:"remark"` + FkTableName string `gorm:"" json:"fkTableName"` + FkTableNameClass string `gorm:"" json:"fkTableNameClass"` + FkTableNamePackage string `gorm:"" json:"fkTableNamePackage"` + FkLabelId string `gorm:"" json:"fkLabelId"` + FkLabelName string `gorm:"size:255;" json:"fkLabelName"` + ModelTime + ControlBy +} + +func (SysColumns) TableName() string { + return "sys_columns" +} diff --git a/cmd/migrate/migration/models/sys_config.go b/cmd/migrate/migration/models/sys_config.go new file mode 100644 index 0000000..bd79da3 --- /dev/null +++ b/cmd/migrate/migration/models/sys_config.go @@ -0,0 +1,17 @@ +package models + +type SysConfig struct { + Model + ConfigName string `json:"configName" gorm:"type:varchar(128);comment:ConfigName"` + ConfigKey string `json:"configKey" gorm:"type:varchar(128);comment:ConfigKey"` + ConfigValue string `json:"configValue" gorm:"type:varchar(255);comment:ConfigValue"` + ConfigType string `json:"configType" gorm:"type:varchar(64);comment:ConfigType"` + IsFrontend int `json:"isFrontend" gorm:"type:varchar(64);comment:是否前台"` + Remark string `json:"remark" gorm:"type:varchar(128);comment:Remark"` + ControlBy + ModelTime +} + +func (SysConfig) TableName() string { + return "sys_config" +} diff --git a/cmd/migrate/migration/models/sys_dept.go b/cmd/migrate/migration/models/sys_dept.go new file mode 100644 index 0000000..5f74c62 --- /dev/null +++ b/cmd/migrate/migration/models/sys_dept.go @@ -0,0 +1,19 @@ +package models + +type SysDept struct { + DeptId int `json:"deptId" gorm:"primaryKey;autoIncrement;"` //部门编码 + ParentId int `json:"parentId" gorm:""` //上级部门 + DeptPath string `json:"deptPath" gorm:"size:255;"` // + DeptName string `json:"deptName" gorm:"size:128;"` //部门名称 + Sort int `json:"sort" gorm:"size:4;"` //排序 + Leader string `json:"leader" gorm:"size:128;"` //负责人 + Phone string `json:"phone" gorm:"size:11;"` //手机 + Email string `json:"email" gorm:"size:64;"` //邮箱 + Status int `json:"status" gorm:"size:4;"` //状态 + ControlBy + ModelTime +} + +func (SysDept) TableName() string { + return "sys_dept" +} diff --git a/cmd/migrate/migration/models/sys_dict_data.go b/cmd/migrate/migration/models/sys_dict_data.go new file mode 100644 index 0000000..c2936c8 --- /dev/null +++ b/cmd/migrate/migration/models/sys_dict_data.go @@ -0,0 +1,21 @@ +package models + +type DictData struct { + DictCode int `gorm:"primaryKey;autoIncrement;" json:"dictCode" example:"1"` //字典编码 + DictSort int `gorm:"" json:"dictSort"` //显示顺序 + DictLabel string `gorm:"size:128;" json:"dictLabel"` //数据标签 + DictValue string `gorm:"size:255;" json:"dictValue"` //数据键值 + DictType string `gorm:"size:64;" json:"dictType"` //字典类型 + CssClass string `gorm:"size:128;" json:"cssClass"` // + ListClass string `gorm:"size:128;" json:"listClass"` // + IsDefault string `gorm:"size:8;" json:"isDefault"` // + Status int `gorm:"size:4;" json:"status"` //状态 + Default string `gorm:"size:8;" json:"default"` // + Remark string `gorm:"size:255;" json:"remark"` //备注 + ControlBy + ModelTime +} + +func (DictData) TableName() string { + return "sys_dict_data" +} diff --git a/cmd/migrate/migration/models/sys_dict_type.go b/cmd/migrate/migration/models/sys_dict_type.go new file mode 100644 index 0000000..4c79e37 --- /dev/null +++ b/cmd/migrate/migration/models/sys_dict_type.go @@ -0,0 +1,15 @@ +package models + +type DictType struct { + DictId int `gorm:"primaryKey;autoIncrement;" json:"dictId"` + DictName string `gorm:"size:128;" json:"dictName"` //字典名称 + DictType string `gorm:"size:128;" json:"dictType"` //字典类型 + Status int `gorm:"size:4;" json:"status"` //状态 + Remark string `gorm:"size:255;" json:"remark"` //备注 + ControlBy + ModelTime +} + +func (DictType) TableName() string { + return "sys_dict_type" +} diff --git a/cmd/migrate/migration/models/sys_job.go b/cmd/migrate/migration/models/sys_job.go new file mode 100644 index 0000000..e826d10 --- /dev/null +++ b/cmd/migrate/migration/models/sys_job.go @@ -0,0 +1,21 @@ +package models + +type SysJob struct { + JobId int `json:"jobId" gorm:"primaryKey;autoIncrement"` // 编码 + JobName string `json:"jobName" gorm:"size:255;"` // 名称 + JobGroup string `json:"jobGroup" gorm:"size:255;"` // 任务分组 + JobType int `json:"jobType" gorm:"size:1;"` // 任务类型 + CronExpression string `json:"cronExpression" gorm:"size:255;"` // cron表达式 + InvokeTarget string `json:"invokeTarget" gorm:"size:255;"` // 调用目标 + Args string `json:"args" gorm:"size:255;"` // 目标参数 + MisfirePolicy int `json:"misfirePolicy" gorm:"size:255;"` // 执行策略 + Concurrent int `json:"concurrent" gorm:"size:1;"` // 是否并发 + Status int `json:"status" gorm:"size:1;"` // 状态 + EntryId int `json:"entry_id" gorm:"size:11;"` // job启动时返回的id + ModelTime + ControlBy +} + +func (SysJob) TableName() string { + return "sys_job" +} diff --git a/cmd/migrate/migration/models/sys_login_log.go b/cmd/migrate/migration/models/sys_login_log.go new file mode 100644 index 0000000..f4a878b --- /dev/null +++ b/cmd/migrate/migration/models/sys_login_log.go @@ -0,0 +1,26 @@ +package models + +import ( + "time" +) + +type SysLoginLog struct { + Model + Username string `json:"username" gorm:"type:varchar(128);comment:用户名"` + Status string `json:"status" gorm:"type:varchar(4);comment:状态"` + Ipaddr string `json:"ipaddr" gorm:"type:varchar(255);comment:ip地址"` + LoginLocation string `json:"loginLocation" gorm:"type:varchar(255);comment:归属地"` + Browser string `json:"browser" gorm:"type:varchar(255);comment:浏览器"` + Os string `json:"os" gorm:"type:varchar(255);comment:系统"` + Platform string `json:"platform" gorm:"type:varchar(255);comment:固件"` + LoginTime time.Time `json:"loginTime" gorm:"type:timestamp;comment:登录时间"` + Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"` + Msg string `json:"msg" gorm:"type:varchar(255);comment:信息"` + CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"` + UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"` + ControlBy +} + +func (SysLoginLog) TableName() string { + return "sys_login_log" +} diff --git a/cmd/migrate/migration/models/sys_menu.go b/cmd/migrate/migration/models/sys_menu.go new file mode 100644 index 0000000..c69252f --- /dev/null +++ b/cmd/migrate/migration/models/sys_menu.go @@ -0,0 +1,27 @@ +package models + +type SysMenu struct { + MenuId int `json:"menuId" gorm:"primaryKey;autoIncrement"` + MenuName string `json:"menuName" gorm:"size:128;"` + Title string `json:"title" gorm:"size:128;"` + Icon string `json:"icon" gorm:"size:128;"` + Path string `json:"path" gorm:"size:128;"` + Paths string `json:"paths" gorm:"size:128;"` + MenuType string `json:"menuType" gorm:"size:1;"` + Action string `json:"action" gorm:"size:16;"` + Permission string `json:"permission" gorm:"size:255;"` + ParentId int `json:"parentId" gorm:"size:11;"` + NoCache bool `json:"noCache" gorm:"size:8;"` + Breadcrumb string `json:"breadcrumb" gorm:"size:255;"` + Component string `json:"component" gorm:"size:255;"` + Sort int `json:"sort" gorm:"size:4;"` + Visible string `json:"visible" gorm:"size:1;"` + IsFrame string `json:"isFrame" gorm:"size:1;DEFAULT:0;"` + SysApi []SysApi `json:"sysApi" gorm:"many2many:sys_menu_api_rule"` + ControlBy + ModelTime +} + +func (SysMenu) TableName() string { + return "sys_menu" +} \ No newline at end of file diff --git a/cmd/migrate/migration/models/sys_opera_log.go b/cmd/migrate/migration/models/sys_opera_log.go new file mode 100644 index 0000000..5055b96 --- /dev/null +++ b/cmd/migrate/migration/models/sys_opera_log.go @@ -0,0 +1,34 @@ +package models + +import ( + "time" +) + +type SysOperaLog struct { + Model + Title string `json:"title" gorm:"type:varchar(255);comment:操作模块"` + BusinessType string `json:"businessType" gorm:"type:varchar(128);comment:操作类型"` + BusinessTypes string `json:"businessTypes" gorm:"type:varchar(128);comment:BusinessTypes"` + Method string `json:"method" gorm:"type:varchar(128);comment:函数"` + RequestMethod string `json:"requestMethod" gorm:"type:varchar(128);comment:请求方式: GET POST PUT DELETE"` + OperatorType string `json:"operatorType" gorm:"type:varchar(128);comment:操作类型"` + OperName string `json:"operName" gorm:"type:varchar(128);comment:操作者"` + DeptName string `json:"deptName" gorm:"type:varchar(128);comment:部门名称"` + OperUrl string `json:"operUrl" gorm:"type:varchar(255);comment:访问地址"` + OperIp string `json:"operIp" gorm:"type:varchar(128);comment:客户端ip"` + OperLocation string `json:"operLocation" gorm:"type:varchar(128);comment:访问位置"` + OperParam string `json:"operParam" gorm:"type:text;comment:请求参数"` + Status string `json:"status" gorm:"type:varchar(4);comment:操作状态 1:正常 2:关闭"` + OperTime time.Time `json:"operTime" gorm:"type:timestamp;comment:操作时间"` + JsonResult string `json:"jsonResult" gorm:"type:varchar(255);comment:返回数据"` + Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"` + LatencyTime string `json:"latencyTime" gorm:"type:varchar(128);comment:耗时"` + UserAgent string `json:"userAgent" gorm:"type:varchar(255);comment:ua"` + CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"` + UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"` + ControlBy +} + +func (SysOperaLog) TableName() string { + return "sys_opera_log" +} diff --git a/cmd/migrate/migration/models/sys_post.go b/cmd/migrate/migration/models/sys_post.go new file mode 100644 index 0000000..195208a --- /dev/null +++ b/cmd/migrate/migration/models/sys_post.go @@ -0,0 +1,16 @@ +package models + +type SysPost struct { + PostId int `gorm:"primaryKey;autoIncrement" json:"postId"` //岗位编号 + PostName string `gorm:"size:128;" json:"postName"` //岗位名称 + PostCode string `gorm:"size:128;" json:"postCode"` //岗位代码 + Sort int `gorm:"size:4;" json:"sort"` //岗位排序 + Status int `gorm:"size:4;" json:"status"` //状态 + Remark string `gorm:"size:255;" json:"remark"` //描述 + ControlBy + ModelTime +} + +func (SysPost) TableName() string { + return "sys_post" +} \ No newline at end of file diff --git a/cmd/migrate/migration/models/sys_role.go b/cmd/migrate/migration/models/sys_role.go new file mode 100644 index 0000000..0bd5ee3 --- /dev/null +++ b/cmd/migrate/migration/models/sys_role.go @@ -0,0 +1,20 @@ +package models + +type SysRole struct { + RoleId int `json:"roleId" gorm:"primaryKey;autoIncrement"` // 角色编码 + RoleName string `json:"roleName" gorm:"size:128;"` // 角色名称 + Status string `json:"status" gorm:"size:4;"` // + RoleKey string `json:"roleKey" gorm:"size:128;"` //角色代码 + RoleSort int `json:"roleSort" gorm:""` //角色排序 + Flag string `json:"flag" gorm:"size:128;"` // + Remark string `json:"remark" gorm:"size:255;"` //备注 + Admin bool `json:"admin" gorm:"size:4;"` + DataScope string `json:"dataScope" gorm:"size:128;"` + SysMenu []SysMenu `json:"sysMenu" gorm:"many2many:sys_role_menu;foreignKey:RoleId;joinForeignKey:role_id;references:MenuId;joinReferences:menu_id;"` + ControlBy + ModelTime +} + +func (SysRole) TableName() string { + return "sys_role" +} \ No newline at end of file diff --git a/cmd/migrate/migration/models/sys_tables.go b/cmd/migrate/migration/models/sys_tables.go new file mode 100644 index 0000000..0e53032 --- /dev/null +++ b/cmd/migrate/migration/models/sys_tables.go @@ -0,0 +1,37 @@ +package models + +type SysTables struct { + TableId int `gorm:"primaryKey;autoIncrement" json:"tableId"` //表编码 + TBName string `gorm:"column:table_name;size:255;" json:"tableName"` //表名称 + TableComment string `gorm:"size:255;" json:"tableComment"` //表备注 + ClassName string `gorm:"size:255;" json:"className"` //类名 + TplCategory string `gorm:"size:255;" json:"tplCategory"` // + PackageName string `gorm:"size:255;" json:"packageName"` //包名 + ModuleName string `gorm:"size:255;" json:"moduleName"` //go文件名 + ModuleFrontName string `gorm:"size:255;comment:前端文件名;" json:"moduleFrontName"` //前端文件名 + BusinessName string `gorm:"size:255;" json:"businessName"` // + FunctionName string `gorm:"size:255;" json:"functionName"` //功能名称 + FunctionAuthor string `gorm:"size:255;" json:"functionAuthor"` //功能作者 + PkColumn string `gorm:"size:255;" json:"pkColumn"` + PkGoField string `gorm:"size:255;" json:"pkGoField"` + PkJsonField string `gorm:"size:255;" json:"pkJsonField"` + Options string `gorm:"size:255;" json:"options"` + TreeCode string `gorm:"size:255;" json:"treeCode"` + TreeParentCode string `gorm:"size:255;" json:"treeParentCode"` + TreeName string `gorm:"size:255;" json:"treeName"` + Tree bool `gorm:"size:1;default:0;" json:"tree"` + Crud bool `gorm:"size:1;default:1;" json:"crud"` + Remark string `gorm:"size:255;" json:"remark"` + IsDataScope int `gorm:"size:1;" json:"isDataScope"` + IsActions int `gorm:"size:1;" json:"isActions"` + IsAuth int `gorm:"size:1;" json:"isAuth"` + IsLogicalDelete string `gorm:"size:1;" json:"isLogicalDelete"` + LogicalDelete bool `gorm:"size:1;" json:"logicalDelete"` + LogicalDeleteColumn string `gorm:"size:128;" json:"logicalDeleteColumn"` + ModelTime + ControlBy +} + +func (SysTables) TableName() string { + return "sys_tables" +} diff --git a/cmd/migrate/migration/models/sys_user.go b/cmd/migrate/migration/models/sys_user.go new file mode 100644 index 0000000..31e3637 --- /dev/null +++ b/cmd/migrate/migration/models/sys_user.go @@ -0,0 +1,48 @@ +package models + +import ( + "golang.org/x/crypto/bcrypt" + "gorm.io/gorm" +) + +type SysUser struct { + UserId int `gorm:"primaryKey;autoIncrement;comment:编码" json:"userId"` + Username string `json:"username" gorm:"type:varchar(64);comment:用户名"` + Password string `json:"-" gorm:"type:varchar(128);comment:密码"` + NickName string `json:"nickName" gorm:"type:varchar(128);comment:昵称"` + Phone string `json:"phone" gorm:"type:varchar(11);comment:手机号"` + RoleId int `json:"roleId" gorm:"type:bigint;comment:角色ID"` + Salt string `json:"-" gorm:"type:varchar(255);comment:加盐"` + Avatar string `json:"avatar" gorm:"type:varchar(255);comment:头像"` + Sex string `json:"sex" gorm:"type:varchar(255);comment:性别"` + Email string `json:"email" gorm:"type:varchar(128);comment:邮箱"` + DeptId int `json:"deptId" gorm:"type:bigint;comment:部门"` + PostId int `json:"postId" gorm:"type:bigint;comment:岗位"` + Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"` + Status string `json:"status" gorm:"type:varchar(4);comment:状态"` + ControlBy + ModelTime +} + +func (*SysUser) TableName() string { + return "sys_user" +} + +// Encrypt 加密 +func (e *SysUser) Encrypt() (err error) { + if e.Password == "" { + return + } + + var hash []byte + if hash, err = bcrypt.GenerateFromPassword([]byte(e.Password), bcrypt.DefaultCost); err != nil { + return + } else { + e.Password = string(hash) + return + } +} + +func (e *SysUser) BeforeCreate(_ *gorm.DB) error { + return e.Encrypt() +} diff --git a/cmd/migrate/migration/models/tb_demo.go b/cmd/migrate/migration/models/tb_demo.go new file mode 100644 index 0000000..7d30541 --- /dev/null +++ b/cmd/migrate/migration/models/tb_demo.go @@ -0,0 +1,12 @@ +package models + +type TbDemo struct { + Model + Name string `json:"name" gorm:"type:varchar(128);comment:名称"` + ModelTime + ControlBy +} + +func (TbDemo) TableName() string { + return "tb_demo" +} diff --git a/cmd/migrate/migration/version-local/doc.go b/cmd/migrate/migration/version-local/doc.go new file mode 100644 index 0000000..2cec8bc --- /dev/null +++ b/cmd/migrate/migration/version-local/doc.go @@ -0,0 +1,8 @@ +package version_local + +func init() { +} + +/** +开发者项目的迁移脚本放在这个目录里,init写法参考version目录里的migrate或者自动生成 +*/ diff --git a/cmd/migrate/migration/version/1599190683659_tables.go b/cmd/migrate/migration/version/1599190683659_tables.go new file mode 100644 index 0000000..df2dafa --- /dev/null +++ b/cmd/migrate/migration/version/1599190683659_tables.go @@ -0,0 +1,53 @@ +package version + +import ( + "github.com/go-admin-team/go-admin-core/sdk/config" + "runtime" + + "go-admin/cmd/migrate/migration" + "go-admin/cmd/migrate/migration/models" + common "go-admin/common/models" + + "gorm.io/gorm" +) + +func init() { + _, fileName, _, _ := runtime.Caller(0) + migration.Migrate.SetVersion(migration.GetFilename(fileName), _1599190683659Tables) +} + +func _1599190683659Tables(db *gorm.DB, version string) error { + return db.Transaction(func(tx *gorm.DB) error { + if config.DatabaseConfig.Driver == "mysql" { + tx = tx.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4") + } + err := tx.Migrator().AutoMigrate( + new(models.SysDept), + new(models.SysConfig), + new(models.SysTables), + new(models.SysColumns), + new(models.SysMenu), + new(models.SysLoginLog), + new(models.SysOperaLog), + new(models.SysRoleDept), + new(models.SysUser), + new(models.SysRole), + new(models.SysPost), + new(models.DictData), + new(models.DictType), + new(models.SysJob), + new(models.SysConfig), + new(models.SysApi), + new(models.TbDemo), + ) + if err != nil { + return err + } + if err := models.InitDb(tx); err != nil { + return err + } + return tx.Create(&common.Migration{ + Version: version, + }).Error + }) +} diff --git a/cmd/migrate/migration/version/1653638869132_migrate.go b/cmd/migrate/migration/version/1653638869132_migrate.go new file mode 100644 index 0000000..59a8fa0 --- /dev/null +++ b/cmd/migrate/migration/version/1653638869132_migrate.go @@ -0,0 +1,48 @@ +package version + +import ( + "go-admin/cmd/migrate/migration/models" + common "go-admin/common/models" + "gorm.io/gorm" + "runtime" + "strconv" + + "go-admin/cmd/migrate/migration" +) + +func init() { + _, fileName, _, _ := runtime.Caller(0) + migration.Migrate.SetVersion(migration.GetFilename(fileName), _1653638869132Test) +} + +func _1653638869132Test(db *gorm.DB, version string) error { + return db.Transaction(func(tx *gorm.DB) error { + var list []models.SysMenu + err := tx.Model(&models.SysMenu{}).Order("parent_id,menu_id").Find(&list).Error + if err != nil { + return err + } + for _, v := range list { + if v.ParentId == 0 { + v.Paths = "/0/" + strconv.Itoa(v.MenuId) + } else { + var e models.SysMenu + err = tx.Model(&models.SysMenu{}).Where("menu_id=?", v.ParentId).First(&e).Error + if err != nil { + if err == gorm.ErrRecordNotFound { + continue + } + return err + } + v.Paths = e.Paths + "/" + strconv.Itoa(v.MenuId) + } + err = tx.Model(&v).Update("paths", v.Paths).Error + if err != nil { + return err + } + } + return tx.Create(&common.Migration{ + Version: version, + }).Error + }) +} diff --git a/cmd/migrate/server.go b/cmd/migrate/server.go new file mode 100644 index 0000000..fa25741 --- /dev/null +++ b/cmd/migrate/server.go @@ -0,0 +1,106 @@ +package migrate + +import ( + "bytes" + "fmt" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "strconv" + "text/template" + "time" + + "github.com/go-admin-team/go-admin-core/config/source/file" + "github.com/spf13/cobra" + + "github.com/go-admin-team/go-admin-core/sdk/config" + "go-admin/cmd/migrate/migration" + _ "go-admin/cmd/migrate/migration/version" + _ "go-admin/cmd/migrate/migration/version-local" + "go-admin/common/database" + "go-admin/common/models" +) + +var ( + configYml string + generate bool + goAdmin bool + host string + StartCmd = &cobra.Command{ + Use: "migrate", + Short: "Initialize the database", + Example: "go-admin migrate -c config/settings.yml", + Run: func(cmd *cobra.Command, args []string) { + run() + }, + } +) + +// fixme 在您看不见代码的时候运行迁移,我觉得是不安全的,所以编译后最好不要去执行迁移 +func init() { + StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file") + StartCmd.PersistentFlags().BoolVarP(&generate, "generate", "g", false, "generate migration file") + StartCmd.PersistentFlags().BoolVarP(&goAdmin, "goAdmin", "a", false, "generate go-admin migration file") + StartCmd.PersistentFlags().StringVarP(&host, "domain", "d", "*", "select tenant host") +} + +func run() { + + if !generate { + fmt.Println(`start init`) + //1. 读取配置 + config.Setup( + file.NewSource(file.WithPath(configYml)), + initDB, + ) + } else { + fmt.Println(`generate migration file`) + _ = genFile() + } +} + +func migrateModel() error { + if host == "" { + host = "*" + } + db := sdk.Runtime.GetDbByKey(host) + if config.DatabasesConfig[host].Driver == "mysql" { + //初始化数据库时候用 + db.Set("gorm:table_options", "ENGINE=InnoDB CHARSET=utf8mb4") + } + err := db.Debug().AutoMigrate(&models.Migration{}) + if err != nil { + return err + } + migration.Migrate.SetDb(db.Debug()) + migration.Migrate.Migrate() + return err +} +func initDB() { + //3. 初始化数据库链接 + database.Setup() + //4. 数据库迁移 + fmt.Println("数据库迁移开始") + _ = migrateModel() + fmt.Println(`数据库基础数据初始化成功`) +} + +func genFile() error { + t1, err := template.ParseFiles("template/migrate.template") + if err != nil { + return err + } + m := map[string]string{} + m["GenerateTime"] = strconv.FormatInt(time.Now().UnixNano()/1e6, 10) + m["Package"] = "version_local" + if goAdmin { + m["Package"] = "version" + } + var b1 bytes.Buffer + err = t1.Execute(&b1, m) + if goAdmin { + pkg.FileCreate(b1, "./cmd/migrate/migration/version/"+m["GenerateTime"]+"_migrate.go") + } else { + pkg.FileCreate(b1, "./cmd/migrate/migration/version-local/"+m["GenerateTime"]+"_migrate.go") + } + return nil +} diff --git a/cmd/version/server.go b/cmd/version/server.go new file mode 100644 index 0000000..329e1ea --- /dev/null +++ b/cmd/version/server.go @@ -0,0 +1,26 @@ +package version + +import ( + "fmt" + "github.com/spf13/cobra" + "go-admin/common/global" +) + +var ( + StartCmd = &cobra.Command{ + Use: "version", + Short: "Get version info", + Example: "go-admin version", + PreRun: func(cmd *cobra.Command, args []string) { + + }, + RunE: func(cmd *cobra.Command, args []string) error { + return run() + }, + } +) + +func run() error { + fmt.Println(global.Version) + return nil +} diff --git a/common/actions/create.go b/common/actions/create.go new file mode 100644 index 0000000..81989e5 --- /dev/null +++ b/common/actions/create.go @@ -0,0 +1,49 @@ +package actions + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/common/dto" + "go-admin/common/models" +) + +// CreateAction 通用新增动作 +func CreateAction(control dto.Control) gin.HandlerFunc { + return func(c *gin.Context) { + log := api.GetRequestLogger(c) + db, err := pkg.GetOrm(c) + if err != nil { + log.Error(err) + return + } + + //新增操作 + req := control.Generate() + err = req.Bind(c) + if err != nil { + response.Error(c, http.StatusUnprocessableEntity, err, err.Error()) + return + } + var object models.ActiveRecord + object, err = req.GenerateM() + if err != nil { + response.Error(c, 500, err, "模型生成失败") + return + } + object.SetCreateBy(user.GetUserId(c)) + err = db.WithContext(c).Create(object).Error + if err != nil { + log.Errorf("Create error: %s", err) + response.Error(c, 500, err, "创建失败") + return + } + response.OK(c, object.GetId(), "创建成功") + c.Next() + } +} diff --git a/common/actions/delete.go b/common/actions/delete.go new file mode 100644 index 0000000..811b9bf --- /dev/null +++ b/common/actions/delete.go @@ -0,0 +1,61 @@ +package actions + +import ( + "net/http" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/common/dto" + "go-admin/common/models" +) + +// DeleteAction 通用删除动作 +func DeleteAction(control dto.Control) gin.HandlerFunc { + return func(c *gin.Context) { + db, err := pkg.GetOrm(c) + if err != nil { + log.Error(err) + return + } + + msgID := pkg.GenerateMsgIDFromContext(c) + //删除操作 + req := control.Generate() + err = req.Bind(c) + if err != nil { + log.Errorf("MsgID[%s] Bind error: %s", msgID, err) + response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败") + return + } + var object models.ActiveRecord + object, err = req.GenerateM() + if err != nil { + response.Error(c, 500, err, "模型生成失败") + return + } + + object.SetUpdateBy(user.GetUserId(c)) + + //数据权限检查 + p := GetPermissionFromContext(c) + + db = db.WithContext(c).Scopes( + Permission(object.TableName(), p), + ).Where(req.GetId()).Delete(object) + if err = db.Error; err != nil { + log.Errorf("MsgID[%s] Delete error: %s", msgID, err) + response.Error(c, 500, err, "删除失败") + return + } + if db.RowsAffected == 0 { + response.Error(c, http.StatusForbidden, nil, "无权删除该数据") + return + } + response.OK(c, object.GetId(), "删除成功") + c.Next() + } +} diff --git a/common/actions/index.go b/common/actions/index.go new file mode 100644 index 0000000..4453094 --- /dev/null +++ b/common/actions/index.go @@ -0,0 +1,58 @@ +package actions + +import ( + "errors" + "net/http" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "gorm.io/gorm" + + "go-admin/common/dto" + "go-admin/common/models" +) + +// IndexAction 通用查询动作 +func IndexAction(m models.ActiveRecord, d dto.Index, f func() interface{}) gin.HandlerFunc { + return func(c *gin.Context) { + db, err := pkg.GetOrm(c) + if err != nil { + log.Error(err) + return + } + + msgID := pkg.GenerateMsgIDFromContext(c) + list := f() + object := m.Generate() + req := d.Generate() + var count int64 + + //查询列表 + err = req.Bind(c) + if err != nil { + response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败") + return + } + + //数据权限检查 + p := GetPermissionFromContext(c) + + err = db.WithContext(c).Model(object). + Scopes( + dto.MakeCondition(req.GetNeedSearch()), + dto.Paginate(req.GetPageSize(), req.GetPageIndex()), + Permission(object.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(&count).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + log.Errorf("MsgID[%s] Index error: %s", msgID, err) + response.Error(c, 500, err, "查询失败") + return + } + response.PageOK(c, list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") + c.Next() + } +} diff --git a/common/actions/permission.go b/common/actions/permission.go new file mode 100644 index 0000000..82532c4 --- /dev/null +++ b/common/actions/permission.go @@ -0,0 +1,96 @@ +package actions + +import ( + "errors" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "gorm.io/gorm" +) + +type DataPermission struct { + DataScope string + UserId int + DeptId int + RoleId int +} + +func PermissionAction() gin.HandlerFunc { + return func(c *gin.Context) { + db, err := pkg.GetOrm(c) + if err != nil { + log.Error(err) + return + } + + msgID := pkg.GenerateMsgIDFromContext(c) + var p = new(DataPermission) + if userId := user.GetUserIdStr(c); userId != "" { + p, err = newDataPermission(db, userId) + if err != nil { + log.Errorf("MsgID[%s] PermissionAction error: %s", msgID, err) + response.Error(c, 500, err, "权限范围鉴定错误") + c.Abort() + return + } + } + c.Set(PermissionKey, p) + c.Next() + } +} + +func newDataPermission(tx *gorm.DB, userId interface{}) (*DataPermission, error) { + var err error + p := &DataPermission{} + + err = tx.Table("sys_user"). + Select("sys_user.user_id", "sys_role.role_id", "sys_user.dept_id", "sys_role.data_scope"). + Joins("left join sys_role on sys_role.role_id = sys_user.role_id"). + Where("sys_user.user_id = ?", userId). + Scan(p).Error + if err != nil { + err = errors.New("获取用户数据出错 msg:" + err.Error()) + return nil, err + } + return p, nil +} + +func Permission(tableName string, p *DataPermission) func(db *gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + if !config.ApplicationConfig.EnableDP { + return db + } + switch p.DataScope { + case "2": + return db.Where(tableName+".create_by in (select sys_user.user_id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ?)", p.RoleId) + case "3": + return db.Where(tableName+".create_by in (SELECT user_id from sys_user where dept_id = ? )", p.DeptId) + case "4": + return db.Where(tableName+".create_by in (SELECT user_id from sys_user where sys_user.dept_id in(select dept_id from sys_dept where dept_path like ? ))", "%/"+pkg.IntToString(p.DeptId)+"/%") + case "5": + return db.Where(tableName+".create_by = ?", p.UserId) + default: + return db + } + } +} + +func getPermissionFromContext(c *gin.Context) *DataPermission { + p := new(DataPermission) + if pm, ok := c.Get(PermissionKey); ok { + switch pm.(type) { + case *DataPermission: + p = pm.(*DataPermission) + } + } + return p +} + +// GetPermissionFromContext 提供非action写法数据范围约束 +func GetPermissionFromContext(c *gin.Context) *DataPermission { + return getPermissionFromContext(c) +} diff --git a/common/actions/type.go b/common/actions/type.go new file mode 100644 index 0000000..69beb8c --- /dev/null +++ b/common/actions/type.go @@ -0,0 +1,5 @@ +package actions + +const ( + PermissionKey = "dataPermission" +) diff --git a/common/actions/update.go b/common/actions/update.go new file mode 100644 index 0000000..7052334 --- /dev/null +++ b/common/actions/update.go @@ -0,0 +1,59 @@ +package actions + +import ( + "net/http" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/common/dto" + "go-admin/common/models" +) + +// UpdateAction 通用更新动作 +func UpdateAction(control dto.Control) gin.HandlerFunc { + return func(c *gin.Context) { + db, err := pkg.GetOrm(c) + if err != nil { + log.Error(err) + return + } + + msgID := pkg.GenerateMsgIDFromContext(c) + req := control.Generate() + //更新操作 + err = req.Bind(c) + if err != nil { + response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败") + return + } + var object models.ActiveRecord + object, err = req.GenerateM() + if err != nil { + response.Error(c, 500, err, "模型生成失败") + return + } + object.SetUpdateBy(user.GetUserId(c)) + + //数据权限检查 + p := GetPermissionFromContext(c) + + db = db.WithContext(c).Scopes( + Permission(object.TableName(), p), + ).Where(req.GetId()).Updates(object) + if err = db.Error; err != nil { + log.Errorf("MsgID[%s] Update error: %s", msgID, err) + response.Error(c, 500, err, "更新失败") + return + } + if db.RowsAffected == 0 { + response.Error(c, http.StatusForbidden, nil, "无权更新该数据") + return + } + response.OK(c, object.GetId(), "更新成功") + c.Next() + } +} diff --git a/common/actions/view.go b/common/actions/view.go new file mode 100644 index 0000000..b134f53 --- /dev/null +++ b/common/actions/view.go @@ -0,0 +1,67 @@ +package actions + +import ( + "errors" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "net/http" + + "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "gorm.io/gorm" + + "go-admin/common/dto" + "go-admin/common/models" +) + +// ViewAction 通用详情动作 +func ViewAction(control dto.Control, f func() interface{}) gin.HandlerFunc { + return func(c *gin.Context) { + db, err := pkg.GetOrm(c) + if err != nil { + log.Error(err) + return + } + + msgID := pkg.GenerateMsgIDFromContext(c) + //查看详情 + req := control.Generate() + err = req.Bind(c) + if err != nil { + response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败") + return + } + var object models.ActiveRecord + object, err = req.GenerateM() + if err != nil { + response.Error(c, 500, err, "模型生成失败") + return + } + + var rsp interface{} + if f != nil { + rsp = f() + } else { + rsp, _ = req.GenerateM() + } + + //数据权限检查 + p := GetPermissionFromContext(c) + + err = db.Model(object).WithContext(c).Scopes( + Permission(object.TableName(), p), + ).Where(req.GetId()).First(rsp).Error + + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + response.Error(c, http.StatusNotFound, nil, "查看对象不存在或无权查看") + return + } + if err != nil { + log.Errorf("MsgID[%s] View error: %s", msgID, err) + response.Error(c, 500, err, "查看失败") + return + } + response.OK(c, rsp, "查询成功") + c.Next() + } +} diff --git a/common/apis/api.go b/common/apis/api.go new file mode 100644 index 0000000..4b2c58b --- /dev/null +++ b/common/apis/api.go @@ -0,0 +1,135 @@ +package apis + +import ( + "errors" + "fmt" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "gorm.io/gorm" + + "go-admin/common/service" +) + +type Api struct { + Context *gin.Context + Logger *logger.Helper + Orm *gorm.DB + Errors error +} + +func (e *Api) AddError(err error) { + if e.Errors == nil { + e.Errors = err + } else if err != nil { + e.Logger.Error(err) + e.Errors = fmt.Errorf("%v; %w", e.Errors, err) + } +} + +// MakeContext 设置http上下文 +func (e *Api) MakeContext(c *gin.Context) *Api { + e.Context = c + e.Logger = api.GetRequestLogger(c) + return e +} + +// GetLogger 获取上下文提供的日志 +func (e *Api) GetLogger() *logger.Helper { + return api.GetRequestLogger(e.Context) +} + +func (e *Api) Bind(d interface{}, bindings ...binding.Binding) *Api { + var err error + if len(bindings) == 0 { + bindings = append(bindings, binding.JSON, nil) + } + for i := range bindings { + switch bindings[i] { + case binding.JSON: + err = e.Context.ShouldBindWith(d, binding.JSON) + case binding.XML: + err = e.Context.ShouldBindWith(d, binding.XML) + case binding.Form: + err = e.Context.ShouldBindWith(d, binding.Form) + case binding.Query: + err = e.Context.ShouldBindWith(d, binding.Query) + case binding.FormPost: + err = e.Context.ShouldBindWith(d, binding.FormPost) + case binding.FormMultipart: + err = e.Context.ShouldBindWith(d, binding.FormMultipart) + case binding.ProtoBuf: + err = e.Context.ShouldBindWith(d, binding.ProtoBuf) + case binding.MsgPack: + err = e.Context.ShouldBindWith(d, binding.MsgPack) + case binding.YAML: + err = e.Context.ShouldBindWith(d, binding.YAML) + case binding.Header: + err = e.Context.ShouldBindWith(d, binding.Header) + default: + err = e.Context.ShouldBindUri(d) + } + if err != nil { + e.AddError(err) + } + } + return e +} + +// GetOrm 获取Orm DB +func (e *Api) GetOrm() (*gorm.DB, error) { + db, err := pkg.GetOrm(e.Context) + if err != nil { + e.Error(500, err, "数据库连接获取失败") + return nil, err + } + return db, nil +} + +// MakeOrm 设置Orm DB +func (e *Api) MakeOrm() *Api { + var err error + if e.Logger == nil { + err = errors.New("at MakeOrm logger is nil") + //e.Logger.Error(500, err, "at MakeOrm logger is nil") + e.AddError(err) + return e + } + db, err := pkg.GetOrm(e.Context) + if err != nil { + e.Logger.Error(500, err, "数据库连接获取失败") + e.AddError(err) + } + e.Orm = db + return e +} + +func (e *Api) MakeService(c *service.Service) *Api { + c.Log = e.Logger + c.Orm = e.Orm + return e +} + +// Error 通常错误数据处理 +func (e *Api) Error(code int, err error, msg string) { + response.Error(e.Context, code, err, msg) +} + +// OK 通常成功数据处理 +func (e *Api) OK(data interface{}, msg string) { + response.OK(e.Context, data, msg) +} + +// PageOK 分页数据处理 +func (e *Api) PageOK(result interface{}, count int, pageIndex int, pageSize int, msg string) { + response.PageOK(e.Context, result, count, pageIndex, pageSize, msg) +} + +// Custom 兼容函数 +func (e *Api) Custom(data gin.H) { + response.Custum(e.Context, data) +} diff --git a/common/database/initialize.go b/common/database/initialize.go new file mode 100644 index 0000000..22e6d61 --- /dev/null +++ b/common/database/initialize.go @@ -0,0 +1,65 @@ +package database + +import ( + "time" + + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + toolsConfig "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + mycasbin "github.com/go-admin-team/go-admin-core/sdk/pkg/casbin" + toolsDB "github.com/go-admin-team/go-admin-core/tools/database" + . "github.com/go-admin-team/go-admin-core/tools/gorm/logger" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "gorm.io/gorm/schema" + + "go-admin/common/global" +) + +// Setup 配置数据库 +func Setup() { + for k := range toolsConfig.DatabasesConfig { + setupSimpleDatabase(k, toolsConfig.DatabasesConfig[k]) + } +} + +func setupSimpleDatabase(host string, c *toolsConfig.Database) { + if global.Driver == "" { + global.Driver = c.Driver + } + log.Infof("%s => %s", host, pkg.Green(c.Source)) + registers := make([]toolsDB.ResolverConfigure, len(c.Registers)) + for i := range c.Registers { + registers[i] = toolsDB.NewResolverConfigure( + c.Registers[i].Sources, + c.Registers[i].Replicas, + c.Registers[i].Policy, + c.Registers[i].Tables) + } + resolverConfig := toolsDB.NewConfigure(c.Source, c.MaxIdleConns, c.MaxOpenConns, c.ConnMaxIdleTime, c.ConnMaxLifeTime, registers) + db, err := resolverConfig.Init(&gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + }, + Logger: New( + logger.Config{ + SlowThreshold: time.Second, + Colorful: true, + LogLevel: logger.LogLevel( + log.DefaultLogger.Options().Level.LevelForGorm()), + }, + ), + }, opens[c.Driver]) + + if err != nil { + log.Fatal(pkg.Red(c.Driver+" connect error :"), err) + } else { + log.Info(pkg.Green(c.Driver + " connect success !")) + } + + e := mycasbin.Setup(db, "") + + sdk.Runtime.SetDb(host, db) + sdk.Runtime.SetCasbin(host, e) +} diff --git a/common/database/open.go b/common/database/open.go new file mode 100644 index 0000000..de02868 --- /dev/null +++ b/common/database/open.go @@ -0,0 +1,16 @@ +//go:build !sqlite3 + +package database + +import ( + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" + "gorm.io/driver/sqlserver" + "gorm.io/gorm" +) + +var opens = map[string]func(string) gorm.Dialector{ + "mysql": mysql.Open, + "postgres": postgres.Open, + "sqlserver": sqlserver.Open, +} diff --git a/common/database/open_sqlite3.go b/common/database/open_sqlite3.go new file mode 100644 index 0000000..aaebe94 --- /dev/null +++ b/common/database/open_sqlite3.go @@ -0,0 +1,19 @@ +//go:build sqlite3 +// +build sqlite3 + +package database + +import ( + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/driver/sqlserver" + "gorm.io/gorm" +) + +var opens = map[string]func(string) gorm.Dialector{ + "mysql": mysql.Open, + "postgres": postgres.Open, + "sqlite3": sqlite.Open, + "sqlserver": sqlserver.Open, +} diff --git a/common/dto/auto_form.go b/common/dto/auto_form.go new file mode 100644 index 0000000..c99976a --- /dev/null +++ b/common/dto/auto_form.go @@ -0,0 +1,74 @@ +package dto + +type AutoForm struct { + Fields []Field `json:"fields"` + FormRef string `json:"formRef"` + FormModel string `json:"formModel"` + Size string `json:"size"` + LabelPosition string `json:"labelPosition"` + LabelWidth int `json:"labelWidth"` + FormRules string `json:"formRules"` + Gutter int `json:"gutter"` + Disabled bool `json:"disabled"` + Span int `json:"span"` + FormBtns bool `json:"formBtns"` +} + +type Config struct { + Label string `json:"label"` + LabelWidth interface{} `json:"labelWidth"` + ShowLabel bool `json:"showLabel"` + ChangeTag bool `json:"changeTag"` + Tag string `json:"tag"` + TagIcon string `json:"tagIcon"` + Required bool `json:"required"` + Layout string `json:"layout"` + Span int `json:"span"` + Document string `json:"document"` + RegList []interface{} `json:"regList"` + FormId int `json:"formId"` + RenderKey int64 `json:"renderKey"` + DefaultValue interface{} `json:"defaultValue"` + ShowTip bool `json:"showTip,omitempty"` + ButtonText string `json:"buttonText,omitempty"` + FileSize int `json:"fileSize,omitempty"` + SizeUnit string `json:"sizeUnit,omitempty"` +} + +type Option struct { + Label string `json:"label"` + Value string `json:"value"` +} + +type Slot struct { + Prepend string `json:"prepend,omitempty"` + Append string `json:"append,omitempty"` + ListType bool `json:"list-type,omitempty"` + Options []Option `json:"options,omitempty"` +} + +type Field struct { + Config Config `json:"__config__"` + Slot Slot `json:"__slot__"` + Placeholder string `json:"placeholder,omitempty"` + Style Style `json:"style,omitempty"` + Clearable bool `json:"clearable,omitempty"` + PrefixIcon string `json:"prefix-icon,omitempty"` + SuffixIcon string `json:"suffix-icon,omitempty"` + Maxlength interface{} `json:"maxlength"` + ShowWordLimit bool `json:"show-word-limit,omitempty"` + Readonly bool `json:"readonly,omitempty"` + Disabled bool `json:"disabled"` + VModel string `json:"__vModel__"` + Action string `json:"action,omitempty"` + Accept string `json:"accept,omitempty"` + Name string `json:"name,omitempty"` + AutoUpload bool `json:"auto-upload,omitempty"` + ListType string `json:"list-type,omitempty"` + Multiple bool `json:"multiple,omitempty"` + Filterable bool `json:"filterable,omitempty"` +} + +type Style struct { + Width string `json:"width"` +} diff --git a/common/dto/exhausted_account.go b/common/dto/exhausted_account.go new file mode 100644 index 0000000..96bb416 --- /dev/null +++ b/common/dto/exhausted_account.go @@ -0,0 +1,7 @@ +package dto + +// tmPlatformAccount +type ExhaustedAccountMessage struct { + Id int `json:"id"` + Platform string `json:"platform"` +} diff --git a/common/dto/generate.go b/common/dto/generate.go new file mode 100644 index 0000000..313ae6a --- /dev/null +++ b/common/dto/generate.go @@ -0,0 +1,106 @@ +package dto + +import ( + vd "github.com/bytedance/go-tagexpr/v2/validator" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" +) + +type ObjectById struct { + Id int `uri:"id"` + Ids []int `json:"ids"` +} + +func (s *ObjectById) Bind(ctx *gin.Context) error { + var err error + log := api.GetRequestLogger(ctx) + err = ctx.ShouldBindUri(s) + if err != nil { + log.Warnf("ShouldBindUri error: %s", err.Error()) + return err + } + if ctx.Request.Method == http.MethodDelete { + err = ctx.ShouldBind(&s) + if err != nil { + log.Warnf("ShouldBind error: %s", err.Error()) + return err + } + if len(s.Ids) > 0 { + return nil + } + if s.Ids == nil { + s.Ids = make([]int, 0) + } + if s.Id != 0 { + s.Ids = append(s.Ids, s.Id) + } + } + if err = vd.Validate(s); err != nil { + log.Errorf("Validate error: %s", err.Error()) + return err + } + return err +} + +func (s *ObjectById) GetId() interface{} { + if len(s.Ids) > 0 { + s.Ids = append(s.Ids, s.Id) + return s.Ids + } + return s.Id +} + +type ObjectGetReq struct { + Id int `uri:"id"` +} + +func (s *ObjectGetReq) Bind(ctx *gin.Context) error { + var err error + log := api.GetRequestLogger(ctx) + err = ctx.ShouldBindUri(s) + if err != nil { + log.Warnf("ShouldBindUri error: %s", err.Error()) + return err + } + if err = vd.Validate(s); err != nil { + log.Errorf("Validate error: %s", err.Error()) + return err + } + return err +} + +func (s *ObjectGetReq) GetId() interface{} { + return s.Id +} + +type ObjectDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *ObjectDeleteReq) Bind(ctx *gin.Context) error { + var err error + log := api.GetRequestLogger(ctx) + err = ctx.ShouldBind(&s) + if err != nil { + log.Warnf("ShouldBind error: %s", err.Error()) + return err + } + if len(s.Ids) > 0 { + return nil + } + if s.Ids == nil { + s.Ids = make([]int, 0) + } + + if err = vd.Validate(s); err != nil { + log.Errorf("Validate error: %s", err.Error()) + return err + } + return err +} + +func (s *ObjectDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/common/dto/order.go b/common/dto/order.go new file mode 100644 index 0000000..25455fb --- /dev/null +++ b/common/dto/order.go @@ -0,0 +1,12 @@ +package dto + +import ( + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +func OrderDest(sort string, bl bool) func(db *gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + return db.Order(clause.OrderByColumn{Column: clause.Column{Name: sort}, Desc: bl}) + } +} diff --git a/common/dto/pagination.go b/common/dto/pagination.go new file mode 100644 index 0000000..ee438e5 --- /dev/null +++ b/common/dto/pagination.go @@ -0,0 +1,20 @@ +package dto + +type Pagination struct { + PageIndex int `form:"pageIndex"` + PageSize int `form:"pageSize"` +} + +func (m *Pagination) GetPageIndex() int { + if m.PageIndex <= 0 { + m.PageIndex = 1 + } + return m.PageIndex +} + +func (m *Pagination) GetPageSize() int { + if m.PageSize <= 0 { + m.PageSize = 10 + } + return m.PageSize +} diff --git a/common/dto/search.go b/common/dto/search.go new file mode 100644 index 0000000..72cc60e --- /dev/null +++ b/common/dto/search.go @@ -0,0 +1,84 @@ +package dto + +import ( + "github.com/go-admin-team/go-admin-core/tools/search" + "go-admin/common/global" + "gorm.io/gorm" +) + +type GeneralDelDto struct { + Id int `uri:"id" json:"id" validate:"required"` + Ids []int `json:"ids"` +} + +func (g GeneralDelDto) GetIds() []int { + ids := make([]int, 0) + if g.Id != 0 { + ids = append(ids, g.Id) + } + if len(g.Ids) > 0 { + for _, id := range g.Ids { + if id > 0 { + ids = append(ids, id) + } + } + } else { + if g.Id > 0 { + ids = append(ids, g.Id) + } + } + if len(ids) <= 0 { + //方式全部删除 + ids = append(ids, 0) + } + return ids +} + +type GeneralGetDto struct { + Id int `uri:"id" json:"id" validate:"required"` +} + +func MakeCondition(q interface{}) func(db *gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + condition := &search.GormCondition{ + GormPublic: search.GormPublic{}, + Join: make([]*search.GormJoin, 0), + } + search.ResolveSearchQuery(global.Driver, q, condition) + for _, join := range condition.Join { + if join == nil { + continue + } + db = db.Joins(join.JoinOn) + for k, v := range join.Where { + db = db.Where(k, v...) + } + for k, v := range join.Or { + db = db.Or(k, v...) + } + for _, o := range join.Order { + db = db.Order(o) + } + } + for k, v := range condition.Where { + db = db.Where(k, v...) + } + for k, v := range condition.Or { + db = db.Or(k, v...) + } + for _, o := range condition.Order { + db = db.Order(o) + } + return db + } +} + +func Paginate(pageSize, pageIndex int) func(db *gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + offset := (pageIndex - 1) * pageSize + if offset < 0 { + offset = 0 + } + return db.Offset(offset).Limit(pageSize) + } +} diff --git a/common/dto/type.go b/common/dto/type.go new file mode 100644 index 0000000..e029943 --- /dev/null +++ b/common/dto/type.go @@ -0,0 +1,21 @@ +package dto + +import ( + "github.com/gin-gonic/gin" + "go-admin/common/models" +) + +type Index interface { + Generate() Index + Bind(ctx *gin.Context) error + GetPageIndex() int + GetPageSize() int + GetNeedSearch() interface{} +} + +type Control interface { + Generate() Control + Bind(ctx *gin.Context) error + GenerateM() (models.ActiveRecord, error) + GetId() interface{} +} diff --git a/common/file_store/initialize.go b/common/file_store/initialize.go new file mode 100644 index 0000000..fabce9f --- /dev/null +++ b/common/file_store/initialize.go @@ -0,0 +1,45 @@ +package file_store + +import "fmt" + +type OXS struct { + // Endpoint 访问域名 + Endpoint string + // AccessKeyID AK + AccessKeyID string + // AccessKeySecret AKS + AccessKeySecret string + // BucketName 桶名称 + BucketName string +} + +// Setup 配置文件存储driver +func (e *OXS) Setup(driver DriverType, options ...ClientOption) FileStoreType { + fileStoreType := driver + var fileStore FileStoreType + switch fileStoreType { + case AliYunOSS: + fileStore = new(ALiYunOSS) + err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName) + if err != nil { + fmt.Println(err) + } + return fileStore + case HuaweiOBS: + fileStore = new(HuaWeiOBS) + err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName) + if err != nil { + fmt.Println(err) + } + return fileStore + case QiNiuKodo: + fileStore = new(QiNiuKODO) + err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName) + if err != nil { + fmt.Println(err) + } + return fileStore + } + + return nil +} diff --git a/common/file_store/interface.go b/common/file_store/interface.go new file mode 100644 index 0000000..acecbe9 --- /dev/null +++ b/common/file_store/interface.go @@ -0,0 +1,27 @@ +package file_store + +// DriverType 驱动类型 +type DriverType string + +const ( + // HuaweiOBS 华为云OBS + HuaweiOBS DriverType = "HuaweiOBS" + // AliYunOSS 阿里云OSS + AliYunOSS DriverType = "AliYunOSS" + // QiNiuKodo 七牛云kodo + QiNiuKodo DriverType = "QiNiuKodo" +) + +type ClientOption map[string]interface{} + +// TODO: FileStoreType名称待定 + +// FileStoreType OXS +type FileStoreType interface { + // Setup 装载 endpoint sss + Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error + // UpLoad 上传 + UpLoad(yourObjectName string, localFile interface{}) error + // GetTempToken 获取临时Token + GetTempToken() (string, error) +} diff --git a/common/file_store/kodo.go b/common/file_store/kodo.go new file mode 100644 index 0000000..db896e2 --- /dev/null +++ b/common/file_store/kodo.go @@ -0,0 +1,111 @@ +package file_store + +import ( + "context" + "fmt" + "github.com/qiniu/go-sdk/v7/auth/qbox" + "github.com/qiniu/go-sdk/v7/storage" +) + +type Zone string + +const ( + // HuaDong 华东 + HuaDong Zone = "HuaDong" + // HuaBei 华北 + HuaBei Zone = "HuaBei" + // HuaNan 华南 + HuaNan Zone = "HuaNan" + // BeiMei 北美 + BeiMei Zone = "BeiMei" + // XinJiaPo 新加坡 + XinJiaPo Zone = "XinJiaPo" +) + +type QiNiuKODO struct { + Client interface{} + BucketName string + cfg storage.Config + options []ClientOption +} + +func (e *QiNiuKODO) getToken() string { + putPolicy := storage.PutPolicy{ + Scope: e.BucketName, + } + if len(e.options) > 0 && e.options[0]["Expires"] != nil { + putPolicy.Expires = e.options[0]["Expires"].(uint64) + } + upToken := putPolicy.UploadToken(e.Client.(*qbox.Mac)) + return upToken +} + +//Setup 装载 +//endpoint sss +func (e *QiNiuKODO) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error { + + mac := qbox.NewMac(accessKeyID, accessKeySecret) + // 获取存储空间。 + cfg := storage.Config{} + // 空间对应的机房 + e.setZoneORDefault(cfg, options...) + // 是否使用https域名 + cfg.UseHTTPS = true + // 上传是否使用CDN上传加速 + cfg.UseCdnDomains = false + + e.Client = mac + e.BucketName = BucketName + e.cfg = cfg + e.options = options + return nil +} + +// setZoneORDefault 设置Zone或者默认华东 +func (e *QiNiuKODO) setZoneORDefault(cfg storage.Config, options ...ClientOption) { + if len(options) > 0 && options[0]["Zone"] != nil { + if _, ok := options[0]["Zone"].(Zone); !ok { + cfg.Zone = &storage.ZoneHuadong + } + switch options[0]["Zone"].(Zone) { + case HuaDong: + cfg.Zone = &storage.ZoneHuadong + case HuaBei: + cfg.Zone = &storage.ZoneHuabei + case HuaNan: + cfg.Zone = &storage.ZoneHuanan + case BeiMei: + cfg.Zone = &storage.ZoneBeimei + case XinJiaPo: + cfg.Zone = &storage.ZoneXinjiapo + default: + cfg.Zone = &storage.ZoneHuadong + } + } +} + +// UpLoad 文件上传 +func (e *QiNiuKODO) UpLoad(yourObjectName string, localFile interface{}) error { + + // 构建表单上传的对象 + formUploader := storage.NewFormUploader(&e.cfg) + ret := storage.PutRet{} + // 可选配置 + putExtra := storage.PutExtra{ + Params: map[string]string{ + "x:name": "github logo", + }, + } + err := formUploader.PutFile(context.Background(), &ret, e.getToken(), yourObjectName, localFile.(string), &putExtra) + if err != nil { + fmt.Println(err) + return err + } + fmt.Println(ret.Key, ret.Hash) + return nil +} + +func (e *QiNiuKODO) GetTempToken() (string, error) { + token := e.getToken() + return token, nil +} diff --git a/common/file_store/kodo_test.go b/common/file_store/kodo_test.go new file mode 100644 index 0000000..a8767ae --- /dev/null +++ b/common/file_store/kodo_test.go @@ -0,0 +1,23 @@ +package file_store + +import ( + "testing" +) + +func TestKODOUpload(t *testing.T) { + e := OXS{"", "", "", ""} + var oxs = e.Setup(QiNiuKodo, map[string]interface{}{"Zone": "华东"}) + err := oxs.UpLoad("test.png", "./test.png") + if err != nil { + t.Error(err) + } + t.Log("ok") +} + +func TestKODOGetTempToken(t *testing.T) { + e := OXS{"", "", "", ""} + var oxs = e.Setup(QiNiuKodo, map[string]interface{}{"Zone": "华东"}) + token, _ := oxs.GetTempToken() + t.Log(token) + t.Log("ok") +} diff --git a/common/file_store/obs.go b/common/file_store/obs.go new file mode 100644 index 0000000..e937729 --- /dev/null +++ b/common/file_store/obs.go @@ -0,0 +1,52 @@ +package file_store + +import ( + "fmt" + "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" + "log" +) + +type HuaWeiOBS struct { + Client interface{} + BucketName string +} + +func (e *HuaWeiOBS) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error { + // 创建ObsClient结构体 + client, err := obs.New(accessKeyID, accessKeySecret, endpoint) + if err != nil { + log.Println("Error:", err) + return err + } + e.Client = client + e.BucketName = BucketName + return nil +} + +// UpLoad 文件上传 +// yourObjectName 文件路径名称,与objectKey是同一概念,表示断点续传上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg +func (e *HuaWeiOBS) UpLoad(yourObjectName string, localFile interface{}) error { + // 获取存储空间。 + input := &obs.PutFileInput{} + input.Bucket = e.BucketName + input.Key = yourObjectName + input.SourceFile = localFile.(string) + output, err := e.Client.(*obs.ObsClient).PutFile(input) + + if err == nil { + fmt.Printf("RequestId:%s\n", output.RequestId) + fmt.Printf("ETag:%s, StorageClass:%s\n", output.ETag, output.StorageClass) + } else { + if obsError, ok := err.(obs.ObsError); ok { + fmt.Println(obsError.Code) + fmt.Println(obsError.Message) + } else { + fmt.Println(err) + } + } + return nil +} + +func (e *HuaWeiOBS) GetTempToken() (string, error) { + return "", nil +} diff --git a/common/file_store/obs_test.go b/common/file_store/obs_test.go new file mode 100644 index 0000000..0960750 --- /dev/null +++ b/common/file_store/obs_test.go @@ -0,0 +1,15 @@ +package file_store + +import ( + "testing" +) + +func TestOBSUpload(t *testing.T) { + e := OXS{"", "", "", ""} + var oxs = e.Setup(HuaweiOBS) + err := oxs.UpLoad("test.png", "./test.png") + if err != nil { + t.Error(err) + } + t.Log("ok") +} diff --git a/common/file_store/oss.go b/common/file_store/oss.go new file mode 100644 index 0000000..c35627b --- /dev/null +++ b/common/file_store/oss.go @@ -0,0 +1,48 @@ +package file_store + +import ( + "github.com/aliyun/aliyun-oss-go-sdk/oss" + "log" +) + +type ALiYunOSS struct { + Client interface{} + BucketName string +} + +//Setup 装载 +//endpoint sss +func (e *ALiYunOSS) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error { + client, err := oss.New(endpoint, accessKeyID, accessKeySecret) + if err != nil { + log.Println("Error:", err) + return err + } + e.Client = client + e.BucketName = BucketName + + return nil +} + +// UpLoad 文件上传 +func (e *ALiYunOSS) UpLoad(yourObjectName string, localFile interface{}) error { + // 获取存储空间。 + bucket, err := e.Client.(*oss.Client).Bucket(e.BucketName) + if err != nil { + log.Println("Error:", err) + return err + } + // 设置分片大小为100 KB,指定分片上传并发数为3,并开启断点续传上传。 + // 其中与objectKey是同一概念,表示断点续传上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 + // "LocalFile"为filePath,100*1024为partSize。 + err = bucket.UploadFile(yourObjectName, localFile.(string), 100*1024, oss.Routines(3), oss.Checkpoint(true, "")) + if err != nil { + log.Println("Error:", err) + return err + } + return nil +} + +func (e *ALiYunOSS) GetTempToken() (string, error) { + return "", nil +} diff --git a/common/file_store/oss_test.go b/common/file_store/oss_test.go new file mode 100644 index 0000000..f04dd22 --- /dev/null +++ b/common/file_store/oss_test.go @@ -0,0 +1,16 @@ +package file_store + +import ( + "testing" +) + +func TestOSSUpload(t *testing.T) { + // 打括号内填写自己的测试信息即可 + e := OXS{} + var oxs = e.Setup(AliYunOSS) + err := oxs.UpLoad("test.png", "./test.png") + if err != nil { + t.Error(err) + } + t.Log("ok") +} diff --git a/common/global/adm.go b/common/global/adm.go new file mode 100644 index 0000000..1344cac --- /dev/null +++ b/common/global/adm.go @@ -0,0 +1,11 @@ +package global + +const ( + // Version go-admin version info + Version = "2.1.2" +) + +var ( + // Driver 数据库驱动 + Driver string +) diff --git a/common/global/casbin.go b/common/global/casbin.go new file mode 100644 index 0000000..72b7e6c --- /dev/null +++ b/common/global/casbin.go @@ -0,0 +1,18 @@ +package global + +import ( + "github.com/casbin/casbin/v2" + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/api" +) + +func LoadPolicy(c *gin.Context) (*casbin.SyncedEnforcer, error) { + log := api.GetRequestLogger(c) + if err := sdk.Runtime.GetCasbinKey(c.Request.Host).LoadPolicy(); err == nil { + return sdk.Runtime.GetCasbinKey(c.Request.Host), err + } else { + log.Errorf("casbin rbac_model or policy init error, %s ", err.Error()) + return nil, err + } +} diff --git a/common/global/logo.go b/common/global/logo.go new file mode 100644 index 0000000..e4ed471 --- /dev/null +++ b/common/global/logo.go @@ -0,0 +1,4 @@ +package global + +// LogoContent go-admin ascii显示,减少静态文件依赖 +var LogoContent = []byte{10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 95, 95, 95, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 44, 45, 45, 45, 44, 32, 32, 32, 32, 32, 32, 32, 32, 44, 39, 32, 32, 44, 32, 96, 46, 32, 32, 44, 45, 45, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 44, 45, 45, 45, 46, 32, 32, 32, 32, 32, 32, 44, 45, 45, 45, 44, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 44, 45, 45, 45, 46, 39, 124, 32, 32, 32, 32, 32, 44, 45, 43, 45, 44, 46, 39, 32, 95, 32, 124, 44, 45, 45, 46, 39, 124, 32, 32, 32, 32, 32, 32, 32, 32, 32, 44, 45, 45, 45, 44, 10, 32, 32, 44, 45, 45, 45, 45, 46, 95, 44, 46, 32, 32, 39, 32, 32, 32, 44, 39, 92, 32, 32, 32, 44, 39, 32, 32, 46, 39, 32, 124, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 124, 32, 32, 32, 124, 32, 58, 32, 32, 44, 45, 43, 45, 46, 32, 59, 32, 32, 32, 44, 32, 124, 124, 124, 32, 32, 124, 44, 32, 32, 32, 32, 32, 32, 44, 45, 43, 45, 46, 32, 47, 32, 32, 124, 10, 32, 47, 32, 32, 32, 47, 32, 32, 39, 32, 47, 32, 47, 32, 32, 32, 47, 32, 32, 32, 124, 44, 45, 45, 45, 46, 39, 32, 32, 32, 44, 32, 44, 45, 45, 46, 45, 45, 46, 32, 32, 32, 32, 32, 32, 124, 32, 32, 32, 124, 32, 124, 32, 44, 45, 45, 46, 39, 124, 39, 32, 32, 32, 124, 32, 32, 124, 124, 96, 45, 45, 39, 95, 32, 32, 32, 32, 32, 44, 45, 45, 46, 39, 124, 39, 32, 32, 32, 124, 10, 124, 32, 32, 32, 58, 32, 32, 32, 32, 32, 124, 46, 32, 32, 32, 59, 32, 44, 46, 32, 58, 124, 32, 32, 32, 124, 32, 32, 32, 32, 124, 47, 32, 32, 32, 32, 32, 32, 32, 92, 32, 32, 32, 44, 45, 45, 46, 95, 95, 124, 32, 124, 124, 32, 32, 32, 124, 32, 32, 44, 39, 44, 32, 124, 32, 32, 124, 44, 44, 39, 32, 44, 39, 124, 32, 32, 32, 124, 32, 32, 32, 124, 32, 32, 44, 34, 39, 32, 124, 10, 124, 32, 32, 32, 124, 32, 46, 92, 32, 32, 46, 39, 32, 32, 32, 124, 32, 124, 58, 32, 58, 58, 32, 32, 32, 58, 32, 32, 46, 39, 46, 45, 45, 46, 32, 32, 46, 45, 46, 32, 124, 32, 47, 32, 32, 32, 44, 39, 32, 32, 32, 124, 124, 32, 32, 32, 124, 32, 47, 32, 32, 124, 32, 124, 45, 45, 39, 32, 39, 32, 32, 124, 32, 124, 32, 32, 32, 124, 32, 32, 32, 124, 32, 47, 32, 32, 124, 32, 124, 10, 46, 32, 32, 32, 59, 32, 39, 59, 32, 32, 124, 39, 32, 32, 32, 124, 32, 46, 59, 32, 58, 58, 32, 32, 32, 124, 46, 39, 32, 32, 32, 92, 95, 95, 92, 47, 58, 32, 46, 32, 46, 46, 32, 32, 32, 39, 32, 32, 47, 32, 32, 124, 124, 32, 32, 32, 58, 32, 124, 32, 32, 124, 32, 44, 32, 32, 32, 32, 124, 32, 32, 124, 32, 58, 32, 32, 32, 124, 32, 32, 32, 124, 32, 124, 32, 32, 124, 32, 124, 10, 39, 32, 32, 32, 46, 32, 32, 32, 46, 32, 124, 124, 32, 32, 32, 58, 32, 32, 32, 32, 124, 96, 45, 45, 45, 39, 32, 32, 32, 32, 32, 44, 34, 32, 46, 45, 45, 46, 59, 32, 124, 39, 32, 32, 32, 59, 32, 124, 58, 32, 32, 124, 124, 32, 32, 32, 58, 32, 124, 32, 32, 124, 47, 32, 32, 32, 32, 32, 39, 32, 32, 58, 32, 124, 95, 95, 32, 124, 32, 32, 32, 124, 32, 124, 32, 32, 124, 47, 10, 32, 96, 45, 45, 45, 96, 45, 39, 124, 32, 124, 32, 92, 32, 32, 32, 92, 32, 32, 47, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 47, 32, 32, 47, 32, 32, 44, 46, 32, 32, 124, 124, 32, 32, 32, 124, 32, 39, 47, 32, 32, 39, 124, 32, 32, 32, 124, 32, 124, 96, 45, 39, 32, 32, 32, 32, 32, 32, 124, 32, 32, 124, 32, 39, 46, 39, 124, 124, 32, 32, 32, 124, 32, 124, 45, 45, 39, 10, 32, 46, 39, 95, 95, 47, 92, 95, 58, 32, 124, 32, 32, 96, 45, 45, 45, 45, 39, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 59, 32, 32, 58, 32, 32, 32, 46, 39, 32, 32, 32, 92, 32, 32, 32, 58, 32, 32, 32, 32, 58, 124, 124, 32, 32, 32, 59, 47, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 59, 32, 32, 58, 32, 32, 32, 32, 59, 124, 32, 32, 32, 124, 47, 10, 32, 124, 32, 32, 32, 58, 32, 32, 32, 32, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 124, 32, 32, 44, 32, 32, 32, 32, 32, 46, 45, 46, 47, 92, 32, 32, 32, 92, 32, 32, 47, 32, 32, 39, 45, 45, 45, 39, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 124, 32, 32, 44, 32, 32, 32, 47, 32, 39, 45, 45, 45, 39, 10, 32, 32, 92, 32, 32, 32, 92, 32, 32, 47, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96, 45, 45, 96, 45, 45, 45, 39, 32, 32, 32, 32, 32, 96, 45, 45, 45, 45, 39, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 96, 45, 39, 10, 32, 32, 32, 96, 45, 45, 96, 45, 39, 10} diff --git a/common/global/topic.go b/common/global/topic.go new file mode 100644 index 0000000..60e1d34 --- /dev/null +++ b/common/global/topic.go @@ -0,0 +1,7 @@ +package global + +const ( + LoginLog = "login_log_queue" + OperateLog = "operate_log_queue" + ApiCheck = "api_check_queue" +) diff --git a/common/ip.go b/common/ip.go new file mode 100644 index 0000000..bc4d9ef --- /dev/null +++ b/common/ip.go @@ -0,0 +1,27 @@ +package common + +import ( + "github.com/gin-gonic/gin" + "strings" +) + +func GetClientIP(c *gin.Context) string { + ClientIP := c.ClientIP() + //fmt.Println("ClientIP:", ClientIP) + RemoteIP := c.RemoteIP() + //fmt.Println("RemoteIP:", RemoteIP) + ip := c.Request.Header.Get("X-Forwarded-For") + if strings.Contains(ip, "127.0.0.1") || ip == "" { + ip = c.Request.Header.Get("X-real-ip") + } + if ip == "" { + ip = "127.0.0.1" + } + if RemoteIP != "127.0.0.1" { + ip = RemoteIP + } + if ClientIP != "127.0.0.1" { + ip = ClientIP + } + return ip +} diff --git a/common/middleware/auth.go b/common/middleware/auth.go new file mode 100644 index 0000000..a4efa9b --- /dev/null +++ b/common/middleware/auth.go @@ -0,0 +1,178 @@ +package middleware + +import ( + "fmt" + "time" + + "go-admin/common/middleware/handler" + rediskey "go-admin/common/redis_key" + "go-admin/common/statuscode" + "go-admin/utils/redishelper" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/config" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" +) + +// AuthInit jwt验证new +func AuthInit() (*jwt.GinJWTMiddleware, error) { + timeout := time.Hour + if config.ApplicationConfig.Mode == "dev" { + timeout = time.Duration(876010) * time.Hour + } else { + if config.JwtConfig.Timeout != 0 { + timeout = time.Duration(config.JwtConfig.Timeout) * time.Second + } + } + return jwt.New(&jwt.GinJWTMiddleware{ + Realm: "test zone", + Key: []byte(config.JwtConfig.Secret), + Timeout: timeout, + MaxRefresh: time.Hour, + PayloadFunc: handler.PayloadFunc, + IdentityHandler: handler.IdentityHandler, + Authenticator: handler.Authenticator, + Authorizator: handler.Authorizator, + Unauthorized: handler.Unauthorized, + TokenLookup: "header: Authorization, query: token, cookie: jwt", + TokenHeadName: "Bearer", + TimeFunc: time.Now, + }) + +} + +// apikey授权认证 +func FrontedAuth(c *gin.Context) { + // 从请求头中获取 token 和 os + apikey := c.GetHeader("x-api-key") + // 如果 token 不存在,返回未登录的状态 + if len(apikey) == 0 { + err := ResponseWithStatus(c, statuscode.Unauthorized) + if err != nil { + return + } + c.Abort() // 停止后续中间件的执行 + return + } + // 验证 token 并获取结果 + key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, apikey) + val, err := redishelper.DefaultRedis.GetString(key) + + if err != nil || val == "" { + ResponseWithStatus(c, statuscode.Unauthorized) + c.Abort() // 停止后续中间件的执行 + } + + // 将解析后的 token 设置到请求头中 + c.Set("apiKey", apikey) + // 继续处理请求 + c.Next() +} + +// ResponseWithStatus 带状态的响应 +func ResponseWithStatus(ctx *gin.Context, code int, data ...interface{}) error { + // 获取语言对应的 msg + // msg := statuscode.GetStatusCodeDescription(ctx, code) + // if msg == `` { + // msg = strconv.Itoa(code) + // } else { + // // 配置了语言包参数 + // if strings.Contains(msg, "%") && len(data) > 1 { + // msg = fmt.Sprintf(msg, data[1:]...) + // } + // } + + resp := statuscode.Response{ + Code: code, + Msg: "un authorized", + } + + // resp.RequestID = pkg.GenerateMsgIDFromContext(ctx) + if len(data) > 0 { + resp.Data = data[0] + } + + switch code { + case 401, 500, 405, 404: + ctx.JSON(code, resp) + default: + ctx.JSON(200, resp) + } + + return nil +} + +// func AuthApiInit() (*jwt.GinJWTMiddleware, error) gin.HandlerFunc { +// return func(c *gin.Context) { +// // 1. 从请求头或查询参数中获取 API Key +// // 优先从 Header "X-API-Key" 获取,其次从查询参数 "api_key" 获取 +// apiKey := c.GetHeader("X-API-Key") +// if apiKey == "" { +// apiKey = c.Query("api_key") +// } + +// // 2. 检查 API Key 是否存在 +// if apiKey == "" { +// logger.Debug("API Key not provided in header or query parameter.") +// response.Unauthorized(c, "API Key is required.") +// c.Abort() // 终止请求处理链 +// return +// } + +// // 3. 验证 API Key 的有效性 +// // 实际项目中,这里需要查询数据库或缓存来验证 API Key,并获取其关联的用户ID或权限 +// // 伪代码示例: +// // user, isValid := service.AuthService.ValidateApiKey(apiKey) +// // if !isValid { +// // response.Unauthorized(c, "Invalid API Key.") +// // c.Abort() +// // return +// // } +// // c.Set("user_id", user.ID) // 将关联的用户ID设置到 Gin Context 中 + +// // 简化示例:从配置中获取一个硬编码的有效 API Key +// // **警告:生产环境中,绝不能硬编码 API Key!这只是一个演示。** +// // 假设 config.APIKeyConfig.ValidKeys 是一个 map[string]string,存储 apiKey -> userID 的映射 +// // 或者 config.APIKeyConfig.MasterKey 是一个单一的预设主密钥 + +// isValid := false +// associatedUserID := "" // 存储与 API Key 关联的用户ID + +// // 假设 API Key 存储在 config.APIKeyConfig 中,例如: +// // type APIKeyConfig struct { +// // MasterKey string `mapstructure:"master_key"` +// // ValidKeys map[string]string `mapstructure:"valid_keys"` // key: API Key, value: UserID +// // } +// // 你可能需要根据你的 config.go 中 API Key 配置的实际结构来调整 + +// // 示例:检查是否是 MasterKey +// if apiKey == config.APIKeyConfig.MasterKey { // 假设你有一个MasterKey +// isValid = true +// associatedUserID = "platform_admin" // 或者一个特殊的管理员ID +// } else { +// // 示例:检查是否在有效键列表中 +// for key, uid := range config.APIKeyConfig.ValidKeys { // 假设 ValidKeys 是一个 map +// if apiKey == key { +// isValid = true +// associatedUserID = uid +// break +// } +// } +// } + +// if !isValid { +// logger.Warnf("Attempted to use invalid API Key: %s", apiKey) +// response.Unauthorized(c, "Invalid API Key.") +// c.Abort() +// return +// } + +// // 4. API Key 验证成功,将关联的用户ID或信息设置到 Gin Context +// // 这样后续的业务逻辑(如翻译服务中的扣费)就可以通过 c.GetString("user_id") 获取到用户身份 +// c.Set("user_id", associatedUserID) +// logger.Debugf("API Key authenticated successfully for user: %s", associatedUserID) + +// // 5. 继续处理请求 +// c.Next() +// } +// } diff --git a/common/middleware/customerror.go b/common/middleware/customerror.go new file mode 100644 index 0000000..1f92628 --- /dev/null +++ b/common/middleware/customerror.go @@ -0,0 +1,61 @@ +package middleware + +import ( + "fmt" + "net/http" + "runtime" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" +) + +func CustomError(c *gin.Context) { + defer func() { + if err := recover(); err != nil { + + if c.IsAborted() { + c.Status(200) + } + switch errStr := err.(type) { + case string: + p := strings.Split(errStr, "#") + if len(p) == 3 && p[0] == "CustomError" { + statusCode, e := strconv.Atoi(p[1]) + if e != nil { + break + } + c.Status(statusCode) + fmt.Println( + time.Now().Format("2006-01-02 15:04:05"), + "[ERROR]", + c.Request.Method, + c.Request.URL, + statusCode, + c.Request.RequestURI, + c.ClientIP(), + p[2], + ) + c.JSON(http.StatusOK, gin.H{ + "code": statusCode, + "msg": p[2], + }) + } else { + c.JSON(http.StatusOK, gin.H{ + "code": 500, + "msg": errStr, + }) + } + case runtime.Error: + c.JSON(http.StatusOK, gin.H{ + "code": 500, + "msg": errStr.Error(), + }) + default: + panic(err) + } + } + }() + c.Next() +} diff --git a/common/middleware/db.go b/common/middleware/db.go new file mode 100644 index 0000000..0e73a2d --- /dev/null +++ b/common/middleware/db.go @@ -0,0 +1,11 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk" +) + +func WithContextDb(c *gin.Context) { + c.Set("db", sdk.Runtime.GetDbByKey(c.Request.Host).WithContext(c)) + c.Next() +} diff --git a/common/middleware/demo.go b/common/middleware/demo.go new file mode 100644 index 0000000..f13f28f --- /dev/null +++ b/common/middleware/demo.go @@ -0,0 +1,29 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/config" + "net/http" +) + +func DemoEvn() gin.HandlerFunc { + return func(c *gin.Context) { + method := c.Request.Method + if config.ApplicationConfig.Mode == "demo" { + if method == "GET" || + method == "OPTIONS" || + c.Request.RequestURI == "/api/v1/login" || + c.Request.RequestURI == "/api/v1/logout" { + c.Next() + } else { + c.JSON(http.StatusOK, gin.H{ + "code": 500, + "msg": "谢谢您的参与,但为了大家更好的体验,所以本次提交就算了吧!\U0001F600\U0001F600\U0001F600", + }) + c.Abort() + return + } + } + c.Next() + } +} diff --git a/common/middleware/handler/auth.go b/common/middleware/handler/auth.go new file mode 100644 index 0000000..ddb6791 --- /dev/null +++ b/common/middleware/handler/auth.go @@ -0,0 +1,182 @@ +package handler + +import ( + "go-admin/app/admin/models" + "go-admin/common" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/captcha" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + "github.com/mssola/user_agent" + "go-admin/common/global" +) + +func PayloadFunc(data interface{}) jwt.MapClaims { + if v, ok := data.(map[string]interface{}); ok { + u, _ := v["user"].(SysUser) + r, _ := v["role"].(SysRole) + return jwt.MapClaims{ + jwt.IdentityKey: u.UserId, + jwt.RoleIdKey: r.RoleId, + jwt.RoleKey: r.RoleKey, + jwt.NiceKey: u.Username, + jwt.DataScopeKey: r.DataScope, + jwt.RoleNameKey: r.RoleName, + } + } + return jwt.MapClaims{} +} + +func IdentityHandler(c *gin.Context) interface{} { + claims := jwt.ExtractClaims(c) + return map[string]interface{}{ + "IdentityKey": claims["identity"], + "UserName": claims["nice"], + "RoleKey": claims["rolekey"], + "UserId": claims["identity"], + "RoleIds": claims["roleid"], + "DataScope": claims["datascope"], + } +} + +// Authenticator 获取token +// @Summary 登陆 +// @Description 获取token +// @Description LoginHandler can be used by clients to get a jwt token. +// @Description Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}. +// @Description Reply will be of the form {"token": "TOKEN"}. +// @Description dev mode:It should be noted that all fields cannot be empty, and a value of 0 can be passed in addition to the account password +// @Description 注意:开发模式:需要注意全部字段不能为空,账号密码外可以传入0值 +// @Tags 登陆 +// @Accept application/json +// @Product application/json +// @Param account body Login true "account" +// @Success 200 {string} string "{"code": 200, "expire": "2019-08-07T12:45:48+08:00", "token": ".eyJleHAiOjE1NjUxNTMxNDgsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU2NTE0OTU0OH0.-zvzHvbg0A" }" +// @Router /api/v1/login [post] +func Authenticator(c *gin.Context) (interface{}, error) { + log := api.GetRequestLogger(c) + db, err := pkg.GetOrm(c) + if err != nil { + log.Errorf("get db error, %s", err.Error()) + response.Error(c, 500, err, "数据库连接获取失败") + return nil, jwt.ErrFailedAuthentication + } + + var loginVals Login + var status = "2" + var msg = "登录成功" + var username = "" + defer func() { + LoginLogToDB(c, status, msg, username) + }() + + if err = c.ShouldBind(&loginVals); err != nil { + username = loginVals.Username + msg = "数据解析失败" + status = "1" + + return nil, jwt.ErrMissingLoginValues + } + if config.ApplicationConfig.Mode != "dev" { + if !captcha.Verify(loginVals.UUID, loginVals.Code, true) { + username = loginVals.Username + msg = "验证码错误" + status = "1" + + return nil, jwt.ErrInvalidVerificationode + } + } + sysUser, role, e := loginVals.GetUser(db) + if e == nil { + username = loginVals.Username + + return map[string]interface{}{"user": sysUser, "role": role}, nil + } else { + msg = "登录失败" + status = "1" + log.Warnf("%s login failed!", loginVals.Username) + } + return nil, jwt.ErrFailedAuthentication +} + +// LoginLogToDB Write log to database +func LoginLogToDB(c *gin.Context, status string, msg string, username string) { + if !config.LoggerConfig.EnabledDB { + return + } + log := api.GetRequestLogger(c) + l := make(map[string]interface{}) + + ua := user_agent.New(c.Request.UserAgent()) + l["ipaddr"] = common.GetClientIP(c) + l["loginLocation"] = "" // pkg.GetLocation(common.GetClientIP(c),gaConfig.ExtConfig.AMap.Key) + l["loginTime"] = pkg.GetCurrentTime() + l["status"] = status + l["remark"] = c.Request.UserAgent() + browserName, browserVersion := ua.Browser() + l["browser"] = browserName + " " + browserVersion + l["os"] = ua.OS() + l["platform"] = ua.Platform() + l["username"] = username + l["msg"] = msg + + q := sdk.Runtime.GetMemoryQueue(c.Request.Host) + message, err := sdk.Runtime.GetStreamMessage("", global.LoginLog, l) + if err != nil { + log.Errorf("GetStreamMessage error, %s", err.Error()) + //日志报错错误,不中断请求 + } else { + err = q.Append(message) + if err != nil { + log.Errorf("Append message error, %s", err.Error()) + } + } +} + +// LogOut +// @Summary 退出登录 +// @Description 获取token +// LoginHandler can be used by clients to get a jwt token. +// Reply will be of the form {"token": "TOKEN"}. +// @Accept application/json +// @Product application/json +// @Success 200 {string} string "{"code": 200, "msg": "成功退出系统" }" +// @Router /logout [post] +// @Security Bearer +func LogOut(c *gin.Context) { + LoginLogToDB(c, "2", "退出成功", user.GetUserName(c)) + c.JSON(http.StatusOK, gin.H{ + "code": 200, + "msg": "退出成功", + }) + +} + +func Authorizator(data interface{}, c *gin.Context) bool { + + if v, ok := data.(map[string]interface{}); ok { + u, _ := v["user"].(models.SysUser) + r, _ := v["role"].(models.SysRole) + c.Set("role", r.RoleName) + c.Set("roleIds", r.RoleId) + c.Set("userId", u.UserId) + c.Set("userName", u.Username) + c.Set("dataScope", r.DataScope) + return true + } + return false +} + +func Unauthorized(c *gin.Context, code int, message string) { + c.JSON(http.StatusOK, gin.H{ + "code": code, + "msg": message, + }) +} diff --git a/common/middleware/handler/httpshandler.go b/common/middleware/handler/httpshandler.go new file mode 100644 index 0000000..e127439 --- /dev/null +++ b/common/middleware/handler/httpshandler.go @@ -0,0 +1,22 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + "github.com/unrolled/secure" + + "github.com/go-admin-team/go-admin-core/sdk/config" +) + +func TlsHandler() gin.HandlerFunc { + return func(c *gin.Context) { + secureMiddleware := secure.New(secure.Options{ + SSLRedirect: true, + SSLHost: config.SslConfig.Domain, + }) + err := secureMiddleware.Process(c.Writer, c.Request) + if err != nil { + return + } + c.Next() + } +} diff --git a/common/middleware/handler/login.go b/common/middleware/handler/login.go new file mode 100644 index 0000000..d17626c --- /dev/null +++ b/common/middleware/handler/login.go @@ -0,0 +1,33 @@ +package handler + +import ( + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "gorm.io/gorm" +) + +type Login struct { + Username string `form:"UserName" json:"username" binding:"required"` + Password string `form:"Password" json:"password" binding:"required"` + Code string `form:"Code" json:"code" binding:"required"` + UUID string `form:"UUID" json:"uuid" binding:"required"` +} + +func (u *Login) GetUser(tx *gorm.DB) (user SysUser, role SysRole, err error) { + err = tx.Table("sys_user").Where("username = ? and status = '2'", u.Username).First(&user).Error + if err != nil { + log.Errorf("get user error, %s", err.Error()) + return + } + _, err = pkg.CompareHashAndPassword(user.Password, u.Password) + if err != nil { + log.Errorf("user login error, %s", err.Error()) + return + } + err = tx.Table("sys_role").Where("role_id = ? ", user.RoleId).First(&role).Error + if err != nil { + log.Errorf("get role error, %s", err.Error()) + return + } + return +} diff --git a/common/middleware/handler/ping.go b/common/middleware/handler/ping.go new file mode 100644 index 0000000..ab4d645 --- /dev/null +++ b/common/middleware/handler/ping.go @@ -0,0 +1,11 @@ +package handler + +import ( + "github.com/gin-gonic/gin" +) + +func Ping(c *gin.Context) { + c.JSON(200, gin.H{ + "message": "ok", + }) +} diff --git a/common/middleware/handler/role.go b/common/middleware/handler/role.go new file mode 100644 index 0000000..0895ebc --- /dev/null +++ b/common/middleware/handler/role.go @@ -0,0 +1,24 @@ +package handler + +import "go-admin/common/models" + +type SysRole struct { + RoleId int `json:"roleId" gorm:"primaryKey;autoIncrement"` // 角色编码 + RoleName string `json:"roleName" gorm:"size:128;"` // 角色名称 + Status string `json:"status" gorm:"size:4;"` // + RoleKey string `json:"roleKey" gorm:"size:128;"` //角色代码 + RoleSort int `json:"roleSort" gorm:""` //角色排序 + Flag string `json:"flag" gorm:"size:128;"` // + Remark string `json:"remark" gorm:"size:255;"` //备注 + Admin bool `json:"admin" gorm:"size:4;"` + DataScope string `json:"dataScope" gorm:"size:128;"` + Params string `json:"params" gorm:"-"` + MenuIds []int `json:"menuIds" gorm:"-"` + DeptIds []int `json:"deptIds" gorm:"-"` + models.ControlBy + models.ModelTime +} + +func (SysRole) TableName() string { + return "sys_role" +} diff --git a/common/middleware/handler/user.go b/common/middleware/handler/user.go new file mode 100644 index 0000000..b34d4db --- /dev/null +++ b/common/middleware/handler/user.go @@ -0,0 +1,40 @@ +package handler + +import ( + "go-admin/common/models" + "gorm.io/gorm" +) + +type SysUser struct { + UserId int `gorm:"primaryKey;autoIncrement;comment:编码" json:"userId"` + Username string `json:"username" gorm:"size:64;comment:用户名"` + Password string `json:"-" gorm:"size:128;comment:密码"` + NickName string `json:"nickName" gorm:"size:128;comment:昵称"` + Phone string `json:"phone" gorm:"size:11;comment:手机号"` + RoleId int `json:"roleId" gorm:"size:20;comment:角色ID"` + Salt string `json:"-" gorm:"size:255;comment:加盐"` + Avatar string `json:"avatar" gorm:"size:255;comment:头像"` + Sex string `json:"sex" gorm:"size:255;comment:性别"` + Email string `json:"email" gorm:"size:128;comment:邮箱"` + DeptId int `json:"deptId" gorm:"size:20;comment:部门"` + PostId int `json:"postId" gorm:"size:20;comment:岗位"` + Remark string `json:"remark" gorm:"size:255;comment:备注"` + Status string `json:"status" gorm:"size:4;comment:状态"` + DeptIds []int `json:"deptIds" gorm:"-"` + PostIds []int `json:"postIds" gorm:"-"` + RoleIds []int `json:"roleIds" gorm:"-"` + //Dept *SysDept `json:"dept"` + models.ControlBy + models.ModelTime +} + +func (*SysUser) TableName() string { + return "sys_user" +} + +func (e *SysUser) AfterFind(_ *gorm.DB) error { + e.DeptIds = []int{e.DeptId} + e.PostIds = []int{e.PostId} + e.RoleIds = []int{e.RoleId} + return nil +} diff --git a/common/middleware/header.go b/common/middleware/header.go new file mode 100644 index 0000000..b1411e5 --- /dev/null +++ b/common/middleware/header.go @@ -0,0 +1,48 @@ +package middleware + +import ( + "net/http" + "time" + + "github.com/gin-gonic/gin" +) + +// NoCache is a middleware function that appends headers +// to prevent the client from caching the HTTP response. +func NoCache(c *gin.Context) { + c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value") + c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT") + c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) + c.Next() +} + +// Options is a middleware function that appends headers +// for options requests and aborts then exits the middleware +// chain and ends the request. +func Options(c *gin.Context) { + if c.Request.Method != "OPTIONS" { + c.Next() + } else { + c.Header("Access-Control-Allow-Origin", "*") + c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS") + c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept") + c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS") + c.Header("Content-Type", "application/json") + c.AbortWithStatus(200) + } +} + +// Secure is a middleware function that appends security +// and resource access headers. +func Secure(c *gin.Context) { + c.Header("Access-Control-Allow-Origin", "*") + //c.Header("X-Frame-Options", "DENY") + c.Header("X-Content-Type-Options", "nosniff") + c.Header("X-XSS-Protection", "1; mode=block") + if c.Request.TLS != nil { + c.Header("Strict-Transport-Security", "max-age=31536000") + } + + // Also consider adding Content-Security-Policy headers + // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com") +} diff --git a/common/middleware/init.go b/common/middleware/init.go new file mode 100644 index 0000000..9902698 --- /dev/null +++ b/common/middleware/init.go @@ -0,0 +1,35 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "go-admin/common/actions" +) + +const ( + JwtTokenCheck string = "JwtToken" + RoleCheck string = "AuthCheckRole" + PermissionCheck string = "PermissionAction" +) + +func InitMiddleware(r *gin.Engine) { + r.Use(DemoEvn()) + // 数据库链接 + r.Use(WithContextDb) + // 日志处理 + r.Use(LoggerToFile()) + // 自定义错误处理 + r.Use(CustomError) + // NoCache is a middleware function that appends headers + r.Use(NoCache) + // 跨域处理 + r.Use(Options) + // Secure is a middleware function that appends security + r.Use(Secure) + // 链路追踪 + //r.Use(middleware.Trace()) + sdk.Runtime.SetMiddleware(JwtTokenCheck, (*jwt.GinJWTMiddleware).MiddlewareFunc) + sdk.Runtime.SetMiddleware(RoleCheck, AuthCheckRole()) + sdk.Runtime.SetMiddleware(PermissionCheck, actions.PermissionAction()) +} diff --git a/common/middleware/logger.go b/common/middleware/logger.go new file mode 100644 index 0000000..89c2c07 --- /dev/null +++ b/common/middleware/logger.go @@ -0,0 +1,136 @@ +package middleware + +import ( + "bufio" + "bytes" + "encoding/json" + "go-admin/app/admin/service/dto" + "go-admin/common" + "io" + "io/ioutil" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + + "go-admin/common/global" +) + +// LoggerToFile 日志记录到文件 +func LoggerToFile() gin.HandlerFunc { + return func(c *gin.Context) { + log := api.GetRequestLogger(c) + // 开始时间 + startTime := time.Now() + // 处理请求 + var body string + switch c.Request.Method { + case http.MethodPost, http.MethodPut, http.MethodGet, http.MethodDelete: + bf := bytes.NewBuffer(nil) + wt := bufio.NewWriter(bf) + _, err := io.Copy(wt, c.Request.Body) + if err != nil { + log.Warnf("copy body error, %s", err.Error()) + err = nil + } + rb, _ := ioutil.ReadAll(bf) + c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(rb)) + body = string(rb) + } + + c.Next() + url := c.Request.RequestURI + if strings.Index(url, "logout") > -1 || + strings.Index(url, "login") > -1 { + return + } + // 结束时间 + endTime := time.Now() + if c.Request.Method == http.MethodOptions { + return + } + + rt, bl := c.Get("result") + var result = "" + if bl { + rb, err := json.Marshal(rt) + if err != nil { + log.Warnf("json Marshal result error, %s", err.Error()) + } else { + result = string(rb) + } + } + + st, bl := c.Get("status") + var statusBus = 0 + if bl { + statusBus = st.(int) + } + + // 请求方式 + reqMethod := c.Request.Method + // 请求路由 + reqUri := c.Request.RequestURI + // 状态码 + statusCode := c.Writer.Status() + // 请求IP + clientIP := common.GetClientIP(c) + // 执行时间 + latencyTime := endTime.Sub(startTime) + // 日志格式 + logData := map[string]interface{}{ + "statusCode": statusCode, + "latencyTime": latencyTime, + "clientIP": clientIP, + "method": reqMethod, + "uri": reqUri, + } + log.WithFields(logData).Info() + + if c.Request.Method != "OPTIONS" && config.LoggerConfig.EnabledDB && statusCode != 404 { + SetDBOperLog(c, clientIP, statusCode, reqUri, reqMethod, latencyTime, body, result, statusBus) + } + } +} + +// SetDBOperLog 写入操作日志表 fixme 该方法后续即将弃用 +func SetDBOperLog(c *gin.Context, clientIP string, statusCode int, reqUri string, reqMethod string, latencyTime time.Duration, body string, result string, status int) { + + log := api.GetRequestLogger(c) + l := make(map[string]interface{}) + l["_fullPath"] = c.FullPath() + l["operUrl"] = reqUri + l["operIp"] = clientIP + l["operLocation"] = "" // pkg.GetLocation(clientIP, gaConfig.ExtConfig.AMap.Key) + l["operName"] = user.GetUserName(c) + l["requestMethod"] = reqMethod + l["operParam"] = body + l["operTime"] = time.Now() + l["jsonResult"] = result + l["latencyTime"] = latencyTime.String() + l["statusCode"] = statusCode + l["userAgent"] = c.Request.UserAgent() + l["createBy"] = user.GetUserId(c) + l["updateBy"] = user.GetUserId(c) + if status == http.StatusOK { + l["status"] = dto.OperaStatusEnabel + } else { + l["status"] = dto.OperaStatusDisable + } + q := sdk.Runtime.GetMemoryQueue(c.Request.Host) + message, err := sdk.Runtime.GetStreamMessage("", global.OperateLog, l) + if err != nil { + log.Errorf("GetStreamMessage error, %s", err.Error()) + //日志报错错误,不中断请求 + } else { + err = q.Append(message) + if err != nil { + log.Errorf("Append message error, %s", err.Error()) + } + } +} diff --git a/common/middleware/permission.go b/common/middleware/permission.go new file mode 100644 index 0000000..00d1b1f --- /dev/null +++ b/common/middleware/permission.go @@ -0,0 +1,61 @@ +package middleware + +import ( + "github.com/casbin/casbin/v2/util" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + "github.com/go-admin-team/go-admin-core/sdk/pkg/response" +) + +// AuthCheckRole 权限检查中间件 +func AuthCheckRole() gin.HandlerFunc { + return func(c *gin.Context) { + log := api.GetRequestLogger(c) + data, _ := c.Get(jwtauth.JwtPayloadKey) + v := data.(jwtauth.MapClaims) + e := sdk.Runtime.GetCasbinKey(c.Request.Host) + var res, casbinExclude bool + var err error + //检查权限 + if v["rolekey"] == "admin" { + res = true + c.Next() + return + } + for _, i := range CasbinExclude { + if util.KeyMatch2(c.Request.URL.Path, i.Url) && c.Request.Method == i.Method { + casbinExclude = true + break + } + } + if casbinExclude { + log.Infof("Casbin exclusion, no validation method:%s path:%s", c.Request.Method, c.Request.URL.Path) + c.Next() + return + } + res, err = e.Enforce(v["rolekey"], c.Request.URL.Path, c.Request.Method) + if err != nil { + log.Errorf("AuthCheckRole error:%s method:%s path:%s", err, c.Request.Method, c.Request.URL.Path) + response.Error(c, 500, err, "") + return + } + + if res { + log.Infof("isTrue: %v role: %s method: %s path: %s", res, v["rolekey"], c.Request.Method, c.Request.URL.Path) + c.Next() + } else { + log.Warnf("isTrue: %v role: %s method: %s path: %s message: %s", res, v["rolekey"], c.Request.Method, c.Request.URL.Path, "当前request无权限,请管理员确认!") + c.JSON(http.StatusOK, gin.H{ + "code": 403, + "msg": "对不起,您没有该接口访问权限,请联系管理员", + }) + c.Abort() + return + } + + } +} diff --git a/common/middleware/request_id.go b/common/middleware/request_id.go new file mode 100644 index 0000000..8dedd83 --- /dev/null +++ b/common/middleware/request_id.go @@ -0,0 +1,36 @@ +package middleware + +import ( + "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk/pkg" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// RequestId 自动增加requestId +func RequestId(trafficKey string) gin.HandlerFunc { + return func(c *gin.Context) { + if c.Request.Method == http.MethodOptions { + c.Next() + return + } + requestId := c.GetHeader(trafficKey) + if requestId == "" { + requestId = c.GetHeader(strings.ToLower(trafficKey)) + } + if requestId == "" { + requestId = uuid.New().String() + } + c.Request.Header.Set(trafficKey, requestId) + c.Set(trafficKey, requestId) + c.Set(pkg.LoggerKey, + logger.NewHelper(logger.DefaultLogger). + WithFields(map[string]interface{}{ + trafficKey: requestId, + })) + c.Next() + } +} diff --git a/common/middleware/sentinel.go b/common/middleware/sentinel.go new file mode 100644 index 0000000..603559a --- /dev/null +++ b/common/middleware/sentinel.go @@ -0,0 +1,30 @@ +package middleware + +import ( + "github.com/alibaba/sentinel-golang/core/system" + sentinel "github.com/alibaba/sentinel-golang/pkg/adapters/gin" + "github.com/gin-gonic/gin" + + log "github.com/go-admin-team/go-admin-core/logger" +) + +// Sentinel 限流 +func Sentinel() gin.HandlerFunc { + if _, err := system.LoadRules([]*system.Rule{ + { + MetricType: system.InboundQPS, + TriggerCount: 200, + Strategy: system.BBR, + }, + }); err != nil { + log.Fatalf("Unexpected error: %+v", err) + } + return sentinel.SentinelMiddleware( + sentinel.WithBlockFallback(func(ctx *gin.Context) { + ctx.AbortWithStatusJSON(200, map[string]interface{}{ + "msg": "too many request; the quota used up!", + "code": 500, + }) + }), + ) +} diff --git a/common/middleware/settings.go b/common/middleware/settings.go new file mode 100644 index 0000000..daf8d30 --- /dev/null +++ b/common/middleware/settings.go @@ -0,0 +1,43 @@ +package middleware + +type UrlInfo struct { + Url string + Method string +} + +// CasbinExclude casbin 排除的路由列表 +var CasbinExclude = []UrlInfo{ + {Url: "/api/v1/dict/type-option-select", Method: "GET"}, + {Url: "/api/v1/dict-data/option-select", Method: "GET"}, + {Url: "/api/v1/deptTree", Method: "GET"}, + {Url: "/api/v1/db/tables/page", Method: "GET"}, + {Url: "/api/v1/db/columns/page", Method: "GET"}, + {Url: "/api/v1/gen/toproject/:tableId", Method: "GET"}, + {Url: "/api/v1/gen/todb/:tableId", Method: "GET"}, + {Url: "/api/v1/gen/tabletree", Method: "GET"}, + {Url: "/api/v1/gen/preview/:tableId", Method: "GET"}, + {Url: "/api/v1/gen/apitofile/:tableId", Method: "GET"}, + {Url: "/api/v1/getCaptcha", Method: "GET"}, + {Url: "/api/v1/getinfo", Method: "GET"}, + {Url: "/api/v1/menuTreeselect", Method: "GET"}, + {Url: "/api/v1/menurole", Method: "GET"}, + {Url: "/api/v1/menuids", Method: "GET"}, + {Url: "/api/v1/roleMenuTreeselect/:roleId", Method: "GET"}, + {Url: "/api/v1/roleDeptTreeselect/:roleId", Method: "GET"}, + {Url: "/api/v1/refresh_token", Method: "GET"}, + {Url: "/api/v1/configKey/:configKey", Method: "GET"}, + {Url: "/api/v1/app-config", Method: "GET"}, + {Url: "/api/v1/user/profile", Method: "GET"}, + {Url: "/info", Method: "GET"}, + {Url: "/api/v1/login", Method: "POST"}, + {Url: "/api/v1/logout", Method: "POST"}, + {Url: "/api/v1/user/avatar", Method: "POST"}, + {Url: "/api/v1/user/pwd", Method: "PUT"}, + {Url: "/api/v1/metrics", Method: "GET"}, + {Url: "/api/v1/health", Method: "GET"}, + {Url: "/", Method: "GET"}, + {Url: "/api/v1/server-monitor", Method: "GET"}, + {Url: "/api/v1/public/uploadFile", Method: "POST"}, + {Url: "/api/v1/user/pwd/set", Method: "PUT"}, + {Url: "/api/v1/sys-user", Method: "PUT"}, +} diff --git a/common/middleware/trace.go b/common/middleware/trace.go new file mode 100644 index 0000000..6cce4a3 --- /dev/null +++ b/common/middleware/trace.go @@ -0,0 +1,27 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "github.com/opentracing/opentracing-go" +) + +// Trace 链路追踪 +func Trace() gin.HandlerFunc { + return func(ctx *gin.Context) { + var sp opentracing.Span + opName := ctx.Request.URL.Path + // Attempt to join a trace by getting trace context from the headers. + wireContext, err := opentracing.GlobalTracer().Extract( + opentracing.TextMap, + opentracing.HTTPHeadersCarrier(ctx.Request.Header)) + if err != nil { + // If for whatever reason we can't join, go ahead and start a new root span. + sp = opentracing.StartSpan(opName) + } else { + sp = opentracing.StartSpan(opName, opentracing.ChildOf(wireContext)) + } + ctx.Set("traceSpan", sp) + ctx.Next() + sp.Finish() + } +} diff --git a/common/models/by.go b/common/models/by.go new file mode 100644 index 0000000..181c7ed --- /dev/null +++ b/common/models/by.go @@ -0,0 +1,32 @@ +package models + +import ( + "time" + + "gorm.io/gorm" +) + +type ControlBy struct { + CreateBy int `json:"createBy" gorm:"index;comment:创建者"` + UpdateBy int `json:"updateBy" gorm:"index;comment:更新者"` +} + +// SetCreateBy 设置创建人id +func (e *ControlBy) SetCreateBy(createBy int) { + e.CreateBy = createBy +} + +// SetUpdateBy 设置修改人id +func (e *ControlBy) SetUpdateBy(updateBy int) { + e.UpdateBy = updateBy +} + +type Model struct { + Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"` +} + +type ModelTime struct { + CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"` + UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"` + DeletedAt gorm.DeletedAt `json:"-" gorm:"index;comment:删除时间"` +} \ No newline at end of file diff --git a/common/models/menu.go b/common/models/menu.go new file mode 100644 index 0000000..e3b0c92 --- /dev/null +++ b/common/models/menu.go @@ -0,0 +1,11 @@ +package models + +// Menu 菜单中的类型枚举值 +const ( + // Directory 目录 + Directory string = "M" + // Menu 菜单 + Menu string = "C" + // Button 按钮 + Button string = "F" +) diff --git a/common/models/migrate.go b/common/models/migrate.go new file mode 100644 index 0000000..5573cb2 --- /dev/null +++ b/common/models/migrate.go @@ -0,0 +1,12 @@ +package models + +import "time" + +type Migration struct { + Version string `gorm:"primaryKey"` + ApplyTime time.Time `gorm:"autoCreateTime"` +} + +func (Migration) TableName() string { + return "sys_migration" +} diff --git a/common/models/response.go b/common/models/response.go new file mode 100644 index 0000000..8ee0625 --- /dev/null +++ b/common/models/response.go @@ -0,0 +1,30 @@ +package models + +type Response struct { + // 代码 + Code int `json:"code" example:"200"` + // 数据集 + Data interface{} `json:"data"` + // 消息 + Msg string `json:"msg"` + RequestId string `json:"requestId"` +} + +type Page struct { + List interface{} `json:"list"` + Count int `json:"count"` + PageIndex int `json:"pageIndex"` + PageSize int `json:"pageSize"` +} + +// ReturnOK 正常返回 +func (res *Response) ReturnOK() *Response { + res.Code = 200 + return res +} + +// ReturnError 错误返回 +func (res *Response) ReturnError(code int) *Response { + res.Code = code + return res +} diff --git a/common/models/type.go b/common/models/type.go new file mode 100644 index 0000000..2087d55 --- /dev/null +++ b/common/models/type.go @@ -0,0 +1,11 @@ +package models + +import "gorm.io/gorm/schema" + +type ActiveRecord interface { + schema.Tabler + SetCreateBy(createBy int) + SetUpdateBy(updateBy int) + Generate() ActiveRecord + GetId() interface{} +} diff --git a/common/models/user.go b/common/models/user.go new file mode 100644 index 0000000..6053bb3 --- /dev/null +++ b/common/models/user.go @@ -0,0 +1,42 @@ +package models + +import ( + "gorm.io/gorm" + + "github.com/go-admin-team/go-admin-core/sdk/pkg" +) + +// BaseUser 密码登录基础用户 +type BaseUser struct { + Username string `json:"username" gorm:"type:varchar(100);comment:用户名"` + Salt string `json:"-" gorm:"type:varchar(255);comment:加盐;<-"` + PasswordHash string `json:"-" gorm:"type:varchar(128);comment:密码hash;<-"` + Password string `json:"password" gorm:"-"` +} + +// SetPassword 设置密码 +func (u *BaseUser) SetPassword(value string) { + u.Password = value + u.generateSalt() + u.PasswordHash = u.GetPasswordHash() +} + +// GetPasswordHash 获取密码hash +func (u *BaseUser) GetPasswordHash() string { + passwordHash, err := pkg.SetPassword(u.Password, u.Salt) + if err != nil { + return "" + } + return passwordHash +} + +// generateSalt 生成加盐值 +func (u *BaseUser) generateSalt() { + u.Salt = pkg.GenerateRandomKey16() +} + +// Verify 验证密码 +func (u *BaseUser) Verify(db *gorm.DB, tableName string) bool { + db.Table(tableName).Where("username = ?", u.Username).First(u) + return u.GetPasswordHash() == u.PasswordHash +} diff --git a/common/mq/client.go b/common/mq/client.go new file mode 100644 index 0000000..214aec6 --- /dev/null +++ b/common/mq/client.go @@ -0,0 +1,82 @@ +package mq + +import ( + amqp "github.com/rabbitmq/amqp091-go" +) + +// MQClient 是 RabbitMQ 的封装结构体 +type MQClient struct { + Conn *amqp.Connection + Channel *amqp.Channel +} + +var MQ *MQClient // 全局复用实例 + +// InitMQ 初始化 RabbitMQ 连接和通道 +func InitMQ(rabbitURL string) (*MQClient, error) { + if rabbitURL == "" { + rabbitURL = "amqp://guest:guest@localhost:5672/" + } + + conn, err := amqp.Dial(rabbitURL) + if err != nil { + return nil, err + } + + ch, err := conn.Channel() + if err != nil { + return nil, err + } + + MQ = &MQClient{Conn: conn, Channel: ch} + return MQ, nil +} + +// Close 关闭连接和通道 +func (c *MQClient) Close() { + if c.Channel != nil { + _ = c.Channel.Close() + } + if c.Conn != nil { + _ = c.Conn.Close() + } +} + +// Publish 发布消息到指定队列 +func (c *MQClient) Publish(queue string, body []byte) error { + return c.Channel.Publish( + "", // exchange + queue, // routing key + false, + false, + amqp.Publishing{ + ContentType: "application/json", + Body: body, + }, + ) +} + +// DeclareQueue 声明队列 +func (c *MQClient) DeclareQueue(name string) (amqp.Queue, error) { + return c.Channel.QueueDeclare( + name, + true, // durable + false, // auto-delete + false, // exclusive + false, // no-wait + nil, // arguments + ) +} + +// Consume 注册消费者 +func (c *MQClient) Consume(queue string) (<-chan amqp.Delivery, error) { + return c.Channel.Consume( + queue, + "", // consumer tag + true, // auto ack + false, // exclusive + false, // no local + false, // no wait + nil, // args + ) +} diff --git a/common/redis_key/sys_config.go b/common/redis_key/sys_config.go new file mode 100644 index 0000000..b614513 --- /dev/null +++ b/common/redis_key/sys_config.go @@ -0,0 +1,6 @@ +package rediskey + +const ( + //配置参数详情 {key} + SYS_CONFIG_KEY = "sys_config:%s" +) diff --git a/common/redis_key/sys_dict.go b/common/redis_key/sys_dict.go new file mode 100644 index 0000000..7ab65c5 --- /dev/null +++ b/common/redis_key/sys_dict.go @@ -0,0 +1,10 @@ +package rediskey + +const ( + //字典 {dictKey} + SysDictKey = "sys_dict:%s" + //字典数据 {dictKey} + SysDictDataList = "sys_dict_data_list:%s" + //字典数据详情 {dictValue} + SysDictData = "sys_dict_data:%s" +) diff --git a/common/redis_key/tm_member.go b/common/redis_key/tm_member.go new file mode 100644 index 0000000..24e8e10 --- /dev/null +++ b/common/redis_key/tm_member.go @@ -0,0 +1,14 @@ +package rediskey + +const ( + //用户翻译详情 {key} + TM_MEMBER_BY_KEY = "tm_member_by_key:%s" + //用户每日翻译字符数 {date(yyyyMMdd),key,plateformCode} + TM_MEMBER_DAILY_COUNT = "tm_member_daily_count:%s:%s:%s" + //用户每日翻译字符数 {date(yyyyMMdd)} 只有前缀 + TM_MEMBER_DAILY_COUNT_PURE = "tm_member_daily_count" + //用户剩余翻译字符数 {key,plateformCode} + TM_MEMBER_REMAIN_COUNT = "tm_member_remain_count:%s:%s" + //用户剩余翻译字符数 {key} 只有前缀 + TM_MEMBER_REMAIN_COUNT_PURE = "tm_member_remain_count" +) diff --git a/common/redis_key/tm_platform.go b/common/redis_key/tm_platform.go new file mode 100644 index 0000000..63a4551 --- /dev/null +++ b/common/redis_key/tm_platform.go @@ -0,0 +1,14 @@ +package rediskey + +const ( + //详情 + TM_PLATFORM_KEY = "tm_platform:%s" + //列表 + TM_PLATFORM_LIST_KEY = "tm_platform_list" + + //平台账号列表 {platformCode} + TM_PLATFORM_ACCOUNT_LIST_KEY = "tm_platform_account_list:%s" + + //平台账号剩余字符 {platformCode,apikey} + TM_PLATEFORM_ACCOUNT_REMAIN_KEY = "tm_platform_account_remain:%s:%s" +) diff --git a/common/response/binding.go b/common/response/binding.go new file mode 100644 index 0000000..6cf279a --- /dev/null +++ b/common/response/binding.go @@ -0,0 +1,105 @@ +package response + +import ( + "fmt" + "github.com/gin-gonic/gin/binding" + "reflect" + "strings" + "sync" +) + +const ( + _ uint8 = iota + json + xml + yaml + form + query +) + +//var constructor = &bindConstructor{} + +type bindConstructor struct { + cache map[string][]uint8 + mux sync.Mutex +} + +func (e *bindConstructor) GetBindingForGin(d interface{}) []binding.Binding { + bs := e.getBinding(reflect.TypeOf(d).String()) + if bs == nil { + //重新构建 + bs = e.resolve(d) + } + gbs := make([]binding.Binding, len(bs)) + for i, b := range bs { + switch b { + case json: + gbs[i] = binding.JSON + case xml: + gbs[i] = binding.XML + case yaml: + gbs[i] = binding.YAML + case form: + gbs[i] = binding.Form + case query: + gbs[i] = binding.Query + default: + gbs[i] = nil + } + } + return gbs +} + +func (e *bindConstructor) resolve(d interface{}) []uint8 { + bs := make([]uint8, 0) + qType := reflect.TypeOf(d).Elem() + var tag reflect.StructTag + var ok bool + fmt.Println(qType.Kind()) + for i := 0; i < qType.NumField(); i++ { + tag = qType.Field(i).Tag + if _, ok = tag.Lookup("json"); ok { + bs = append(bs, json) + } + if _, ok = tag.Lookup("xml"); ok { + bs = append(bs, xml) + } + if _, ok = tag.Lookup("yaml"); ok { + bs = append(bs, yaml) + } + if _, ok = tag.Lookup("form"); ok { + bs = append(bs, form) + } + if _, ok = tag.Lookup("query"); ok { + bs = append(bs, query) + } + if _, ok = tag.Lookup("uri"); ok { + bs = append(bs, 0) + } + if t, ok := tag.Lookup("binding"); ok && strings.Index(t, "dive") > -1 { + qValue := reflect.ValueOf(d) + bs = append(bs, e.resolve(qValue.Field(i))...) + continue + } + if t, ok := tag.Lookup("validate"); ok && strings.Index(t, "dive") > -1 { + qValue := reflect.ValueOf(d) + bs = append(bs, e.resolve(qValue.Field(i))...) + } + } + return bs +} + +func (e *bindConstructor) getBinding(name string) []uint8 { + e.mux.Lock() + defer e.mux.Unlock() + return e.cache[name] +} + +func (e *bindConstructor) setBinding(name string, bs []uint8) { + e.mux.Lock() + defer e.mux.Unlock() + if e.cache == nil { + e.cache = make(map[string][]uint8) + } + e.cache[name] = bs +} diff --git a/common/service/service.go b/common/service/service.go new file mode 100644 index 0000000..0deb4a9 --- /dev/null +++ b/common/service/service.go @@ -0,0 +1,25 @@ +package service + +import ( + "fmt" + + "github.com/go-admin-team/go-admin-core/logger" + "gorm.io/gorm" +) + +type Service struct { + Orm *gorm.DB + Msg string + MsgID string + Log *logger.Helper + Error error +} + +func (db *Service) AddError(err error) error { + if db.Error == nil { + db.Error = err + } else if err != nil { + db.Error = fmt.Errorf("%v; %w", db.Error, err) + } + return db.Error +} diff --git a/common/statuscode/status_1.go b/common/statuscode/status_1.go new file mode 100644 index 0000000..d479bf0 --- /dev/null +++ b/common/statuscode/status_1.go @@ -0,0 +1,40 @@ +package statuscode + +// Response 响应结构 +type Response struct { + Status int `json:"status"` + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data"` + RequestID string `json:"RequestId"` +} + +var ErrorMessage = map[int]string{ + Success: "success", + Unauthorized: "unauthorized", + ServerError: "server error", + NotFound: "not found", + Forbidden: "forbidden", + InvalidParams: "invalid params", + InSufficRemainChar: "insufficent remain char", + PlatformNotSupport: "platform not support", + TransactionNotAvailable: "transaction not available", + ApiUnauthorized: "api unauthorized", +} + +const ( + Success = 200 //成功 + Unauthorized = 401 //未授权 + ServerError = 500 //服务器错误 + NotFound = 404 //未找到 + Forbidden = 403 //禁止访问 + + //=============== 公共code ================ + InvalidParams = 10001 //参数错误 + + //================ 翻译code =============== + InSufficRemainChar = 20001 //剩余字数不足 + PlatformNotSupport = 20002 //平台不支持 + TransactionNotAvailable = 20003 //翻译服务不可用 + ApiUnauthorized = 20004 //api禁止访问 +) diff --git a/common/storage/initialize.go b/common/storage/initialize.go new file mode 100644 index 0000000..8b11555 --- /dev/null +++ b/common/storage/initialize.go @@ -0,0 +1,53 @@ +/* + * @Author: lwnmengjing + * @Date: 2021/6/10 3:39 下午 + * @Last Modified by: lwnmengjing + * @Last Modified time: 2021/6/10 3:39 下午 + */ + +package storage + +import ( + "log" + + "github.com/go-admin-team/go-admin-core/sdk" + "github.com/go-admin-team/go-admin-core/sdk/config" + "github.com/go-admin-team/go-admin-core/sdk/pkg/captcha" +) + +// Setup 配置storage组件 +func Setup() { + //4. 设置缓存 + cacheAdapter, err := config.CacheConfig.Setup() + if err != nil { + log.Fatalf("cache setup error, %s\n", err.Error()) + } + + sdk.Runtime.SetCacheAdapter(cacheAdapter) + //5. 设置验证码store + captcha.SetStore(captcha.NewCacheStore(cacheAdapter, 600)) + + //6. 设置队列 + if !config.QueueConfig.Empty() { + if q := sdk.Runtime.GetQueueAdapter(); q != nil { + q.Shutdown() + } + queueAdapter, err := config.QueueConfig.Setup() + if err != nil { + log.Fatalf("queue setup error, %s\n", err.Error()) + } + sdk.Runtime.SetQueueAdapter(queueAdapter) + defer func() { + go queueAdapter.Run() + }() + } + + //7. 设置分布式锁 + if !config.LockerConfig.Empty() { + lockerAdapter, err := config.LockerConfig.Setup() + if err != nil { + log.Fatalf("locker setup error, %s\n", err.Error()) + } + sdk.Runtime.SetLockerAdapter(lockerAdapter) + } +} diff --git a/config/READMEN.md b/config/READMEN.md new file mode 100644 index 0000000..8ff880d --- /dev/null +++ b/config/READMEN.md @@ -0,0 +1,37 @@ +# ⚙ 配置详情 + +1. 配置文件说明 +```yml +settings: + application: + # 项目启动环境 + mode: dev # dev开发环境 test测试环境 prod线上环境; + host: 0.0.0.0 # 主机ip 或者域名,默认0.0.0.0 + # 服务名称 + name: go-admin + # 服务端口 + port: 8000 + readtimeout: 1 + writertimeout: 2 + log: + # 日志文件存放路径 + dir: temp/logs + jwt: + # JWT加密字符串 + secret: go-admin + # 过期时间单位:秒 + timeout: 3600 + database: + # 数据库名称 + name: dbname + # 数据库类型 + dbtype: mysql + # 数据库地址 + host: 127.0.0.1 + # 数据库密码 + password: password + # 数据库端口 + port: 3306 + # 数据库用户名 + username: root +``` \ No newline at end of file diff --git a/config/db-begin-mysql.sql b/config/db-begin-mysql.sql new file mode 100644 index 0000000..04da2f1 --- /dev/null +++ b/config/db-begin-mysql.sql @@ -0,0 +1,2 @@ +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; \ No newline at end of file diff --git a/config/db-end-mysql.sql b/config/db-end-mysql.sql new file mode 100644 index 0000000..4bd9d01 --- /dev/null +++ b/config/db-end-mysql.sql @@ -0,0 +1 @@ +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/config/db-sqlserver.sql b/config/db-sqlserver.sql new file mode 100644 index 0000000..0ba4168 --- /dev/null +++ b/config/db-sqlserver.sql @@ -0,0 +1,342 @@ +-- 开始初始化数据 ; +SET IDENTITY_INSERT sys_api ON; +INSERT INTO sys_api (id, handle, title, path, type, "action", created_at, updated_at, deleted_at, create_by, update_by)VALUES +(5, 'go-admin/app/admin/apis.SysLoginLog.Get-fm', '登录日志通过id获取', '/api/v1/sys-login-log/:id', 'BUS', 'GET', '2021-05-13 19:59:00.728', '2021-06-17 11:37:12.331', NULL, 0, 0), +(6, 'go-admin/app/admin/apis.SysOperaLog.GetPage-fm', '操作日志列表', '/api/v1/sys-opera-log', 'BUS', 'GET', '2021-05-13 19:59:00.778', '2021-06-17 11:48:40.732', NULL, 0, 0), +(7, 'go-admin/app/admin/apis.SysOperaLog.Get-fm', '操作日志通过id获取', '/api/v1/sys-opera-log/:id', 'BUS', 'GET', '2021-05-13 19:59:00.821', '2021-06-16 21:49:48.598', NULL, 0, 0), +(8, 'go-admin/common/actions.IndexAction.func1', '分类列表', '/api/v1/syscategory', 'BUS', 'GET', '2021-05-13 19:59:00.870', '2021-06-13 20:53:47.883', NULL, 0, 0), +(9, 'go-admin/common/actions.ViewAction.func1', '分类通过id获取', '/api/v1/syscategory/:id', 'BUS', 'GET', '2021-05-13 19:59:00.945', '2021-06-13 20:53:47.926', NULL, 0, 0), +(10, 'go-admin/common/actions.IndexAction.func1', '内容列表', '/api/v1/syscontent', 'BUS', 'GET', '2021-05-13 19:59:01.005', '2021-06-13 20:53:47.966', NULL, 0, 0), +(11, 'go-admin/common/actions.ViewAction.func1', '内容通过id获取', '/api/v1/syscontent/:id', 'BUS', 'GET', '2021-05-13 19:59:01.056', '2021-06-13 20:53:48.005', NULL, 0, 0), +(15, 'go-admin/common/actions.IndexAction.func1', 'job列表', '/api/v1/sysjob', 'BUS', 'GET', '2021-05-13 19:59:01.248', '2021-06-13 20:53:48.169', NULL, 0, 0), +(16, 'go-admin/common/actions.ViewAction.func1', 'job通过id获取', '/api/v1/sysjob/:id', 'BUS', 'GET', '2021-05-13 19:59:01.298', '2021-06-13 20:53:48.214', NULL, 0, 0), +(21, 'go-admin/app/admin/apis.SysDictType.GetPage-fm', '字典类型列表', '/api/v1/dict/type', 'BUS', 'GET', '2021-05-13 19:59:01.525', '2021-06-17 11:48:40.732', NULL, 0, 0), +(22, 'go-admin/app/admin/apis.SysDictType.GetAll-fm', '字典类型查询【代码生成】', '/api/v1/dict/type-option-select', 'SYS', 'GET', '2021-05-13 19:59:01.582', '2021-06-13 20:53:48.388', NULL, 0, 0), +(23, 'go-admin/app/admin/apis.SysDictType.Get-fm', '字典类型通过id获取', '/api/v1/dict/type/:id', 'BUS', 'GET', '2021-05-13 19:59:01.632', '2021-06-17 11:48:40.732', NULL, 0, 0), +(24, 'go-admin/app/admin/apis.SysDictData.GetPage-fm', '字典数据列表', '/api/v1/dict/data', 'BUS', 'GET', '2021-05-13 19:59:01.684', '2021-06-17 11:48:40.732', NULL, 0, 0), +(25, 'go-admin/app/admin/apis.SysDictData.Get-fm', '字典数据通过code获取', '/api/v1/dict/data/:dictCode', 'BUS', 'GET', '2021-05-13 19:59:01.732', '2021-06-17 11:48:40.732', NULL, 0, 0), +(26, 'go-admin/app/admin/apis.SysDictData.GetSysDictDataAll-fm', '数据字典根据key获取', '/api/v1/dict-data/option-select', 'SYS', 'GET', '2021-05-13 19:59:01.832', '2021-06-17 11:48:40.732', NULL, 0, 0), +(27, 'go-admin/app/admin/apis.SysDept.GetPage-fm', '部门列表', '/api/v1/dept', 'BUS', 'GET', '2021-05-13 19:59:01.940', '2021-06-17 11:48:40.732', NULL, 0, 0), +(28, 'go-admin/app/admin/apis.SysDept.Get-fm', '部门通过id获取', '/api/v1/dept/:id', 'BUS', 'GET', '2021-05-13 19:59:02.009', '2021-06-17 11:48:40.732', NULL, 0, 0), +(29, 'go-admin/app/admin/apis.SysDept.Get2Tree-fm', '查询部门下拉树【角色权限-自定权限】', '/api/v1/deptTree', 'SYS', 'GET', '2021-05-13 19:59:02.050', '2021-06-17 11:48:40.732', NULL, 0, 0), +(30, 'go-admin/app/admin/apis/tools.(*Gen).GetDBTableList-fm', '数据库表列表', '/api/v1/db/tables/page', 'SYS', 'GET', '2021-05-13 19:59:02.098', '2021-06-13 20:53:48.730', NULL, 0, 0), +(31, 'go-admin/app/admin/apis/tools.(*Gen).GetDBColumnList-fm', '数据表列列表', '/api/v1/db/columns/page', 'SYS', 'GET', '2021-05-13 19:59:02.140', '2021-06-13 20:53:48.771', NULL, 0, 0), +(32, 'go-admin/app/admin/apis/tools.Gen.GenCode-fm', '数据库表生成到项目', '/api/v1/gen/toproject/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.183', '2021-06-13 20:53:48.812', NULL, 0, 0), +(33, 'go-admin/app/admin/apis/tools.Gen.GenMenuAndApi-fm', '数据库表生成到DB', '/api/v1/gen/todb/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.227', '2021-06-13 20:53:48.853', NULL, 0, 0), +(34, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTablesTree-fm', '关系表数据【代码生成】', '/api/v1/gen/tabletree', 'SYS', 'GET', '2021-05-13 19:59:02.271', '2021-06-13 20:53:48.893', NULL, 0, 0), +(35, 'go-admin/app/admin/apis/tools.Gen.Preview-fm', '生成预览通过id获取', '/api/v1/gen/preview/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.315', '2021-06-13 20:53:48.935', NULL, 0, 0), +(36, 'go-admin/app/admin/apis/tools.Gen.GenApiToFile-fm', '生成api带文件', '/api/v1/gen/apitofile/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.357', '2021-06-13 20:53:48.977', NULL, 0, 0), +(37, 'go-admin/app/admin/apis.System.GenerateCaptchaHandler-fm', '验证码获取', '/api/v1/getCaptcha', 'SYS', 'GET', '2021-05-13 19:59:02.405', '2021-06-13 20:53:49.020', NULL, 0, 0), +(38, 'go-admin/app/admin/apis.SysUser.GetInfo-fm', '用户信息获取', '/api/v1/getinfo', 'SYS', 'GET', '2021-05-13 19:59:02.447', '2021-06-13 20:53:49.065', NULL, 0, 0), +(39, 'go-admin/app/admin/apis.SysMenu.GetPage-fm', '菜单列表', '/api/v1/menu', 'BUS', 'GET', '2021-05-13 19:59:02.497', '2021-06-17 11:48:40.732', NULL, 0, 0), +(40, 'go-admin/app/admin/apis.SysMenu.GetMenuTreeSelect-fm', '查询菜单下拉树结构【废弃】', '/api/v1/menuTreeselect', 'SYS', 'GET', '2021-05-13 19:59:02.542', '2021-06-03 22:37:21.857', NULL, 0, 0), +(41, 'go-admin/app/admin/apis.SysMenu.Get-fm', '菜单通过id获取', '/api/v1/menu/:id', 'BUS', 'GET', '2021-05-13 19:59:02.584', '2021-06-17 11:48:40.732', NULL, 0, 0), +(42, 'go-admin/app/admin/apis.SysMenu.GetMenuRole-fm', '角色菜单【顶部左侧菜单】', '/api/v1/menurole', 'SYS', 'GET', '2021-05-13 19:59:02.630', '2021-06-13 20:53:49.574', NULL, 0, 0), +(43, 'go-admin/app/admin/apis.SysMenu.GetMenuIDS-fm', '获取角色对应的菜单id数组【废弃】', '/api/v1/menuids', 'SYS', 'GET', '2021-05-13 19:59:02.675', '2021-06-03 22:39:52.500', NULL, 0, 0), +(44, 'go-admin/app/admin/apis.SysRole.GetPage-fm', '角色列表', '/api/v1/role', 'BUS', 'GET', '2021-05-13 19:59:02.720', '2021-06-17 11:48:40.732', NULL, 0, 0), +(45, 'go-admin/app/admin/apis.SysMenu.GetMenuTreeSelect-fm', '菜单权限列表【角色配菜单使用】', '/api/v1/roleMenuTreeselect/:roleId', 'SYS', 'GET', '2021-05-13 19:59:02.762', '2021-06-17 11:48:40.732', NULL, 0, 0), +(46, 'go-admin/app/admin/apis.SysDept.GetDeptTreeRoleSelect-fm', '角色部门结构树【自定义数据权限】', '/api/v1/roleDeptTreeselect/:roleId', 'SYS', 'GET', '2021-05-13 19:59:02.809', '2021-06-17 11:48:40.732', NULL, 0, 0), +(47, 'go-admin/app/admin/apis.SysRole.Get-fm', '角色通过id获取', '/api/v1/role/:id', 'BUS', 'GET', '2021-05-13 19:59:02.850', '2021-06-17 11:48:40.732', NULL, 0, 0), +(48, 'github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth.(*GinJWTMiddleware).RefreshHandler-fm', '刷新token', '/api/v1/refresh_token', 'SYS', 'GET', '2021-05-13 19:59:02.892', '2021-06-13 20:53:49.278', NULL, 0, 0), +(53, 'go-admin/app/admin/apis.SysConfig.GetPage-fm', '参数列表', '/api/v1/config', 'BUS', 'GET', '2021-05-13 19:59:03.116', '2021-06-17 11:48:40.732', NULL, 0, 0), +(54, 'go-admin/app/admin/apis.SysConfig.Get-fm', '参数通过id获取', '/api/v1/config/:id', 'BUS', 'GET', '2021-05-13 19:59:03.157', '2021-06-17 11:48:40.732', NULL, 0, 0), +(55, 'go-admin/app/admin/apis.SysConfig.GetSysConfigByKEYForService-fm', '参数通过键名搜索【基础默认配置】', '/api/v1/configKey/:configKey', 'SYS', 'GET', '2021-05-13 19:59:03.198', '2021-06-13 20:53:49.745', NULL, 0, 0), +(57, 'go-admin/app/jobs/apis.SysJob.RemoveJobForService-fm', 'job移除', '/api/v1/job/remove/:id', 'BUS', 'GET', '2021-05-13 19:59:03.295', '2021-06-13 20:53:49.786', NULL, 0, 0), +(58, 'go-admin/app/jobs/apis.SysJob.StartJobForService-fm', 'job启动', '/api/v1/job/start/:id', 'BUS', 'GET', '2021-05-13 19:59:03.339', '2021-06-13 20:53:49.829', NULL, 0, 0), +(59, 'go-admin/app/admin/apis.SysPost.GetPage-fm', '岗位列表', '/api/v1/post', 'BUS', 'GET', '2021-05-13 19:59:03.381', '2021-06-17 11:48:40.732', NULL, 0, 0), +(60, 'go-admin/app/admin/apis.SysPost.Get-fm', '岗位通过id获取', '/api/v1/post/:id', 'BUS', 'GET', '2021-05-13 19:59:03.433', '2021-06-17 11:48:40.732', NULL, 0, 0), +(62, 'go-admin/app/admin/apis.SysConfig.GetSysConfigBySysApp-fm', '系统前端参数', '/api/v1/app-config', 'SYS', 'GET', '2021-05-13 19:59:03.526', '2021-06-13 20:53:49.994', NULL, 0, 0), +(63, 'go-admin/app/admin/apis.SysUser.GetProfile-fm', '*用户信息获取', '/api/v1/user/profile', 'SYS', 'GET', '2021-05-13 19:59:03.567', '2021-06-13 20:53:50.038', NULL, 0, 0), +(66, 'github.com/go-admin-team/go-admin-core/sdk/pkg/ws.(*Manager).WsClient-fm', '链接ws【定时任务log】', '/ws/:id/:channel', 'BUS', 'GET', '2021-05-13 19:59:03.705', '2021-06-13 20:53:50.167', NULL, 0, 0), +(67, 'github.com/go-admin-team/go-admin-core/sdk/pkg/ws.(*Manager).UnWsClient-fm', '退出ws【定时任务log】', '/wslogout/:id/:channel', 'BUS', 'GET', '2021-05-13 19:59:03.756', '2021-06-13 20:53:50.209', NULL, 0, 0), +(68, 'go-admin/common/middleware/handler.Ping', '*用户基本信息', '/info', 'SYS', 'GET', '2021-05-13 19:59:03.800', '2021-06-13 20:53:50.251', NULL, 0, 0), +(72, 'go-admin/common/actions.CreateAction.func1', '分类创建', '/api/v1/syscategory', 'BUS', 'POST', '2021-05-13 19:59:03.982', '2021-06-13 20:53:50.336', NULL, 0, 0), +(73, 'go-admin/common/actions.CreateAction.func1', '内容创建', '/api/v1/syscontent', 'BUS', 'POST', '2021-05-13 19:59:04.027', '2021-06-13 20:53:50.375', NULL, 0, 0), +(76, 'go-admin/common/actions.CreateAction.func1', 'job创建', '/api/v1/sysjob', 'BUS', 'POST', '2021-05-13 19:59:04.164', '2021-06-13 20:53:50.500', NULL, 0, 0), +(80, 'go-admin/app/admin/apis.SysDictData.Insert-fm', '字典数据创建', '/api/v1/dict/data', 'BUS', 'POST', '2021-05-13 19:59:04.347', '2021-06-17 11:48:40.732', NULL, 0, 0), +(81, 'go-admin/app/admin/apis.SysDictType.Insert-fm', '字典类型创建', '/api/v1/dict/type', 'BUS', 'POST', '2021-05-13 19:59:04.391', '2021-06-17 11:48:40.732', NULL, 0, 0), +(82, 'go-admin/app/admin/apis.SysDept.Insert-fm', '部门创建', '/api/v1/dept', 'BUS', 'POST', '2021-05-13 19:59:04.435', '2021-06-17 11:48:40.732', NULL, 0, 0), +(85, 'github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth.(*GinJWTMiddleware).LoginHandler-fm', '*登录', '/api/v1/login', 'SYS', 'POST', '2021-05-13 19:59:04.597', '2021-06-13 20:53:50.784', NULL, 0, 0), +(86, 'go-admin/common/middleware/handler.LogOut', '*退出', '/api/v1/logout', 'SYS', 'POST', '2021-05-13 19:59:04.642', '2021-06-13 20:53:50.824', NULL, 0, 0), +(87, 'go-admin/app/admin/apis.SysConfig.Insert-fm', '参数创建', '/api/v1/config', 'BUS', 'POST', '2021-05-13 19:59:04.685', '2021-06-17 11:48:40.732', NULL, 0, 0), +(88, 'go-admin/app/admin/apis.SysMenu.Insert-fm', '菜单创建', '/api/v1/menu', 'BUS', 'POST', '2021-05-13 19:59:04.777', '2021-06-17 11:48:40.732', NULL, 0, 0), +(89, 'go-admin/app/admin/apis.SysPost.Insert-fm', '岗位创建', '/api/v1/post', 'BUS', 'POST', '2021-05-13 19:59:04.886', '2021-06-17 11:48:40.732', NULL, 0, 0), +(90, 'go-admin/app/admin/apis.SysRole.Insert-fm', '角色创建', '/api/v1/role', 'BUS', 'POST', '2021-05-13 19:59:04.975', '2021-06-17 11:48:40.732', NULL, 0, 0), +(91, 'go-admin/app/admin/apis.SysUser.InsetAvatar-fm', '*用户头像编辑', '/api/v1/user/avatar', 'SYS', 'POST', '2021-05-13 19:59:05.058', '2021-06-13 20:53:51.079', NULL, 0, 0), +(92, 'go-admin/app/admin/apis.SysApi.Update-fm', '接口编辑', '/api/v1/sys-api/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.122', '2021-06-17 11:48:40.732', NULL, 0, 0), +(95, 'go-admin/common/actions.UpdateAction.func1', '分类编辑', '/api/v1/syscategory/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.255', '2021-06-13 20:53:51.247', NULL, 0, 0), +(96, 'go-admin/common/actions.UpdateAction.func1', '内容编辑', '/api/v1/syscontent/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.299', '2021-06-13 20:53:51.289', NULL, 0, 0), +(97, 'go-admin/common/actions.UpdateAction.func1', 'job编辑', '/api/v1/sysjob', 'BUS', 'PUT', '2021-05-13 19:59:05.343', '2021-06-13 20:53:51.331', NULL, 0, 0), +(101, 'go-admin/app/admin/apis.SysDictData.Update-fm', '字典数据编辑', '/api/v1/dict/data/:dictCode', 'BUS', 'PUT', '2021-05-13 19:59:05.519', '2021-06-17 11:48:40.732', NULL, 0, 0), +(102, 'go-admin/app/admin/apis.SysDictType.Update-fm', '字典类型编辑', '/api/v1/dict/type/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.569', '2021-06-17 11:48:40.732', NULL, 0, 0), +(103, 'go-admin/app/admin/apis.SysDept.Update-fm', '部门编辑', '/api/v1/dept/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.613', '2021-06-17 11:48:40.732', NULL, 0, 0), +(104, 'go-admin/app/other/apis.SysFileDir.Update-fm', '文件夹编辑', '/api/v1/file-dir/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.662', '2021-06-13 20:53:51.847', NULL, 0, 0), +(105, 'go-admin/app/other/apis.SysFileInfo.Update-fm', '文件编辑', '/api/v1/file-info/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.709', '2021-06-13 20:53:51.892', NULL, 0, 0), +(106, 'go-admin/app/admin/apis.SysRole.Update-fm', '角色编辑', '/api/v1/role/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.752', '2021-06-17 11:48:40.732', NULL, 0, 0), +(107, 'go-admin/app/admin/apis.SysRole.Update2DataScope-fm', '角色数据权限修改', '/api/v1/roledatascope', 'BUS', 'PUT', '2021-05-13 19:59:05.803', '2021-06-17 11:48:40.732', NULL, 0, 0), +(108, 'go-admin/app/admin/apis.SysConfig.Update-fm', '参数编辑', '/api/v1/config/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.848', '2021-06-17 11:48:40.732', NULL, 0, 0), +(109, 'go-admin/app/admin/apis.SysMenu.Update-fm', '编辑菜单', '/api/v1/menu/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.891', '2021-06-17 11:48:40.732', NULL, 0, 0), +(110, 'go-admin/app/admin/apis.SysPost.Update-fm', '岗位编辑', '/api/v1/post/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.934', '2021-06-17 11:48:40.732', NULL, 0, 0), +(111, 'go-admin/app/admin/apis.SysUser.UpdatePwd-fm', '*用户修改密码', '/api/v1/user/pwd', 'SYS', 'PUT', '2021-05-13 19:59:05.987', '2021-06-13 20:53:51.724', NULL, 0, 0), +(112, 'go-admin/common/actions.DeleteAction.func1', '分类删除', '/api/v1/syscategory', 'BUS', 'DELETE', '2021-05-13 19:59:06.030', '2021-06-13 20:53:52.237', NULL, 0, 0), +(113, 'go-admin/common/actions.DeleteAction.func1', '内容删除', '/api/v1/syscontent', 'BUS', 'DELETE', '2021-05-13 19:59:06.076', '2021-06-13 20:53:52.278', NULL, 0, 0), +(114, 'go-admin/app/admin/apis.SysLoginLog.Delete-fm', '登录日志删除', '/api/v1/sys-login-log', 'BUS', 'DELETE', '2021-05-13 19:59:06.118', '2021-06-17 11:48:40.732', NULL, 0, 0), +(115, 'go-admin/app/admin/apis.SysOperaLog.Delete-fm', '操作日志删除', '/api/v1/sys-opera-log', 'BUS', 'DELETE', '2021-05-13 19:59:06.162', '2021-06-17 11:48:40.732', NULL, 0, 0), +(116, 'go-admin/common/actions.DeleteAction.func1', 'job删除', '/api/v1/sysjob', 'BUS', 'DELETE', '2021-05-13 19:59:06.206', '2021-06-13 20:53:52.323', NULL, 0, 0), +(117, 'go-admin/app/other/apis.SysChinaAreaData.Delete-fm', '行政区删除', '/api/v1/sys-area-data', 'BUS', 'DELETE', '2021-05-13 19:59:06.249', '2021-06-13 20:53:52.061', NULL, 0, 0), +(120, 'go-admin/app/admin/apis.SysDictData.Delete-fm', '字典数据删除', '/api/v1/dict/data', 'BUS', 'DELETE', '2021-05-13 19:59:06.387', '2021-06-17 11:48:40.732', NULL, 0, 0), +(121, 'go-admin/app/admin/apis.SysDictType.Delete-fm', '字典类型删除', '/api/v1/dict/type', 'BUS', 'DELETE', '2021-05-13 19:59:06.432', '2021-06-17 11:48:40.732', NULL, 0, 0), +(122, 'go-admin/app/admin/apis.SysDept.Delete-fm', '部门删除', '/api/v1/dept/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.475', '2021-06-17 11:48:40.732', NULL, 0, 0), +(123, 'go-admin/app/other/apis.SysFileDir.Delete-fm', '文件夹删除', '/api/v1/file-dir/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.520', '2021-06-13 20:53:52.539', NULL, 0, 0), +(124, 'go-admin/app/other/apis.SysFileInfo.Delete-fm', '文件删除', '/api/v1/file-info/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.566', '2021-06-13 20:53:52.580', NULL, 0, 0), +(125, 'go-admin/app/admin/apis.SysConfig.Delete-fm', '参数删除', '/api/v1/config', 'BUS', 'DELETE', '2021-05-13 19:59:06.612', '2021-06-17 11:48:40.732', NULL, 0, 0), +(126, 'go-admin/app/admin/apis.SysMenu.Delete-fm', '删除菜单', '/api/v1/menu', 'BUS', 'DELETE', '2021-05-13 19:59:06.654', '2021-06-17 11:48:40.732', NULL, 0, 0), +(127, 'go-admin/app/admin/apis.SysPost.Delete-fm', '岗位删除', '/api/v1/post/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.702', '2021-06-17 11:48:40.732', NULL, 0, 0), +(128, 'go-admin/app/admin/apis.SysRole.Delete-fm', '角色删除', '/api/v1/role', 'BUS', 'DELETE', '2021-05-13 19:59:06.746', '2021-06-17 11:48:40.732', NULL, 0, 0), +(131, 'github.com/go-admin-team/go-admin-core/tools/transfer.Handler.func1', '系统指标', '/api/v1/metrics', 'SYS', 'GET', '2021-05-17 22:13:55.933', '2021-06-13 20:53:49.614', NULL, 0, 0), +(132, 'go-admin/app/other/router.registerMonitorRouter.func1', '健康状态', '/api/v1/health', 'SYS', 'GET', '2021-05-17 22:13:56.285', '2021-06-13 20:53:49.951', NULL, 0, 0), +(133, 'go-admin/app/admin/apis.HelloWorld', '项目默认接口', '/', 'SYS', 'GET', '2021-05-24 10:30:44.553', '2021-06-13 20:53:47.406', NULL, 0, 0), +(134, 'go-admin/app/other/apis.ServerMonitor.ServerInfo-fm', '服务器基本状态', '/api/v1/server-monitor', 'SYS', 'GET', '2021-05-24 10:30:44.937', '2021-06-13 20:53:48.255', NULL, 0, 0), +(135, 'go-admin/app/admin/apis.SysApi.GetPage-fm', '接口列表', '/api/v1/sys-api', 'BUS', 'GET', '2021-05-24 11:37:53.303', '2021-06-17 11:48:40.732', NULL, 0, 0), +(136, 'go-admin/app/admin/apis.SysApi.Get-fm', '接口通过id获取', '/api/v1/sys-api/:id', 'BUS', 'GET', '2021-05-24 11:37:53.359', '2021-06-17 11:48:40.732', NULL, 0, 0), +(137, 'go-admin/app/admin/apis.SysLoginLog.GetPage-fm', '登录日志列表', '/api/v1/sys-login-log', 'BUS', 'GET', '2021-05-24 11:47:30.397', '2021-06-17 11:48:40.732', NULL, 0, 0), +(138, 'go-admin/app/other/apis.File.UploadFile-fm', '文件上传', '/api/v1/public/uploadFile', 'SYS', 'POST', '2021-05-25 19:16:18.493', '2021-06-13 20:53:50.866', NULL, 0, 0), +(139, 'go-admin/app/admin/apis.SysConfig.Update2Set-fm', '参数信息修改【参数配置】', '/api/v1/set-config', 'BUS', 'PUT', '2021-05-27 09:45:14.853', '2021-06-17 11:48:40.732', NULL, 0, 0), +(140, 'go-admin/app/admin/apis.SysConfig.Get2Set-fm', '参数获取全部【配置使用】', '/api/v1/set-config', 'BUS', 'GET', '2021-05-27 11:54:14.384', '2021-06-17 11:48:40.732', NULL, 0, 0), +(141, 'go-admin/app/admin/apis.SysUser.GetPage-fm', '管理员列表', '/api/v1/sys-user', 'BUS', 'GET', '2021-06-13 19:24:57.111', '2021-06-17 20:31:14.318', NULL, 0, 0), +(142, 'go-admin/app/admin/apis.SysUser.Get-fm', '管理员通过id获取', '/api/v1/sys-user/:id', 'BUS', 'GET', '2021-06-13 19:24:57.188', '2021-06-17 20:31:14.318', NULL, 0, 0), +(143, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTablesInfo-fm', '', '/api/v1/sys/tables/info', '', 'GET', '2021-06-13 19:24:57.437', '2021-06-13 20:53:48.047', NULL, 0, 0), +(144, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTables-fm', '', '/api/v1/sys/tables/info/:tableId', '', 'GET', '2021-06-13 19:24:57.510', '2021-06-13 20:53:48.088', NULL, 0, 0), +(145, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTableList-fm', '', '/api/v1/sys/tables/page', '', 'GET', '2021-06-13 19:24:57.582', '2021-06-13 20:53:48.128', NULL, 0, 0), +(146, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/static/*filepath', '', 'GET', '2021-06-13 19:24:59.641', '2021-06-13 20:53:50.081', NULL, 0, 0), +(147, 'github.com/swaggo/gin-swagger.CustomWrapHandler.func1', '', '/swagger/*any', '', 'GET', '2021-06-13 19:24:59.713', '2021-06-13 20:53:50.123', NULL, 0, 0), +(148, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/form-generator/*filepath', '', 'GET', '2021-06-13 19:24:59.914', '2021-06-13 20:53:50.295', NULL, 0, 0), +(149, 'go-admin/app/admin/apis/tools.(*SysTable).InsertSysTable-fm', '', '/api/v1/sys/tables/info', '', 'POST', '2021-06-13 19:25:00.163', '2021-06-13 20:53:50.539', NULL, 0, 0), +(150, 'go-admin/app/admin/apis.SysUser.Insert-fm', '管理员创建', '/api/v1/sys-user', 'BUS', 'POST', '2021-06-13 19:25:00.233', '2021-06-17 20:31:14.318', NULL, 0, 0), +(151, 'go-admin/app/admin/apis.SysUser.Update-fm', '管理员编辑', '/api/v1/sys-user', 'BUS', 'PUT', '2021-06-13 19:25:00.986', '2021-06-17 20:31:14.318', NULL, 0, 0), +(152, 'go-admin/app/admin/apis/tools.(*SysTable).UpdateSysTable-fm', '', '/api/v1/sys/tables/info', '', 'PUT', '2021-06-13 19:25:01.149', '2021-06-13 20:53:51.375', NULL, 0, 0), +(153, 'go-admin/app/admin/apis.SysRole.Update2Status-fm', '', '/api/v1/role-status', '', 'PUT', '2021-06-13 19:25:01.446', '2021-06-13 20:53:51.636', NULL, 0, 0), +(154, 'go-admin/app/admin/apis.SysUser.ResetPwd-fm', '', '/api/v1/user/pwd/reset', '', 'PUT', '2021-06-13 19:25:01.601', '2021-06-13 20:53:51.764', NULL, 0, 0), +(155, 'go-admin/app/admin/apis.SysUser.UpdateStatus-fm', '', '/api/v1/user/status', '', 'PUT', '2021-06-13 19:25:01.671', '2021-06-13 20:53:51.806', NULL, 0, 0), +(156, 'go-admin/app/admin/apis.SysUser.Delete-fm', '管理员删除', '/api/v1/sys-user', 'BUS', 'DELETE', '2021-06-13 19:25:02.043', '2021-06-17 20:31:14.318', NULL, 0, 0), +(157, 'go-admin/app/admin/apis/tools.(*SysTable).DeleteSysTables-fm', '', '/api/v1/sys/tables/info/:tableId', '', 'DELETE', '2021-06-13 19:25:02.283', '2021-06-13 20:53:52.367', NULL, 0, 0), +(158, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/static/*filepath', '', 'HEAD', '2021-06-13 19:25:02.734', '2021-06-13 20:53:52.791', NULL, 0, 0), +(159, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/form-generator/*filepath', '', 'HEAD', '2021-06-13 19:25:02.808', '2021-06-13 20:53:52.838', NULL, 0, 0); +SET IDENTITY_INSERT sys_api OFF; + +INSERT INTO sys_config VALUES +(1, '皮肤样式', 'sys_index_skinName', 'skin-green', 'Y', '0', '主框架页-默认皮肤样式名称:蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 13:50:13.123', NULL), +(2, '初始密码', 'sys_user_initPassword', '123456', 'Y', '0', '用户管理-账号初始密码:123456', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL), +(3, '侧栏主题', 'sys_index_sideTheme', 'theme-dark', 'Y', '0', '主框架页-侧边栏主题:深色主题theme-dark,浅色主题theme-light', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL), +(4, '系统名称', 'sys_app_name', 'go-admin管理系统', 'Y', '1', '', 1, 0, '2021-03-17 08:52:06.067', '2021-05-28 10:08:25.248', NULL), +(5, '系统logo', 'sys_app_logo', 'https://gitee.com/mydearzwj/image/raw/master/img/go-admin.png', 'Y', '1', '', 1, 0, '2021-03-17 08:53:19.462', '2021-03-17 08:53:19.462', NULL); + +SET IDENTITY_INSERT sys_dept ON; +INSERT INTO sys_dept (dept_id, parent_id, dept_path, dept_name, sort, leader, phone, email, status, create_by, update_by, created_at, updated_at, deleted_at)VALUES +(1, 0, '/0/1/', '爱拓科技', 0, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 17:06:44.960', NULL), +(7, 1, '/0/1/7/', '研发部', 1, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-16 21:35:00.109', NULL), +(8, 1, '/0/1/8/', '运维部', 0, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-16 21:41:39.747', NULL), +(9, 1, '/0/1/9/', '客服部', 0, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 17:07:05.993', NULL), +(10, 1, '/0/1/10/', '人力资源', 3, 'aituo', '13782218188', 'atuo@aituo.com', '1', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 17:07:08.503', NULL); +SET IDENTITY_INSERT sys_dept OFF; + +INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, + status, "default", remark, create_by, update_by, created_at, updated_at, deleted_at)VALUES +(1, 0, '正常', '2', 'sys_normal_disable', '', '', '', '2', '', '系统正常', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:40.168', NULL); +INSERT INTO sys_dict_data VALUES (2, 0, '停用', '1', 'sys_normal_disable', '', '', '', '2', '', '系统停用', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (3, 0, '男', '0', 'sys_user_sex', '', '', '', '2', '', '性别男', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (4, 0, '女', '1', 'sys_user_sex', '', '', '', '2', '', '性别女', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (5, 0, '未知', '2', 'sys_user_sex', '', '', '', '2', '', '性别未知', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (6, 0, '显示', '0', 'sys_show_hide', '', '', '', '2', '', '显示菜单', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (7, 0, '隐藏', '1', 'sys_show_hide', '', '', '', '2', '', '隐藏菜单', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (8, 0, '是', 'Y', 'sys_yes_no', '', '', '', '2', '', '系统默认是', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (9, 0, '否', 'N', 'sys_yes_no', '', '', '', '2', '', '系统默认否', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (10, 0, '正常', '2', 'sys_job_status', '', '', '', '2', '', '正常状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (11, 0, '停用', '1', 'sys_job_status', '', '', '', '2', '', '停用状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (12, 0, '默认', 'DEFAULT', 'sys_job_group', '', '', '', '2', '', '默认分组', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (13, 0, '系统', 'SYSTEM', 'sys_job_group', '', '', '', '2', '', '系统分组', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (14, 0, '通知', '1', 'sys_notice_type', '', '', '', '2', '', '通知', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (15, 0, '公告', '2', 'sys_notice_type', '', '', '', '2', '', '公告', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (16, 0, '正常', '2', 'sys_common_status', '', '', '', '2', '', '正常状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (17, 0, '关闭', '1', 'sys_common_status', '', '', '', '2', '', '关闭状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (18, 0, '新增', '1', 'sys_oper_type', '', '', '', '2', '', '新增操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (19, 0, '修改', '2', 'sys_oper_type', '', '', '', '2', '', '修改操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (20, 0, '删除', '3', 'sys_oper_type', '', '', '', '2', '', '删除操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (21, 0, '授权', '4', 'sys_oper_type', '', '', '', '2', '', '授权操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (22, 0, '导出', '5', 'sys_oper_type', '', '', '', '2', '', '导出操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (23, 0, '导入', '6', 'sys_oper_type', '', '', '', '2', '', '导入操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (24, 0, '强退', '7', 'sys_oper_type', '', '', '', '2', '', '强退操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (25, 0, '生成代码', '8', 'sys_oper_type', '', '', '', '2', '', '生成操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (26, 0, '清空数据', '9', 'sys_oper_type', '', '', '', '2', '', '清空操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (27, 0, '成功', '0', 'sys_notice_status', '', '', '', '2', '', '成功状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (28, 0, '失败', '1', 'sys_notice_status', '', '', '', '2', '', '失败状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (29, 0, '登录', '10', 'sys_oper_type', '', '', '', '2', '', '登录操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (30, 0, '退出', '11', 'sys_oper_type', '', '', '', '2', '', '', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (31, 0, '获取验证码', '12', 'sys_oper_type', '', '', '', '2', '', '获取验证码', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (32, 0, '正常', '1', 'sys_content_status', '', '', '', '1', '', '', 1, 1, '2021-05-13 19:56:40.845', '2021-05-13 19:56:40.845', NULL); +INSERT INTO sys_dict_data VALUES (33, 1, '禁用', '2', 'sys_content_status', '', '', '', '1', '', '', 1, 1, '2021-05-13 19:56:40.845', '2021-05-13 19:56:40.845', NULL); + + +INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, remark, create_by, update_by, created_at, updated_at, + deleted_at)VALUES (1, '系统开关', 'sys_normal_disable', '2', '系统开关列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (2, '用户性别', 'sys_user_sex', '2', '用户性别列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (3, '菜单状态', 'sys_show_hide', '2', '菜单状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (4, '系统是否', 'sys_yes_no', '2', '系统是否列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (5, '任务状态', 'sys_job_status', '2', '任务状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (6, '任务分组', 'sys_job_group', '2', '任务分组列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (7, '通知类型', 'sys_notice_type', '2', '通知类型列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (8, '系统状态', 'sys_common_status', '2', '登录状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (9, '操作类型', 'sys_oper_type', '2', '操作类型列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (10, '通知状态', 'sys_notice_status', '2', '通知状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (11, '内容状态', 'sys_content_status', '2', '', 1, 1, '2021-05-13 19:56:40.813', '2021-05-13 19:56:40.813', NULL); + + +INSERT INTO sys_job (job_id, job_name, job_group, job_type, cron_expression, invoke_target, args, misfire_policy, concurrent, status, entry_id, created_at, updated_at, deleted_at, create_by, update_by)VALUES +(1, '接口测试', 'DEFAULT', 1, '0/5 * * * * ', 'http://localhost:8000', '', 1, 1, 1, 0, '2021-05-13 19:56:37.914', '2021-06-14 20:59:55.417', NULL, 1, 1), +(2, '函数测试', 'DEFAULT', 2, '0/5 * * * * ', 'ExamplesOne', '参数', 1, 1, 1, 0, '2021-05-13 19:56:37.914', '2021-05-31 23:55:37.221', NULL, 1, 1); + +SET IDENTITY_INSERT sys_menu ON; +INSERT INTO sys_menu (menu_id, menu_name, title, icon, path, paths, menu_type, "action", permission, parent_id, no_cache, breadcrumb, component, sort, visible, is_frame, create_by, update_by, created_at, updated_at, deleted_at)VALUES +(2, 'Admin', '系统管理', 'api-server', '/admin', '/0/2', 'M', '无', '', 0, 1, '', 'Layout', 10, '0', '1', 0, 1, '2021-05-20 21:58:45.679', '2021-06-17 11:48:40.703', NULL), +(3, 'SysUserManage', '用户管理', 'user', '/admin/sys-user', '/0/2/3', 'C', '无', 'admin:sysUser:list', 2, 0, '', '/admin/sys-user/index', 10, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL), +(43, '', '新增管理员', 'app-group-fill', '', '/0/2/3/43', 'F', 'POST', 'admin:sysUser:add', 3, 0, '', '', 10, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL), +(44, '', '查询管理员', 'app-group-fill', '', '/0/2/3/44', 'F', 'GET', 'admin:sysUser:query', 3, 0, '', '', 40, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL), +(45, '', '修改管理员', 'app-group-fill', '', '/0/2/3/45', 'F', 'PUT', 'admin:sysUser:edit', 3, 0, '', '', 30, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL), +(46, '', '删除管理员', 'app-group-fill', '', '/0/2/3/46', 'F', 'DELETE', 'admin:sysUser:remove', 3, 0, '', '', 20, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL), +(51, 'SysMenuManage', '菜单管理', 'tree-table', '/admin/sys-menu', '/0/2/51', 'C', '无', 'admin:sysMenu:list', 2, 1, '', '/admin/sys-menu/index', 30, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(52, 'SysRoleManage', '角色管理', 'peoples', '/admin/sys-role', '/0/2/52', 'C', '无', 'admin:sysRole:list', 2, 1, '', '/admin/sys-role/index', 20, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(56, 'SysDeptManage', '部门管理', 'tree', '/admin/sys-dept', '/0/2/56', 'C', '无', 'admin:sysDept:list', 2, 0, '', '/admin/sys-dept/index', 40, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(57, 'SysPostManage', '岗位管理', 'pass', '/admin/sys-post', '/0/2/57', 'C', '无', 'admin:sysPost:list', 2, 0, '', '/admin/sys-post/index', 50, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(58, 'Dict', '字典管理', 'education', '/admin/dict', '/0/2/58', 'C', '无', 'admin:sysDictType:list', 2, 0, '', '/admin/dict/index', 60, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(59, 'SysDictDataManage', '字典数据', 'education', '/admin/dict/data/:dictId', '/0/2/59', 'C', '无', 'admin:sysDictData:list', 2, 0, '', '/admin/dict/data', 100, '1', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(60, 'Tools', '开发工具', 'dev-tools', '/dev-tools', '/0/60', 'M', '无', '', 0, 0, '', 'Layout', 40, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-05 22:15:03.465', NULL), +(61, 'Swagger', '系统接口', 'guide', '/dev-tools/swagger', '/0/60/61', 'C', '无', '', 60, 0, '', '/dev-tools/swagger/index', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-05 22:15:03.465', NULL), +(62, 'SysConfigManage', '参数管理', 'swagger', '/admin/sys-config', '/0/2/62', 'C', '无', 'admin:sysConfig:list', 2, 0, '', '/admin/sys-config/index', 70, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(211, 'Log', '日志管理', 'log', '/log', '/0/2/211', 'M', '', '', 2, 0, '', '/log/index', 80, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(212, 'SysLoginLogManage', '登录日志', 'logininfor', '/admin/sys-login-log', '/0/2/211/212', 'C', '', 'admin:sysLoginLog:list', 211, 0, '', '/admin/sys-login-log/index', 1, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(216, 'OperLog', '操作日志', 'skill', '/admin/sys-oper-log', '/0/2/211/216', 'C', '', 'admin:sysOperLog:list', 211, 0, '', '/admin/sys-oper-log/index', 1, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(220, '', '新增菜单', 'app-group-fill', '', '/0/2/51/220', 'F', '', 'admin:sysMenu:add', 51, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(221, '', '修改菜单', 'app-group-fill', '', '/0/2/51/221', 'F', '', 'admin:sysMenu:edit', 51, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(222, '', '查询菜单', 'app-group-fill', '', '/0/2/51/222', 'F', '', 'admin:sysMenu:query', 51, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(223, '', '删除菜单', 'app-group-fill', '', '/0/2/51/223', 'F', '', 'admin:sysMenu:remove', 51, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(224, '', '新增角色', 'app-group-fill', '', '/0/2/52/224', 'F', '', 'admin:sysRole:add', 52, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(225, '', '查询角色', 'app-group-fill', '', '/0/2/52/225', 'F', '', 'admin:sysRole:query', 52, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(226, '', '修改角色', 'app-group-fill', '', '/0/2/52/226', 'F', '', 'admin:sysRole:update', 52, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(227, '', '删除角色', 'app-group-fill', '', '/0/2/52/227', 'F', '', 'admin:sysRole:remove', 52, 0, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(228, '', '查询部门', 'app-group-fill', '', '/0/2/56/228', 'F', '', 'admin:sysDept:query', 56, 0, '', '', 40, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(229, '', '新增部门', 'app-group-fill', '', '/0/2/56/229', 'F', '', 'admin:sysDept:add', 56, 0, '', '', 10, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(230, '', '修改部门', 'app-group-fill', '', '/0/2/56/230', 'F', '', 'admin:sysDept:edit', 56, 0, '', '', 30, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(231, '', '删除部门', 'app-group-fill', '', '/0/2/56/231', 'F', '', 'admin:sysDept:remove', 56, 0, '', '', 20, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(232, '', '查询岗位', 'app-group-fill', '', '/0/2/57/232', 'F', '', 'admin:sysPost:query', 57, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(233, '', '新增岗位', 'app-group-fill', '', '/0/2/57/233', 'F', '', 'admin:sysPost:add', 57, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(234, '', '修改岗位', 'app-group-fill', '', '/0/2/57/234', 'F', '', 'admin:sysPost:edit', 57, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(235, '', '删除岗位', 'app-group-fill', '', '/0/2/57/235', 'F', '', 'admin:sysPost:remove', 57, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(236, '', '查询字典', 'app-group-fill', '', '/0/2/58/236', 'F', '', 'admin:sysDictType:query', 58, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(237, '', '新增类型', 'app-group-fill', '', '/0/2/58/237', 'F', '', 'admin:sysDictType:add', 58, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(238, '', '修改类型', 'app-group-fill', '', '/0/2/58/238', 'F', '', 'admin:sysDictType:edit', 58, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(239, '', '删除类型', 'app-group-fill', '', '/0/2/58/239', 'F', '', 'system:sysdicttype:remove', 58, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(240, '', '查询数据', 'app-group-fill', '', '/0/2/59/240', 'F', '', 'admin:sysDictData:query', 59, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(241, '', '新增数据', 'app-group-fill', '', '/0/2/59/241', 'F', '', 'admin:sysDictData:add', 59, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(242, '', '修改数据', 'app-group-fill', '', '/0/2/59/242', 'F', '', 'admin:sysDictData:edit', 59, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(243, '', '删除数据', 'app-group-fill', '', '/0/2/59/243', 'F', '', 'admin:sysDictData:remove', 59, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(244, '', '查询参数', 'app-group-fill', '', '/0/2/62/244', 'F', '', 'admin:sysConfig:query', 62, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(245, '', '新增参数', 'app-group-fill', '', '/0/2/62/245', 'F', '', 'admin:sysConfig:add', 62, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(246, '', '修改参数', 'app-group-fill', '', '/0/2/62/246', 'F', '', 'admin:sysConfig:edit', 62, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(247, '', '删除参数', 'app-group-fill', '', '/0/2/62/247', 'F', '', 'admin:sysConfig:remove', 62, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(248, '', '查询登录日志', 'app-group-fill', '', '/0/2/211/212/248', 'F', '', 'admin:sysLoginLog:query', 212, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(249, '', '删除登录日志', 'app-group-fill', '', '/0/2/211/212/249', 'F', '', 'admin:sysLoginLog:remove', 212, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(250, '', '查询操作日志', 'app-group-fill', '', '/0/2/211/216/250', 'F', '', 'admin:sysOperLog:query', 216, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(251, '', '删除操作日志', 'app-group-fill', '', '/0/2/211/216/251', 'F', '', 'admin:sysOperLog:remove', 216, 0, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL), +(261, 'Gen', '代码生成', 'code', '/dev-tools/gen', '/0/60/261', 'C', '', '', 60, 0, '', '/dev-tools/gen/index', 2, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-16 21:26:12.446', NULL), +(262, 'EditTable', '代码生成修改', 'build', '/dev-tools/editTable', '/0/60/262', 'C', '', '', 60, 0, '', '/dev-tools/gen/editTable', 100, '1', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-16 21:26:12.446', NULL), +(264, 'Build', '表单构建', 'build', '/dev-tools/build', '/0/60/264', 'C', '', '', 60, 0, '', '/dev-tools/build/index', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-16 21:26:12.446', NULL), +(269, 'ServerMonitor', '服务监控', 'druid', '/sys-tools/monitor', '/0/60/269', 'C', '', 'sysTools:serverMonitor:list', 537, 0, '', '/sys-tools/monitor', 0, '0', '1', 1, 1, '2020-04-14 00:28:19.000', '2021-06-16 21:26:12.446', NULL), +(459, 'Schedule', '定时任务', 'time-range', '/schedule', '/0/459', 'M', '无', '', 0, 0, '', 'Layout', 20, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL), +(460, 'ScheduleManage', 'Schedule', 'job', '/schedule/manage', '/0/459/460', 'C', '无', 'job:sysJob:list', 459, 0, '', '/schedule/index', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL), +(461, 'sys_job', '分页获取定时任务', 'app-group-fill', '', '/0/459/460/461', 'F', '无', 'job:sysJob:query', 460, 0, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL), +(462, 'sys_job', '创建定时任务', 'app-group-fill', '', '/0/459/460/462', 'F', '无', 'job:sysJob:add', 460, 0, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL), +(463, 'sys_job', '修改定时任务', 'app-group-fill', '', '/0/459/460/463', 'F', '无', 'job:sysJob:edit', 460, 0, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL), +(464, 'sys_job', '删除定时任务', 'app-group-fill', '', '/0/459/460/464', 'F', '无', 'job:sysJob:remove', 460, 0, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL), +(471, 'JobLog', '日志', 'bug', '/schedule/log', '/0/459/471', 'C', '', '', 459, 0, '', '/schedule/log', 0, '1', '1', 1, 1, '2020-08-05 21:24:46.000', '2021-06-05 22:15:03.465', NULL), +(528, 'SysApiManage', '接口管理', 'api-doc', '/admin/sys-api', '/0/527/528', 'C', '无', 'admin:sysApi:list', 2, 0, '', '/admin/sys-api/index', 0, '0', '0', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(529, '', '查询接口', 'app-group-fill', '', '/0/527/528/529', 'F', '无', 'admin:sysApi:query', 528, 0, '', '', 40, '0', '0', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(531, '', '修改接口', 'app-group-fill', '', '/0/527/528/531', 'F', '无', 'admin:sysApi:edit', 528, 0, '', '', 30, '0', '0', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL), +(537, 'SysTools', '系统工具', 'system-tools', '/sys-tools', '', 'M', '', '', 0, 0, '', 'Layout', 30, '0', '1', 1, 1, '2021-05-21 11:13:32.166', '2021-06-16 21:26:12.446', NULL), +(540, 'SysConfigSet', '参数设置', 'system-tools', '/admin/sys-config/set', '', 'C', '', 'admin:sysConfigSet:list', 2, 0, '', '/admin/sys-config/set', 0, '0', '1', 1, 1, '2021-05-25 16:06:52.560', '2021-06-17 11:48:40.703', NULL), +(542, '', '修改', 'upload', '', '', 'F', '', 'admin:sysConfigSet:update', 540, 0, '', '', 0, '0', '1', 1, 1, '2021-06-13 11:45:48.670', '2021-06-17 11:48:40.703', NULL); +SET IDENTITY_INSERT sys_menu OFF; +INSERT INTO sys_menu_api_rule (sys_menu_menu_id, sys_api_id)VALUES (216, 6); +(250, 6), +(58, 21), +(236, 21), +(238, 23), +(59, 24), +(240, 24), +(242, 25), +(58, 26), +(236, 26), +(56, 27), +(228, 27), +(230, 28), +(226, 29), +(51, 39), +(51, 135), +(222, 39), +(221, 41), +(52, 44), +(225, 44), +(226, 45), +(226, 46), +(226, 47), +(62, 53), +(244, 53), +(246, 54), +(57, 59), +(232, 59), +(234, 60), +(241, 80), +(237, 81), +(229, 82), +(245, 87), +(220, 88), +(233, 89), +(224, 90), +(531, 92), +(242, 101), +(238, 102), +(230, 103), +(226, 106), +(226, 107), +(246, 108), +(221, 109), +(234, 110), +(249, 114), +(251, 115), +(243, 120), +(239, 121), +(231, 122), +(247, 125), +(223, 126), +(235, 127), +(227, 128), +(528, 135), +(529, 135), +(531, 136), +(212, 137), +(248, 137), +(542, 139), +(540, 140), +(3, 141), +(44, 141), +(45, 142), +(43, 150), +(45, 151), +(46, 156); +INSERT INTO sys_post (post_id, post_name, post_code, sort, status, remark, create_by, update_by, created_at, updated_at, deleted_at)VALUES +(1, '首席执行官', 'CEO', 0, '2','首席执行官', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL), +(2, '首席技术执行官', 'CTO', 2, '2','首席技术执行官', 1, 1,'2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL), +(3, '首席运营官', 'COO', 3, '2','测试工程师', 1, 1,'2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_role (role_id, role_name, status, role_key, role_sort, flag, remark, admin, data_scope, create_by, update_by, created_at, updated_at, deleted_at)VALUES +(1, '系统管理员', '2', 'admin', 1, '', '', 1, '', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_user VALUES (1, 'admin', '$2a$10$/Glr4g9Svr6O0kvjsRJCXu3f0W8/dsP3XZyVNi1019ratWpSPMyw.', 'zhangwj', '13818888888', 1, '', '', '1', '1@qq.com', 1, 1, '', '2', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:40.205', NULL); +-- 数据完成 ; \ No newline at end of file diff --git a/config/db.sql b/config/db.sql new file mode 100644 index 0000000..5c84adf --- /dev/null +++ b/config/db.sql @@ -0,0 +1,324 @@ +-- 开始初始化数据 ; +INSERT INTO sys_api VALUES (5, 'go-admin/app/admin/apis.SysLoginLog.Get-fm', '登录日志通过id获取', '/api/v1/sys-login-log/:id', 'BUS', 'GET', '2021-05-13 19:59:00.728', '2021-06-17 11:37:12.331', NULL, 0, 0); +INSERT INTO sys_api VALUES (6, 'go-admin/app/admin/apis.SysOperaLog.GetPage-fm', '操作日志列表', '/api/v1/sys-opera-log', 'BUS', 'GET', '2021-05-13 19:59:00.778', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (7, 'go-admin/app/admin/apis.SysOperaLog.Get-fm', '操作日志通过id获取', '/api/v1/sys-opera-log/:id', 'BUS', 'GET', '2021-05-13 19:59:00.821', '2021-06-16 21:49:48.598', NULL, 0, 0); +INSERT INTO sys_api VALUES (8, 'go-admin/common/actions.IndexAction.func1', '分类列表', '/api/v1/syscategory', 'BUS', 'GET', '2021-05-13 19:59:00.870', '2021-06-13 20:53:47.883', NULL, 0, 0); +INSERT INTO sys_api VALUES (9, 'go-admin/common/actions.ViewAction.func1', '分类通过id获取', '/api/v1/syscategory/:id', 'BUS', 'GET', '2021-05-13 19:59:00.945', '2021-06-13 20:53:47.926', NULL, 0, 0); +INSERT INTO sys_api VALUES (10, 'go-admin/common/actions.IndexAction.func1', '内容列表', '/api/v1/syscontent', 'BUS', 'GET', '2021-05-13 19:59:01.005', '2021-06-13 20:53:47.966', NULL, 0, 0); +INSERT INTO sys_api VALUES (11, 'go-admin/common/actions.ViewAction.func1', '内容通过id获取', '/api/v1/syscontent/:id', 'BUS', 'GET', '2021-05-13 19:59:01.056', '2021-06-13 20:53:48.005', NULL, 0, 0); +INSERT INTO sys_api VALUES (15, 'go-admin/common/actions.IndexAction.func1', 'job列表', '/api/v1/sysjob', 'BUS', 'GET', '2021-05-13 19:59:01.248', '2021-06-13 20:53:48.169', NULL, 0, 0); +INSERT INTO sys_api VALUES (16, 'go-admin/common/actions.ViewAction.func1', 'job通过id获取', '/api/v1/sysjob/:id', 'BUS', 'GET', '2021-05-13 19:59:01.298', '2021-06-13 20:53:48.214', NULL, 0, 0); +INSERT INTO sys_api VALUES (21, 'go-admin/app/admin/apis.SysDictType.GetPage-fm', '字典类型列表', '/api/v1/dict/type', 'BUS', 'GET', '2021-05-13 19:59:01.525', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (22, 'go-admin/app/admin/apis.SysDictType.GetAll-fm', '字典类型查询【代码生成】', '/api/v1/dict/type-option-select', 'SYS', 'GET', '2021-05-13 19:59:01.582', '2021-06-13 20:53:48.388', NULL, 0, 0); +INSERT INTO sys_api VALUES (23, 'go-admin/app/admin/apis.SysDictType.Get-fm', '字典类型通过id获取', '/api/v1/dict/type/:id', 'BUS', 'GET', '2021-05-13 19:59:01.632', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (24, 'go-admin/app/admin/apis.SysDictData.GetPage-fm', '字典数据列表', '/api/v1/dict/data', 'BUS', 'GET', '2021-05-13 19:59:01.684', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (25, 'go-admin/app/admin/apis.SysDictData.Get-fm', '字典数据通过code获取', '/api/v1/dict/data/:dictCode', 'BUS', 'GET', '2021-05-13 19:59:01.732', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (26, 'go-admin/app/admin/apis.SysDictData.GetSysDictDataAll-fm', '数据字典根据key获取', '/api/v1/dict-data/option-select', 'SYS', 'GET', '2021-05-13 19:59:01.832', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (27, 'go-admin/app/admin/apis.SysDept.GetPage-fm', '部门列表', '/api/v1/dept', 'BUS', 'GET', '2021-05-13 19:59:01.940', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (28, 'go-admin/app/admin/apis.SysDept.Get-fm', '部门通过id获取', '/api/v1/dept/:id', 'BUS', 'GET', '2021-05-13 19:59:02.009', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (29, 'go-admin/app/admin/apis.SysDept.Get2Tree-fm', '查询部门下拉树【角色权限-自定权限】', '/api/v1/deptTree', 'SYS', 'GET', '2021-05-13 19:59:02.050', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (30, 'go-admin/app/admin/apis/tools.(*Gen).GetDBTableList-fm', '数据库表列表', '/api/v1/db/tables/page', 'SYS', 'GET', '2021-05-13 19:59:02.098', '2021-06-13 20:53:48.730', NULL, 0, 0); +INSERT INTO sys_api VALUES (31, 'go-admin/app/admin/apis/tools.(*Gen).GetDBColumnList-fm', '数据表列列表', '/api/v1/db/columns/page', 'SYS', 'GET', '2021-05-13 19:59:02.140', '2021-06-13 20:53:48.771', NULL, 0, 0); +INSERT INTO sys_api VALUES (32, 'go-admin/app/admin/apis/tools.Gen.GenCode-fm', '数据库表生成到项目', '/api/v1/gen/toproject/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.183', '2021-06-13 20:53:48.812', NULL, 0, 0); +INSERT INTO sys_api VALUES (33, 'go-admin/app/admin/apis/tools.Gen.GenMenuAndApi-fm', '数据库表生成到DB', '/api/v1/gen/todb/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.227', '2021-06-13 20:53:48.853', NULL, 0, 0); +INSERT INTO sys_api VALUES (34, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTablesTree-fm', '关系表数据【代码生成】', '/api/v1/gen/tabletree', 'SYS', 'GET', '2021-05-13 19:59:02.271', '2021-06-13 20:53:48.893', NULL, 0, 0); +INSERT INTO sys_api VALUES (35, 'go-admin/app/admin/apis/tools.Gen.Preview-fm', '生成预览通过id获取', '/api/v1/gen/preview/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.315', '2021-06-13 20:53:48.935', NULL, 0, 0); +INSERT INTO sys_api VALUES (36, 'go-admin/app/admin/apis/tools.Gen.GenApiToFile-fm', '生成api带文件', '/api/v1/gen/apitofile/:tableId', 'SYS', 'GET', '2021-05-13 19:59:02.357', '2021-06-13 20:53:48.977', NULL, 0, 0); +INSERT INTO sys_api VALUES (37, 'go-admin/app/admin/apis.System.GenerateCaptchaHandler-fm', '验证码获取', '/api/v1/getCaptcha', 'SYS', 'GET', '2021-05-13 19:59:02.405', '2021-06-13 20:53:49.020', NULL, 0, 0); +INSERT INTO sys_api VALUES (38, 'go-admin/app/admin/apis.SysUser.GetInfo-fm', '用户信息获取', '/api/v1/getinfo', 'SYS', 'GET', '2021-05-13 19:59:02.447', '2021-06-13 20:53:49.065', NULL, 0, 0); +INSERT INTO sys_api VALUES (39, 'go-admin/app/admin/apis.SysMenu.GetPage-fm', '菜单列表', '/api/v1/menu', 'BUS', 'GET', '2021-05-13 19:59:02.497', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (40, 'go-admin/app/admin/apis.SysMenu.GetMenuTreeSelect-fm', '查询菜单下拉树结构【废弃】', '/api/v1/menuTreeselect', 'SYS', 'GET', '2021-05-13 19:59:02.542', '2021-06-03 22:37:21.857', NULL, 0, 0); +INSERT INTO sys_api VALUES (41, 'go-admin/app/admin/apis.SysMenu.Get-fm', '菜单通过id获取', '/api/v1/menu/:id', 'BUS', 'GET', '2021-05-13 19:59:02.584', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (42, 'go-admin/app/admin/apis.SysMenu.GetMenuRole-fm', '角色菜单【顶部左侧菜单】', '/api/v1/menurole', 'SYS', 'GET', '2021-05-13 19:59:02.630', '2021-06-13 20:53:49.574', NULL, 0, 0); +INSERT INTO sys_api VALUES (43, 'go-admin/app/admin/apis.SysMenu.GetMenuIDS-fm', '获取角色对应的菜单id数组【废弃】', '/api/v1/menuids', 'SYS', 'GET', '2021-05-13 19:59:02.675', '2021-06-03 22:39:52.500', NULL, 0, 0); +INSERT INTO sys_api VALUES (44, 'go-admin/app/admin/apis.SysRole.GetPage-fm', '角色列表', '/api/v1/role', 'BUS', 'GET', '2021-05-13 19:59:02.720', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (45, 'go-admin/app/admin/apis.SysMenu.GetMenuTreeSelect-fm', '菜单权限列表【角色配菜单使用】', '/api/v1/roleMenuTreeselect/:roleId', 'SYS', 'GET', '2021-05-13 19:59:02.762', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (46, 'go-admin/app/admin/apis.SysDept.GetDeptTreeRoleSelect-fm', '角色部门结构树【自定义数据权限】', '/api/v1/roleDeptTreeselect/:roleId', 'SYS', 'GET', '2021-05-13 19:59:02.809', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (47, 'go-admin/app/admin/apis.SysRole.Get-fm', '角色通过id获取', '/api/v1/role/:id', 'BUS', 'GET', '2021-05-13 19:59:02.850', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (48, 'github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth.(*GinJWTMiddleware).RefreshHandler-fm', '刷新token', '/api/v1/refresh_token', 'SYS', 'GET', '2021-05-13 19:59:02.892', '2021-06-13 20:53:49.278', NULL, 0, 0); +INSERT INTO sys_api VALUES (53, 'go-admin/app/admin/apis.SysConfig.GetPage-fm', '参数列表', '/api/v1/config', 'BUS', 'GET', '2021-05-13 19:59:03.116', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (54, 'go-admin/app/admin/apis.SysConfig.Get-fm', '参数通过id获取', '/api/v1/config/:id', 'BUS', 'GET', '2021-05-13 19:59:03.157', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (55, 'go-admin/app/admin/apis.SysConfig.GetSysConfigByKEYForService-fm', '参数通过键名搜索【基础默认配置】', '/api/v1/configKey/:configKey', 'SYS', 'GET', '2021-05-13 19:59:03.198', '2021-06-13 20:53:49.745', NULL, 0, 0); +INSERT INTO sys_api VALUES (57, 'go-admin/app/jobs/apis.SysJob.RemoveJobForService-fm', 'job移除', '/api/v1/job/remove/:id', 'BUS', 'GET', '2021-05-13 19:59:03.295', '2021-06-13 20:53:49.786', NULL, 0, 0); +INSERT INTO sys_api VALUES (58, 'go-admin/app/jobs/apis.SysJob.StartJobForService-fm', 'job启动', '/api/v1/job/start/:id', 'BUS', 'GET', '2021-05-13 19:59:03.339', '2021-06-13 20:53:49.829', NULL, 0, 0); +INSERT INTO sys_api VALUES (59, 'go-admin/app/admin/apis.SysPost.GetPage-fm', '岗位列表', '/api/v1/post', 'BUS', 'GET', '2021-05-13 19:59:03.381', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (60, 'go-admin/app/admin/apis.SysPost.Get-fm', '岗位通过id获取', '/api/v1/post/:id', 'BUS', 'GET', '2021-05-13 19:59:03.433', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (62, 'go-admin/app/admin/apis.SysConfig.GetSysConfigBySysApp-fm', '系统前端参数', '/api/v1/app-config', 'SYS', 'GET', '2021-05-13 19:59:03.526', '2021-06-13 20:53:49.994', NULL, 0, 0); +INSERT INTO sys_api VALUES (63, 'go-admin/app/admin/apis.SysUser.GetProfile-fm', '*用户信息获取', '/api/v1/user/profile', 'SYS', 'GET', '2021-05-13 19:59:03.567', '2021-06-13 20:53:50.038', NULL, 0, 0); +INSERT INTO sys_api VALUES (66, 'github.com/go-admin-team/go-admin-core/sdk/pkg/ws.(*Manager).WsClient-fm', '链接ws【定时任务log】', '/ws/:id/:channel', 'BUS', 'GET', '2021-05-13 19:59:03.705', '2021-06-13 20:53:50.167', NULL, 0, 0); +INSERT INTO sys_api VALUES (67, 'github.com/go-admin-team/go-admin-core/sdk/pkg/ws.(*Manager).UnWsClient-fm', '退出ws【定时任务log】', '/wslogout/:id/:channel', 'BUS', 'GET', '2021-05-13 19:59:03.756', '2021-06-13 20:53:50.209', NULL, 0, 0); +INSERT INTO sys_api VALUES (68, 'go-admin/common/middleware/handler.Ping', '*用户基本信息', '/info', 'SYS', 'GET', '2021-05-13 19:59:03.800', '2021-06-13 20:53:50.251', NULL, 0, 0); +INSERT INTO sys_api VALUES (72, 'go-admin/common/actions.CreateAction.func1', '分类创建', '/api/v1/syscategory', 'BUS', 'POST', '2021-05-13 19:59:03.982', '2021-06-13 20:53:50.336', NULL, 0, 0); +INSERT INTO sys_api VALUES (73, 'go-admin/common/actions.CreateAction.func1', '内容创建', '/api/v1/syscontent', 'BUS', 'POST', '2021-05-13 19:59:04.027', '2021-06-13 20:53:50.375', NULL, 0, 0); +INSERT INTO sys_api VALUES (76, 'go-admin/common/actions.CreateAction.func1', 'job创建', '/api/v1/sysjob', 'BUS', 'POST', '2021-05-13 19:59:04.164', '2021-06-13 20:53:50.500', NULL, 0, 0); +INSERT INTO sys_api VALUES (80, 'go-admin/app/admin/apis.SysDictData.Insert-fm', '字典数据创建', '/api/v1/dict/data', 'BUS', 'POST', '2021-05-13 19:59:04.347', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (81, 'go-admin/app/admin/apis.SysDictType.Insert-fm', '字典类型创建', '/api/v1/dict/type', 'BUS', 'POST', '2021-05-13 19:59:04.391', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (82, 'go-admin/app/admin/apis.SysDept.Insert-fm', '部门创建', '/api/v1/dept', 'BUS', 'POST', '2021-05-13 19:59:04.435', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (85, 'github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth.(*GinJWTMiddleware).LoginHandler-fm', '*登录', '/api/v1/login', 'SYS', 'POST', '2021-05-13 19:59:04.597', '2021-06-13 20:53:50.784', NULL, 0, 0); +INSERT INTO sys_api VALUES (86, 'go-admin/common/middleware/handler.LogOut', '*退出', '/api/v1/logout', 'SYS', 'POST', '2021-05-13 19:59:04.642', '2021-06-13 20:53:50.824', NULL, 0, 0); +INSERT INTO sys_api VALUES (87, 'go-admin/app/admin/apis.SysConfig.Insert-fm', '参数创建', '/api/v1/config', 'BUS', 'POST', '2021-05-13 19:59:04.685', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (88, 'go-admin/app/admin/apis.SysMenu.Insert-fm', '菜单创建', '/api/v1/menu', 'BUS', 'POST', '2021-05-13 19:59:04.777', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (89, 'go-admin/app/admin/apis.SysPost.Insert-fm', '岗位创建', '/api/v1/post', 'BUS', 'POST', '2021-05-13 19:59:04.886', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (90, 'go-admin/app/admin/apis.SysRole.Insert-fm', '角色创建', '/api/v1/role', 'BUS', 'POST', '2021-05-13 19:59:04.975', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (91, 'go-admin/app/admin/apis.SysUser.InsetAvatar-fm', '*用户头像编辑', '/api/v1/user/avatar', 'SYS', 'POST', '2021-05-13 19:59:05.058', '2021-06-13 20:53:51.079', NULL, 0, 0); +INSERT INTO sys_api VALUES (92, 'go-admin/app/admin/apis.SysApi.Update-fm', '接口编辑', '/api/v1/sys-api/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.122', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (95, 'go-admin/common/actions.UpdateAction.func1', '分类编辑', '/api/v1/syscategory/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.255', '2021-06-13 20:53:51.247', NULL, 0, 0); +INSERT INTO sys_api VALUES (96, 'go-admin/common/actions.UpdateAction.func1', '内容编辑', '/api/v1/syscontent/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.299', '2021-06-13 20:53:51.289', NULL, 0, 0); +INSERT INTO sys_api VALUES (97, 'go-admin/common/actions.UpdateAction.func1', 'job编辑', '/api/v1/sysjob', 'BUS', 'PUT', '2021-05-13 19:59:05.343', '2021-06-13 20:53:51.331', NULL, 0, 0); +INSERT INTO sys_api VALUES (101, 'go-admin/app/admin/apis.SysDictData.Update-fm', '字典数据编辑', '/api/v1/dict/data/:dictCode', 'BUS', 'PUT', '2021-05-13 19:59:05.519', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (102, 'go-admin/app/admin/apis.SysDictType.Update-fm', '字典类型编辑', '/api/v1/dict/type/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.569', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (103, 'go-admin/app/admin/apis.SysDept.Update-fm', '部门编辑', '/api/v1/dept/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.613', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (104, 'go-admin/app/other/apis.SysFileDir.Update-fm', '文件夹编辑', '/api/v1/file-dir/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.662', '2021-06-13 20:53:51.847', NULL, 0, 0); +INSERT INTO sys_api VALUES (105, 'go-admin/app/other/apis.SysFileInfo.Update-fm', '文件编辑', '/api/v1/file-info/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.709', '2021-06-13 20:53:51.892', NULL, 0, 0); +INSERT INTO sys_api VALUES (106, 'go-admin/app/admin/apis.SysRole.Update-fm', '角色编辑', '/api/v1/role/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.752', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (107, 'go-admin/app/admin/apis.SysRole.Update2DataScope-fm', '角色数据权限修改', '/api/v1/roledatascope', 'BUS', 'PUT', '2021-05-13 19:59:05.803', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (108, 'go-admin/app/admin/apis.SysConfig.Update-fm', '参数编辑', '/api/v1/config/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.848', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (109, 'go-admin/app/admin/apis.SysMenu.Update-fm', '编辑菜单', '/api/v1/menu/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.891', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (110, 'go-admin/app/admin/apis.SysPost.Update-fm', '岗位编辑', '/api/v1/post/:id', 'BUS', 'PUT', '2021-05-13 19:59:05.934', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (111, 'go-admin/app/admin/apis.SysUser.UpdatePwd-fm', '*用户修改密码', '/api/v1/user/pwd', 'SYS', 'PUT', '2021-05-13 19:59:05.987', '2021-06-13 20:53:51.724', NULL, 0, 0); +INSERT INTO sys_api VALUES (112, 'go-admin/common/actions.DeleteAction.func1', '分类删除', '/api/v1/syscategory', 'BUS', 'DELETE', '2021-05-13 19:59:06.030', '2021-06-13 20:53:52.237', NULL, 0, 0); +INSERT INTO sys_api VALUES (113, 'go-admin/common/actions.DeleteAction.func1', '内容删除', '/api/v1/syscontent', 'BUS', 'DELETE', '2021-05-13 19:59:06.076', '2021-06-13 20:53:52.278', NULL, 0, 0); +INSERT INTO sys_api VALUES (114, 'go-admin/app/admin/apis.SysLoginLog.Delete-fm', '登录日志删除', '/api/v1/sys-login-log', 'BUS', 'DELETE', '2021-05-13 19:59:06.118', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (115, 'go-admin/app/admin/apis.SysOperaLog.Delete-fm', '操作日志删除', '/api/v1/sys-opera-log', 'BUS', 'DELETE', '2021-05-13 19:59:06.162', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (116, 'go-admin/common/actions.DeleteAction.func1', 'job删除', '/api/v1/sysjob', 'BUS', 'DELETE', '2021-05-13 19:59:06.206', '2021-06-13 20:53:52.323', NULL, 0, 0); +INSERT INTO sys_api VALUES (117, 'go-admin/app/other/apis.SysChinaAreaData.Delete-fm', '行政区删除', '/api/v1/sys-area-data', 'BUS', 'DELETE', '2021-05-13 19:59:06.249', '2021-06-13 20:53:52.061', NULL, 0, 0); +INSERT INTO sys_api VALUES (120, 'go-admin/app/admin/apis.SysDictData.Delete-fm', '字典数据删除', '/api/v1/dict/data', 'BUS', 'DELETE', '2021-05-13 19:59:06.387', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (121, 'go-admin/app/admin/apis.SysDictType.Delete-fm', '字典类型删除', '/api/v1/dict/type', 'BUS', 'DELETE', '2021-05-13 19:59:06.432', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (122, 'go-admin/app/admin/apis.SysDept.Delete-fm', '部门删除', '/api/v1/dept/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.475', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (123, 'go-admin/app/other/apis.SysFileDir.Delete-fm', '文件夹删除', '/api/v1/file-dir/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.520', '2021-06-13 20:53:52.539', NULL, 0, 0); +INSERT INTO sys_api VALUES (124, 'go-admin/app/other/apis.SysFileInfo.Delete-fm', '文件删除', '/api/v1/file-info/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.566', '2021-06-13 20:53:52.580', NULL, 0, 0); +INSERT INTO sys_api VALUES (125, 'go-admin/app/admin/apis.SysConfig.Delete-fm', '参数删除', '/api/v1/config', 'BUS', 'DELETE', '2021-05-13 19:59:06.612', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (126, 'go-admin/app/admin/apis.SysMenu.Delete-fm', '删除菜单', '/api/v1/menu', 'BUS', 'DELETE', '2021-05-13 19:59:06.654', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (127, 'go-admin/app/admin/apis.SysPost.Delete-fm', '岗位删除', '/api/v1/post/:id', 'BUS', 'DELETE', '2021-05-13 19:59:06.702', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (128, 'go-admin/app/admin/apis.SysRole.Delete-fm', '角色删除', '/api/v1/role', 'BUS', 'DELETE', '2021-05-13 19:59:06.746', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (131, 'github.com/go-admin-team/go-admin-core/tools/transfer.Handler.func1', '系统指标', '/api/v1/metrics', 'SYS', 'GET', '2021-05-17 22:13:55.933', '2021-06-13 20:53:49.614', NULL, 0, 0); +INSERT INTO sys_api VALUES (132, 'go-admin/app/other/router.registerMonitorRouter.func1', '健康状态', '/api/v1/health', 'SYS', 'GET', '2021-05-17 22:13:56.285', '2021-06-13 20:53:49.951', NULL, 0, 0); +INSERT INTO sys_api VALUES (133, 'go-admin/app/admin/apis.HelloWorld', '项目默认接口', '/', 'SYS', 'GET', '2021-05-24 10:30:44.553', '2021-06-13 20:53:47.406', NULL, 0, 0); +INSERT INTO sys_api VALUES (134, 'go-admin/app/other/apis.ServerMonitor.ServerInfo-fm', '服务器基本状态', '/api/v1/server-monitor', 'SYS', 'GET', '2021-05-24 10:30:44.937', '2021-06-13 20:53:48.255', NULL, 0, 0); +INSERT INTO sys_api VALUES (135, 'go-admin/app/admin/apis.SysApi.GetPage-fm', '接口列表', '/api/v1/sys-api', 'BUS', 'GET', '2021-05-24 11:37:53.303', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (136, 'go-admin/app/admin/apis.SysApi.Get-fm', '接口通过id获取', '/api/v1/sys-api/:id', 'BUS', 'GET', '2021-05-24 11:37:53.359', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (137, 'go-admin/app/admin/apis.SysLoginLog.GetPage-fm', '登录日志列表', '/api/v1/sys-login-log', 'BUS', 'GET', '2021-05-24 11:47:30.397', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (138, 'go-admin/app/other/apis.File.UploadFile-fm', '文件上传', '/api/v1/public/uploadFile', 'SYS', 'POST', '2021-05-25 19:16:18.493', '2021-06-13 20:53:50.866', NULL, 0, 0); +INSERT INTO sys_api VALUES (139, 'go-admin/app/admin/apis.SysConfig.Update2Set-fm', '参数信息修改【参数配置】', '/api/v1/set-config', 'BUS', 'PUT', '2021-05-27 09:45:14.853', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (140, 'go-admin/app/admin/apis.SysConfig.Get2Set-fm', '参数获取全部【配置使用】', '/api/v1/set-config', 'BUS', 'GET', '2021-05-27 11:54:14.384', '2021-06-17 11:48:40.732', NULL, 0, 0); +INSERT INTO sys_api VALUES (141, 'go-admin/app/admin/apis.SysUser.GetPage-fm', '管理员列表', '/api/v1/sys-user', 'BUS', 'GET', '2021-06-13 19:24:57.111', '2021-06-17 20:31:14.318', NULL, 0, 0); +INSERT INTO sys_api VALUES (142, 'go-admin/app/admin/apis.SysUser.Get-fm', '管理员通过id获取', '/api/v1/sys-user/:id', 'BUS', 'GET', '2021-06-13 19:24:57.188', '2021-06-17 20:31:14.318', NULL, 0, 0); +INSERT INTO sys_api VALUES (143, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTablesInfo-fm', '', '/api/v1/sys/tables/info', '', 'GET', '2021-06-13 19:24:57.437', '2021-06-13 20:53:48.047', NULL, 0, 0); +INSERT INTO sys_api VALUES (144, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTables-fm', '', '/api/v1/sys/tables/info/:tableId', '', 'GET', '2021-06-13 19:24:57.510', '2021-06-13 20:53:48.088', NULL, 0, 0); +INSERT INTO sys_api VALUES (145, 'go-admin/app/admin/apis/tools.(*SysTable).GetSysTableList-fm', '', '/api/v1/sys/tables/page', '', 'GET', '2021-06-13 19:24:57.582', '2021-06-13 20:53:48.128', NULL, 0, 0); +INSERT INTO sys_api VALUES (146, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/static/*filepath', '', 'GET', '2021-06-13 19:24:59.641', '2021-06-13 20:53:50.081', NULL, 0, 0); +INSERT INTO sys_api VALUES (147, 'github.com/swaggo/gin-swagger.CustomWrapHandler.func1', '', '/swagger/*any', '', 'GET', '2021-06-13 19:24:59.713', '2021-06-13 20:53:50.123', NULL, 0, 0); +INSERT INTO sys_api VALUES (148, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/form-generator/*filepath', '', 'GET', '2021-06-13 19:24:59.914', '2021-06-13 20:53:50.295', NULL, 0, 0); +INSERT INTO sys_api VALUES (149, 'go-admin/app/admin/apis/tools.(*SysTable).InsertSysTable-fm', '', '/api/v1/sys/tables/info', '', 'POST', '2021-06-13 19:25:00.163', '2021-06-13 20:53:50.539', NULL, 0, 0); +INSERT INTO sys_api VALUES (150, 'go-admin/app/admin/apis.SysUser.Insert-fm', '管理员创建', '/api/v1/sys-user', 'BUS', 'POST', '2021-06-13 19:25:00.233', '2021-06-17 20:31:14.318', NULL, 0, 0); +INSERT INTO sys_api VALUES (151, 'go-admin/app/admin/apis.SysUser.Update-fm', '管理员编辑', '/api/v1/sys-user', 'BUS', 'PUT', '2021-06-13 19:25:00.986', '2021-06-17 20:31:14.318', NULL, 0, 0); +INSERT INTO sys_api VALUES (152, 'go-admin/app/admin/apis/tools.(*SysTable).UpdateSysTable-fm', '', '/api/v1/sys/tables/info', '', 'PUT', '2021-06-13 19:25:01.149', '2021-06-13 20:53:51.375', NULL, 0, 0); +INSERT INTO sys_api VALUES (153, 'go-admin/app/admin/apis.SysRole.Update2Status-fm', '', '/api/v1/role-status', '', 'PUT', '2021-06-13 19:25:01.446', '2021-06-13 20:53:51.636', NULL, 0, 0); +INSERT INTO sys_api VALUES (154, 'go-admin/app/admin/apis.SysUser.ResetPwd-fm', '', '/api/v1/user/pwd/reset', '', 'PUT', '2021-06-13 19:25:01.601', '2021-06-13 20:53:51.764', NULL, 0, 0); +INSERT INTO sys_api VALUES (155, 'go-admin/app/admin/apis.SysUser.UpdateStatus-fm', '', '/api/v1/user/status', '', 'PUT', '2021-06-13 19:25:01.671', '2021-06-13 20:53:51.806', NULL, 0, 0); +INSERT INTO sys_api VALUES (156, 'go-admin/app/admin/apis.SysUser.Delete-fm', '管理员删除', '/api/v1/sys-user', 'BUS', 'DELETE', '2021-06-13 19:25:02.043', '2021-06-17 20:31:14.318', NULL, 0, 0); +INSERT INTO sys_api VALUES (157, 'go-admin/app/admin/apis/tools.(*SysTable).DeleteSysTables-fm', '', '/api/v1/sys/tables/info/:tableId', '', 'DELETE', '2021-06-13 19:25:02.283', '2021-06-13 20:53:52.367', NULL, 0, 0); +INSERT INTO sys_api VALUES (158, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/static/*filepath', '', 'HEAD', '2021-06-13 19:25:02.734', '2021-06-13 20:53:52.791', NULL, 0, 0); +INSERT INTO sys_api VALUES (159, 'github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1', '', '/form-generator/*filepath', '', 'HEAD', '2021-06-13 19:25:02.808', '2021-06-13 20:53:52.838', NULL, 0, 0); + +INSERT INTO sys_config VALUES (1, '皮肤样式', 'sys_index_skinName', 'skin-green', 'Y', '0', '主框架页-默认皮肤样式名称:蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 13:50:13.123', NULL); +INSERT INTO sys_config VALUES (2, '初始密码', 'sys_user_initPassword', '123456', 'Y', '0', '用户管理-账号初始密码:123456', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_config VALUES (3, '侧栏主题', 'sys_index_sideTheme', 'theme-dark', 'Y', '0', '主框架页-侧边栏主题:深色主题theme-dark,浅色主题theme-light', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_config VALUES (4, '系统名称', 'sys_app_name', 'go-admin管理系统', 'Y', '1', '', 1, 0, '2021-03-17 08:52:06.067', '2021-05-28 10:08:25.248', NULL); +INSERT INTO sys_config VALUES (5, '系统logo', 'sys_app_logo', 'https://doc-image.zhangwj.com/img/go-admin.png', 'Y', '1', '', 1, 0, '2021-03-17 08:53:19.462', '2021-03-17 08:53:19.462', NULL); + +INSERT INTO sys_dept VALUES (1, 0, '/0/1/', '爱拓科技', 0, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 17:06:44.960', NULL); +INSERT INTO sys_dept VALUES (7, 1, '/0/1/7/', '研发部', 1, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-16 21:35:00.109', NULL); +INSERT INTO sys_dept VALUES (8, 1, '/0/1/8/', '运维部', 0, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-16 21:41:39.747', NULL); +INSERT INTO sys_dept VALUES (9, 1, '/0/1/9/', '客服部', 0, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 17:07:05.993', NULL); +INSERT INTO sys_dept VALUES (10, 1, '/0/1/10/', '人力资源', 3, 'aituo', '13782218188', 'atuo@aituo.com', '1', 1, 1, '2021-05-13 19:56:37.913', '2021-06-05 17:07:08.503', NULL); + +INSERT INTO sys_dict_data VALUES (1, 0, '正常', '2', 'sys_normal_disable', '', '', '', '2', '', '系统正常', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:40.168', NULL); +INSERT INTO sys_dict_data VALUES (2, 0, '停用', '1', 'sys_normal_disable', '', '', '', '2', '', '系统停用', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (3, 0, '男', '0', 'sys_user_sex', '', '', '', '2', '', '性别男', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (4, 0, '女', '1', 'sys_user_sex', '', '', '', '2', '', '性别女', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (5, 0, '未知', '2', 'sys_user_sex', '', '', '', '2', '', '性别未知', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (6, 0, '显示', '0', 'sys_show_hide', '', '', '', '2', '', '显示菜单', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (7, 0, '隐藏', '1', 'sys_show_hide', '', '', '', '2', '', '隐藏菜单', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (8, 0, '是', 'Y', 'sys_yes_no', '', '', '', '2', '', '系统默认是', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (9, 0, '否', 'N', 'sys_yes_no', '', '', '', '2', '', '系统默认否', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (10, 0, '正常', '2', 'sys_job_status', '', '', '', '2', '', '正常状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (11, 0, '停用', '1', 'sys_job_status', '', '', '', '2', '', '停用状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (12, 0, '默认', 'DEFAULT', 'sys_job_group', '', '', '', '2', '', '默认分组', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (13, 0, '系统', 'SYSTEM', 'sys_job_group', '', '', '', '2', '', '系统分组', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (14, 0, '通知', '1', 'sys_notice_type', '', '', '', '2', '', '通知', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (15, 0, '公告', '2', 'sys_notice_type', '', '', '', '2', '', '公告', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (16, 0, '正常', '2', 'sys_common_status', '', '', '', '2', '', '正常状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (17, 0, '关闭', '1', 'sys_common_status', '', '', '', '2', '', '关闭状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (18, 0, '新增', '1', 'sys_oper_type', '', '', '', '2', '', '新增操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (19, 0, '修改', '2', 'sys_oper_type', '', '', '', '2', '', '修改操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (20, 0, '删除', '3', 'sys_oper_type', '', '', '', '2', '', '删除操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (21, 0, '授权', '4', 'sys_oper_type', '', '', '', '2', '', '授权操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (22, 0, '导出', '5', 'sys_oper_type', '', '', '', '2', '', '导出操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (23, 0, '导入', '6', 'sys_oper_type', '', '', '', '2', '', '导入操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (24, 0, '强退', '7', 'sys_oper_type', '', '', '', '2', '', '强退操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (25, 0, '生成代码', '8', 'sys_oper_type', '', '', '', '2', '', '生成操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (26, 0, '清空数据', '9', 'sys_oper_type', '', '', '', '2', '', '清空操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (27, 0, '成功', '0', 'sys_notice_status', '', '', '', '2', '', '成功状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (28, 0, '失败', '1', 'sys_notice_status', '', '', '', '2', '', '失败状态', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (29, 0, '登录', '10', 'sys_oper_type', '', '', '', '2', '', '登录操作', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (30, 0, '退出', '11', 'sys_oper_type', '', '', '', '2', '', '', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (31, 0, '获取验证码', '12', 'sys_oper_type', '', '', '', '2', '', '获取验证码', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_data VALUES (32, 0, '正常', '1', 'sys_content_status', '', '', '', '1', '', '', 1, 1, '2021-05-13 19:56:40.845', '2021-05-13 19:56:40.845', NULL); +INSERT INTO sys_dict_data VALUES (33, 1, '禁用', '2', 'sys_content_status', '', '', '', '1', '', '', 1, 1, '2021-05-13 19:56:40.845', '2021-05-13 19:56:40.845', NULL); + +INSERT INTO sys_dict_type VALUES (1, '系统开关', 'sys_normal_disable', '2', '系统开关列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (2, '用户性别', 'sys_user_sex', '2', '用户性别列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (3, '菜单状态', 'sys_show_hide', '2', '菜单状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (4, '系统是否', 'sys_yes_no', '2', '系统是否列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (5, '任务状态', 'sys_job_status', '2', '任务状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (6, '任务分组', 'sys_job_group', '2', '任务分组列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (7, '通知类型', 'sys_notice_type', '2', '通知类型列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (8, '系统状态', 'sys_common_status', '2', '登录状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (9, '操作类型', 'sys_oper_type', '2', '操作类型列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (10, '通知状态', 'sys_notice_status', '2', '通知状态列表', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:37.914', NULL); +INSERT INTO sys_dict_type VALUES (11, '内容状态', 'sys_content_status', '2', '', 1, 1, '2021-05-13 19:56:40.813', '2021-05-13 19:56:40.813', NULL); + +INSERT INTO sys_job VALUES (1, '接口测试', 'DEFAULT', 1, '0/5 * * * * ', 'http://localhost:8000', '', 1, 1, 1, 0, '2021-05-13 19:56:37.914', '2021-06-14 20:59:55.417', NULL, 1, 1); +INSERT INTO sys_job VALUES (2, '函数测试', 'DEFAULT', 2, '0/5 * * * * ', 'ExamplesOne', '参数', 1, 1, 1, 0, '2021-05-13 19:56:37.914', '2021-05-31 23:55:37.221', NULL, 1, 1); + +INSERT INTO sys_menu VALUES (2, 'Admin', '系统管理', 'api-server', '/admin', '/0/2', 'M', '无', '', 0, true, '', 'Layout', 10, '0', '1', 0, 1, '2021-05-20 21:58:45.679', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (3, 'SysUserManage', '用户管理', 'user', '/admin/sys-user', '/0/2/3', 'C', '无', 'admin:sysUser:list', 2, false, '', '/admin/sys-user/index', 10, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL); +INSERT INTO sys_menu VALUES (43, '', '新增管理员', 'app-group-fill', '', '/0/2/3/43', 'F', 'POST', 'admin:sysUser:add', 3, false, '', '', 10, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL); +INSERT INTO sys_menu VALUES (44, '', '查询管理员', 'app-group-fill', '', '/0/2/3/44', 'F', 'GET', 'admin:sysUser:query', 3, false, '', '', 40, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL); +INSERT INTO sys_menu VALUES (45, '', '修改管理员', 'app-group-fill', '', '/0/2/3/45', 'F', 'PUT', 'admin:sysUser:edit', 3, false, '', '', 30, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL); +INSERT INTO sys_menu VALUES (46, '', '删除管理员', 'app-group-fill', '', '/0/2/3/46', 'F', 'DELETE', 'admin:sysUser:remove', 3, false, '', '', 20, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 20:31:14.305', NULL); +INSERT INTO sys_menu VALUES (51, 'SysMenuManage', '菜单管理', 'tree-table', '/admin/sys-menu', '/0/2/51', 'C', '无', 'admin:sysMenu:list', 2, true, '', '/admin/sys-menu/index', 30, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (52, 'SysRoleManage', '角色管理', 'peoples', '/admin/sys-role', '/0/2/52', 'C', '无', 'admin:sysRole:list', 2, true, '', '/admin/sys-role/index', 20, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (56, 'SysDeptManage', '部门管理', 'tree', '/admin/sys-dept', '/0/2/56', 'C', '无', 'admin:sysDept:list', 2, false, '', '/admin/sys-dept/index', 40, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (57, 'SysPostManage', '岗位管理', 'pass', '/admin/sys-post', '/0/2/57', 'C', '无', 'admin:sysPost:list', 2, false, '', '/admin/sys-post/index', 50, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (58, 'Dict', '字典管理', 'education', '/admin/dict', '/0/2/58', 'C', '无', 'admin:sysDictType:list', 2, false, '', '/admin/dict/index', 60, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (59, 'SysDictDataManage', '字典数据', 'education', '/admin/dict/data/:dictId', '/0/2/59', 'C', '无', 'admin:sysDictData:list', 2, false, '', '/admin/dict/data', 100, '1', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (60, 'Tools', '开发工具', 'dev-tools', '/dev-tools', '/0/60', 'M', '无', '', 0, false, '', 'Layout', 40, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (61, 'Swagger', '系统接口', 'guide', '/dev-tools/swagger', '/0/60/61', 'C', '无', '', 60, false, '', '/dev-tools/swagger/index', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (62, 'SysConfigManage', '参数管理', 'swagger', '/admin/sys-config', '/0/2/62', 'C', '无', 'admin:sysConfig:list', 2, false, '', '/admin/sys-config/index', 70, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (211, 'Log', '日志管理', 'log', '/log', '/0/2/211', 'M', '', '', 2, false, '', '/log/index', 80, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (212, 'SysLoginLogManage', '登录日志', 'logininfor', '/admin/sys-login-log', '/0/2/211/212', 'C', '', 'admin:sysLoginLog:list', 211, false, '', '/admin/sys-login-log/index', 1, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (216, 'OperLog', '操作日志', 'skill', '/admin/sys-oper-log', '/0/2/211/216', 'C', '', 'admin:sysOperLog:list', 211, false, '', '/admin/sys-oper-log/index', 1, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (220, '', '新增菜单', 'app-group-fill', '', '/0/2/51/220', 'F', '', 'admin:sysMenu:add', 51, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (221, '', '修改菜单', 'app-group-fill', '', '/0/2/51/221', 'F', '', 'admin:sysMenu:edit', 51, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (222, '', '查询菜单', 'app-group-fill', '', '/0/2/51/222', 'F', '', 'admin:sysMenu:query', 51, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (223, '', '删除菜单', 'app-group-fill', '', '/0/2/51/223', 'F', '', 'admin:sysMenu:remove', 51, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (224, '', '新增角色', 'app-group-fill', '', '/0/2/52/224', 'F', '', 'admin:sysRole:add', 52, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (225, '', '查询角色', 'app-group-fill', '', '/0/2/52/225', 'F', '', 'admin:sysRole:query', 52, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (226, '', '修改角色', 'app-group-fill', '', '/0/2/52/226', 'F', '', 'admin:sysRole:update', 52, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (227, '', '删除角色', 'app-group-fill', '', '/0/2/52/227', 'F', '', 'admin:sysRole:remove', 52, false, '', '', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (228, '', '查询部门', 'app-group-fill', '', '/0/2/56/228', 'F', '', 'admin:sysDept:query', 56, false, '', '', 40, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (229, '', '新增部门', 'app-group-fill', '', '/0/2/56/229', 'F', '', 'admin:sysDept:add', 56, false, '', '', 10, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (230, '', '修改部门', 'app-group-fill', '', '/0/2/56/230', 'F', '', 'admin:sysDept:edit', 56, false, '', '', 30, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (231, '', '删除部门', 'app-group-fill', '', '/0/2/56/231', 'F', '', 'admin:sysDept:remove', 56, false, '', '', 20, '0', '1', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (232, '', '查询岗位', 'app-group-fill', '', '/0/2/57/232', 'F', '', 'admin:sysPost:query', 57, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (233, '', '新增岗位', 'app-group-fill', '', '/0/2/57/233', 'F', '', 'admin:sysPost:add', 57, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (234, '', '修改岗位', 'app-group-fill', '', '/0/2/57/234', 'F', '', 'admin:sysPost:edit', 57, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (235, '', '删除岗位', 'app-group-fill', '', '/0/2/57/235', 'F', '', 'admin:sysPost:remove', 57, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (236, '', '查询字典', 'app-group-fill', '', '/0/2/58/236', 'F', '', 'admin:sysDictType:query', 58, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (237, '', '新增类型', 'app-group-fill', '', '/0/2/58/237', 'F', '', 'admin:sysDictType:add', 58, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (238, '', '修改类型', 'app-group-fill', '', '/0/2/58/238', 'F', '', 'admin:sysDictType:edit', 58, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (239, '', '删除类型', 'app-group-fill', '', '/0/2/58/239', 'F', '', 'system:sysdicttype:remove', 58, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (240, '', '查询数据', 'app-group-fill', '', '/0/2/59/240', 'F', '', 'admin:sysDictData:query', 59, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (241, '', '新增数据', 'app-group-fill', '', '/0/2/59/241', 'F', '', 'admin:sysDictData:add', 59, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (242, '', '修改数据', 'app-group-fill', '', '/0/2/59/242', 'F', '', 'admin:sysDictData:edit', 59, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (243, '', '删除数据', 'app-group-fill', '', '/0/2/59/243', 'F', '', 'admin:sysDictData:remove', 59, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (244, '', '查询参数', 'app-group-fill', '', '/0/2/62/244', 'F', '', 'admin:sysConfig:query', 62, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (245, '', '新增参数', 'app-group-fill', '', '/0/2/62/245', 'F', '', 'admin:sysConfig:add', 62, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (246, '', '修改参数', 'app-group-fill', '', '/0/2/62/246', 'F', '', 'admin:sysConfig:edit', 62, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (247, '', '删除参数', 'app-group-fill', '', '/0/2/62/247', 'F', '', 'admin:sysConfig:remove', 62, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (248, '', '查询登录日志', 'app-group-fill', '', '/0/2/211/212/248', 'F', '', 'admin:sysLoginLog:query', 212, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (249, '', '删除登录日志', 'app-group-fill', '', '/0/2/211/212/249', 'F', '', 'admin:sysLoginLog:remove', 212, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (250, '', '查询操作日志', 'app-group-fill', '', '/0/2/211/216/250', 'F', '', 'admin:sysOperLog:query', 216, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (251, '', '删除操作日志', 'app-group-fill', '', '/0/2/211/216/251', 'F', '', 'admin:sysOperLog:remove', 216, false, '', '', 0, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (261, 'Gen', '代码生成', 'code', '/dev-tools/gen', '/0/60/261', 'C', '', '', 60, false, '', '/dev-tools/gen/index', 2, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-16 21:26:12.446', NULL); +INSERT INTO sys_menu VALUES (262, 'EditTable', '代码生成修改', 'build', '/dev-tools/editTable', '/0/60/262', 'C', '', '', 60, false, '', '/dev-tools/gen/editTable', 100, '1', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-16 21:26:12.446', NULL); +INSERT INTO sys_menu VALUES (264, 'Build', '表单构建', 'build', '/dev-tools/build', '/0/60/264', 'C', '', '', 60, false, '', '/dev-tools/build/index', 1, '0', '1', 1, 1, '2020-04-11 15:52:48.000', '2021-06-16 21:26:12.446', NULL); +INSERT INTO sys_menu VALUES (269, 'ServerMonitor', '服务监控', 'druid', '/sys-tools/monitor', '/0/60/269', 'C', '', 'sysTools:serverMonitor:list', 537, false, '', '/sys-tools/monitor', 0, '0', '1', 1, 1, '2020-04-14 00:28:19.000', '2021-06-16 21:26:12.446', NULL); +INSERT INTO sys_menu VALUES (459, 'Schedule', '定时任务', 'time-range', '/schedule', '/0/459', 'M', '无', '', 0, false, '', 'Layout', 20, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (460, 'ScheduleManage', 'Schedule', 'job', '/schedule/manage', '/0/459/460', 'C', '无', 'job:sysJob:list', 459, false, '', '/schedule/index', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (461, 'sys_job', '分页获取定时任务', 'app-group-fill', '', '/0/459/460/461', 'F', '无', 'job:sysJob:query', 460, false, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (462, 'sys_job', '创建定时任务', 'app-group-fill', '', '/0/459/460/462', 'F', '无', 'job:sysJob:add', 460, false, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (463, 'sys_job', '修改定时任务', 'app-group-fill', '', '/0/459/460/463', 'F', '无', 'job:sysJob:edit', 460, false, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (464, 'sys_job', '删除定时任务', 'app-group-fill', '', '/0/459/460/464', 'F', '无', 'job:sysJob:remove', 460, false, '', '', 0, '0', '1', 1, 1, '2020-08-03 09:17:37.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (471, 'JobLog', '日志', 'bug', '/schedule/log', '/0/459/471', 'C', '', '', 459, false, '', '/schedule/log', 0, '1', '1', 1, 1, '2020-08-05 21:24:46.000', '2021-06-05 22:15:03.465', NULL); +INSERT INTO sys_menu VALUES (528, 'SysApiManage', '接口管理', 'api-doc', '/admin/sys-api', '/0/527/528', 'C', '无', 'admin:sysApi:list', 2, false, '', '/admin/sys-api/index', 0, '0', '0', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (529, '', '查询接口', 'app-group-fill', '', '/0/527/528/529', 'F', '无', 'admin:sysApi:query', 528, false, '', '', 40, '0', '0', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (531, '', '修改接口', 'app-group-fill', '', '/0/527/528/531', 'F', '无', 'admin:sysApi:edit', 528, false, '', '', 30, '0', '0', 0, 1, '2021-05-20 22:08:44.526', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (537, 'SysTools', '系统工具', 'system-tools', '/sys-tools', '', 'M', '', '', 0, false, '', 'Layout', 30, '0', '1', 1, 1, '2021-05-21 11:13:32.166', '2021-06-16 21:26:12.446', NULL); +INSERT INTO sys_menu VALUES (540, 'SysConfigSet', '参数设置', 'system-tools', '/admin/sys-config/set', '', 'C', '', 'admin:sysConfigSet:list', 2, false, '', '/admin/sys-config/set', 0, '0', '1', 1, 1, '2021-05-25 16:06:52.560', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu VALUES (542, '', '修改', 'upload', '', '', 'F', '', 'admin:sysConfigSet:update', 540, false, '', '', 0, '0', '1', 1, 1, '2021-06-13 11:45:48.670', '2021-06-17 11:48:40.703', NULL); +INSERT INTO sys_menu_api_rule VALUES (216, 6); +INSERT INTO sys_menu_api_rule VALUES (250, 6); +INSERT INTO sys_menu_api_rule VALUES (58, 21); +INSERT INTO sys_menu_api_rule VALUES (236, 21); +INSERT INTO sys_menu_api_rule VALUES (238, 23); +INSERT INTO sys_menu_api_rule VALUES (59, 24); +INSERT INTO sys_menu_api_rule VALUES (240, 24); +INSERT INTO sys_menu_api_rule VALUES (242, 25); +INSERT INTO sys_menu_api_rule VALUES (58, 26); +INSERT INTO sys_menu_api_rule VALUES (236, 26); +INSERT INTO sys_menu_api_rule VALUES (56, 27); +INSERT INTO sys_menu_api_rule VALUES (228, 27); +INSERT INTO sys_menu_api_rule VALUES (230, 28); +INSERT INTO sys_menu_api_rule VALUES (226, 29); +INSERT INTO sys_menu_api_rule VALUES (51, 39); +INSERT INTO sys_menu_api_rule VALUES (51, 135); +INSERT INTO sys_menu_api_rule VALUES (222, 39); +INSERT INTO sys_menu_api_rule VALUES (221, 41); +INSERT INTO sys_menu_api_rule VALUES (52, 44); +INSERT INTO sys_menu_api_rule VALUES (225, 44); +INSERT INTO sys_menu_api_rule VALUES (226, 45); +INSERT INTO sys_menu_api_rule VALUES (226, 46); +INSERT INTO sys_menu_api_rule VALUES (226, 47); +INSERT INTO sys_menu_api_rule VALUES (62, 53); +INSERT INTO sys_menu_api_rule VALUES (244, 53); +INSERT INTO sys_menu_api_rule VALUES (246, 54); +INSERT INTO sys_menu_api_rule VALUES (57, 59); +INSERT INTO sys_menu_api_rule VALUES (232, 59); +INSERT INTO sys_menu_api_rule VALUES (234, 60); +INSERT INTO sys_menu_api_rule VALUES (241, 80); +INSERT INTO sys_menu_api_rule VALUES (237, 81); +INSERT INTO sys_menu_api_rule VALUES (229, 82); +INSERT INTO sys_menu_api_rule VALUES (245, 87); +INSERT INTO sys_menu_api_rule VALUES (220, 88); +INSERT INTO sys_menu_api_rule VALUES (233, 89); +INSERT INTO sys_menu_api_rule VALUES (224, 90); +INSERT INTO sys_menu_api_rule VALUES (531, 92); +INSERT INTO sys_menu_api_rule VALUES (242, 101); +INSERT INTO sys_menu_api_rule VALUES (238, 102); +INSERT INTO sys_menu_api_rule VALUES (230, 103); +INSERT INTO sys_menu_api_rule VALUES (226, 106); +INSERT INTO sys_menu_api_rule VALUES (226, 107); +INSERT INTO sys_menu_api_rule VALUES (246, 108); +INSERT INTO sys_menu_api_rule VALUES (221, 109); +INSERT INTO sys_menu_api_rule VALUES (234, 110); +INSERT INTO sys_menu_api_rule VALUES (249, 114); +INSERT INTO sys_menu_api_rule VALUES (251, 115); +INSERT INTO sys_menu_api_rule VALUES (243, 120); +INSERT INTO sys_menu_api_rule VALUES (239, 121); +INSERT INTO sys_menu_api_rule VALUES (231, 122); +INSERT INTO sys_menu_api_rule VALUES (247, 125); +INSERT INTO sys_menu_api_rule VALUES (223, 126); +INSERT INTO sys_menu_api_rule VALUES (235, 127); +INSERT INTO sys_menu_api_rule VALUES (227, 128); +INSERT INTO sys_menu_api_rule VALUES (528, 135); +INSERT INTO sys_menu_api_rule VALUES (529, 135); +INSERT INTO sys_menu_api_rule VALUES (531, 136); +INSERT INTO sys_menu_api_rule VALUES (212, 137); +INSERT INTO sys_menu_api_rule VALUES (248, 137); +INSERT INTO sys_menu_api_rule VALUES (542, 139); +INSERT INTO sys_menu_api_rule VALUES (540, 140); +INSERT INTO sys_menu_api_rule VALUES (3, 141); +INSERT INTO sys_menu_api_rule VALUES (44, 141); +INSERT INTO sys_menu_api_rule VALUES (45, 142); +INSERT INTO sys_menu_api_rule VALUES (43, 150); +INSERT INTO sys_menu_api_rule VALUES (45, 151); +INSERT INTO sys_menu_api_rule VALUES (46, 156); +INSERT INTO sys_post VALUES (1, '首席执行官', 'CEO', 0, '2','首席执行官', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_post VALUES (2, '首席技术执行官', 'CTO', 2, '2','首席技术执行官', 1, 1,'2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_post VALUES (3, '首席运营官', 'COO', 3, '2','测试工程师', 1, 1,'2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_role VALUES (1, '系统管理员', '2', 'admin', 1, '', '', true, '', 1, 1, '2021-05-13 19:56:37.913', '2021-05-13 19:56:37.913', NULL); +INSERT INTO sys_user VALUES (1, 'admin', '$2a$10$/Glr4g9Svr6O0kvjsRJCXu3f0W8/dsP3XZyVNi1019ratWpSPMyw.', 'zhangwj', '13818888888', 1, '', '', '1', '1@qq.com', 1, 1, '', '2', 1, 1, '2021-05-13 19:56:37.914', '2021-05-13 19:56:40.205', NULL); +-- 数据完成 ; \ No newline at end of file diff --git a/config/extend.go b/config/extend.go new file mode 100644 index 0000000..d7cd20a --- /dev/null +++ b/config/extend.go @@ -0,0 +1,26 @@ +package config + +var ExtConfig Extend + +// Extend 扩展配置 +// +// extend: +// demo: +// name: demo-name +// +// 使用方法: config.ExtConfig......即可!! +type Extend struct { + AMap AMap // 这里配置对应配置文件的结构即可 + Mq MqConfig +} + +type AMap struct { + Key string +} + +type MqConfig struct { + Addr string `yaml:"addr"` + Username string `yaml:"username"` + // Password string `yaml:"password"` + Pass string `yaml:"pass"` +} diff --git a/config/pg.sql b/config/pg.sql new file mode 100644 index 0000000..ba3c0c8 --- /dev/null +++ b/config/pg.sql @@ -0,0 +1,21 @@ +-- 开始初始化数据 ; +create sequence if not exists sys_role_role_id_seq; +create sequence if not exists sys_user_user_id_seq; +create sequence if not exists sys_post_post_id_seq; +create sequence if not exists sys_menu_menu_id_seq; +create sequence if not exists sys_dict_type_dict_id_seq; +create sequence if not exists sys_dict_data_dict_code_seq; +create sequence if not exists sys_dept_dept_id_seq; +create sequence if not exists sys_config_config_id_seq; +create sequence if not exists sys_job_id_seq; + +select setval('sys_role_role_id_seq',4); +select setval('sys_user_user_id_seq',5); +select setval('sys_post_post_id_seq',4); +select setval('sys_menu_menu_id_seq',543); +select setval('sys_dict_type_dict_id_seq',12); +select setval('sys_dict_data_dict_code_seq',34); +select setval('sys_dept_dept_id_seq',11); +select setval('sys_config_config_id_seq',6); +select setval('sys_job_id_seq',3); +-- 数据完成 ; diff --git a/config/settings.demo.yml b/config/settings.demo.yml new file mode 100644 index 0000000..9b297e6 --- /dev/null +++ b/config/settings.demo.yml @@ -0,0 +1,34 @@ +settings: + application: + demomsg: "谢谢您的参与,但为了大家更好的体验,所以本次提交就算了吧!\U0001F600\U0001F600\U0001F600" + enabledp: true + host: 0.0.0.0 + mode: demo + name: testApp + port: 8000 + readtimeout: 10000 + writertimeout: 20000 + database: + driver: sqlite3 + source: ./go-admin-db.db + gen: + dbname: testhhh + frontpath: ../go-admin-ui/src + jwt: + secret: go-admin + timeout: 3600 + logger: + # 日志存放路径 + path: temp/logs + # 日志输出,file:文件,default:命令行,其他:命令行 + stdout: '' #控制台日志,启用后,不输出到文件 + # 日志等级, trace, debug, info, warn, error, fatal + level: trace + # 数据库日志开关 + enableddb: true + queue: + memory: + poolSize: 100 + extend: + amap: + key: de7a062c984bf828d5d1b3a631a517e4 \ No newline at end of file diff --git a/config/settings.full.yml b/config/settings.full.yml new file mode 100644 index 0000000..bcca7e2 --- /dev/null +++ b/config/settings.full.yml @@ -0,0 +1,58 @@ +settings: + application: + # dev开发环境 test测试环境 prod线上环境 + mode: dev + # 服务器ip,默认使用 0.0.0.0 + host: 0.0.0.0 + # 服务名称 + name: testApp + # 端口号 + port: 8000 # 服务端口号 + readtimeout: 1 + writertimeout: 2 + # 数据权限功能开关 + enabledp: false + ssl: + # https对应的域名 + domain: localhost:8000 + # https开关 + enable: false + # ssl 证书key + key: keystring + # ssl 证书路径 + pem: temp/pem.pem + logger: + # 日志存放路径 + path: temp/logs + # 日志输出,file:文件,default:命令行,其他:命令行 + stdout: '' #控制台日志,启用后,不输出到文件 + # 日志等级, trace, debug, info, warn, error, fatal + level: trace + # 数据库日志开关 + enableddb: false + jwt: + # token 密钥,生产环境时及的修改 + secret: go-admin + # token 过期时间 单位:秒 + timeout: 3600 + database: + # 数据库类型 mysql,sqlite3, postgres + driver: mysql + # 数据库连接字符串 mysql 缺省信息 charset=utf8&parseTime=True&loc=Local&timeout=1000ms + source: user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms + # source: sqlite3.db + # source: host=myhost port=myport user=gorm dbname=gorm password=mypassword + registers: + - sources: + - user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms + gen: + # 代码生成读取的数据库名称 + dbname: dbname + # 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径 + frontpath: ../go-admin-ui/src + queue: + memory: + poolSize: 100 + extend: # 扩展项使用说明 + demo: + name: data diff --git a/config/settings.sqlite.yml b/config/settings.sqlite.yml new file mode 100644 index 0000000..90e98e2 --- /dev/null +++ b/config/settings.sqlite.yml @@ -0,0 +1,38 @@ +settings: + application: + # dev开发环境 test测试环境 prod线上环境 + mode: dev + # 服务器ip,默认使用 0.0.0.0 + host: 0.0.0.0 + # 服务名称 + name: testApp + # 端口号 + port: 8000 # 服务端口号 + readtimeout: 3000 + writertimeout: 2000 + # 数据权限功能开关 + enabledp: false + logger: + # 日志存放路径 + path: temp/logs + # 日志输出,file:文件,default:命令行,其他:命令行 + stdout: '' #控制台日志,启用后,不输出到文件 + # 日志等级, trace, debug, info, warn, error, fatal + level: trace + # 数据库日志开关 + enableddb: false + jwt: + # token 密钥,生产环境时及的修改 + secret: go-admin + # token 过期时间 单位:秒 + timeout: 3600 + database: + # 数据库类型 mysql,sqlite3, postgres + driver: sqlite3 + # 数据库连接sqlite3数据文件的路径 + source: go-admin-db.db + gen: + # 代码生成读取的数据库名称 + dbname: dbname + # 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径 + frontpath: ../go-admin-ui/src diff --git a/config/settings.yml b/config/settings.yml new file mode 100644 index 0000000..9769c79 --- /dev/null +++ b/config/settings.yml @@ -0,0 +1,79 @@ +settings: + application: + # dev开发环境 test测试环境 prod线上环境 + mode: dev + # 服务器ip,默认使用 0.0.0.0 + host: 0.0.0.0 + # 服务名称 + name: aggregate_translate_server + # 端口号 + port: 8085 # 服务端口号 + readtimeout: 1 + writertimeout: 2 + # 数据权限功能开关 + enabledp: true + logger: + # 日志存放路径 + path: temp/logs + # 日志输出,file:文件,default:命令行,其他:命令行 + stdout: '' #控制台日志,启用后,不输出到文件 + # 日志等级, trace, debug, info, warn, error, fatal + level: trace + # 数据库日志开关 + enableddb: false + jwt: + # token 密钥,生产环境时及的修改 + secret: go-admin + # token 过期时间 单位:秒 + timeout: 3600 + database: + # 数据库类型 mysql, sqlite3, postgres, sqlserver + # sqlserver: sqlserver://用户名:密码@地址?database=数据库名 + driver: mysql + # 数据库连接字符串 mysql 缺省信息 charset=utf8&parseTime=True&loc=Local&timeout=1000ms + source: root:123456@tcp(127.0.0.1:3306)/aggregate_translate?charset=utf8&parseTime=True&loc=Local&timeout=1000ms +# databases: +# 'locaohost:8000': +# driver: mysql +# # 数据库连接字符串 mysql 缺省信息 charset=utf8&parseTime=True&loc=Local&timeout=1000ms +# source: user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms +# registers: +# - sources: +# - user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms + gen: + # 代码生成读取的数据库名称 + dbname: aggregate_translate + # 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径 + frontpath: ../go-admin-ui/src + extend: # 扩展项使用说明 + demo: + name: data + mq: + addr: 127.0.0.1:5672 + username: admin + password: '123456' + pass: "123456" + cache: + redis: + addr: 127.0.0.1:6379 + password: + db: 1 + # key存在即可 + memory: '' + queue: + memory: + poolSize: 100 +# redis: +# addr: 127.0.0.1:6379 +# password: xxxxxx +# producer: +# streamMaxLength: 100 +# approximateMaxLength: true +# consumer: +# visibilityTimeout: 60 +# bufferSize: 100 +# concurrency: 10 +# blockingTimeout: 5 +# reclaimInterval: 1 + locker: + redis: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..41d94de --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3.8' +services: + go-admin-api: + container_name: go-admin + image: go-admin:latest + privileged: true + restart: always + ports: + - 8000:8000 + volumes: + - ./config/:/go-admin-api/config/ + - ./static/:/go-admin-api/static/ + - ./temp/:/go-admin-api/temp/ + networks: + - myweb +networks: + myweb: + driver: bridge + diff --git a/docs/admin/admin_docs.go b/docs/admin/admin_docs.go new file mode 100644 index 0000000..31c596a --- /dev/null +++ b/docs/admin/admin_docs.go @@ -0,0 +1,4373 @@ +// Package admin GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag +package admin + +import "github.com/swaggo/swag" + +const docTemplateadmin = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "license": { + "name": "MIT", + "url": "https://github.com/go-admin-team/go-admin/blob/master/LICENSE.md" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/api/v1/app-config": { + "get": { + "description": "获取系统配置信息,主要注意这里不在验证权限", + "tags": [ + "配置管理" + ], + "summary": "获取系统前台配置信息,主要注意这里不在验证权限", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + ] + } + } + } + } + }, + "/api/v1/captcha": { + "get": { + "description": "获取验证码", + "tags": [ + "登陆" + ], + "summary": "获取验证码", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + }, + "id": { + "type": "string" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/v1/db/columns/page": { + "get": { + "description": "数据库表列分页列表 / database table column page list", + "tags": [ + "工具 / 生成工具" + ], + "summary": "分页列表数据 / page list data", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tableName", + "in": "query" + }, + { + "type": "integer", + "description": "pageSize / 页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "pageIndex / 页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/db/tables/page": { + "get": { + "description": "数据库表分页列表 / database table page list", + "tags": [ + "工具 / 生成工具" + ], + "summary": "分页列表数据 / page list data", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tableName", + "in": "query" + }, + { + "type": "integer", + "description": "pageSize / 页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "pageIndex / 页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dept": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "分页列表", + "tags": [ + "部门" + ], + "summary": "分页部门列表数据", + "parameters": [ + { + "type": "string", + "description": "deptName", + "name": "deptName", + "in": "query" + }, + { + "type": "string", + "description": "deptId", + "name": "deptId", + "in": "query" + }, + { + "type": "string", + "description": "position", + "name": "position", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "部门" + ], + "summary": "添加部门", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDeptInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "部门" + ], + "summary": "删除部门", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDeptDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"删除失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/dept/{deptId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "部门" + ], + "summary": "获取部门数据", + "parameters": [ + { + "type": "string", + "description": "deptId", + "name": "deptId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "部门" + ], + "summary": "修改部门", + "parameters": [ + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDeptUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/dict-data/option-select": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "数据字典根据key获取", + "tags": [ + "字典数据" + ], + "summary": "数据字典根据key获取", + "parameters": [ + { + "type": "integer", + "description": "dictType", + "name": "dictType", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.SysDictDataGetAllResp" + } + } + } + } + ] + } + } + } + } + }, + "/api/v1/dict/data": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典数据" + ], + "summary": "字典数据列表", + "parameters": [ + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "dictCode", + "name": "dictCode", + "in": "query" + }, + { + "type": "string", + "description": "dictType", + "name": "dictType", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "添加字典数据", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictDataInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"添加成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "字典数据" + ], + "summary": "删除字典数据", + "parameters": [ + { + "description": "body", + "name": "dictCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictDataDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"删除成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/data/{dictCode}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典数据" + ], + "summary": "通过编码获取字典数据", + "parameters": [ + { + "type": "integer", + "description": "字典编码", + "name": "dictCode", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "修改字典数据", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictDataUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/type": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典类型" + ], + "summary": "字典类型列表数据", + "parameters": [ + { + "type": "string", + "description": "dictName", + "name": "dictName", + "in": "query" + }, + { + "type": "string", + "description": "dictId", + "name": "dictId", + "in": "query" + }, + { + "type": "string", + "description": "dictType", + "name": "dictType", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "添加字典类型", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictTypeInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "字典类型" + ], + "summary": "删除字典类型", + "parameters": [ + { + "description": "body", + "name": "dictCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictTypeDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/type-option-select": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典类型" + ], + "summary": "字典类型全部数据 代码生成使用接口", + "parameters": [ + { + "type": "string", + "description": "dictName", + "name": "dictName", + "in": "query" + }, + { + "type": "string", + "description": "dictId", + "name": "dictId", + "in": "query" + }, + { + "type": "string", + "description": "dictType", + "name": "dictType", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/type/{dictId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典类型" + ], + "summary": "字典类型通过字典id获取", + "parameters": [ + { + "type": "integer", + "description": "字典类型编码", + "name": "dictId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "修改字典类型", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictTypeUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/getinfo": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "个人中心" + ], + "summary": "获取个人信息", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/login": { + "post": { + "description": "获取token\nLoginHandler can be used by clients to get a jwt token.\nPayload needs to be json in the form of {\"username\": \"USERNAME\", \"password\": \"PASSWORD\"}.\nReply will be of the form {\"token\": \"TOKEN\"}.\ndev mode:It should be noted that all fields cannot be empty, and a value of 0 can be passed in addition to the account password\n注意:开发模式:需要注意全部字段不能为空,账号密码外可以传入0值", + "consumes": [ + "application/json" + ], + "tags": [ + "登陆" + ], + "summary": "登陆", + "parameters": [ + { + "description": "account", + "name": "account", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.Login" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"expire\": \"2019-08-07T12:45:48+08:00\", \"token\": \".eyJleHAiOjE1NjUxNTMxNDgsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU2NTE0OTU0OH0.-zvzHvbg0A\" }", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/menu": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "菜单" + ], + "summary": "Menu列表数据", + "parameters": [ + { + "type": "string", + "description": "menuName", + "name": "menuName", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "菜单" + ], + "summary": "创建菜单", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysMenuInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "菜单" + ], + "summary": "删除菜单", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysMenuDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/menu/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "菜单" + ], + "summary": "Menu详情数据", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "菜单" + ], + "summary": "修改菜单", + "parameters": [ + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysMenuUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/menuTreeselect/{roleId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "菜单" + ], + "summary": "角色修改使用的菜单列表", + "parameters": [ + { + "type": "integer", + "description": "roleId", + "name": "roleId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/menurole": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "菜单" + ], + "summary": "根据登录角色名称获取菜单列表数据(左菜单使用)", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/post": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "岗位" + ], + "summary": "岗位列表数据", + "parameters": [ + { + "type": "string", + "description": "postName", + "name": "postName", + "in": "query" + }, + { + "type": "string", + "description": "postCode", + "name": "postCode", + "in": "query" + }, + { + "type": "string", + "description": "postId", + "name": "postId", + "in": "query" + }, + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "岗位" + ], + "summary": "添加岗位", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysPostInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "岗位" + ], + "summary": "删除岗位", + "parameters": [ + { + "description": "请求参数", + "name": "id", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysPostDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/post/{id}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "岗位" + ], + "summary": "修改岗位", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysPostUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/post/{postId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "岗位" + ], + "summary": "获取岗位信息", + "parameters": [ + { + "type": "integer", + "description": "编码", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/public/uploadFile": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "multipart/form-data" + ], + "tags": [ + "公共接口" + ], + "summary": "上传图片", + "parameters": [ + { + "type": "string", + "description": "type", + "name": "type", + "in": "query", + "required": true + }, + { + "type": "file", + "description": "file", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/role": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get JSON", + "tags": [ + "角色/Role" + ], + "summary": "角色列表数据", + "parameters": [ + { + "type": "string", + "description": "roleName", + "name": "roleName", + "in": "query" + }, + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "roleKey", + "name": "roleKey", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "角色/Role" + ], + "summary": "创建角色", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysRoleInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "角色/Role" + ], + "summary": "删除用户角色", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysRoleDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/role-status/{id}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "角色/Role" + ], + "summary": "更新角色数据权限", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.RoleDataScopeReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/role/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "角色/Role" + ], + "summary": "获取Role数据", + "parameters": [ + { + "type": "string", + "description": "roleId", + "name": "roleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "角色/Role" + ], + "summary": "修改用户角色", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysRoleUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/server-monitor": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "系统信息" + ], + "summary": "系统信息", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/set-config": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "界面操作设置配置值的获取", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "获取配置", + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "界面操作设置配置值", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "设置配置", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.GetSetSysConfigReq" + } + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-api": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取接口管理列表", + "tags": [ + "接口管理" + ], + "summary": "获取接口管理列表", + "parameters": [ + { + "type": "string", + "description": "名称", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "标题", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "地址", + "name": "path", + "in": "query" + }, + { + "type": "string", + "description": "类型", + "name": "action", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/response.Page" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + } + } + } + ] + } + } + } + ] + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除接口管理", + "tags": [ + "接口管理" + ], + "summary": "删除接口管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysApiDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"删除成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-api/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取接口管理", + "tags": [ + "接口管理" + ], + "summary": "获取接口管理", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.SysApi" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "修改接口管理", + "consumes": [ + "application/json" + ], + "tags": [ + "接口管理" + ], + "summary": "修改接口管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysApiUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-config": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取配置管理列表", + "tags": [ + "配置管理" + ], + "summary": "获取配置管理列表", + "parameters": [ + { + "type": "string", + "description": "名称", + "name": "configName", + "in": "query" + }, + { + "type": "string", + "description": "key", + "name": "configKey", + "in": "query" + }, + { + "type": "string", + "description": "类型", + "name": "configType", + "in": "query" + }, + { + "type": "integer", + "description": "是否前端", + "name": "isFrontend", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/response.Page" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + } + } + } + ] + } + } + } + ] + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "创建配置管理", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "创建配置管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysConfigControl" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"创建成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除配置管理", + "tags": [ + "配置管理" + ], + "summary": "删除配置管理", + "parameters": [ + { + "description": "ids", + "name": "ids", + "in": "body", + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"删除成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-config/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "根据Key获取SysConfig的Service", + "tags": [ + "配置管理" + ], + "summary": "根据Key获取SysConfig的Service", + "parameters": [ + { + "type": "string", + "description": "configKey", + "name": "configKey", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/dto.SysConfigByKeyReq" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "修改配置管理", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "修改配置管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysConfigControl" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-login-log": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "登录日志" + ], + "summary": "登录日志列表", + "parameters": [ + { + "type": "string", + "description": "用户名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "ip地址", + "name": "ipaddr", + "in": "query" + }, + { + "type": "string", + "description": "归属地", + "name": "loginLocation", + "in": "query" + }, + { + "type": "string", + "description": "状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "开始时间", + "name": "beginTime", + "in": "query" + }, + { + "type": "string", + "description": "结束时间", + "name": "endTime", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "登录日志删除", + "tags": [ + "登录日志" + ], + "summary": "登录日志删除", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysLoginLogDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-login-log/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "登录日志" + ], + "summary": "登录日志通过id获取", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-opera-log": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "操作日志" + ], + "summary": "操作日志列表", + "parameters": [ + { + "type": "string", + "description": "title", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "method", + "name": "method", + "in": "query" + }, + { + "type": "string", + "description": "requestMethod", + "name": "requestMethod", + "in": "query" + }, + { + "type": "string", + "description": "operUrl", + "name": "operUrl", + "in": "query" + }, + { + "type": "string", + "description": "operIp", + "name": "operIp", + "in": "query" + }, + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "beginTime", + "name": "beginTime", + "in": "query" + }, + { + "type": "string", + "description": "endTime", + "name": "endTime", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "操作日志" + ], + "summary": "删除操作日志", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysOperaLogDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-opera-log/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "操作日志" + ], + "summary": "操作日志通过id获取", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-user": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "用户" + ], + "summary": "列表用户信息数据", + "parameters": [ + { + "type": "string", + "description": "username", + "name": "username", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "type": "string" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "创建用户", + "parameters": [ + { + "description": "用户数据", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysUserInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-user/{userId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "用户" + ], + "summary": "获取用户", + "parameters": [ + { + "type": "integer", + "description": "用户编码", + "name": "userId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "修改用户数据", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysUserUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "用户" + ], + "summary": "删除用户数据", + "parameters": [ + { + "type": "integer", + "description": "userId", + "name": "userId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys/tables/info": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "修改表结构", + "consumes": [ + "application/json" + ], + "tags": [ + "工具 / 生成工具" + ], + "summary": "修改表结构", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/tools.SysTables" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "添加表结构", + "consumes": [ + "application/json" + ], + "tags": [ + "工具 / 生成工具" + ], + "summary": "添加表结构", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tables", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/sys/tables/info/{tableId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "工具 / 生成工具" + ], + "summary": "获取配置", + "parameters": [ + { + "type": "integer", + "description": "configKey", + "name": "configKey", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "description": "删除表结构", + "tags": [ + "工具 / 生成工具" + ], + "summary": "删除表结构", + "parameters": [ + { + "type": "integer", + "description": "tableId", + "name": "tableId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"删除失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/sys/tables/page": { + "get": { + "description": "生成表分页列表", + "tags": [ + "工具 / 生成工具" + ], + "summary": "分页列表数据", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tableName", + "in": "query" + }, + { + "type": "integer", + "description": "pageSize / 页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "pageIndex / 页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/avatar": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "multipart/form-data" + ], + "tags": [ + "个人中心" + ], + "summary": "修改头像", + "parameters": [ + { + "type": "file", + "description": "file", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "个人中心" + ], + "summary": "获取个人中心用户", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/pwd/reset": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "重置用户密码", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ResetSysUserPwdReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/pwd/set": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "修改密码", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.PassWord" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/status": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "修改用户状态", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.UpdateSysUserStatusReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/logout": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取token", + "consumes": [ + "application/json" + ], + "summary": "退出登录", + "responses": { + "200": { + "description": "{\"code\": 200, \"msg\": \"成功退出系统\" }", + "schema": { + "type": "string" + } + } + } + } + } + }, + "definitions": { + "dto.GetSetSysConfigReq": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + }, + "configValue": { + "type": "string" + } + } + }, + "dto.PassWord": { + "type": "object", + "properties": { + "newPassword": { + "type": "string" + }, + "oldPassword": { + "type": "string" + } + } + }, + "dto.ResetSysUserPwdReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "password": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + } + } + }, + "dto.RoleDataScopeReq": { + "type": "object", + "required": [ + "dataScope", + "roleId" + ], + "properties": { + "dataScope": { + "type": "string" + }, + "deptIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "roleId": { + "type": "integer" + } + } + }, + "dto.SysApiDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysApiUpdateReq": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "handle": { + "type": "string" + }, + "id": { + "description": "编码", + "type": "integer" + }, + "path": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysConfigByKeyReq": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + } + } + }, + "dto.SysConfigControl": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + }, + "configName": { + "type": "string" + }, + "configType": { + "type": "string" + }, + "configValue": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "id": { + "description": "编码", + "type": "integer" + }, + "isFrontend": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDeptDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysDeptInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "deptId": { + "description": "编码", + "type": "integer" + }, + "deptName": { + "description": "部门名称", + "type": "string" + }, + "deptPath": { + "description": "路径", + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "leader": { + "description": "负责人", + "type": "string" + }, + "parentId": { + "description": "上级部门", + "type": "integer" + }, + "phone": { + "description": "手机", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDeptUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "deptId": { + "description": "编码", + "type": "integer" + }, + "deptName": { + "description": "部门名称", + "type": "string" + }, + "deptPath": { + "description": "路径", + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "leader": { + "description": "负责人", + "type": "string" + }, + "parentId": { + "description": "上级部门", + "type": "integer" + }, + "phone": { + "description": "手机", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictDataDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictDataGetAllResp": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "dto.SysDictDataInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "cssClass": { + "type": "string" + }, + "default": { + "type": "string" + }, + "dictLabel": { + "type": "string" + }, + "dictSort": { + "type": "integer" + }, + "dictType": { + "type": "string" + }, + "dictValue": { + "type": "string" + }, + "isDefault": { + "type": "string" + }, + "listClass": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictDataUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "cssClass": { + "type": "string" + }, + "default": { + "type": "string" + }, + "dictLabel": { + "type": "string" + }, + "dictSort": { + "type": "integer" + }, + "dictType": { + "type": "string" + }, + "dictValue": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "isDefault": { + "type": "string" + }, + "listClass": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictTypeDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictTypeInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "dictName": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictTypeUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "dictName": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysLoginLogDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysMenuDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysMenuInsertReq": { + "type": "object", + "properties": { + "action": { + "description": "请求方式", + "type": "string" + }, + "apis": { + "type": "array", + "items": { + "type": "integer" + } + }, + "breadcrumb": { + "description": "是否面包屑", + "type": "string" + }, + "component": { + "description": "组件", + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "icon": { + "description": "图标", + "type": "string" + }, + "isFrame": { + "description": "是否frame", + "type": "string" + }, + "menuId": { + "description": "编码", + "type": "integer" + }, + "menuName": { + "description": "菜单name", + "type": "string" + }, + "menuType": { + "description": "菜单类型", + "type": "string" + }, + "noCache": { + "description": "是否缓存", + "type": "boolean" + }, + "parentId": { + "description": "上级菜单", + "type": "integer" + }, + "path": { + "description": "路径", + "type": "string" + }, + "paths": { + "description": "id路径", + "type": "string" + }, + "permission": { + "description": "权限编码", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "sysApi": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + }, + "title": { + "description": "显示名称", + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "visible": { + "description": "是否显示", + "type": "string" + } + } + }, + "dto.SysMenuUpdateReq": { + "type": "object", + "properties": { + "action": { + "description": "请求方式", + "type": "string" + }, + "apis": { + "type": "array", + "items": { + "type": "integer" + } + }, + "breadcrumb": { + "description": "是否面包屑", + "type": "string" + }, + "component": { + "description": "组件", + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "icon": { + "description": "图标", + "type": "string" + }, + "isFrame": { + "description": "是否frame", + "type": "string" + }, + "menuId": { + "description": "编码", + "type": "integer" + }, + "menuName": { + "description": "菜单name", + "type": "string" + }, + "menuType": { + "description": "菜单类型", + "type": "string" + }, + "noCache": { + "description": "是否缓存", + "type": "boolean" + }, + "parentId": { + "description": "上级菜单", + "type": "integer" + }, + "path": { + "description": "路径", + "type": "string" + }, + "paths": { + "description": "id路径", + "type": "string" + }, + "permission": { + "description": "权限编码", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "sysApi": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + }, + "title": { + "description": "显示名称", + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "visible": { + "description": "是否显示", + "type": "string" + } + } + }, + "dto.SysOperaLogDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysPostDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysPostInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "postCode": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "postName": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "sort": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysPostUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "postCode": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "postName": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "sort": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysRoleDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysRoleInsertReq": { + "type": "object", + "properties": { + "admin": { + "type": "boolean" + }, + "createBy": { + "type": "integer" + }, + "dataScope": { + "type": "string" + }, + "deptIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "flag": { + "description": "标记", + "type": "string" + }, + "menuIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "remark": { + "description": "备注", + "type": "string" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "roleKey": { + "description": "角色代码", + "type": "string" + }, + "roleName": { + "description": "角色名称", + "type": "string" + }, + "roleSort": { + "description": "角色排序", + "type": "integer" + }, + "status": { + "description": "状态 1禁用 2正常", + "type": "string" + }, + "sysDept": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysDept" + } + }, + "sysMenu": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysMenu" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysRoleUpdateReq": { + "type": "object", + "properties": { + "admin": { + "type": "boolean" + }, + "createBy": { + "type": "integer" + }, + "dataScope": { + "type": "string" + }, + "deptIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "flag": { + "description": "标记", + "type": "string" + }, + "menuIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "remark": { + "description": "备注", + "type": "string" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "roleKey": { + "description": "角色代码", + "type": "string" + }, + "roleName": { + "description": "角色名称", + "type": "string" + }, + "roleSort": { + "description": "角色排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "string" + }, + "sysDept": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysDept" + } + }, + "sysMenu": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysMenu" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysUserInsertReq": { + "type": "object", + "properties": { + "avatar": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "deptId": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "nickName": { + "type": "string" + }, + "password": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "roleId": { + "type": "integer" + }, + "sex": { + "type": "string" + }, + "status": { + "type": "string", + "default": "1" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + }, + "username": { + "type": "string" + } + } + }, + "dto.SysUserUpdateReq": { + "type": "object", + "properties": { + "avatar": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "deptId": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "nickName": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "roleId": { + "type": "integer" + }, + "sex": { + "type": "string" + }, + "status": { + "type": "string", + "default": "1" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + }, + "username": { + "type": "string" + } + } + }, + "dto.UpdateStatusReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "string" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.UpdateSysUserStatusReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + } + } + }, + "handler.Login": { + "type": "object", + "required": [ + "code", + "password", + "username", + "uuid" + ], + "properties": { + "code": { + "type": "string" + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + }, + "uuid": { + "type": "string" + } + } + }, + "models.SysApi": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "handle": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + }, + "models.SysConfig": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + }, + "configName": { + "type": "string" + }, + "configType": { + "type": "string" + }, + "configValue": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "isFrontend": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + }, + "models.SysDept": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysDept" + } + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "deptId": { + "description": "部门编码", + "type": "integer" + }, + "deptName": { + "description": "部门名称", + "type": "string" + }, + "deptPath": { + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "leader": { + "description": "负责人", + "type": "string" + }, + "params": { + "type": "string" + }, + "parentId": { + "description": "上级部门", + "type": "integer" + }, + "phone": { + "description": "手机", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "integer" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + }, + "models.SysMenu": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "apis": { + "type": "array", + "items": { + "type": "integer" + } + }, + "breadcrumb": { + "type": "string" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysMenu" + } + }, + "component": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "isFrame": { + "type": "string" + }, + "is_select": { + "type": "boolean" + }, + "menuId": { + "type": "integer" + }, + "menuName": { + "type": "string" + }, + "menuType": { + "type": "string" + }, + "noCache": { + "type": "boolean" + }, + "params": { + "type": "string" + }, + "parentId": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "paths": { + "type": "string" + }, + "permission": { + "type": "string" + }, + "roleId": { + "type": "integer" + }, + "sort": { + "type": "integer" + }, + "sysApi": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + }, + "title": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + }, + "visible": { + "type": "string" + } + } + }, + "response.Page": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "pageIndex": { + "type": "integer" + }, + "pageSize": { + "type": "integer" + } + } + }, + "response.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "msg": { + "type": "string" + }, + "requestId": { + "description": "数据集", + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "tools.Params": { + "type": "object", + "properties": { + "treeCode": { + "type": "string" + }, + "treeName": { + "type": "string" + }, + "treeParentCode": { + "type": "string" + } + } + }, + "tools.SysColumns": { + "type": "object", + "properties": { + "columnComment": { + "type": "string" + }, + "columnId": { + "type": "integer" + }, + "columnName": { + "type": "string" + }, + "columnType": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "deletedAt": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "edit": { + "type": "boolean" + }, + "fkCol": { + "type": "array", + "items": { + "$ref": "#/definitions/tools.SysColumns" + } + }, + "fkLabelId": { + "type": "string" + }, + "fkLabelName": { + "type": "string" + }, + "fkTableName": { + "type": "string" + }, + "fkTableNameClass": { + "type": "string" + }, + "fkTableNamePackage": { + "type": "string" + }, + "goField": { + "type": "string" + }, + "goType": { + "type": "string" + }, + "htmlType": { + "type": "string" + }, + "increment": { + "type": "boolean" + }, + "insert": { + "type": "boolean" + }, + "isEdit": { + "type": "string" + }, + "isIncrement": { + "type": "string" + }, + "isInsert": { + "type": "string" + }, + "isList": { + "type": "string" + }, + "isPk": { + "type": "string" + }, + "isQuery": { + "type": "string" + }, + "isRequired": { + "type": "string" + }, + "jsonField": { + "type": "string" + }, + "list": { + "type": "string" + }, + "pk": { + "type": "boolean" + }, + "query": { + "type": "boolean" + }, + "queryType": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "sort": { + "type": "integer" + }, + "superColumn": { + "type": "boolean" + }, + "tableId": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + }, + "usableColumn": { + "type": "boolean" + } + } + }, + "tools.SysTables": { + "type": "object", + "properties": { + "businessName": { + "type": "string" + }, + "className": { + "description": "类名", + "type": "string" + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/tools.SysColumns" + } + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "crud": { + "type": "boolean" + }, + "dataScope": { + "type": "string" + }, + "deletedAt": { + "type": "string" + }, + "functionAuthor": { + "description": "功能作者", + "type": "string" + }, + "functionName": { + "description": "功能名称", + "type": "string" + }, + "isActions": { + "type": "integer" + }, + "isAuth": { + "type": "integer" + }, + "isDataScope": { + "type": "integer" + }, + "isLogicalDelete": { + "type": "string" + }, + "logicalDelete": { + "type": "boolean" + }, + "logicalDeleteColumn": { + "type": "string" + }, + "moduleFrontName": { + "description": "前端文件名", + "type": "string" + }, + "moduleName": { + "description": "go文件名", + "type": "string" + }, + "options": { + "type": "string" + }, + "packageName": { + "description": "包名", + "type": "string" + }, + "params": { + "$ref": "#/definitions/tools.Params" + }, + "pkColumn": { + "type": "string" + }, + "pkGoField": { + "type": "string" + }, + "pkJsonField": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "tableComment": { + "description": "表备注", + "type": "string" + }, + "tableId": { + "description": "表编码", + "type": "integer" + }, + "tableName": { + "description": "表名称", + "type": "string" + }, + "tplCategory": { + "type": "string" + }, + "tree": { + "type": "boolean" + }, + "treeCode": { + "type": "string" + }, + "treeName": { + "type": "string" + }, + "treeParentCode": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +}` + +// SwaggerInfoadmin holds exported Swagger Info so clients can modify it +var SwaggerInfoadmin = &swag.Spec{ + Version: "2.0.0", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "go-admin API", + Description: "基于Gin + Vue + Element UI的前后端分离权限管理系统的接口文档\n添加qq群: 521386980 进入技术交流群 请先star,谢谢!", + InfoInstanceName: "admin", + SwaggerTemplate: docTemplateadmin, +} + +func init() { + swag.Register(SwaggerInfoadmin.InstanceName(), SwaggerInfoadmin) +} diff --git a/docs/admin/admin_swagger.json b/docs/admin/admin_swagger.json new file mode 100644 index 0000000..d3c32a1 --- /dev/null +++ b/docs/admin/admin_swagger.json @@ -0,0 +1,4348 @@ +{ + "swagger": "2.0", + "info": { + "description": "基于Gin + Vue + Element UI的前后端分离权限管理系统的接口文档\n添加qq群: 521386980 进入技术交流群 请先star,谢谢!", + "title": "go-admin API", + "contact": {}, + "license": { + "name": "MIT", + "url": "https://github.com/go-admin-team/go-admin/blob/master/LICENSE.md" + }, + "version": "2.0.0" + }, + "paths": { + "/api/v1/app-config": { + "get": { + "description": "获取系统配置信息,主要注意这里不在验证权限", + "tags": [ + "配置管理" + ], + "summary": "获取系统前台配置信息,主要注意这里不在验证权限", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + ] + } + } + } + } + }, + "/api/v1/captcha": { + "get": { + "description": "获取验证码", + "tags": [ + "登陆" + ], + "summary": "获取验证码", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + }, + "id": { + "type": "string" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/v1/db/columns/page": { + "get": { + "description": "数据库表列分页列表 / database table column page list", + "tags": [ + "工具 / 生成工具" + ], + "summary": "分页列表数据 / page list data", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tableName", + "in": "query" + }, + { + "type": "integer", + "description": "pageSize / 页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "pageIndex / 页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/db/tables/page": { + "get": { + "description": "数据库表分页列表 / database table page list", + "tags": [ + "工具 / 生成工具" + ], + "summary": "分页列表数据 / page list data", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tableName", + "in": "query" + }, + { + "type": "integer", + "description": "pageSize / 页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "pageIndex / 页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dept": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "分页列表", + "tags": [ + "部门" + ], + "summary": "分页部门列表数据", + "parameters": [ + { + "type": "string", + "description": "deptName", + "name": "deptName", + "in": "query" + }, + { + "type": "string", + "description": "deptId", + "name": "deptId", + "in": "query" + }, + { + "type": "string", + "description": "position", + "name": "position", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "部门" + ], + "summary": "添加部门", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDeptInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "部门" + ], + "summary": "删除部门", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDeptDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"删除失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/dept/{deptId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "部门" + ], + "summary": "获取部门数据", + "parameters": [ + { + "type": "string", + "description": "deptId", + "name": "deptId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "部门" + ], + "summary": "修改部门", + "parameters": [ + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDeptUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/dict-data/option-select": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "数据字典根据key获取", + "tags": [ + "字典数据" + ], + "summary": "数据字典根据key获取", + "parameters": [ + { + "type": "integer", + "description": "dictType", + "name": "dictType", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.SysDictDataGetAllResp" + } + } + } + } + ] + } + } + } + } + }, + "/api/v1/dict/data": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典数据" + ], + "summary": "字典数据列表", + "parameters": [ + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "dictCode", + "name": "dictCode", + "in": "query" + }, + { + "type": "string", + "description": "dictType", + "name": "dictType", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "添加字典数据", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictDataInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"添加成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "字典数据" + ], + "summary": "删除字典数据", + "parameters": [ + { + "description": "body", + "name": "dictCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictDataDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"删除成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/data/{dictCode}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典数据" + ], + "summary": "通过编码获取字典数据", + "parameters": [ + { + "type": "integer", + "description": "字典编码", + "name": "dictCode", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "修改字典数据", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictDataUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/type": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典类型" + ], + "summary": "字典类型列表数据", + "parameters": [ + { + "type": "string", + "description": "dictName", + "name": "dictName", + "in": "query" + }, + { + "type": "string", + "description": "dictId", + "name": "dictId", + "in": "query" + }, + { + "type": "string", + "description": "dictType", + "name": "dictType", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "添加字典类型", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictTypeInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "字典类型" + ], + "summary": "删除字典类型", + "parameters": [ + { + "description": "body", + "name": "dictCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictTypeDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/type-option-select": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典类型" + ], + "summary": "字典类型全部数据 代码生成使用接口", + "parameters": [ + { + "type": "string", + "description": "dictName", + "name": "dictName", + "in": "query" + }, + { + "type": "string", + "description": "dictId", + "name": "dictId", + "in": "query" + }, + { + "type": "string", + "description": "dictType", + "name": "dictType", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/dict/type/{dictId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "字典类型" + ], + "summary": "字典类型通过字典id获取", + "parameters": [ + { + "type": "integer", + "description": "字典类型编码", + "name": "dictId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "修改字典类型", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysDictTypeUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/getinfo": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "个人中心" + ], + "summary": "获取个人信息", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/login": { + "post": { + "description": "获取token\nLoginHandler can be used by clients to get a jwt token.\nPayload needs to be json in the form of {\"username\": \"USERNAME\", \"password\": \"PASSWORD\"}.\nReply will be of the form {\"token\": \"TOKEN\"}.\ndev mode:It should be noted that all fields cannot be empty, and a value of 0 can be passed in addition to the account password\n注意:开发模式:需要注意全部字段不能为空,账号密码外可以传入0值", + "consumes": [ + "application/json" + ], + "tags": [ + "登陆" + ], + "summary": "登陆", + "parameters": [ + { + "description": "account", + "name": "account", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.Login" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"expire\": \"2019-08-07T12:45:48+08:00\", \"token\": \".eyJleHAiOjE1NjUxNTMxNDgsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU2NTE0OTU0OH0.-zvzHvbg0A\" }", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/menu": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "菜单" + ], + "summary": "Menu列表数据", + "parameters": [ + { + "type": "string", + "description": "menuName", + "name": "menuName", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "菜单" + ], + "summary": "创建菜单", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysMenuInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "菜单" + ], + "summary": "删除菜单", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysMenuDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/menu/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "菜单" + ], + "summary": "Menu详情数据", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "菜单" + ], + "summary": "修改菜单", + "parameters": [ + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysMenuUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/menuTreeselect/{roleId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "菜单" + ], + "summary": "角色修改使用的菜单列表", + "parameters": [ + { + "type": "integer", + "description": "roleId", + "name": "roleId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/menurole": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "菜单" + ], + "summary": "根据登录角色名称获取菜单列表数据(左菜单使用)", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/post": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "岗位" + ], + "summary": "岗位列表数据", + "parameters": [ + { + "type": "string", + "description": "postName", + "name": "postName", + "in": "query" + }, + { + "type": "string", + "description": "postCode", + "name": "postCode", + "in": "query" + }, + { + "type": "string", + "description": "postId", + "name": "postId", + "in": "query" + }, + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "岗位" + ], + "summary": "添加岗位", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysPostInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "岗位" + ], + "summary": "删除岗位", + "parameters": [ + { + "description": "请求参数", + "name": "id", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysPostDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/post/{id}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "岗位" + ], + "summary": "修改岗位", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysPostUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/post/{postId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "岗位" + ], + "summary": "获取岗位信息", + "parameters": [ + { + "type": "integer", + "description": "编码", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/public/uploadFile": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "multipart/form-data" + ], + "tags": [ + "公共接口" + ], + "summary": "上传图片", + "parameters": [ + { + "type": "string", + "description": "type", + "name": "type", + "in": "query", + "required": true + }, + { + "type": "file", + "description": "file", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/role": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get JSON", + "tags": [ + "角色/Role" + ], + "summary": "角色列表数据", + "parameters": [ + { + "type": "string", + "description": "roleName", + "name": "roleName", + "in": "query" + }, + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "roleKey", + "name": "roleKey", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "角色/Role" + ], + "summary": "创建角色", + "parameters": [ + { + "description": "data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysRoleInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "角色/Role" + ], + "summary": "删除用户角色", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysRoleDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/role-status/{id}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "角色/Role" + ], + "summary": "更新角色数据权限", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.RoleDataScopeReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/role/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "角色/Role" + ], + "summary": "获取Role数据", + "parameters": [ + { + "type": "string", + "description": "roleId", + "name": "roleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "角色/Role" + ], + "summary": "修改用户角色", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysRoleUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/server-monitor": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "系统信息" + ], + "summary": "系统信息", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/set-config": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "界面操作设置配置值的获取", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "获取配置", + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "界面操作设置配置值", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "设置配置", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.GetSetSysConfigReq" + } + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-api": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取接口管理列表", + "tags": [ + "接口管理" + ], + "summary": "获取接口管理列表", + "parameters": [ + { + "type": "string", + "description": "名称", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "标题", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "地址", + "name": "path", + "in": "query" + }, + { + "type": "string", + "description": "类型", + "name": "action", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/response.Page" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + } + } + } + ] + } + } + } + ] + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除接口管理", + "tags": [ + "接口管理" + ], + "summary": "删除接口管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysApiDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"删除成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-api/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取接口管理", + "tags": [ + "接口管理" + ], + "summary": "获取接口管理", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.SysApi" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "修改接口管理", + "consumes": [ + "application/json" + ], + "tags": [ + "接口管理" + ], + "summary": "修改接口管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysApiUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-config": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取配置管理列表", + "tags": [ + "配置管理" + ], + "summary": "获取配置管理列表", + "parameters": [ + { + "type": "string", + "description": "名称", + "name": "configName", + "in": "query" + }, + { + "type": "string", + "description": "key", + "name": "configKey", + "in": "query" + }, + { + "type": "string", + "description": "类型", + "name": "configType", + "in": "query" + }, + { + "type": "integer", + "description": "是否前端", + "name": "isFrontend", + "in": "query" + }, + { + "type": "integer", + "description": "页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/response.Page" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + } + } + } + ] + } + } + } + ] + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "创建配置管理", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "创建配置管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysConfigControl" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"创建成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除配置管理", + "tags": [ + "配置管理" + ], + "summary": "删除配置管理", + "parameters": [ + { + "description": "ids", + "name": "ids", + "in": "body", + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"删除成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-config/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "根据Key获取SysConfig的Service", + "tags": [ + "配置管理" + ], + "summary": "根据Key获取SysConfig的Service", + "parameters": [ + { + "type": "string", + "description": "configKey", + "name": "configKey", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/dto.SysConfigByKeyReq" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "修改配置管理", + "consumes": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "修改配置管理", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysConfigControl" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"message\": \"修改成功\"}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-login-log": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "登录日志" + ], + "summary": "登录日志列表", + "parameters": [ + { + "type": "string", + "description": "用户名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "ip地址", + "name": "ipaddr", + "in": "query" + }, + { + "type": "string", + "description": "归属地", + "name": "loginLocation", + "in": "query" + }, + { + "type": "string", + "description": "状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "开始时间", + "name": "beginTime", + "in": "query" + }, + { + "type": "string", + "description": "结束时间", + "name": "endTime", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "登录日志删除", + "tags": [ + "登录日志" + ], + "summary": "登录日志删除", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysLoginLogDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-login-log/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "登录日志" + ], + "summary": "登录日志通过id获取", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-opera-log": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "操作日志" + ], + "summary": "操作日志列表", + "parameters": [ + { + "type": "string", + "description": "title", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "method", + "name": "method", + "in": "query" + }, + { + "type": "string", + "description": "requestMethod", + "name": "requestMethod", + "in": "query" + }, + { + "type": "string", + "description": "operUrl", + "name": "operUrl", + "in": "query" + }, + { + "type": "string", + "description": "operIp", + "name": "operIp", + "in": "query" + }, + { + "type": "string", + "description": "status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "beginTime", + "name": "beginTime", + "in": "query" + }, + { + "type": "string", + "description": "endTime", + "name": "endTime", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "操作日志" + ], + "summary": "删除操作日志", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysOperaLogDeleteReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-opera-log/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "操作日志" + ], + "summary": "操作日志通过id获取", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-user": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "用户" + ], + "summary": "列表用户信息数据", + "parameters": [ + { + "type": "string", + "description": "username", + "name": "username", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "type": "string" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "创建用户", + "parameters": [ + { + "description": "用户数据", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysUserInsertReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys-user/{userId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "用户" + ], + "summary": "获取用户", + "parameters": [ + { + "type": "integer", + "description": "用户编码", + "name": "userId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "修改用户数据", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SysUserUpdateReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "删除数据", + "tags": [ + "用户" + ], + "summary": "删除用户数据", + "parameters": [ + { + "type": "integer", + "description": "userId", + "name": "userId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/sys/tables/info": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "修改表结构", + "consumes": [ + "application/json" + ], + "tags": [ + "工具 / 生成工具" + ], + "summary": "修改表结构", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/tools.SysTables" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "添加表结构", + "consumes": [ + "application/json" + ], + "tags": [ + "工具 / 生成工具" + ], + "summary": "添加表结构", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tables", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"添加失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/sys/tables/info/{tableId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "工具 / 生成工具" + ], + "summary": "获取配置", + "parameters": [ + { + "type": "integer", + "description": "configKey", + "name": "configKey", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + }, + "delete": { + "description": "删除表结构", + "tags": [ + "工具 / 生成工具" + ], + "summary": "删除表结构", + "parameters": [ + { + "type": "integer", + "description": "tableId", + "name": "tableId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": -1, \"message\": \"删除失败\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/sys/tables/page": { + "get": { + "description": "生成表分页列表", + "tags": [ + "工具 / 生成工具" + ], + "summary": "分页列表数据", + "parameters": [ + { + "type": "string", + "description": "tableName / 数据表名称", + "name": "tableName", + "in": "query" + }, + { + "type": "integer", + "description": "pageSize / 页条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "pageIndex / 页码", + "name": "pageIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/avatar": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "multipart/form-data" + ], + "tags": [ + "个人中心" + ], + "summary": "修改头像", + "parameters": [ + { + "type": "file", + "description": "file", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "tags": [ + "个人中心" + ], + "summary": "获取个人中心用户", + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/pwd/reset": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "重置用户密码", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ResetSysUserPwdReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/pwd/set": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "修改密码", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.PassWord" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/api/v1/user/status": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取JSON", + "consumes": [ + "application/json" + ], + "tags": [ + "用户" + ], + "summary": "修改用户状态", + "parameters": [ + { + "description": "body", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.UpdateSysUserStatusReq" + } + } + ], + "responses": { + "200": { + "description": "{\"code\": 200, \"data\": [...]}", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, + "/logout": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "获取token", + "consumes": [ + "application/json" + ], + "summary": "退出登录", + "responses": { + "200": { + "description": "{\"code\": 200, \"msg\": \"成功退出系统\" }", + "schema": { + "type": "string" + } + } + } + } + } + }, + "definitions": { + "dto.GetSetSysConfigReq": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + }, + "configValue": { + "type": "string" + } + } + }, + "dto.PassWord": { + "type": "object", + "properties": { + "newPassword": { + "type": "string" + }, + "oldPassword": { + "type": "string" + } + } + }, + "dto.ResetSysUserPwdReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "password": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + } + } + }, + "dto.RoleDataScopeReq": { + "type": "object", + "required": [ + "dataScope", + "roleId" + ], + "properties": { + "dataScope": { + "type": "string" + }, + "deptIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "roleId": { + "type": "integer" + } + } + }, + "dto.SysApiDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysApiUpdateReq": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "handle": { + "type": "string" + }, + "id": { + "description": "编码", + "type": "integer" + }, + "path": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysConfigByKeyReq": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + } + } + }, + "dto.SysConfigControl": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + }, + "configName": { + "type": "string" + }, + "configType": { + "type": "string" + }, + "configValue": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "id": { + "description": "编码", + "type": "integer" + }, + "isFrontend": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDeptDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysDeptInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "deptId": { + "description": "编码", + "type": "integer" + }, + "deptName": { + "description": "部门名称", + "type": "string" + }, + "deptPath": { + "description": "路径", + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "leader": { + "description": "负责人", + "type": "string" + }, + "parentId": { + "description": "上级部门", + "type": "integer" + }, + "phone": { + "description": "手机", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDeptUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "deptId": { + "description": "编码", + "type": "integer" + }, + "deptName": { + "description": "部门名称", + "type": "string" + }, + "deptPath": { + "description": "路径", + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "leader": { + "description": "负责人", + "type": "string" + }, + "parentId": { + "description": "上级部门", + "type": "integer" + }, + "phone": { + "description": "手机", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictDataDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictDataGetAllResp": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "dto.SysDictDataInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "cssClass": { + "type": "string" + }, + "default": { + "type": "string" + }, + "dictLabel": { + "type": "string" + }, + "dictSort": { + "type": "integer" + }, + "dictType": { + "type": "string" + }, + "dictValue": { + "type": "string" + }, + "isDefault": { + "type": "string" + }, + "listClass": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictDataUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "cssClass": { + "type": "string" + }, + "default": { + "type": "string" + }, + "dictLabel": { + "type": "string" + }, + "dictSort": { + "type": "integer" + }, + "dictType": { + "type": "string" + }, + "dictValue": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "isDefault": { + "type": "string" + }, + "listClass": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictTypeDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictTypeInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "dictName": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysDictTypeUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "dictName": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysLoginLogDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysMenuDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysMenuInsertReq": { + "type": "object", + "properties": { + "action": { + "description": "请求方式", + "type": "string" + }, + "apis": { + "type": "array", + "items": { + "type": "integer" + } + }, + "breadcrumb": { + "description": "是否面包屑", + "type": "string" + }, + "component": { + "description": "组件", + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "icon": { + "description": "图标", + "type": "string" + }, + "isFrame": { + "description": "是否frame", + "type": "string" + }, + "menuId": { + "description": "编码", + "type": "integer" + }, + "menuName": { + "description": "菜单name", + "type": "string" + }, + "menuType": { + "description": "菜单类型", + "type": "string" + }, + "noCache": { + "description": "是否缓存", + "type": "boolean" + }, + "parentId": { + "description": "上级菜单", + "type": "integer" + }, + "path": { + "description": "路径", + "type": "string" + }, + "paths": { + "description": "id路径", + "type": "string" + }, + "permission": { + "description": "权限编码", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "sysApi": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + }, + "title": { + "description": "显示名称", + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "visible": { + "description": "是否显示", + "type": "string" + } + } + }, + "dto.SysMenuUpdateReq": { + "type": "object", + "properties": { + "action": { + "description": "请求方式", + "type": "string" + }, + "apis": { + "type": "array", + "items": { + "type": "integer" + } + }, + "breadcrumb": { + "description": "是否面包屑", + "type": "string" + }, + "component": { + "description": "组件", + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "icon": { + "description": "图标", + "type": "string" + }, + "isFrame": { + "description": "是否frame", + "type": "string" + }, + "menuId": { + "description": "编码", + "type": "integer" + }, + "menuName": { + "description": "菜单name", + "type": "string" + }, + "menuType": { + "description": "菜单类型", + "type": "string" + }, + "noCache": { + "description": "是否缓存", + "type": "boolean" + }, + "parentId": { + "description": "上级菜单", + "type": "integer" + }, + "path": { + "description": "路径", + "type": "string" + }, + "paths": { + "description": "id路径", + "type": "string" + }, + "permission": { + "description": "权限编码", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "sysApi": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + }, + "title": { + "description": "显示名称", + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "visible": { + "description": "是否显示", + "type": "string" + } + } + }, + "dto.SysOperaLogDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysPostDeleteReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysPostInsertReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "postCode": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "postName": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "sort": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysPostUpdateReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "postCode": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "postName": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "sort": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysRoleDeleteReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "dto.SysRoleInsertReq": { + "type": "object", + "properties": { + "admin": { + "type": "boolean" + }, + "createBy": { + "type": "integer" + }, + "dataScope": { + "type": "string" + }, + "deptIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "flag": { + "description": "标记", + "type": "string" + }, + "menuIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "remark": { + "description": "备注", + "type": "string" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "roleKey": { + "description": "角色代码", + "type": "string" + }, + "roleName": { + "description": "角色名称", + "type": "string" + }, + "roleSort": { + "description": "角色排序", + "type": "integer" + }, + "status": { + "description": "状态 1禁用 2正常", + "type": "string" + }, + "sysDept": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysDept" + } + }, + "sysMenu": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysMenu" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysRoleUpdateReq": { + "type": "object", + "properties": { + "admin": { + "type": "boolean" + }, + "createBy": { + "type": "integer" + }, + "dataScope": { + "type": "string" + }, + "deptIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "flag": { + "description": "标记", + "type": "string" + }, + "menuIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "remark": { + "description": "备注", + "type": "string" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "roleKey": { + "description": "角色代码", + "type": "string" + }, + "roleName": { + "description": "角色名称", + "type": "string" + }, + "roleSort": { + "description": "角色排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "string" + }, + "sysDept": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysDept" + } + }, + "sysMenu": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysMenu" + } + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.SysUserInsertReq": { + "type": "object", + "properties": { + "avatar": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "deptId": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "nickName": { + "type": "string" + }, + "password": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "roleId": { + "type": "integer" + }, + "sex": { + "type": "string" + }, + "status": { + "type": "string", + "default": "1" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + }, + "username": { + "type": "string" + } + } + }, + "dto.SysUserUpdateReq": { + "type": "object", + "properties": { + "avatar": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "deptId": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "nickName": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "postId": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "roleId": { + "type": "integer" + }, + "sex": { + "type": "string" + }, + "status": { + "type": "string", + "default": "1" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + }, + "username": { + "type": "string" + } + } + }, + "dto.UpdateStatusReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "string" + }, + "updateBy": { + "type": "integer" + } + } + }, + "dto.UpdateSysUserStatusReq": { + "type": "object", + "properties": { + "createBy": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "userId": { + "description": "用户ID", + "type": "integer" + } + } + }, + "handler.Login": { + "type": "object", + "required": [ + "code", + "password", + "username", + "uuid" + ], + "properties": { + "code": { + "type": "string" + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + }, + "uuid": { + "type": "string" + } + } + }, + "models.SysApi": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "handle": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + }, + "models.SysConfig": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + }, + "configName": { + "type": "string" + }, + "configType": { + "type": "string" + }, + "configValue": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "isFrontend": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + }, + "models.SysDept": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysDept" + } + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "deptId": { + "description": "部门编码", + "type": "integer" + }, + "deptName": { + "description": "部门名称", + "type": "string" + }, + "deptPath": { + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "leader": { + "description": "负责人", + "type": "string" + }, + "params": { + "type": "string" + }, + "parentId": { + "description": "上级部门", + "type": "integer" + }, + "phone": { + "description": "手机", + "type": "string" + }, + "sort": { + "description": "排序", + "type": "integer" + }, + "status": { + "description": "状态", + "type": "integer" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + }, + "models.SysMenu": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "apis": { + "type": "array", + "items": { + "type": "integer" + } + }, + "breadcrumb": { + "type": "string" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysMenu" + } + }, + "component": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "isFrame": { + "type": "string" + }, + "is_select": { + "type": "boolean" + }, + "menuId": { + "type": "integer" + }, + "menuName": { + "type": "string" + }, + "menuType": { + "type": "string" + }, + "noCache": { + "type": "boolean" + }, + "params": { + "type": "string" + }, + "parentId": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "paths": { + "type": "string" + }, + "permission": { + "type": "string" + }, + "roleId": { + "type": "integer" + }, + "sort": { + "type": "integer" + }, + "sysApi": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SysApi" + } + }, + "title": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + }, + "visible": { + "type": "string" + } + } + }, + "response.Page": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "pageIndex": { + "type": "integer" + }, + "pageSize": { + "type": "integer" + } + } + }, + "response.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "msg": { + "type": "string" + }, + "requestId": { + "description": "数据集", + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "tools.Params": { + "type": "object", + "properties": { + "treeCode": { + "type": "string" + }, + "treeName": { + "type": "string" + }, + "treeParentCode": { + "type": "string" + } + } + }, + "tools.SysColumns": { + "type": "object", + "properties": { + "columnComment": { + "type": "string" + }, + "columnId": { + "type": "integer" + }, + "columnName": { + "type": "string" + }, + "columnType": { + "type": "string" + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "deletedAt": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "edit": { + "type": "boolean" + }, + "fkCol": { + "type": "array", + "items": { + "$ref": "#/definitions/tools.SysColumns" + } + }, + "fkLabelId": { + "type": "string" + }, + "fkLabelName": { + "type": "string" + }, + "fkTableName": { + "type": "string" + }, + "fkTableNameClass": { + "type": "string" + }, + "fkTableNamePackage": { + "type": "string" + }, + "goField": { + "type": "string" + }, + "goType": { + "type": "string" + }, + "htmlType": { + "type": "string" + }, + "increment": { + "type": "boolean" + }, + "insert": { + "type": "boolean" + }, + "isEdit": { + "type": "string" + }, + "isIncrement": { + "type": "string" + }, + "isInsert": { + "type": "string" + }, + "isList": { + "type": "string" + }, + "isPk": { + "type": "string" + }, + "isQuery": { + "type": "string" + }, + "isRequired": { + "type": "string" + }, + "jsonField": { + "type": "string" + }, + "list": { + "type": "string" + }, + "pk": { + "type": "boolean" + }, + "query": { + "type": "boolean" + }, + "queryType": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "sort": { + "type": "integer" + }, + "superColumn": { + "type": "boolean" + }, + "tableId": { + "type": "integer" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + }, + "usableColumn": { + "type": "boolean" + } + } + }, + "tools.SysTables": { + "type": "object", + "properties": { + "businessName": { + "type": "string" + }, + "className": { + "description": "类名", + "type": "string" + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/tools.SysColumns" + } + }, + "createBy": { + "type": "integer" + }, + "createdAt": { + "type": "string" + }, + "crud": { + "type": "boolean" + }, + "dataScope": { + "type": "string" + }, + "deletedAt": { + "type": "string" + }, + "functionAuthor": { + "description": "功能作者", + "type": "string" + }, + "functionName": { + "description": "功能名称", + "type": "string" + }, + "isActions": { + "type": "integer" + }, + "isAuth": { + "type": "integer" + }, + "isDataScope": { + "type": "integer" + }, + "isLogicalDelete": { + "type": "string" + }, + "logicalDelete": { + "type": "boolean" + }, + "logicalDeleteColumn": { + "type": "string" + }, + "moduleFrontName": { + "description": "前端文件名", + "type": "string" + }, + "moduleName": { + "description": "go文件名", + "type": "string" + }, + "options": { + "type": "string" + }, + "packageName": { + "description": "包名", + "type": "string" + }, + "params": { + "$ref": "#/definitions/tools.Params" + }, + "pkColumn": { + "type": "string" + }, + "pkGoField": { + "type": "string" + }, + "pkJsonField": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "tableComment": { + "description": "表备注", + "type": "string" + }, + "tableId": { + "description": "表编码", + "type": "integer" + }, + "tableName": { + "description": "表名称", + "type": "string" + }, + "tplCategory": { + "type": "string" + }, + "tree": { + "type": "boolean" + }, + "treeCode": { + "type": "string" + }, + "treeName": { + "type": "string" + }, + "treeParentCode": { + "type": "string" + }, + "updateBy": { + "type": "integer" + }, + "updatedAt": { + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/docs/admin/admin_swagger.yaml b/docs/admin/admin_swagger.yaml new file mode 100644 index 0000000..412817e --- /dev/null +++ b/docs/admin/admin_swagger.yaml @@ -0,0 +1,2771 @@ +definitions: + dto.GetSetSysConfigReq: + properties: + configKey: + type: string + configValue: + type: string + type: object + dto.PassWord: + properties: + newPassword: + type: string + oldPassword: + type: string + type: object + dto.ResetSysUserPwdReq: + properties: + createBy: + type: integer + password: + type: string + updateBy: + type: integer + userId: + description: 用户ID + type: integer + type: object + dto.RoleDataScopeReq: + properties: + dataScope: + type: string + deptIds: + items: + type: integer + type: array + roleId: + type: integer + required: + - dataScope + - roleId + type: object + dto.SysApiDeleteReq: + properties: + ids: + items: + type: integer + type: array + type: object + dto.SysApiUpdateReq: + properties: + action: + type: string + createBy: + type: integer + handle: + type: string + id: + description: 编码 + type: integer + path: + type: string + title: + type: string + type: + type: string + updateBy: + type: integer + type: object + dto.SysConfigByKeyReq: + properties: + configKey: + type: string + type: object + dto.SysConfigControl: + properties: + configKey: + type: string + configName: + type: string + configType: + type: string + configValue: + type: string + createBy: + type: integer + id: + description: 编码 + type: integer + isFrontend: + type: string + remark: + type: string + updateBy: + type: integer + type: object + dto.SysDeptDeleteReq: + properties: + ids: + items: + type: integer + type: array + type: object + dto.SysDeptInsertReq: + properties: + createBy: + type: integer + deptId: + description: 编码 + type: integer + deptName: + description: 部门名称 + type: string + deptPath: + description: 路径 + type: string + email: + description: 邮箱 + type: string + leader: + description: 负责人 + type: string + parentId: + description: 上级部门 + type: integer + phone: + description: 手机 + type: string + sort: + description: 排序 + type: integer + status: + description: 状态 + type: integer + updateBy: + type: integer + type: object + dto.SysDeptUpdateReq: + properties: + createBy: + type: integer + deptId: + description: 编码 + type: integer + deptName: + description: 部门名称 + type: string + deptPath: + description: 路径 + type: string + email: + description: 邮箱 + type: string + leader: + description: 负责人 + type: string + parentId: + description: 上级部门 + type: integer + phone: + description: 手机 + type: string + sort: + description: 排序 + type: integer + status: + description: 状态 + type: integer + updateBy: + type: integer + type: object + dto.SysDictDataDeleteReq: + properties: + createBy: + type: integer + ids: + items: + type: integer + type: array + updateBy: + type: integer + type: object + dto.SysDictDataGetAllResp: + properties: + label: + type: string + value: + type: string + type: object + dto.SysDictDataInsertReq: + properties: + createBy: + type: integer + cssClass: + type: string + default: + type: string + dictLabel: + type: string + dictSort: + type: integer + dictType: + type: string + dictValue: + type: string + isDefault: + type: string + listClass: + type: string + remark: + type: string + status: + type: integer + updateBy: + type: integer + type: object + dto.SysDictDataUpdateReq: + properties: + createBy: + type: integer + cssClass: + type: string + default: + type: string + dictLabel: + type: string + dictSort: + type: integer + dictType: + type: string + dictValue: + type: string + id: + type: integer + isDefault: + type: string + listClass: + type: string + remark: + type: string + status: + type: integer + updateBy: + type: integer + type: object + dto.SysDictTypeDeleteReq: + properties: + createBy: + type: integer + ids: + items: + type: integer + type: array + updateBy: + type: integer + type: object + dto.SysDictTypeInsertReq: + properties: + createBy: + type: integer + dictName: + type: string + dictType: + type: string + id: + type: integer + remark: + type: string + status: + type: integer + updateBy: + type: integer + type: object + dto.SysDictTypeUpdateReq: + properties: + createBy: + type: integer + dictName: + type: string + dictType: + type: string + id: + type: integer + remark: + type: string + status: + type: integer + updateBy: + type: integer + type: object + dto.SysLoginLogDeleteReq: + properties: + ids: + items: + type: integer + type: array + type: object + dto.SysMenuDeleteReq: + properties: + createBy: + type: integer + ids: + items: + type: integer + type: array + updateBy: + type: integer + type: object + dto.SysMenuInsertReq: + properties: + action: + description: 请求方式 + type: string + apis: + items: + type: integer + type: array + breadcrumb: + description: 是否面包屑 + type: string + component: + description: 组件 + type: string + createBy: + type: integer + icon: + description: 图标 + type: string + isFrame: + description: 是否frame + type: string + menuId: + description: 编码 + type: integer + menuName: + description: 菜单name + type: string + menuType: + description: 菜单类型 + type: string + noCache: + description: 是否缓存 + type: boolean + parentId: + description: 上级菜单 + type: integer + path: + description: 路径 + type: string + paths: + description: id路径 + type: string + permission: + description: 权限编码 + type: string + sort: + description: 排序 + type: integer + sysApi: + items: + $ref: '#/definitions/models.SysApi' + type: array + title: + description: 显示名称 + type: string + updateBy: + type: integer + visible: + description: 是否显示 + type: string + type: object + dto.SysMenuUpdateReq: + properties: + action: + description: 请求方式 + type: string + apis: + items: + type: integer + type: array + breadcrumb: + description: 是否面包屑 + type: string + component: + description: 组件 + type: string + createBy: + type: integer + icon: + description: 图标 + type: string + isFrame: + description: 是否frame + type: string + menuId: + description: 编码 + type: integer + menuName: + description: 菜单name + type: string + menuType: + description: 菜单类型 + type: string + noCache: + description: 是否缓存 + type: boolean + parentId: + description: 上级菜单 + type: integer + path: + description: 路径 + type: string + paths: + description: id路径 + type: string + permission: + description: 权限编码 + type: string + sort: + description: 排序 + type: integer + sysApi: + items: + $ref: '#/definitions/models.SysApi' + type: array + title: + description: 显示名称 + type: string + updateBy: + type: integer + visible: + description: 是否显示 + type: string + type: object + dto.SysOperaLogDeleteReq: + properties: + ids: + items: + type: integer + type: array + type: object + dto.SysPostDeleteReq: + properties: + createBy: + type: integer + ids: + items: + type: integer + type: array + updateBy: + type: integer + type: object + dto.SysPostInsertReq: + properties: + createBy: + type: integer + postCode: + type: string + postId: + type: integer + postName: + type: string + remark: + type: string + sort: + type: integer + status: + type: integer + updateBy: + type: integer + type: object + dto.SysPostUpdateReq: + properties: + createBy: + type: integer + postCode: + type: string + postId: + type: integer + postName: + type: string + remark: + type: string + sort: + type: integer + status: + type: integer + updateBy: + type: integer + type: object + dto.SysRoleDeleteReq: + properties: + ids: + items: + type: integer + type: array + type: object + dto.SysRoleInsertReq: + properties: + admin: + type: boolean + createBy: + type: integer + dataScope: + type: string + deptIds: + items: + type: integer + type: array + flag: + description: 标记 + type: string + menuIds: + items: + type: integer + type: array + remark: + description: 备注 + type: string + roleId: + description: 角色编码 + type: integer + roleKey: + description: 角色代码 + type: string + roleName: + description: 角色名称 + type: string + roleSort: + description: 角色排序 + type: integer + status: + description: 状态 1禁用 2正常 + type: string + sysDept: + items: + $ref: '#/definitions/models.SysDept' + type: array + sysMenu: + items: + $ref: '#/definitions/models.SysMenu' + type: array + updateBy: + type: integer + type: object + dto.SysRoleUpdateReq: + properties: + admin: + type: boolean + createBy: + type: integer + dataScope: + type: string + deptIds: + items: + type: integer + type: array + flag: + description: 标记 + type: string + menuIds: + items: + type: integer + type: array + remark: + description: 备注 + type: string + roleId: + description: 角色编码 + type: integer + roleKey: + description: 角色代码 + type: string + roleName: + description: 角色名称 + type: string + roleSort: + description: 角色排序 + type: integer + status: + description: 状态 + type: string + sysDept: + items: + $ref: '#/definitions/models.SysDept' + type: array + sysMenu: + items: + $ref: '#/definitions/models.SysMenu' + type: array + updateBy: + type: integer + type: object + dto.SysUserInsertReq: + properties: + avatar: + type: string + createBy: + type: integer + deptId: + type: integer + email: + type: string + nickName: + type: string + password: + type: string + phone: + type: string + postId: + type: integer + remark: + type: string + roleId: + type: integer + sex: + type: string + status: + default: "1" + type: string + updateBy: + type: integer + userId: + description: 用户ID + type: integer + username: + type: string + type: object + dto.SysUserUpdateReq: + properties: + avatar: + type: string + createBy: + type: integer + deptId: + type: integer + email: + type: string + nickName: + type: string + phone: + type: string + postId: + type: integer + remark: + type: string + roleId: + type: integer + sex: + type: string + status: + default: "1" + type: string + updateBy: + type: integer + userId: + description: 用户ID + type: integer + username: + type: string + type: object + dto.UpdateStatusReq: + properties: + createBy: + type: integer + roleId: + description: 角色编码 + type: integer + status: + description: 状态 + type: string + updateBy: + type: integer + type: object + dto.UpdateSysUserStatusReq: + properties: + createBy: + type: integer + status: + type: string + updateBy: + type: integer + userId: + description: 用户ID + type: integer + type: object + handler.Login: + properties: + code: + type: string + password: + type: string + username: + type: string + uuid: + type: string + required: + - code + - password + - username + - uuid + type: object + models.SysApi: + properties: + action: + type: string + createBy: + type: integer + createdAt: + type: string + handle: + type: string + id: + type: integer + path: + type: string + title: + type: string + type: + type: string + updateBy: + type: integer + updatedAt: + type: string + type: object + models.SysConfig: + properties: + configKey: + type: string + configName: + type: string + configType: + type: string + configValue: + type: string + createBy: + type: integer + createdAt: + type: string + id: + type: integer + isFrontend: + type: string + remark: + type: string + updateBy: + type: integer + updatedAt: + type: string + type: object + models.SysDept: + properties: + children: + items: + $ref: '#/definitions/models.SysDept' + type: array + createBy: + type: integer + createdAt: + type: string + dataScope: + type: string + deptId: + description: 部门编码 + type: integer + deptName: + description: 部门名称 + type: string + deptPath: + type: string + email: + description: 邮箱 + type: string + leader: + description: 负责人 + type: string + params: + type: string + parentId: + description: 上级部门 + type: integer + phone: + description: 手机 + type: string + sort: + description: 排序 + type: integer + status: + description: 状态 + type: integer + updateBy: + type: integer + updatedAt: + type: string + type: object + models.SysMenu: + properties: + action: + type: string + apis: + items: + type: integer + type: array + breadcrumb: + type: string + children: + items: + $ref: '#/definitions/models.SysMenu' + type: array + component: + type: string + createBy: + type: integer + createdAt: + type: string + dataScope: + type: string + icon: + type: string + is_select: + type: boolean + isFrame: + type: string + menuId: + type: integer + menuName: + type: string + menuType: + type: string + noCache: + type: boolean + params: + type: string + parentId: + type: integer + path: + type: string + paths: + type: string + permission: + type: string + roleId: + type: integer + sort: + type: integer + sysApi: + items: + $ref: '#/definitions/models.SysApi' + type: array + title: + type: string + updateBy: + type: integer + updatedAt: + type: string + visible: + type: string + type: object + response.Page: + properties: + count: + type: integer + pageIndex: + type: integer + pageSize: + type: integer + type: object + response.Response: + properties: + code: + type: integer + msg: + type: string + requestId: + description: 数据集 + type: string + status: + type: string + type: object + tools.Params: + properties: + treeCode: + type: string + treeName: + type: string + treeParentCode: + type: string + type: object + tools.SysColumns: + properties: + columnComment: + type: string + columnId: + type: integer + columnName: + type: string + columnType: + type: string + createBy: + type: integer + createdAt: + type: string + deletedAt: + type: string + dictType: + type: string + edit: + type: boolean + fkCol: + items: + $ref: '#/definitions/tools.SysColumns' + type: array + fkLabelId: + type: string + fkLabelName: + type: string + fkTableName: + type: string + fkTableNameClass: + type: string + fkTableNamePackage: + type: string + goField: + type: string + goType: + type: string + htmlType: + type: string + increment: + type: boolean + insert: + type: boolean + isEdit: + type: string + isIncrement: + type: string + isInsert: + type: string + isList: + type: string + isPk: + type: string + isQuery: + type: string + isRequired: + type: string + jsonField: + type: string + list: + type: string + pk: + type: boolean + query: + type: boolean + queryType: + type: string + remark: + type: string + required: + type: boolean + sort: + type: integer + superColumn: + type: boolean + tableId: + type: integer + updateBy: + type: integer + updatedAt: + type: string + usableColumn: + type: boolean + type: object + tools.SysTables: + properties: + businessName: + type: string + className: + description: 类名 + type: string + columns: + items: + $ref: '#/definitions/tools.SysColumns' + type: array + createBy: + type: integer + createdAt: + type: string + crud: + type: boolean + dataScope: + type: string + deletedAt: + type: string + functionAuthor: + description: 功能作者 + type: string + functionName: + description: 功能名称 + type: string + isActions: + type: integer + isAuth: + type: integer + isDataScope: + type: integer + isLogicalDelete: + type: string + logicalDelete: + type: boolean + logicalDeleteColumn: + type: string + moduleFrontName: + description: 前端文件名 + type: string + moduleName: + description: go文件名 + type: string + options: + type: string + packageName: + description: 包名 + type: string + params: + $ref: '#/definitions/tools.Params' + pkColumn: + type: string + pkGoField: + type: string + pkJsonField: + type: string + remark: + type: string + tableComment: + description: 表备注 + type: string + tableId: + description: 表编码 + type: integer + tableName: + description: 表名称 + type: string + tplCategory: + type: string + tree: + type: boolean + treeCode: + type: string + treeName: + type: string + treeParentCode: + type: string + updateBy: + type: integer + updatedAt: + type: string + type: object +info: + contact: {} + description: |- + 基于Gin + Vue + Element UI的前后端分离权限管理系统的接口文档 + 添加qq群: 521386980 进入技术交流群 请先star,谢谢! + license: + name: MIT + url: https://github.com/go-admin-team/go-admin/blob/master/LICENSE.md + title: go-admin API + version: 2.0.0 +paths: + /api/v1/app-config: + get: + description: 获取系统配置信息,主要注意这里不在验证权限 + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: + type: string + type: object + type: object + summary: 获取系统前台配置信息,主要注意这里不在验证权限 + tags: + - 配置管理 + /api/v1/captcha: + get: + description: 获取验证码 + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + type: string + id: + type: string + msg: + type: string + type: object + summary: 获取验证码 + tags: + - 登陆 + /api/v1/db/columns/page: + get: + description: 数据库表列分页列表 / database table column page list + parameters: + - description: tableName / 数据表名称 + in: query + name: tableName + type: string + - description: pageSize / 页条数 + in: query + name: pageSize + type: integer + - description: pageIndex / 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + summary: 分页列表数据 / page list data + tags: + - 工具 / 生成工具 + /api/v1/db/tables/page: + get: + description: 数据库表分页列表 / database table page list + parameters: + - description: tableName / 数据表名称 + in: query + name: tableName + type: string + - description: pageSize / 页条数 + in: query + name: pageSize + type: integer + - description: pageIndex / 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + summary: 分页列表数据 / page list data + tags: + - 工具 / 生成工具 + /api/v1/dept: + delete: + description: 删除数据 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysDeptDeleteReq' + responses: + "200": + description: '{"code": -1, "message": "删除失败"}' + schema: + type: string + security: + - Bearer: [] + summary: 删除部门 + tags: + - 部门 + get: + description: 分页列表 + parameters: + - description: deptName + in: query + name: deptName + type: string + - description: deptId + in: query + name: deptId + type: string + - description: position + in: query + name: position + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 分页部门列表数据 + tags: + - 部门 + post: + consumes: + - application/json + description: 获取JSON + parameters: + - description: data + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysDeptInsertReq' + responses: + "200": + description: '{"code": -1, "message": "添加失败"}' + schema: + type: string + security: + - Bearer: [] + summary: 添加部门 + tags: + - 部门 + /api/v1/dept/{deptId}: + get: + description: 获取JSON + parameters: + - description: deptId + in: path + name: deptId + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 获取部门数据 + tags: + - 部门 + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: id + in: path + name: id + required: true + type: integer + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysDeptUpdateReq' + responses: + "200": + description: '{"code": -1, "message": "添加失败"}' + schema: + type: string + security: + - Bearer: [] + summary: 修改部门 + tags: + - 部门 + /api/v1/dict-data/option-select: + get: + description: 数据字典根据key获取 + parameters: + - description: dictType + in: query + name: dictType + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + items: + $ref: '#/definitions/dto.SysDictDataGetAllResp' + type: array + type: object + security: + - Bearer: [] + summary: 数据字典根据key获取 + tags: + - 字典数据 + /api/v1/dict/data: + delete: + description: 删除数据 + parameters: + - description: body + in: body + name: dictCode + required: true + schema: + $ref: '#/definitions/dto.SysDictDataDeleteReq' + responses: + "200": + description: '{"code": 200, "message": "删除成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除字典数据 + tags: + - 字典数据 + get: + description: 获取JSON + parameters: + - description: status + in: query + name: status + type: string + - description: dictCode + in: query + name: dictCode + type: string + - description: dictType + in: query + name: dictType + type: string + - description: 页条数 + in: query + name: pageSize + type: integer + - description: 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 字典数据列表 + tags: + - 字典数据 + post: + consumes: + - application/json + description: 获取JSON + parameters: + - description: data + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysDictDataInsertReq' + responses: + "200": + description: '{"code": 200, "message": "添加成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 添加字典数据 + tags: + - 字典数据 + /api/v1/dict/data/{dictCode}: + get: + description: 获取JSON + parameters: + - description: 字典编码 + in: path + name: dictCode + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 通过编码获取字典数据 + tags: + - 字典数据 + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysDictDataUpdateReq' + responses: + "200": + description: '{"code": 200, "message": "修改成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改字典数据 + tags: + - 字典数据 + /api/v1/dict/type: + delete: + description: 删除数据 + parameters: + - description: body + in: body + name: dictCode + required: true + schema: + $ref: '#/definitions/dto.SysDictTypeDeleteReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除字典类型 + tags: + - 字典类型 + get: + description: 获取JSON + parameters: + - description: dictName + in: query + name: dictName + type: string + - description: dictId + in: query + name: dictId + type: string + - description: dictType + in: query + name: dictType + type: string + - description: 页条数 + in: query + name: pageSize + type: integer + - description: 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 字典类型列表数据 + tags: + - 字典类型 + post: + consumes: + - application/json + description: 获取JSON + parameters: + - description: data + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysDictTypeInsertReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 添加字典类型 + tags: + - 字典类型 + /api/v1/dict/type-option-select: + get: + description: 获取JSON + parameters: + - description: dictName + in: query + name: dictName + type: string + - description: dictId + in: query + name: dictId + type: string + - description: dictType + in: query + name: dictType + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 字典类型全部数据 代码生成使用接口 + tags: + - 字典类型 + /api/v1/dict/type/{dictId}: + get: + description: 获取JSON + parameters: + - description: 字典类型编码 + in: path + name: dictId + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 字典类型通过字典id获取 + tags: + - 字典类型 + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysDictTypeUpdateReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改字典类型 + tags: + - 字典类型 + /api/v1/getinfo: + get: + description: 获取JSON + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 获取个人信息 + tags: + - 个人中心 + /api/v1/login: + post: + consumes: + - application/json + description: |- + 获取token + LoginHandler can be used by clients to get a jwt token. + Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}. + Reply will be of the form {"token": "TOKEN"}. + dev mode:It should be noted that all fields cannot be empty, and a value of 0 can be passed in addition to the account password + 注意:开发模式:需要注意全部字段不能为空,账号密码外可以传入0值 + parameters: + - description: account + in: body + name: account + required: true + schema: + $ref: '#/definitions/handler.Login' + responses: + "200": + description: '{"code": 200, "expire": "2019-08-07T12:45:48+08:00", "token": + ".eyJleHAiOjE1NjUxNTMxNDgsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU2NTE0OTU0OH0.-zvzHvbg0A" + }' + schema: + type: string + summary: 登陆 + tags: + - 登陆 + /api/v1/menu: + delete: + description: 删除数据 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysMenuDeleteReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除菜单 + tags: + - 菜单 + get: + description: 获取JSON + parameters: + - description: menuName + in: query + name: menuName + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: Menu列表数据 + tags: + - 菜单 + post: + consumes: + - application/json + description: 获取JSON + parameters: + - description: data + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysMenuInsertReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 创建菜单 + tags: + - 菜单 + /api/v1/menu/{id}: + get: + description: 获取JSON + parameters: + - description: id + in: path + name: id + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: Menu详情数据 + tags: + - 菜单 + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: id + in: path + name: id + required: true + type: integer + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysMenuUpdateReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改菜单 + tags: + - 菜单 + /api/v1/menuTreeselect/{roleId}: + get: + consumes: + - application/json + description: 获取JSON + parameters: + - description: roleId + in: path + name: roleId + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 角色修改使用的菜单列表 + tags: + - 菜单 + /api/v1/menurole: + get: + description: 获取JSON + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 根据登录角色名称获取菜单列表数据(左菜单使用) + tags: + - 菜单 + /api/v1/post: + delete: + description: 删除数据 + parameters: + - description: 请求参数 + in: body + name: id + required: true + schema: + $ref: '#/definitions/dto.SysPostDeleteReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除岗位 + tags: + - 岗位 + get: + description: 获取JSON + parameters: + - description: postName + in: query + name: postName + type: string + - description: postCode + in: query + name: postCode + type: string + - description: postId + in: query + name: postId + type: string + - description: status + in: query + name: status + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 岗位列表数据 + tags: + - 岗位 + post: + consumes: + - application/json + description: 获取JSON + parameters: + - description: data + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysPostInsertReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 添加岗位 + tags: + - 岗位 + /api/v1/post/{id}: + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysPostUpdateReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改岗位 + tags: + - 岗位 + /api/v1/post/{postId}: + get: + description: 获取JSON + parameters: + - description: 编码 + in: path + name: id + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 获取岗位信息 + tags: + - 岗位 + /api/v1/public/uploadFile: + post: + consumes: + - multipart/form-data + description: 获取JSON + parameters: + - description: type + in: query + name: type + required: true + type: string + - description: file + in: formData + name: file + required: true + type: file + responses: + "200": + description: '{"code": -1, "message": "添加失败"}' + schema: + type: string + security: + - Bearer: [] + summary: 上传图片 + tags: + - 公共接口 + /api/v1/role: + delete: + description: 删除数据 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysRoleDeleteReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除用户角色 + tags: + - 角色/Role + get: + description: Get JSON + parameters: + - description: roleName + in: query + name: roleName + type: string + - description: status + in: query + name: status + type: string + - description: roleKey + in: query + name: roleKey + type: string + - description: 页条数 + in: query + name: pageSize + type: integer + - description: 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 角色列表数据 + tags: + - 角色/Role + post: + consumes: + - application/json + description: 获取JSON + parameters: + - description: data + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysRoleInsertReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 创建角色 + tags: + - 角色/Role + /api/v1/role-status/{id}: + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.RoleDataScopeReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 更新角色数据权限 + tags: + - 角色/Role + /api/v1/role/{id}: + get: + description: 获取JSON + parameters: + - description: roleId + in: path + name: roleId + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 获取Role数据 + tags: + - 角色/Role + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysRoleUpdateReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改用户角色 + tags: + - 角色/Role + /api/v1/server-monitor: + get: + description: 获取JSON + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 系统信息 + tags: + - 系统信息 + /api/v1/set-config: + get: + consumes: + - application/json + description: 界面操作设置配置值的获取 + responses: + "200": + description: '{"code": 200, "message": "修改成功"}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + type: object + security: + - Bearer: [] + summary: 获取配置 + tags: + - 配置管理 + put: + consumes: + - application/json + description: 界面操作设置配置值 + parameters: + - description: body + in: body + name: data + required: true + schema: + items: + $ref: '#/definitions/dto.GetSetSysConfigReq' + type: array + responses: + "200": + description: '{"code": 200, "message": "修改成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 设置配置 + tags: + - 配置管理 + /api/v1/sys-api: + delete: + description: 删除接口管理 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysApiDeleteReq' + responses: + "200": + description: '{"code": 200, "message": "删除成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除接口管理 + tags: + - 接口管理 + get: + description: 获取接口管理列表 + parameters: + - description: 名称 + in: query + name: name + type: string + - description: 标题 + in: query + name: title + type: string + - description: 地址 + in: query + name: path + type: string + - description: 类型 + in: query + name: action + type: string + - description: 页条数 + in: query + name: pageSize + type: integer + - description: 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + allOf: + - $ref: '#/definitions/response.Page' + - properties: + list: + items: + $ref: '#/definitions/models.SysApi' + type: array + type: object + type: object + security: + - Bearer: [] + summary: 获取接口管理列表 + tags: + - 接口管理 + /api/v1/sys-api/{id}: + get: + description: 获取接口管理 + parameters: + - description: id + in: path + name: id + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/models.SysApi' + type: object + security: + - Bearer: [] + summary: 获取接口管理 + tags: + - 接口管理 + put: + consumes: + - application/json + description: 修改接口管理 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysApiUpdateReq' + responses: + "200": + description: '{"code": 200, "message": "修改成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改接口管理 + tags: + - 接口管理 + /api/v1/sys-config: + delete: + description: 删除配置管理 + parameters: + - description: ids + in: body + name: ids + schema: + items: + type: integer + type: array + responses: + "200": + description: '{"code": 200, "message": "删除成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除配置管理 + tags: + - 配置管理 + get: + description: 获取配置管理列表 + parameters: + - description: 名称 + in: query + name: configName + type: string + - description: key + in: query + name: configKey + type: string + - description: 类型 + in: query + name: configType + type: string + - description: 是否前端 + in: query + name: isFrontend + type: integer + - description: 页条数 + in: query + name: pageSize + type: integer + - description: 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + allOf: + - $ref: '#/definitions/response.Page' + - properties: + list: + items: + $ref: '#/definitions/models.SysApi' + type: array + type: object + type: object + security: + - Bearer: [] + summary: 获取配置管理列表 + tags: + - 配置管理 + post: + consumes: + - application/json + description: 创建配置管理 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysConfigControl' + responses: + "200": + description: '{"code": 200, "message": "创建成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 创建配置管理 + tags: + - 配置管理 + /api/v1/sys-config/{id}: + get: + description: 根据Key获取SysConfig的Service + parameters: + - description: configKey + in: path + name: configKey + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/dto.SysConfigByKeyReq' + type: object + security: + - Bearer: [] + summary: 根据Key获取SysConfig的Service + tags: + - 配置管理 + put: + consumes: + - application/json + description: 修改配置管理 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysConfigControl' + responses: + "200": + description: '{"code": 200, "message": "修改成功"}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改配置管理 + tags: + - 配置管理 + /api/v1/sys-login-log: + delete: + description: 登录日志删除 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysLoginLogDeleteReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 登录日志删除 + tags: + - 登录日志 + get: + description: 获取JSON + parameters: + - description: 用户名 + in: query + name: username + type: string + - description: ip地址 + in: query + name: ipaddr + type: string + - description: 归属地 + in: query + name: loginLocation + type: string + - description: 状态 + in: query + name: status + type: string + - description: 开始时间 + in: query + name: beginTime + type: string + - description: 结束时间 + in: query + name: endTime + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 登录日志列表 + tags: + - 登录日志 + /api/v1/sys-login-log/{id}: + get: + description: 获取JSON + parameters: + - description: id + in: path + name: id + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 登录日志通过id获取 + tags: + - 登录日志 + /api/v1/sys-opera-log: + delete: + description: 删除数据 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysOperaLogDeleteReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除操作日志 + tags: + - 操作日志 + get: + description: 获取JSON + parameters: + - description: title + in: query + name: title + type: string + - description: method + in: query + name: method + type: string + - description: requestMethod + in: query + name: requestMethod + type: string + - description: operUrl + in: query + name: operUrl + type: string + - description: operIp + in: query + name: operIp + type: string + - description: status + in: query + name: status + type: string + - description: beginTime + in: query + name: beginTime + type: string + - description: endTime + in: query + name: endTime + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 操作日志列表 + tags: + - 操作日志 + /api/v1/sys-opera-log/{id}: + get: + description: 获取JSON + parameters: + - description: id + in: path + name: id + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 操作日志通过id获取 + tags: + - 操作日志 + /api/v1/sys-user: + get: + description: 获取JSON + parameters: + - description: username + in: query + name: username + type: string + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + type: string + security: + - Bearer: [] + summary: 列表用户信息数据 + tags: + - 用户 + post: + consumes: + - application/json + description: 获取JSON + parameters: + - description: 用户数据 + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysUserInsertReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 创建用户 + tags: + - 用户 + /api/v1/sys-user/{userId}: + delete: + description: 删除数据 + parameters: + - description: userId + in: path + name: userId + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 删除用户数据 + tags: + - 用户 + get: + description: 获取JSON + parameters: + - description: 用户编码 + in: path + name: userId + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 获取用户 + tags: + - 用户 + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.SysUserUpdateReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改用户数据 + tags: + - 用户 + /api/v1/sys/tables/info: + post: + consumes: + - application/json + description: 添加表结构 + parameters: + - description: tableName / 数据表名称 + in: query + name: tables + type: string + responses: + "200": + description: '{"code": -1, "message": "添加失败"}' + schema: + type: string + security: + - Bearer: [] + summary: 添加表结构 + tags: + - 工具 / 生成工具 + put: + consumes: + - application/json + description: 修改表结构 + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/tools.SysTables' + responses: + "200": + description: '{"code": -1, "message": "添加失败"}' + schema: + type: string + security: + - Bearer: [] + summary: 修改表结构 + tags: + - 工具 / 生成工具 + /api/v1/sys/tables/info/{tableId}: + delete: + description: 删除表结构 + parameters: + - description: tableId + in: path + name: tableId + required: true + type: integer + responses: + "200": + description: '{"code": -1, "message": "删除失败"}' + schema: + type: string + summary: 删除表结构 + tags: + - 工具 / 生成工具 + get: + description: 获取JSON + parameters: + - description: configKey + in: path + name: configKey + required: true + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 获取配置 + tags: + - 工具 / 生成工具 + /api/v1/sys/tables/page: + get: + description: 生成表分页列表 + parameters: + - description: tableName / 数据表名称 + in: query + name: tableName + type: string + - description: pageSize / 页条数 + in: query + name: pageSize + type: integer + - description: pageIndex / 页码 + in: query + name: pageIndex + type: integer + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + summary: 分页列表数据 + tags: + - 工具 / 生成工具 + /api/v1/user/avatar: + post: + consumes: + - multipart/form-data + description: 获取JSON + parameters: + - description: file + in: formData + name: file + required: true + type: file + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改头像 + tags: + - 个人中心 + /api/v1/user/profile: + get: + description: 获取JSON + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 获取个人中心用户 + tags: + - 个人中心 + /api/v1/user/pwd/reset: + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.ResetSysUserPwdReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 重置用户密码 + tags: + - 用户 + /api/v1/user/pwd/set: + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.PassWord' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改密码 + tags: + - 用户 + /api/v1/user/status: + put: + consumes: + - application/json + description: 获取JSON + parameters: + - description: body + in: body + name: data + required: true + schema: + $ref: '#/definitions/dto.UpdateSysUserStatusReq' + responses: + "200": + description: '{"code": 200, "data": [...]}' + schema: + $ref: '#/definitions/response.Response' + security: + - Bearer: [] + summary: 修改用户状态 + tags: + - 用户 + /logout: + post: + consumes: + - application/json + description: 获取token + responses: + "200": + description: '{"code": 200, "msg": "成功退出系统" }' + schema: + type: string + security: + - Bearer: [] + summary: 退出登录 +securityDefinitions: + Bearer: + in: header + name: Authorization + type: apiKey +swagger: "2.0" diff --git a/examples/run.go b/examples/run.go new file mode 100644 index 0000000..2bb61e2 --- /dev/null +++ b/examples/run.go @@ -0,0 +1,28 @@ +// +build examples + +package main + +import ( + "github.com/go-admin-team/go-admin-core/sdk" + "log" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" + + myCasbin "github.com/go-admin-team/go-admin-core/sdk/pkg/casbin" + "gorm.io/driver/mysql" +) + +func main() { + db, err := gorm.Open(mysql.Open("root:123456@tcp/inmg?charset=utf8&parseTime=True&loc=Local"), &gorm.Config{}) + if err != nil { + panic(err) + } + syncEnforce := myCasbin.Setup(db, "sys_") + sdk.Runtime.SetDb("*", db) + sdk.Runtime.SetCasbin("*", syncEnforce) + + e := gin.Default() + sdk.Runtime.SetEngine(e) + log.Fatal(e.Run(":8000")) +} diff --git a/go-admin-db.db b/go-admin-db.db new file mode 100644 index 0000000..fe73e03 Binary files /dev/null and b/go-admin-db.db differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7bd32cc --- /dev/null +++ b/go.mod @@ -0,0 +1,161 @@ +module go-admin + +go 1.18 + +require ( + github.com/alibaba/sentinel-golang v1.0.4 + github.com/alibaba/sentinel-golang/pkg/adapters/gin v0.0.0-20220808015021-c5f1f1d055c5 + github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5 + github.com/bitly/go-simplejson v0.5.0 + github.com/bytedance/go-tagexpr/v2 v2.7.12 + github.com/casbin/casbin/v2 v2.51.2 + github.com/gin-gonic/gin v1.9.1 + github.com/go-admin-team/go-admin-core v1.4.1-0.20220809101213-21187928f7d9 + github.com/go-admin-team/go-admin-core/sdk v1.4.1-0.20220809101213-21187928f7d9 + github.com/google/uuid v1.3.0 + github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible + github.com/mssola/user_agent v0.5.2 + github.com/opentracing/opentracing-go v1.1.0 + github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.11.1 + github.com/qiniu/go-sdk/v7 v7.11.1 + github.com/robfig/cron/v3 v3.0.1 + github.com/shirou/gopsutil/v3 v3.22.1 + github.com/spf13/cobra v1.0.0 + github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a + github.com/swaggo/gin-swagger v1.5.0 + github.com/swaggo/swag v1.8.3 + github.com/unrolled/secure v1.0.8 + golang.org/x/crypto v0.9.0 + gorm.io/driver/mysql v1.3.5 + gorm.io/driver/postgres v1.3.8 + gorm.io/driver/sqlite v1.3.6 + gorm.io/driver/sqlserver v1.3.2 + gorm.io/gorm v1.23.8 +) + +require ( + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bsm/redislock v0.5.0 // indirect + github.com/bytedance/sonic v1.13.3 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/casbin/redis-watcher/v2 v2.0.0-20220614104201-0e70bf2be930 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // indirect + github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/denisenkom/go-mssqldb v0.12.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fatih/color v1.9.0 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/git-chglog/git-chglog v0.0.0-20190611050339-63a4e637021f // indirect + github.com/go-admin-team/go-admin-core/plugins/logger/zap v0.0.0-20210610020726-2db73adb505d // indirect + github.com/go-admin-team/gorm-adapter/v3 v3.7.8-0.20220809100335-eaf9f67b3d21 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-redis/redis/v7 v7.4.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt/v4 v4.4.2 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/protobuf v1.5.0 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/henrylee2cn/ameda v1.4.10 // indirect + github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect + github.com/imdario/mergo v0.3.9 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.12.1 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect + github.com/jackc/pgtype v1.11.0 // indirect + github.com/jackc/pgx/v4 v4.16.1 // indirect + github.com/jinzhu/copier v0.4.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-colorable v0.1.7 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-sqlite3 v1.14.12 // indirect + github.com/mattn/goveralls v0.0.2 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mojocn/base64Captcha v1.3.1 // indirect + github.com/nsqio/go-nsq v1.0.8 // indirect + github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.26.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect + github.com/rabbitmq/amqp091-go v1.10.0 // indirect + github.com/robinjoseph08/redisqueue/v2 v2.1.0 // indirect + github.com/rs/xid v1.6.0 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shamsher31/goimgext v1.0.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/pflag v1.0.3 // indirect + github.com/tklauser/go-sysconf v0.3.9 // indirect + github.com/tklauser/numcpus v0.3.0 // indirect + github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/urfave/cli v1.22.1 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect + go.uber.org/atomic v1.6.0 // indirect + go.uber.org/multierr v1.5.0 // indirect + go.uber.org/zap v1.15.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/image v0.1.0 // indirect + golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect + golang.org/x/tools v0.6.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/AlecAivazis/survey.v1 v1.8.5 // indirect + gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/plugin/dbresolver v1.2.2 // indirect +) + +//replace ( +// github.com/go-admin-team/go-admin-core v1.4.0 => ../../go-admin-core +// github.com/go-admin-team/go-admin-core/sdk v1.4.0 => ../../go-admin-core/sdk +//) diff --git a/main.go b/main.go new file mode 100644 index 0000000..e25407e --- /dev/null +++ b/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "go-admin/cmd" +) + +//go:generate swag init --parseDependency --parseDepth=6 --instanceName admin -o ./docs/admin + +// @title go-admin API +// @version 2.0.0 +// @description 基于Gin + Vue + Element UI的前后端分离权限管理系统的接口文档 +// @description 添加qq群: 521386980 进入技术交流群 请先star,谢谢! +// @license.name MIT +// @license.url https://github.com/go-admin-team/go-admin/blob/master/LICENSE.md + +// @securityDefinitions.apikey Bearer +// @in header +// @name Authorization +func main() { + cmd.Execute() +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..48e341a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/restart.sh b/restart.sh new file mode 100644 index 0000000..ef8c4c1 --- /dev/null +++ b/restart.sh @@ -0,0 +1,10 @@ +#!/bin/bash +echo "go build" +go mod tidy +go build -o go-admin main.go +chmod +x ./go-admin +echo "kill go-admin service" +killall go-admin # kill go-admin service +nohup ./go-admin server -c=config/settings.dev.yml >> access.log 2>&1 & #后台启动服务将日志写入access.log文件 +echo "run go-admin success" +ps -aux | grep go-admin diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 0000000..01bdeb8 --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,6 @@ +FROM alpine + +COPY ./go-admin / +EXPOSE 8000 + +CMD ["/go-admin","server","-c", "/config/settings.yml"] diff --git a/scripts/k8s/deploy.yml b/scripts/k8s/deploy.yml new file mode 100644 index 0000000..4479227 --- /dev/null +++ b/scripts/k8s/deploy.yml @@ -0,0 +1,57 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: go-admin + labels: + app: go-admin + service: go-admin +spec: + ports: + - port: 8000 + name: http + protocol: TCP + selector: + app: go-admin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: go-admin-v1 + labels: + app: go-admin + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: go-admin + version: v1 + template: + metadata: + labels: + app: go-admin + version: v1 + spec: + containers: + - name: go-admin + image: registry.cn-shanghai.aliyuncs.com/go-admin-team/go-admin + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8000 + volumeMounts: + - name: go-admin + mountPath: /temp + - name: go-admin + mountPath: /static + - name: go-admin-config + mountPath: /config/ + readOnly: true + volumes: + - name: go-admin + persistentVolumeClaim: + claimName: go-admin + - name: go-admin-config + configMap: + name: settings-admin +--- diff --git a/scripts/k8s/prerun.sh b/scripts/k8s/prerun.sh new file mode 100644 index 0000000..f7bb046 --- /dev/null +++ b/scripts/k8s/prerun.sh @@ -0,0 +1,3 @@ +#!/bin/bash +kubectl create ns go-admin +kubectl create configmap settings-admin --from-file=../../config/settings.yml -n go-admin diff --git a/scripts/k8s/storage.yml b/scripts/k8s/storage.yml new file mode 100644 index 0000000..2866a90 --- /dev/null +++ b/scripts/k8s/storage.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: go-admin + namespace: go-admin +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: "1Mi" + volumeName: + storageClassName: nfs-csi \ No newline at end of file diff --git a/ssh/swag.sh b/ssh/swag.sh new file mode 100644 index 0000000..48139df --- /dev/null +++ b/ssh/swag.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +swag i -g init_router.go -dir app/admin/router --instanceName admin --parseDependency -o docs/admin diff --git a/static/form-generator/css/index.1a124643.css b/static/form-generator/css/index.1a124643.css new file mode 100644 index 0000000..0aa38db --- /dev/null +++ b/static/form-generator/css/index.1a124643.css @@ -0,0 +1 @@ +.add-item[data-v-60dcec16]{margin-top:8px}.url-item[data-v-60dcec16]{margin-bottom:12px}.tab-editor[data-v-3157a144]{position:absolute;top:33px;bottom:0;left:0;right:0;font-size:14px}.left-editor[data-v-3157a144]{position:relative;height:100%;background:#1e1e1e;overflow:hidden}.setting[data-v-3157a144]{position:absolute;right:15px;top:3px;color:#a9f122;font-size:18px;cursor:pointer;z-index:1}.right-preview[data-v-3157a144]{height:100%}.right-preview .result-wrapper[data-v-3157a144]{height:calc(100vh - 33px);width:100%;overflow:auto;padding:12px;-webkit-box-sizing:border-box;box-sizing:border-box}.action-bar[data-v-3157a144]{height:33px;background:#f2fafb;padding:0 15px;-webkit-box-sizing:border-box;box-sizing:border-box}.action-bar .bar-btn[data-v-3157a144]{display:inline-block;padding:0 6px;line-height:32px;color:#8285f5;cursor:pointer;font-size:14px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.action-bar .bar-btn i[data-v-3157a144]{font-size:20px}.action-bar .bar-btn[data-v-3157a144]:hover{color:#4348d4}.action-bar .bar-btn+.bar-btn[data-v-3157a144]{margin-left:8px}.action-bar .delete-btn[data-v-3157a144]{color:#f56c6c}.action-bar .delete-btn[data-v-3157a144]:hover{color:#ea0b30}[data-v-3157a144] .el-drawer__header,[data-v-44793736] .el-drawer__header{display:none}.action-bar[data-v-44793736]{height:33px;background:#f2fafb;padding:0 15px;-webkit-box-sizing:border-box;box-sizing:border-box}.action-bar .bar-btn[data-v-44793736]{display:inline-block;padding:0 6px;line-height:32px;color:#8285f5;cursor:pointer;font-size:14px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.action-bar .bar-btn i[data-v-44793736]{font-size:20px}.action-bar .bar-btn[data-v-44793736]:hover{color:#4348d4}.action-bar .bar-btn+.bar-btn[data-v-44793736]{margin-left:8px}.action-bar .delete-btn[data-v-44793736]{color:#f56c6c}.action-bar .delete-btn[data-v-44793736]:hover{color:#ea0b30}.json-editor[data-v-44793736]{height:calc(100vh - 33px)}.icon-ul[data-v-3ba3d51c]{margin:0;padding:0;font-size:0}.icon-ul li[data-v-3ba3d51c]{list-style-type:none;text-align:center;font-size:14px;display:inline-block;width:16.66%;-webkit-box-sizing:border-box;box-sizing:border-box;height:108px;padding:15px 6px 6px 6px;cursor:pointer;overflow:hidden}.icon-ul li[data-v-3ba3d51c]:hover{background:#f2f2f2}.icon-ul li.active-item[data-v-3ba3d51c]{background:#e1f3fb;color:#7a6df0}.icon-ul li>i[data-v-3ba3d51c]{font-size:30px;line-height:50px}.icon-dialog[data-v-3ba3d51c] .el-dialog{border-radius:8px;margin-bottom:0;margin-top:4vh!important;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;max-height:92vh;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}.icon-dialog[data-v-3ba3d51c] .el-dialog .el-dialog__header{padding-top:14px}.icon-dialog[data-v-3ba3d51c] .el-dialog .el-dialog__body{margin:0 20px 20px 20px;padding:0;overflow:auto}.right-board[data-v-0c0004cd]{width:350px;position:absolute;right:0;top:0;padding-top:3px}.right-board .field-box[data-v-0c0004cd]{position:relative;height:calc(100vh - 42px);-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden}.right-board .el-scrollbar[data-v-0c0004cd]{height:100%}.select-item[data-v-0c0004cd]{display:-webkit-box;display:-ms-flexbox;display:flex;border:1px dashed #fff;-webkit-box-sizing:border-box;box-sizing:border-box}.select-item .close-btn[data-v-0c0004cd]{cursor:pointer;color:#f56c6c}.select-item .el-input+.el-input[data-v-0c0004cd]{margin-left:4px}.select-item+.select-item[data-v-0c0004cd]{margin-top:4px}.select-item.sortable-chosen[data-v-0c0004cd]{border:1px dashed #409eff}.select-line-icon[data-v-0c0004cd]{line-height:32px;font-size:22px;padding:0 4px;color:#777}.option-drag[data-v-0c0004cd]{cursor:move}.time-range .el-date-editor[data-v-0c0004cd]{width:227px}.time-range[data-v-0c0004cd] .el-icon-time{display:none}.document-link[data-v-0c0004cd]{position:absolute;display:block;width:26px;height:26px;top:0;left:0;cursor:pointer;background:#409eff;z-index:1;border-radius:0 0 6px 0;text-align:center;line-height:26px;color:#fff;font-size:18px}.node-label[data-v-0c0004cd]{font-size:14px}.node-icon[data-v-0c0004cd]{color:#bebfc3}.container{position:relative;width:100%;height:100%}.components-list{padding:8px;-webkit-box-sizing:border-box;box-sizing:border-box;height:100%}.components-list .components-item{display:inline-block;width:48%;margin:1%;-webkit-transition:-webkit-transform 0ms!important;transition:-webkit-transform 0ms!important;transition:transform 0ms!important;transition:transform 0ms,-webkit-transform 0ms!important}.components-draggable{padding-bottom:20px}.components-title{font-size:14px;color:#222;margin:6px 2px}.components-title .svg-icon{color:#666;font-size:18px}.components-body{padding:8px 10px;background:#f6f7ff;font-size:12px;cursor:move;border:1px dashed #f6f7ff;border-radius:3px}.components-body .svg-icon{color:#777;font-size:15px}.components-body:hover{border:1px dashed #787be8;color:#787be8}.components-body:hover .svg-icon{color:#787be8}.left-board{width:260px;position:absolute;left:0;top:0;height:100vh}.center-scrollbar,.left-scrollbar{height:calc(100vh - 42px);overflow:hidden}.center-scrollbar{border-left:1px solid #f1e8e8;border-right:1px solid #f1e8e8}.center-board,.center-scrollbar{-webkit-box-sizing:border-box;box-sizing:border-box}.center-board{height:100vh;width:auto;margin:0 350px 0 260px}.empty-info{position:absolute;top:46%;left:0;right:0;text-align:center;font-size:18px;color:#ccb1ea;letter-spacing:4px}.action-bar{position:relative;height:42px;text-align:right;padding:0 15px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #f1e8e8;border-top:none;border-left:none}.action-bar .delete-btn{color:#f56c6c}.logo-wrapper{position:relative;height:42px;background:#fff;border-bottom:1px solid #f1e8e8;-webkit-box-sizing:border-box;box-sizing:border-box}.logo{position:absolute;left:12px;top:6px;line-height:30px;color:#00afff;font-weight:600;font-size:17px;white-space:nowrap}.logo>img{width:30px;height:30px;vertical-align:top}.logo .github{display:inline-block;vertical-align:sub;margin-left:15px}.logo .github>img{height:22px}.center-board-row{padding:12px 12px 15px 12px;-webkit-box-sizing:border-box;box-sizing:border-box}.center-board-row>.el-form{height:calc(100vh - 69px)}.drawing-board{height:100%;position:relative}.drawing-board .components-body{padding:0;margin:0;font-size:0}.drawing-board .sortable-ghost{position:relative;display:block;overflow:hidden}.drawing-board .sortable-ghost:before{content:" ";position:absolute;left:0;right:0;top:0;height:3px;background:#5959df;z-index:2}.drawing-board .components-item.sortable-ghost{width:100%;height:60px;background-color:#f6f7ff}.drawing-board .active-from-item>.el-form-item{background:#f6f7ff;border-radius:6px}.drawing-board .active-from-item>.drawing-item-copy,.drawing-board .active-from-item>.drawing-item-delete{display:initial}.drawing-board .active-from-item>.component-name{color:#409eff}.drawing-board .el-form-item{margin-bottom:15px}.drawing-item{position:relative;cursor:move}.drawing-item.unfocus-bordered:not(.active-from-item)>div:first-child{border:1px dashed #ccc}.drawing-item .el-form-item{padding:12px 10px}.drawing-row-item{position:relative;cursor:move;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px dashed #ccc;border-radius:3px;padding:0 2px;margin-bottom:15px}.drawing-row-item .drawing-row-item{margin-bottom:2px}.drawing-row-item .el-col{margin-top:22px}.drawing-row-item .el-form-item{margin-bottom:0}.drawing-row-item .drag-wrapper{min-height:80px}.drawing-row-item.active-from-item{border:1px dashed #409eff}.drawing-row-item .component-name{position:absolute;top:0;left:0;font-size:12px;color:#bbb;display:inline-block;padding:0 6px}.drawing-item:hover>.el-form-item,.drawing-row-item:hover>.el-form-item{background:#f6f7ff;border-radius:6px}.drawing-item:hover>.drawing-item-copy,.drawing-item:hover>.drawing-item-delete,.drawing-row-item:hover>.drawing-item-copy,.drawing-row-item:hover>.drawing-item-delete{display:initial}.drawing-item>.drawing-item-copy,.drawing-item>.drawing-item-delete,.drawing-row-item>.drawing-item-copy,.drawing-row-item>.drawing-item-delete{display:none;position:absolute;top:-10px;width:22px;height:22px;line-height:22px;text-align:center;border-radius:50%;font-size:12px;border:1px solid;cursor:pointer;z-index:1}.drawing-item>.drawing-item-copy,.drawing-row-item>.drawing-item-copy{right:56px;border-color:#409eff;color:#409eff;background:#fff}.drawing-item>.drawing-item-copy:hover,.drawing-row-item>.drawing-item-copy:hover{background:#409eff;color:#fff}.drawing-item>.drawing-item-delete,.drawing-row-item>.drawing-item-delete{right:24px;border-color:#f56c6c;color:#f56c6c;background:#fff}.drawing-item>.drawing-item-delete:hover,.drawing-row-item>.drawing-item-delete:hover{background:#f56c6c;color:#fff}body,html{margin:0;padding:0;background:#fff;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}body,html,input,textarea{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji}.editor-tabs{background:#121315}.editor-tabs .el-tabs__header{margin:0;border-bottom-color:#121315}.editor-tabs .el-tabs__header .el-tabs__nav{border-color:#121315}.editor-tabs .el-tabs__item{height:32px;line-height:32px;color:#888a8e;border-left:1px solid #121315!important;background:#363636;margin-right:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.editor-tabs .el-tabs__item.is-active{background:#1e1e1e;border-bottom-color:#1e1e1e!important;color:#fff}.editor-tabs .el-icon-edit{color:#f1fa8c}.editor-tabs .el-icon-document{color:#a95812}.right-scrollbar .el-scrollbar__view{padding:12px 18px 15px 15px}.el-scrollbar__wrap{-webkit-box-sizing:border-box;box-sizing:border-box;overflow-x:hidden!important}.center-tabs .el-tabs__header,.el-scrollbar__wrap{margin-bottom:0!important}.center-tabs .el-tabs__item{width:50%;text-align:center}.center-tabs .el-tabs__nav{width:100%}.reg-item{padding:12px 6px;background:#f8f8f8;position:relative;border-radius:4px}.reg-item .close-btn{position:absolute;right:-6px;top:-6px;display:block;width:16px;height:16px;line-height:16px;background:rgba(0,0,0,.2);border-radius:50%;color:#fff;text-align:center;z-index:1;cursor:pointer;font-size:12px}.reg-item .close-btn:hover{background:rgba(210,23,23,.5)}.reg-item+.reg-item{margin-top:18px}.action-bar .el-button+.el-button{margin-left:15px}.action-bar i{font-size:20px;vertical-align:middle;position:relative;top:-1px}.custom-tree-node{width:100%;font-size:14px}.custom-tree-node .node-operation{float:right}.custom-tree-node i[class*=el-icon]+i[class*=el-icon]{margin-left:6px}.custom-tree-node .el-icon-plus{color:#409eff}.custom-tree-node .el-icon-delete{color:#157a0c}.el-scrollbar__view{overflow-x:hidden}.el-rate{display:inline-block;vertical-align:text-top}.el-upload__tip{line-height:1.2}.svg-icon[data-v-19957a58]{width:1em;height:1em;vertical-align:-.15em;fill:currentColor;overflow:hidden}.svg-external-icon[data-v-19957a58]{background-color:currentColor;-webkit-mask-size:cover!important;mask-size:cover!important;display:inline-block} \ No newline at end of file diff --git a/static/form-generator/css/parser-example.69e16e51.css b/static/form-generator/css/parser-example.69e16e51.css new file mode 100644 index 0000000..09cac88 --- /dev/null +++ b/static/form-generator/css/parser-example.69e16e51.css @@ -0,0 +1 @@ +.test-form[data-v-77b1aafa]{margin:15px auto;width:800px;padding:15px} \ No newline at end of file diff --git a/static/form-generator/img/logo.e1bc3747.png b/static/form-generator/img/logo.e1bc3747.png new file mode 100644 index 0000000..9838306 Binary files /dev/null and b/static/form-generator/img/logo.e1bc3747.png differ diff --git a/static/form-generator/index.html b/static/form-generator/index.html new file mode 100644 index 0000000..b888095 --- /dev/null +++ b/static/form-generator/index.html @@ -0,0 +1 @@ +form-generator
\ No newline at end of file diff --git a/static/form-generator/js/chunk-vendors.971555db.js b/static/form-generator/js/chunk-vendors.971555db.js new file mode 100644 index 0000000..762db7c --- /dev/null +++ b/static/form-generator/js/chunk-vendors.971555db.js @@ -0,0 +1,19 @@ +(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-vendors"],{"00ee":function(t,e,s){var i=s("b622"),r=i("toStringTag"),n={};n[r]="z",t.exports="[object z]"===String(n)},"0366":function(t,e,s){var i=s("1c0b");t.exports=function(t,e,s){if(i(t),void 0===e)return t;switch(s){case 0:return function(){return t.call(e)};case 1:return function(s){return t.call(e,s)};case 2:return function(s,i){return t.call(e,s,i)};case 3:return function(s,i,r){return t.call(e,s,i,r)}}return function(){return t.apply(e,arguments)}}},"057f":function(t,e,s){var i=s("fc6a"),r=s("241c").f,n={}.toString,a="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],o=function(t){try{return r(t)}catch(e){return a.slice()}};t.exports.f=function(t){return a&&"[object Window]"==n.call(t)?o(t):r(i(t))}},"06cf":function(t,e,s){var i=s("83ab"),r=s("d1e7"),n=s("5c6c"),a=s("fc6a"),o=s("c04e"),c=s("5135"),h=s("0cfb"),l=Object.getOwnPropertyDescriptor;e.f=i?l:function(t,e){if(t=a(t),e=o(e,!0),h)try{return l(t,e)}catch(s){}if(c(t,e))return n(!r.f.call(t,e),t[e])}},"0cfb":function(t,e,s){var i=s("83ab"),r=s("d039"),n=s("cc12");t.exports=!i&&!r((function(){return 7!=Object.defineProperty(n("div"),"a",{get:function(){return 7}}).a}))},1276:function(t,e,s){"use strict";var i=s("d784"),r=s("44e7"),n=s("825a"),a=s("1d80"),o=s("4840"),c=s("8aa5"),h=s("50c4"),l=s("14c3"),p=s("9263"),u=s("d039"),d=[].push,f=Math.min,m=4294967295,y=!u((function(){return!RegExp(m,"y")}));i("split",2,(function(t,e,s){var i;return i="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,s){var i=String(a(this)),n=void 0===s?m:s>>>0;if(0===n)return[];if(void 0===t)return[i];if(!r(t))return e.call(i,t,n);var o,c,h,l=[],u=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),f=0,y=new RegExp(t.source,u+"g");while(o=p.call(y,i)){if(c=y.lastIndex,c>f&&(l.push(i.slice(f,o.index)),o.length>1&&o.index=n))break;y.lastIndex===o.index&&y.lastIndex++}return f===i.length?!h&&y.test("")||l.push(""):l.push(i.slice(f)),l.length>n?l.slice(0,n):l}:"0".split(void 0,0).length?function(t,s){return void 0===t&&0===s?[]:e.call(this,t,s)}:e,[function(e,s){var r=a(this),n=void 0==e?void 0:e[t];return void 0!==n?n.call(e,r,s):i.call(String(r),e,s)},function(t,r){var a=s(i,t,this,r,i!==e);if(a.done)return a.value;var p=n(t),u=String(this),d=o(p,RegExp),g=p.unicode,x=(p.ignoreCase?"i":"")+(p.multiline?"m":"")+(p.unicode?"u":"")+(y?"y":"g"),b=new d(y?p:"^(?:"+p.source+")",x),v=void 0===r?m:r>>>0;if(0===v)return[];if(0===u.length)return null===l(b,u)?[u]:[];var w=0,P=0,T=[];while(P1?arguments[1]:void 0)}},1861:function(t,e,s){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const i=!0,r=!0,n=!0,a=!0,o=!0,c=!0;class h{constructor(t,e={}){this.label=t,this.keyword=e.keyword,this.beforeExpr=!!e.beforeExpr,this.startsExpr=!!e.startsExpr,this.rightAssociative=!!e.rightAssociative,this.isLoop=!!e.isLoop,this.isAssign=!!e.isAssign,this.prefix=!!e.prefix,this.postfix=!!e.postfix,this.binop=null!=e.binop?e.binop:null,this.updateContext=null}}const l=new Map;function p(t,e={}){e.keyword=t;const s=new h(t,e);return l.set(t,s),s}function u(t,e){return new h(t,{beforeExpr:i,binop:e})}const d={num:new h("num",{startsExpr:r}),bigint:new h("bigint",{startsExpr:r}),regexp:new h("regexp",{startsExpr:r}),string:new h("string",{startsExpr:r}),name:new h("name",{startsExpr:r}),eof:new h("eof"),bracketL:new h("[",{beforeExpr:i,startsExpr:r}),bracketHashL:new h("#[",{beforeExpr:i,startsExpr:r}),bracketBarL:new h("[|",{beforeExpr:i,startsExpr:r}),bracketR:new h("]"),bracketBarR:new h("|]"),braceL:new h("{",{beforeExpr:i,startsExpr:r}),braceBarL:new h("{|",{beforeExpr:i,startsExpr:r}),braceHashL:new h("#{",{beforeExpr:i,startsExpr:r}),braceR:new h("}"),braceBarR:new h("|}"),parenL:new h("(",{beforeExpr:i,startsExpr:r}),parenR:new h(")"),comma:new h(",",{beforeExpr:i}),semi:new h(";",{beforeExpr:i}),colon:new h(":",{beforeExpr:i}),doubleColon:new h("::",{beforeExpr:i}),dot:new h("."),question:new h("?",{beforeExpr:i}),questionDot:new h("?."),arrow:new h("=>",{beforeExpr:i}),template:new h("template"),ellipsis:new h("...",{beforeExpr:i}),backQuote:new h("`",{startsExpr:r}),dollarBraceL:new h("${",{beforeExpr:i,startsExpr:r}),at:new h("@"),hash:new h("#",{startsExpr:r}),interpreterDirective:new h("#!..."),eq:new h("=",{beforeExpr:i,isAssign:a}),assign:new h("_=",{beforeExpr:i,isAssign:a}),incDec:new h("++/--",{prefix:o,postfix:c,startsExpr:r}),bang:new h("!",{beforeExpr:i,prefix:o,startsExpr:r}),tilde:new h("~",{beforeExpr:i,prefix:o,startsExpr:r}),pipeline:u("|>",0),nullishCoalescing:u("??",1),logicalOR:u("||",1),logicalAND:u("&&",2),bitwiseOR:u("|",3),bitwiseXOR:u("^",4),bitwiseAND:u("&",5),equality:u("==/!=/===/!==",6),relational:u("/<=/>=",7),bitShift:u("<>/>>>",8),plusMin:new h("+/-",{beforeExpr:i,binop:9,prefix:o,startsExpr:r}),modulo:new h("%",{beforeExpr:i,binop:10,startsExpr:r}),star:u("*",10),slash:u("/",10),exponent:new h("**",{beforeExpr:i,binop:11,rightAssociative:!0}),_break:p("break"),_case:p("case",{beforeExpr:i}),_catch:p("catch"),_continue:p("continue"),_debugger:p("debugger"),_default:p("default",{beforeExpr:i}),_do:p("do",{isLoop:n,beforeExpr:i}),_else:p("else",{beforeExpr:i}),_finally:p("finally"),_for:p("for",{isLoop:n}),_function:p("function",{startsExpr:r}),_if:p("if"),_return:p("return",{beforeExpr:i}),_switch:p("switch"),_throw:p("throw",{beforeExpr:i,prefix:o,startsExpr:r}),_try:p("try"),_var:p("var"),_const:p("const"),_while:p("while",{isLoop:n}),_with:p("with"),_new:p("new",{beforeExpr:i,startsExpr:r}),_this:p("this",{startsExpr:r}),_super:p("super",{startsExpr:r}),_class:p("class",{startsExpr:r}),_extends:p("extends",{beforeExpr:i}),_export:p("export"),_import:p("import",{startsExpr:r}),_null:p("null",{startsExpr:r}),_true:p("true",{startsExpr:r}),_false:p("false",{startsExpr:r}),_in:p("in",{beforeExpr:i,binop:7}),_instanceof:p("instanceof",{beforeExpr:i,binop:7}),_typeof:p("typeof",{beforeExpr:i,prefix:o,startsExpr:r}),_void:p("void",{beforeExpr:i,prefix:o,startsExpr:r}),_delete:p("delete",{beforeExpr:i,prefix:o,startsExpr:r})},f=0,m=1,y=2,g=4,x=8,b=16,v=32,w=64,P=128,T=m|y|P,E=1,A=2,S=4,C=8,k=16,N=64,I=128,O=256,D=512,M=1024,L=E|A|C|I,_=0|E|C|0,R=0|E|S|0,j=0|E|k|0,F=0|A|I,B=0|A,U=E|A|C|O,q=0|M,V=0|N,H=0|E|N,z=U|D,W=0|M,K=4,$=2,X=1,G=$|X,Y=$|K,J=X|K,Q=$,Z=X,tt=0,et=/\r\n?|[\n\u2028\u2029]/,st=new RegExp(et.source,"g");function it(t){switch(t){case 10:case 13:case 8232:case 8233:return!0;default:return!1}}const rt=/(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g;function nt(t){switch(t){case 9:case 11:case 12:case 32:case 160:case 5760:case 8192:case 8193:case 8194:case 8195:case 8196:case 8197:case 8198:case 8199:case 8200:case 8201:case 8202:case 8239:case 8287:case 12288:case 65279:return!0;default:return!1}}class at{constructor(t,e){this.line=t,this.column=e}}class ot{constructor(t,e){this.start=t,this.end=e}}function ct(t,e){let s,i=1,r=0;st.lastIndex=0;while((s=st.exec(t))&&s.index0)i=e[--r];if(null===i)return;for(let a=0;a0?i.trailingComments=n:void 0!==i.trailingComments&&(i.trailingComments=[])}processComment(t){if("Program"===t.type&&t.body.length>0)return;const e=this.state.commentStack;let s,i,r,n,a;if(this.state.trailingComments.length>0)this.state.trailingComments[0].start>=t.end?(r=this.state.trailingComments,this.state.trailingComments=[]):this.state.trailingComments.length=0;else if(e.length>0){const s=lt(e);s.trailingComments&&s.trailingComments[0].start>=t.end&&(r=s.trailingComments,delete s.trailingComments)}e.length>0&<(e).start>=t.start&&(s=e.pop());while(e.length>0&<(e).start>=t.start)i=e.pop();if(!i&&s&&(i=s),s)switch(t.type){case"ObjectExpression":this.adjustCommentsAfterTrailingComma(t,t.properties);break;case"ObjectPattern":this.adjustCommentsAfterTrailingComma(t,t.properties,!0);break;case"CallExpression":this.adjustCommentsAfterTrailingComma(t,t.arguments);break;case"ArrayExpression":this.adjustCommentsAfterTrailingComma(t,t.elements);break;case"ArrayPattern":this.adjustCommentsAfterTrailingComma(t,t.elements,!0);break}else this.state.commentPreviousNode&&("ImportSpecifier"===this.state.commentPreviousNode.type&&"ImportSpecifier"!==t.type||"ExportSpecifier"===this.state.commentPreviousNode.type&&"ExportSpecifier"!==t.type)&&this.adjustCommentsAfterTrailingComma(t,[this.state.commentPreviousNode]);if(i){if(i.leadingComments)if(i!==t&&i.leadingComments.length>0&<(i.leadingComments).end<=t.start)t.leadingComments=i.leadingComments,delete i.leadingComments;else for(n=i.leadingComments.length-2;n>=0;--n)if(i.leadingComments[n].end<=t.start){t.leadingComments=i.leadingComments.splice(0,n+1);break}}else if(this.state.leadingComments.length>0)if(lt(this.state.leadingComments).end<=t.start){if(this.state.commentPreviousNode)for(a=0;a0&&(t.leadingComments=this.state.leadingComments,this.state.leadingComments=[])}else{for(n=0;nt.start)break;const e=this.state.leadingComments.slice(0,n);e.length&&(t.leadingComments=e),r=this.state.leadingComments.slice(n),0===r.length&&(r=null)}if(this.state.commentPreviousNode=t,r)if(r.length&&r[0].start>=t.start&<(r).end<=t.end)t.innerComments=r;else{const e=r.findIndex(e=>e.end>=t.end);e>0?(t.innerComments=r.slice(0,e),t.trailingComments=r.slice(e)):t.trailingComments=r}e.push(t)}}const ut=Object.freeze({ArgumentsDisallowedInInitializer:"'arguments' is not allowed in class field initializer",AsyncFunctionInSingleStatementContext:"Async functions can only be declared at the top level or inside a block",AwaitBindingIdentifier:"Can not use 'await' as identifier inside an async function",AwaitExpressionFormalParameter:"await is not allowed in async function parameters",AwaitNotInAsyncFunction:"Can not use keyword 'await' outside an async function",BadGetterArity:"getter must not have any formal parameters",BadSetterArity:"setter must have exactly one formal parameter",BadSetterRestParameter:"setter function argument must not be a rest parameter",ConstructorClassField:"Classes may not have a field named 'constructor'",ConstructorClassPrivateField:"Classes may not have a private field named '#constructor'",ConstructorIsAccessor:"Class constructor may not be an accessor",ConstructorIsAsync:"Constructor can't be an async function",ConstructorIsGenerator:"Constructor can't be a generator",DeclarationMissingInitializer:"%0 require an initialization value",DecoratorBeforeExport:"Decorators must be placed *before* the 'export' keyword. You can set the 'decoratorsBeforeExport' option to false to use the 'export @decorator class {}' syntax",DecoratorConstructor:"Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?",DecoratorExportClass:"Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.",DecoratorSemicolon:"Decorators must not be followed by a semicolon",DeletePrivateField:"Deleting a private field is not allowed",DestructureNamedImport:"ES2015 named imports do not destructure. Use another statement for destructuring after the import.",DuplicateConstructor:"Duplicate constructor in the same class",DuplicateDefaultExport:"Only one default export allowed per module.",DuplicateExport:"`%0` has already been exported. Exported identifiers must be unique.",DuplicateProto:"Redefinition of __proto__ property",DuplicateRegExpFlags:"Duplicate regular expression flag",ElementAfterRest:"Rest element must be last element",EscapedCharNotAnIdentifier:"Invalid Unicode escape",ExportDefaultFromAsIdentifier:"'from' is not allowed as an identifier after 'export default'",ForInOfLoopInitializer:"%0 loop variable declaration may not have an initializer",GeneratorInSingleStatementContext:"Generators can only be declared at the top level or inside a block",IllegalBreakContinue:"Unsyntactic %0",IllegalLanguageModeDirective:"Illegal 'use strict' directive in function with non-simple parameter list",IllegalReturn:"'return' outside of function",ImportCallArgumentTrailingComma:"Trailing comma is disallowed inside import(...) arguments",ImportCallArity:"import() requires exactly %0",ImportCallNotNewExpression:"Cannot use new with import(...)",ImportCallSpreadArgument:"... is not allowed in import()",ImportMetaOutsideModule:"import.meta may appear only with 'sourceType: \"module\"'",ImportOutsideModule:"'import' and 'export' may appear only with 'sourceType: \"module\"'",InvalidBigIntLiteral:"Invalid BigIntLiteral",InvalidCodePoint:"Code point out of bounds",InvalidDigit:"Expected number in radix %0",InvalidEscapeSequence:"Bad character escape sequence",InvalidEscapeSequenceTemplate:"Invalid escape sequence in template",InvalidEscapedReservedWord:"Escape sequence in keyword %0",InvalidIdentifier:"Invalid identifier %0",InvalidLhs:"Invalid left-hand side in %0",InvalidLhsBinding:"Binding invalid left-hand side in %0",InvalidNumber:"Invalid number",InvalidOrUnexpectedToken:"Unexpected character '%0'",InvalidParenthesizedAssignment:"Invalid parenthesized assignment pattern",InvalidPrivateFieldResolution:"Private name #%0 is not defined",InvalidPropertyBindingPattern:"Binding member expression",InvalidRecordProperty:"Only properties and spread elements are allowed in record definitions",InvalidRestAssignmentPattern:"Invalid rest operator's argument",LabelRedeclaration:"Label '%0' is already declared",LetInLexicalBinding:"'let' is not allowed to be used as a name in 'let' or 'const' declarations.",MalformedRegExpFlags:"Invalid regular expression flag",MissingClassName:"A class name is required",MissingEqInAssignment:"Only '=' operator can be used for specifying default value.",MissingUnicodeEscape:"Expecting Unicode escape sequence \\uXXXX",MixingCoalesceWithLogical:"Nullish coalescing operator(??) requires parens when mixing with logical operators",ModuleAttributeDifferentFromType:"The only accepted module attribute is `type`",ModuleAttributeInvalidValue:"Only string literals are allowed as module attribute values",ModuleAttributesWithDuplicateKeys:'Duplicate key "%0" is not allowed in module attributes',ModuleExportUndefined:"Export '%0' is not defined",MultipleDefaultsInSwitch:"Multiple default clauses",NewlineAfterThrow:"Illegal newline after throw",NoCatchOrFinally:"Missing catch or finally clause",NumberIdentifier:"Identifier directly after number",NumericSeparatorInEscapeSequence:"Numeric separators are not allowed inside unicode escape sequences or hex escape sequences",ObsoleteAwaitStar:"await* has been removed from the async functions proposal. Use Promise.all() instead.",OptionalChainingNoNew:"constructors in/after an Optional Chain are not allowed",OptionalChainingNoTemplate:"Tagged Template Literals are not allowed in optionalChain",ParamDupe:"Argument name clash",PatternHasAccessor:"Object pattern can't contain getter or setter",PatternHasMethod:"Object pattern can't contain methods",PipelineBodyNoArrow:'Unexpected arrow "=>" after pipeline body; arrow function in pipeline body must be parenthesized',PipelineBodySequenceExpression:"Pipeline body may not be a comma-separated sequence expression",PipelineHeadSequenceExpression:"Pipeline head should not be a comma-separated sequence expression",PipelineTopicUnused:"Pipeline is in topic style but does not use topic reference",PrimaryTopicNotAllowed:"Topic reference was used in a lexical context without topic binding",PrimaryTopicRequiresSmartPipeline:"Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.",PrivateInExpectedIn:"Private names are only allowed in property accesses (`obj.#%0`) or in `in` expressions (`#%0 in obj`)",PrivateNameRedeclaration:"Duplicate private name #%0",RecordExpressionBarIncorrectEndSyntaxType:"Record expressions ending with '|}' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",RecordExpressionBarIncorrectStartSyntaxType:"Record expressions starting with '{|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",RecordExpressionHashIncorrectStartSyntaxType:"Record expressions starting with '#{' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'",RecordNoProto:"'__proto__' is not allowed in Record expressions",RestTrailingComma:"Unexpected trailing comma after rest element",SloppyFunction:"In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement",StaticPrototype:"Classes may not have static property named prototype",StrictDelete:"Deleting local variable in strict mode",StrictEvalArguments:"Assigning to '%0' in strict mode",StrictEvalArgumentsBinding:"Binding '%0' in strict mode",StrictFunction:"In strict mode code, functions can only be declared at top level or inside a block",StrictOctalLiteral:"Legacy octal literals are not allowed in strict mode",StrictWith:"'with' in strict mode",SuperNotAllowed:"super() is only valid inside a class constructor of a subclass. Maybe a typo in the method name ('constructor') or not extending another class?",SuperPrivateField:"Private fields can't be accessed on super",TrailingDecorator:"Decorators must be attached to a class element",TupleExpressionBarIncorrectEndSyntaxType:"Tuple expressions ending with '|]' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",TupleExpressionBarIncorrectStartSyntaxType:"Tuple expressions starting with '[|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",TupleExpressionHashIncorrectStartSyntaxType:"Tuple expressions starting with '#[' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'",UnexpectedArgumentPlaceholder:"Unexpected argument placeholder",UnexpectedAwaitAfterPipelineBody:'Unexpected "await" after pipeline body; await must have parentheses in minimal proposal',UnexpectedDigitAfterHash:"Unexpected digit after hash token",UnexpectedImportExport:"'import' and 'export' may only appear at the top level",UnexpectedKeyword:"Unexpected keyword '%0'",UnexpectedLeadingDecorator:"Leading decorators must be attached to a class declaration",UnexpectedLexicalDeclaration:"Lexical declaration cannot appear in a single-statement context",UnexpectedNewTarget:"new.target can only be used in functions",UnexpectedNumericSeparator:"A numeric separator is only allowed between two digits",UnexpectedPrivateField:"Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p).",UnexpectedReservedWord:"Unexpected reserved word '%0'",UnexpectedSuper:"super is only allowed in object methods and classes",UnexpectedToken:"Unexpected token '%0'",UnexpectedTokenUnaryExponentiation:"Illegal expression. Wrap left hand side or entire exponentiation in parentheses.",UnsupportedBind:"Binding should be performed on object property.",UnsupportedDecoratorExport:"A decorated export must export a class declaration",UnsupportedDefaultExport:"Only expressions, functions or classes are allowed as the `default` export.",UnsupportedImport:"import can only be used in import() or import.meta",UnsupportedMetaProperty:"The only valid meta property for %0 is %0.%1",UnsupportedParameterDecorator:"Decorators cannot be used to decorate parameters",UnsupportedPropertyDecorator:"Decorators cannot be used to decorate object literal properties",UnsupportedSuper:"super can only be used with function calls (i.e. super()) or in property accesses (i.e. super.prop or super[prop])",UnterminatedComment:"Unterminated comment",UnterminatedRegExp:"Unterminated regular expression",UnterminatedString:"Unterminated string constant",UnterminatedTemplate:"Unterminated template",VarRedeclaration:"Identifier '%0' has already been declared",YieldBindingIdentifier:"Can not use 'yield' as identifier inside a generator",YieldInParameter:"yield is not allowed in generator parameters",ZeroDigitNumericSeparator:"Numeric separator can not be used after leading 0"});class dt extends pt{getLocationForPosition(t){let e;return e=t===this.state.start?this.state.startLoc:t===this.state.lastTokStart?this.state.lastTokStartLoc:t===this.state.end?this.state.endLoc:t===this.state.lastTokEnd?this.state.lastTokEndLoc:ct(this.input,t),e}raise(t,e,...s){return this.raiseWithData(t,void 0,e,...s)}raiseWithData(t,e,s,...i){const r=this.getLocationForPosition(t),n=s.replace(/%(\d+)/g,(t,e)=>i[e])+` (${r.line}:${r.column})`;return this._raise(Object.assign({loc:r,pos:t},e),n)}_raise(t,e){const s=new SyntaxError(e);if(Object.assign(s,t),this.options.errorRecovery)return this.isLookahead||this.state.errors.push(s),s;throw s}}function ft(t){return null!=t&&"Property"===t.type&&"init"===t.kind&&!1===t.method}var mt=t=>class extends t{estreeParseRegExpLiteral({pattern:t,flags:e}){let s=null;try{s=new RegExp(t,e)}catch(r){}const i=this.estreeParseLiteral(s);return i.regex={pattern:t,flags:e},i}estreeParseBigIntLiteral(t){const e="undefined"!==typeof BigInt?BigInt(t):null,s=this.estreeParseLiteral(e);return s.bigint=String(s.value||t),s}estreeParseLiteral(t){return this.parseLiteral(t,"Literal")}directiveToStmt(t){const e=t.value,s=this.startNodeAt(t.start,t.loc.start),i=this.startNodeAt(e.start,e.loc.start);return i.value=e.value,i.raw=e.extra.raw,s.expression=this.finishNodeAt(i,"Literal",e.end,e.loc.end),s.directive=e.extra.raw.slice(1,-1),this.finishNodeAt(s,"ExpressionStatement",t.end,t.loc.end)}initFunction(t,e){super.initFunction(t,e),t.expression=!1}checkDeclaration(t){ft(t)?this.checkDeclaration(t.value):super.checkDeclaration(t)}checkGetterSetterParams(t){const e=t,s="get"===e.kind?0:1,i=e.start;e.value.params.length!==s?"get"===t.kind?this.raise(i,ut.BadGetterArity):this.raise(i,ut.BadSetterArity):"set"===e.kind&&"RestElement"===e.value.params[0].type&&this.raise(i,ut.BadSetterRestParameter)}checkLVal(t,e=V,s,i,r){switch(t.type){case"ObjectPattern":t.properties.forEach(t=>{this.checkLVal("Property"===t.type?t.value:t,e,s,"object destructuring pattern",r)});break;default:super.checkLVal(t,e,s,i,r)}}checkProto(t,e,s,i){t.method||super.checkProto(t,e,s,i)}isValidDirective(t){var e;return"ExpressionStatement"===t.type&&"Literal"===t.expression.type&&"string"===typeof t.expression.value&&!(null==(e=t.expression.extra)?void 0:e.parenthesized)}stmtToDirective(t){const e=super.stmtToDirective(t),s=t.expression.value;return e.value.value=s,e}parseBlockBody(t,e,s,i){super.parseBlockBody(t,e,s,i);const r=t.directives.map(t=>this.directiveToStmt(t));t.body=r.concat(t.body),delete t.directives}pushClassMethod(t,e,s,i,r,n){this.parseMethod(e,s,i,r,n,"ClassMethod",!0),e.typeParameters&&(e.value.typeParameters=e.typeParameters,delete e.typeParameters),t.body.push(e)}parseExprAtom(t){switch(this.state.type){case d.num:case d.string:return this.estreeParseLiteral(this.state.value);case d.regexp:return this.estreeParseRegExpLiteral(this.state.value);case d.bigint:return this.estreeParseBigIntLiteral(this.state.value);case d._null:return this.estreeParseLiteral(null);case d._true:return this.estreeParseLiteral(!0);case d._false:return this.estreeParseLiteral(!1);default:return super.parseExprAtom(t)}}parseLiteral(t,e,s,i){const r=super.parseLiteral(t,e,s,i);return r.raw=r.extra.raw,delete r.extra,r}parseFunctionBody(t,e,s=!1){super.parseFunctionBody(t,e,s),t.expression="BlockStatement"!==t.body.type}parseMethod(t,e,s,i,r,n,a=!1){let o=this.startNode();return o.kind=t.kind,o=super.parseMethod(o,e,s,i,r,n,a),o.type="FunctionExpression",delete o.kind,t.value=o,n="ClassMethod"===n?"MethodDefinition":n,this.finishNode(t,n)}parseObjectMethod(t,e,s,i,r){const n=super.parseObjectMethod(t,e,s,i,r);return n&&(n.type="Property","method"===n.kind&&(n.kind="init"),n.shorthand=!1),n}parseObjectProperty(t,e,s,i,r){const n=super.parseObjectProperty(t,e,s,i,r);return n&&(n.kind="init",n.type="Property"),n}toAssignable(t){return ft(t)?(this.toAssignable(t.value),t):super.toAssignable(t)}toAssignableObjectExpressionProp(t,e){if("get"===t.kind||"set"===t.kind)throw this.raise(t.key.start,ut.PatternHasAccessor);if(t.method)throw this.raise(t.key.start,ut.PatternHasMethod);super.toAssignableObjectExpressionProp(t,e)}finishCallExpression(t,e){return super.finishCallExpression(t,e),"Import"===t.callee.type?(t.type="ImportExpression",t.source=t.arguments[0],delete t.arguments,delete t.callee):"CallExpression"===t.type&&(t.optional=!1),t}toReferencedListDeep(t,e){t&&super.toReferencedListDeep(t,e)}parseExport(t){switch(super.parseExport(t),t.type){case"ExportAllDeclaration":t.exported=null;break;case"ExportNamedDeclaration":1===t.specifiers.length&&"ExportNamespaceSpecifier"===t.specifiers[0].type&&(t.type="ExportAllDeclaration",t.exported=t.specifiers[0].exported,delete t.specifiers);break}return t}parseSubscript(...t){const e=super.parseSubscript(...t);return"MemberExpression"===e.type&&(e.optional=!1),e}};class yt{constructor(t,e,s,i){this.token=t,this.isExpr=!!e,this.preserveSpace=!!s,this.override=i}}const gt={braceStatement:new yt("{",!1),braceExpression:new yt("{",!0),templateQuasi:new yt("${",!1),parenStatement:new yt("(",!1),parenExpression:new yt("(",!0),template:new yt("`",!0,!0,t=>t.readTmplToken()),functionExpression:new yt("function",!0),functionStatement:new yt("function",!1)};d.parenR.updateContext=d.braceR.updateContext=function(){if(1===this.state.context.length)return void(this.state.exprAllowed=!0);let t=this.state.context.pop();t===gt.braceStatement&&"function"===this.curContext().token&&(t=this.state.context.pop()),this.state.exprAllowed=!t.isExpr},d.name.updateContext=function(t){let e=!1;t!==d.dot&&("of"===this.state.value&&!this.state.exprAllowed&&t!==d._function&&t!==d._class||"yield"===this.state.value&&this.prodParam.hasYield)&&(e=!0),this.state.exprAllowed=e,this.state.isIterator&&(this.state.isIterator=!1)},d.braceL.updateContext=function(t){this.state.context.push(this.braceIsBlock(t)?gt.braceStatement:gt.braceExpression),this.state.exprAllowed=!0},d.dollarBraceL.updateContext=function(){this.state.context.push(gt.templateQuasi),this.state.exprAllowed=!0},d.parenL.updateContext=function(t){const e=t===d._if||t===d._for||t===d._with||t===d._while;this.state.context.push(e?gt.parenStatement:gt.parenExpression),this.state.exprAllowed=!0},d.incDec.updateContext=function(){},d._function.updateContext=d._class.updateContext=function(t){t===d.dot||t===d.questionDot||(!t.beforeExpr||t===d.semi||t===d._else||t===d._return&&et.test(this.input.slice(this.state.lastTokEnd,this.state.start))||(t===d.colon||t===d.braceL)&&this.curContext()===gt.b_stat?this.state.context.push(gt.functionStatement):this.state.context.push(gt.functionExpression)),this.state.exprAllowed=!1},d.backQuote.updateContext=function(){this.curContext()===gt.template?this.state.context.pop():this.state.context.push(gt.template),this.state.exprAllowed=!1},d.star.updateContext=function(){this.state.exprAllowed=!1};let xt="ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙՠ-ֈא-תׯ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࡠ-ࡪࢠ-ࢴࢶ-ࣇऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱৼਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡૹଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘ-ౚౠౡಀಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഄ-ഌഎ-ഐഒ-ഺഽൎൔ-ൖൟ-ൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄຆ-ຊຌ-ຣລວ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡸᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᲀ-ᲈᲐ-ᲺᲽ-Ჿᳩ-ᳬᳮ-ᳳᳵᳶᳺᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄯㄱ-ㆎㆠ-ㆿㇰ-ㇿ㐀-䶿一-鿼ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞿꟂ-ꟊꟵ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꣽꣾꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭩꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ",bt="‌‍·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍୕-ୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఄా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ඁ-ඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᪿᫀᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧ꠬ꢀꢁꢴ-ꣅ꣐-꣙꣠-꣱ꣿ-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︯︳︴﹍-﹏0-9_";const vt=new RegExp("["+xt+"]"),wt=new RegExp("["+xt+bt+"]");xt=bt=null;const Pt=[0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,349,41,7,1,79,28,11,0,9,21,107,20,28,22,13,52,76,44,33,24,27,35,30,0,3,0,9,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,21,2,31,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,230,43,117,63,32,7,3,0,3,7,2,1,2,23,16,0,2,0,95,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,190,0,80,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,1237,43,8,8952,286,50,2,18,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,2357,44,11,6,17,0,370,43,1301,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42717,35,4148,12,221,3,5761,15,7472,3104,541,1507,4938],Tt=[509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,370,1,154,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,2,11,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,71,5,2,1,3,3,2,0,2,1,13,9,120,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1014,0,2,54,8,3,82,0,12,1,19628,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,262,6,10,9,419,13,1495,6,110,6,6,9,4759,9,787719,239];function Et(t,e){let s=65536;for(let i=0,r=e.length;it)return!1;if(s+=e[i+1],s>=t)return!0}return!1}function At(t){return t<65?36===t:t<=90||(t<97?95===t:t<=122||(t<=65535?t>=170&&vt.test(String.fromCharCode(t)):Et(t,Pt)))}function St(t){return t<48?36===t:t<58||!(t<65)&&(t<=90||(t<97?95===t:t<=122||(t<=65535?t>=170&&wt.test(String.fromCharCode(t)):Et(t,Pt)||Et(t,Tt))))}const Ct={keyword:["break","case","catch","continue","debugger","default","do","else","finally","for","function","if","return","switch","throw","try","var","const","while","with","new","this","super","class","extends","export","import","null","true","false","in","instanceof","typeof","void","delete"],strict:["implements","interface","let","package","private","protected","public","static","yield"],strictBind:["eval","arguments"]},kt=new Set(Ct.keyword),Nt=new Set(Ct.strict),It=new Set(Ct.strictBind);function Ot(t,e){return e&&"await"===t||"enum"===t}function Dt(t,e){return Ot(t,e)||Nt.has(t)}function Mt(t){return It.has(t)}function Lt(t,e){return Dt(t,e)||Mt(t)}function _t(t){return kt.has(t)}const Rt=/^in(stanceof)?$/;function jt(t,e){return 64===t&&64===e}const Ft=new Set(["_","any","bool","boolean","empty","extends","false","interface","mixed","null","number","static","string","true","typeof","void"]),Bt=Object.freeze({AmbiguousConditionalArrow:"Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.",AmbiguousDeclareModuleKind:"Found both `declare module.exports` and `declare export` in the same module. Modules can only have 1 since they are either an ES module or they are a CommonJS module",AssignReservedType:"Cannot overwrite reserved type %0",DeclareClassElement:"The `declare` modifier can only appear on class fields.",DeclareClassFieldInitializer:"Initializers are not allowed in fields with the `declare` modifier.",DuplicateDeclareModuleExports:"Duplicate `declare module.exports` statement",EnumBooleanMemberNotInitialized:"Boolean enum members need to be initialized. Use either `%0 = true,` or `%0 = false,` in enum `%1`.",EnumDuplicateMemberName:"Enum member names need to be unique, but the name `%0` has already been used before in enum `%1`.",EnumInconsistentMemberValues:"Enum `%0` has inconsistent member initializers. Either use no initializers, or consistently use literals (either booleans, numbers, or strings) for all member initializers.",EnumInvalidExplicitType:"Enum type `%1` is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.",EnumInvalidExplicitTypeUnknownSupplied:"Supplied enum type is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.",EnumInvalidMemberInitializerPrimaryType:"Enum `%0` has type `%2`, so the initializer of `%1` needs to be a %2 literal.",EnumInvalidMemberInitializerSymbolType:"Symbol enum members cannot be initialized. Use `%1,` in enum `%0`.",EnumInvalidMemberInitializerUnknownType:"The enum member initializer for `%1` needs to be a literal (either a boolean, number, or string) in enum `%0`.",EnumInvalidMemberName:"Enum member names cannot start with lowercase 'a' through 'z'. Instead of using `%0`, consider using `%1`, in enum `%2`.",EnumNumberMemberNotInitialized:"Number enum members need to be initialized, e.g. `%1 = 1` in enum `%0`.",EnumStringMemberInconsistentlyInitailized:"String enum members need to consistently either all use initializers, or use no initializers, in enum `%0`.",ImportTypeShorthandOnlyInPureImport:"The `type` and `typeof` keywords on named imports can only be used on regular `import` statements. It cannot be used with `import type` or `import typeof` statements",InexactInsideExact:"Explicit inexact syntax cannot appear inside an explicit exact object type",InexactInsideNonObject:"Explicit inexact syntax cannot appear in class or interface definitions",InexactVariance:"Explicit inexact syntax cannot have variance",InvalidNonTypeImportInDeclareModule:"Imports within a `declare module` body must always be `import type` or `import typeof`",MissingTypeParamDefault:"Type parameter declaration needs a default, since a preceding type parameter declaration has a default.",NestedDeclareModule:"`declare module` cannot be used inside another `declare module`",NestedFlowComment:"Cannot have a flow comment inside another flow comment",OptionalBindingPattern:"A binding pattern parameter cannot be optional in an implementation signature.",SpreadVariance:"Spread properties cannot have variance",TypeBeforeInitializer:"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`",TypeCastInPattern:"The type cast expression is expected to be wrapped with parenthesis",UnexpectedExplicitInexactInObject:"Explicit inexact syntax must appear at the end of an inexact object",UnexpectedReservedType:"Unexpected reserved type %0",UnexpectedReservedUnderscore:"`_` is only allowed as a type argument to call or new",UnexpectedSpaceBetweenModuloChecks:"Spaces between `%` and `checks` are not allowed here.",UnexpectedSpreadType:"Spread operator cannot appear in class or interface definitions",UnexpectedSubtractionOperand:'Unexpected token, expected "number" or "bigint"',UnexpectedTokenAfterTypeParameter:"Expected an arrow function after this type parameter declaration",UnsupportedDeclareExportKind:"`declare export %0` is not supported. Use `%1` instead",UnsupportedStatementInDeclareModule:"Only declares and type imports are allowed inside declare module",UnterminatedFlowComment:"Unterminated flow-comment"});function Ut(t){return"DeclareExportAllDeclaration"===t.type||"DeclareExportDeclaration"===t.type&&(!t.declaration||"TypeAlias"!==t.declaration.type&&"InterfaceDeclaration"!==t.declaration.type)}function qt(t){return"type"===t.importKind||"typeof"===t.importKind}function Vt(t){return(t.type===d.name||!!t.type.keyword)&&"from"!==t.value}const Ht={const:"declare export var",let:"declare export var",type:"export type",interface:"export interface"};function zt(t,e){const s=[],i=[];for(let r=0;rclass extends t{constructor(t,e){super(t,e),this.flowPragma=void 0}shouldParseTypes(){return this.getPluginOption("flow","all")||"flow"===this.flowPragma}shouldParseEnums(){return!!this.getPluginOption("flow","enums")}finishToken(t,e){return t!==d.string&&t!==d.semi&&t!==d.interpreterDirective&&void 0===this.flowPragma&&(this.flowPragma=null),super.finishToken(t,e)}addComment(t){if(void 0===this.flowPragma){const e=Wt.exec(t.value);if(e)if("flow"===e[1])this.flowPragma="flow";else{if("noflow"!==e[1])throw new Error("Unexpected flow pragma");this.flowPragma="noflow"}else;}return super.addComment(t)}flowParseTypeInitialiser(t){const e=this.state.inType;this.state.inType=!0,this.expect(t||d.colon);const s=this.flowParseType();return this.state.inType=e,s}flowParsePredicate(){const t=this.startNode(),e=this.state.startLoc,s=this.state.start;this.expect(d.modulo);const i=this.state.startLoc;return this.expectContextual("checks"),e.line===i.line&&e.column===i.column-1||this.raise(s,Bt.UnexpectedSpaceBetweenModuloChecks),this.eat(d.parenL)?(t.value=this.parseExpression(),this.expect(d.parenR),this.finishNode(t,"DeclaredPredicate")):this.finishNode(t,"InferredPredicate")}flowParseTypeAndPredicateInitialiser(){const t=this.state.inType;this.state.inType=!0,this.expect(d.colon);let e=null,s=null;return this.match(d.modulo)?(this.state.inType=t,s=this.flowParsePredicate()):(e=this.flowParseType(),this.state.inType=t,this.match(d.modulo)&&(s=this.flowParsePredicate())),[e,s]}flowParseDeclareClass(t){return this.next(),this.flowParseInterfaceish(t,!0),this.finishNode(t,"DeclareClass")}flowParseDeclareFunction(t){this.next();const e=t.id=this.parseIdentifier(),s=this.startNode(),i=this.startNode();this.isRelational("<")?s.typeParameters=this.flowParseTypeParameterDeclaration():s.typeParameters=null,this.expect(d.parenL);const r=this.flowParseFunctionTypeParams();return s.params=r.params,s.rest=r.rest,this.expect(d.parenR),[s.returnType,t.predicate]=this.flowParseTypeAndPredicateInitialiser(),i.typeAnnotation=this.finishNode(s,"FunctionTypeAnnotation"),e.typeAnnotation=this.finishNode(i,"TypeAnnotation"),this.resetEndLocation(e),this.semicolon(),this.finishNode(t,"DeclareFunction")}flowParseDeclare(t,e){if(this.match(d._class))return this.flowParseDeclareClass(t);if(this.match(d._function))return this.flowParseDeclareFunction(t);if(this.match(d._var))return this.flowParseDeclareVariable(t);if(this.eatContextual("module"))return this.match(d.dot)?this.flowParseDeclareModuleExports(t):(e&&this.raise(this.state.lastTokStart,Bt.NestedDeclareModule),this.flowParseDeclareModule(t));if(this.isContextual("type"))return this.flowParseDeclareTypeAlias(t);if(this.isContextual("opaque"))return this.flowParseDeclareOpaqueType(t);if(this.isContextual("interface"))return this.flowParseDeclareInterface(t);if(this.match(d._export))return this.flowParseDeclareExportDeclaration(t,e);throw this.unexpected()}flowParseDeclareVariable(t){return this.next(),t.id=this.flowParseTypeAnnotatableIdentifier(!0),this.scope.declareName(t.id.name,R,t.id.start),this.semicolon(),this.finishNode(t,"DeclareVariable")}flowParseDeclareModule(t){this.scope.enter(f),this.match(d.string)?t.id=this.parseExprAtom():t.id=this.parseIdentifier();const e=t.body=this.startNode(),s=e.body=[];this.expect(d.braceL);while(!this.match(d.braceR)){let t=this.startNode();this.match(d._import)?(this.next(),this.isContextual("type")||this.match(d._typeof)||this.raise(this.state.lastTokStart,Bt.InvalidNonTypeImportInDeclareModule),this.parseImport(t)):(this.expectContextual("declare",Bt.UnsupportedStatementInDeclareModule),t=this.flowParseDeclare(t,!0)),s.push(t)}this.scope.exit(),this.expect(d.braceR),this.finishNode(e,"BlockStatement");let i=null,r=!1;return s.forEach(t=>{Ut(t)?("CommonJS"===i&&this.raise(t.start,Bt.AmbiguousDeclareModuleKind),i="ES"):"DeclareModuleExports"===t.type&&(r&&this.raise(t.start,Bt.DuplicateDeclareModuleExports),"ES"===i&&this.raise(t.start,Bt.AmbiguousDeclareModuleKind),i="CommonJS",r=!0)}),t.kind=i||"CommonJS",this.finishNode(t,"DeclareModule")}flowParseDeclareExportDeclaration(t,e){if(this.expect(d._export),this.eat(d._default))return this.match(d._function)||this.match(d._class)?t.declaration=this.flowParseDeclare(this.startNode()):(t.declaration=this.flowParseType(),this.semicolon()),t.default=!0,this.finishNode(t,"DeclareExportDeclaration");if(this.match(d._const)||this.isLet()||(this.isContextual("type")||this.isContextual("interface"))&&!e){const t=this.state.value,e=Ht[t];throw this.raise(this.state.start,Bt.UnsupportedDeclareExportKind,t,e)}if(this.match(d._var)||this.match(d._function)||this.match(d._class)||this.isContextual("opaque"))return t.declaration=this.flowParseDeclare(this.startNode()),t.default=!1,this.finishNode(t,"DeclareExportDeclaration");if(this.match(d.star)||this.match(d.braceL)||this.isContextual("interface")||this.isContextual("type")||this.isContextual("opaque"))return t=this.parseExport(t),"ExportNamedDeclaration"===t.type&&(t.type="ExportDeclaration",t.default=!1,delete t.exportKind),t.type="Declare"+t.type,t;throw this.unexpected()}flowParseDeclareModuleExports(t){return this.next(),this.expectContextual("exports"),t.typeAnnotation=this.flowParseTypeAnnotation(),this.semicolon(),this.finishNode(t,"DeclareModuleExports")}flowParseDeclareTypeAlias(t){return this.next(),this.flowParseTypeAlias(t),t.type="DeclareTypeAlias",t}flowParseDeclareOpaqueType(t){return this.next(),this.flowParseOpaqueType(t,!0),t.type="DeclareOpaqueType",t}flowParseDeclareInterface(t){return this.next(),this.flowParseInterfaceish(t),this.finishNode(t,"DeclareInterface")}flowParseInterfaceish(t,e=!1){if(t.id=this.flowParseRestrictedIdentifier(!e,!0),this.scope.declareName(t.id.name,e?j:_,t.id.start),this.isRelational("<")?t.typeParameters=this.flowParseTypeParameterDeclaration():t.typeParameters=null,t.extends=[],t.implements=[],t.mixins=[],this.eat(d._extends))do{t.extends.push(this.flowParseInterfaceExtends())}while(!e&&this.eat(d.comma));if(this.isContextual("mixins")){this.next();do{t.mixins.push(this.flowParseInterfaceExtends())}while(this.eat(d.comma))}if(this.isContextual("implements")){this.next();do{t.implements.push(this.flowParseInterfaceExtends())}while(this.eat(d.comma))}t.body=this.flowParseObjectType({allowStatic:e,allowExact:!1,allowSpread:!1,allowProto:e,allowInexact:!1})}flowParseInterfaceExtends(){const t=this.startNode();return t.id=this.flowParseQualifiedTypeIdentifier(),this.isRelational("<")?t.typeParameters=this.flowParseTypeParameterInstantiation():t.typeParameters=null,this.finishNode(t,"InterfaceExtends")}flowParseInterface(t){return this.flowParseInterfaceish(t),this.finishNode(t,"InterfaceDeclaration")}checkNotUnderscore(t){"_"===t&&this.raise(this.state.start,Bt.UnexpectedReservedUnderscore)}checkReservedType(t,e,s){Ft.has(t)&&this.raise(e,s?Bt.AssignReservedType:Bt.UnexpectedReservedType,t)}flowParseRestrictedIdentifier(t,e){return this.checkReservedType(this.state.value,this.state.start,e),this.parseIdentifier(t)}flowParseTypeAlias(t){return t.id=this.flowParseRestrictedIdentifier(!1,!0),this.scope.declareName(t.id.name,_,t.id.start),this.isRelational("<")?t.typeParameters=this.flowParseTypeParameterDeclaration():t.typeParameters=null,t.right=this.flowParseTypeInitialiser(d.eq),this.semicolon(),this.finishNode(t,"TypeAlias")}flowParseOpaqueType(t,e){return this.expectContextual("type"),t.id=this.flowParseRestrictedIdentifier(!0,!0),this.scope.declareName(t.id.name,_,t.id.start),this.isRelational("<")?t.typeParameters=this.flowParseTypeParameterDeclaration():t.typeParameters=null,t.supertype=null,this.match(d.colon)&&(t.supertype=this.flowParseTypeInitialiser(d.colon)),t.impltype=null,e||(t.impltype=this.flowParseTypeInitialiser(d.eq)),this.semicolon(),this.finishNode(t,"OpaqueType")}flowParseTypeParameter(t=!1){const e=this.state.start,s=this.startNode(),i=this.flowParseVariance(),r=this.flowParseTypeAnnotatableIdentifier();return s.name=r.name,s.variance=i,s.bound=r.typeAnnotation,this.match(d.eq)?(this.eat(d.eq),s.default=this.flowParseType()):t&&this.raise(e,Bt.MissingTypeParamDefault),this.finishNode(s,"TypeParameter")}flowParseTypeParameterDeclaration(){const t=this.state.inType,e=this.startNode();e.params=[],this.state.inType=!0,this.isRelational("<")||this.match(d.jsxTagStart)?this.next():this.unexpected();let s=!1;do{const t=this.flowParseTypeParameter(s);e.params.push(t),t.default&&(s=!0),this.isRelational(">")||this.expect(d.comma)}while(!this.isRelational(">"));return this.expectRelational(">"),this.state.inType=t,this.finishNode(e,"TypeParameterDeclaration")}flowParseTypeParameterInstantiation(){const t=this.startNode(),e=this.state.inType;t.params=[],this.state.inType=!0,this.expectRelational("<");const s=this.state.noAnonFunctionType;this.state.noAnonFunctionType=!1;while(!this.isRelational(">"))t.params.push(this.flowParseType()),this.isRelational(">")||this.expect(d.comma);return this.state.noAnonFunctionType=s,this.expectRelational(">"),this.state.inType=e,this.finishNode(t,"TypeParameterInstantiation")}flowParseTypeParameterInstantiationCallOrNew(){const t=this.startNode(),e=this.state.inType;t.params=[],this.state.inType=!0,this.expectRelational("<");while(!this.isRelational(">"))t.params.push(this.flowParseTypeOrImplicitInstantiation()),this.isRelational(">")||this.expect(d.comma);return this.expectRelational(">"),this.state.inType=e,this.finishNode(t,"TypeParameterInstantiation")}flowParseInterfaceType(){const t=this.startNode();if(this.expectContextual("interface"),t.extends=[],this.eat(d._extends))do{t.extends.push(this.flowParseInterfaceExtends())}while(this.eat(d.comma));return t.body=this.flowParseObjectType({allowStatic:!1,allowExact:!1,allowSpread:!1,allowProto:!1,allowInexact:!1}),this.finishNode(t,"InterfaceTypeAnnotation")}flowParseObjectPropertyKey(){return this.match(d.num)||this.match(d.string)?this.parseExprAtom():this.parseIdentifier(!0)}flowParseObjectTypeIndexer(t,e,s){return t.static=e,this.lookahead().type===d.colon?(t.id=this.flowParseObjectPropertyKey(),t.key=this.flowParseTypeInitialiser()):(t.id=null,t.key=this.flowParseType()),this.expect(d.bracketR),t.value=this.flowParseTypeInitialiser(),t.variance=s,this.finishNode(t,"ObjectTypeIndexer")}flowParseObjectTypeInternalSlot(t,e){return t.static=e,t.id=this.flowParseObjectPropertyKey(),this.expect(d.bracketR),this.expect(d.bracketR),this.isRelational("<")||this.match(d.parenL)?(t.method=!0,t.optional=!1,t.value=this.flowParseObjectTypeMethodish(this.startNodeAt(t.start,t.loc.start))):(t.method=!1,this.eat(d.question)&&(t.optional=!0),t.value=this.flowParseTypeInitialiser()),this.finishNode(t,"ObjectTypeInternalSlot")}flowParseObjectTypeMethodish(t){t.params=[],t.rest=null,t.typeParameters=null,this.isRelational("<")&&(t.typeParameters=this.flowParseTypeParameterDeclaration()),this.expect(d.parenL);while(!this.match(d.parenR)&&!this.match(d.ellipsis))t.params.push(this.flowParseFunctionTypeParam()),this.match(d.parenR)||this.expect(d.comma);return this.eat(d.ellipsis)&&(t.rest=this.flowParseFunctionTypeParam()),this.expect(d.parenR),t.returnType=this.flowParseTypeInitialiser(),this.finishNode(t,"FunctionTypeAnnotation")}flowParseObjectTypeCallProperty(t,e){const s=this.startNode();return t.static=e,t.value=this.flowParseObjectTypeMethodish(s),this.finishNode(t,"ObjectTypeCallProperty")}flowParseObjectType({allowStatic:t,allowExact:e,allowSpread:s,allowProto:i,allowInexact:r}){const n=this.state.inType;this.state.inType=!0;const a=this.startNode();let o,c;a.callProperties=[],a.properties=[],a.indexers=[],a.internalSlots=[];let h=!1;e&&this.match(d.braceBarL)?(this.expect(d.braceBarL),o=d.braceBarR,c=!0):(this.expect(d.braceL),o=d.braceR,c=!1),a.exact=c;while(!this.match(o)){let e=!1,n=null,o=null;const l=this.startNode();if(i&&this.isContextual("proto")){const e=this.lookahead();e.type!==d.colon&&e.type!==d.question&&(this.next(),n=this.state.start,t=!1)}if(t&&this.isContextual("static")){const t=this.lookahead();t.type!==d.colon&&t.type!==d.question&&(this.next(),e=!0)}const p=this.flowParseVariance();if(this.eat(d.bracketL))null!=n&&this.unexpected(n),this.eat(d.bracketL)?(p&&this.unexpected(p.start),a.internalSlots.push(this.flowParseObjectTypeInternalSlot(l,e))):a.indexers.push(this.flowParseObjectTypeIndexer(l,e,p));else if(this.match(d.parenL)||this.isRelational("<"))null!=n&&this.unexpected(n),p&&this.unexpected(p.start),a.callProperties.push(this.flowParseObjectTypeCallProperty(l,e));else{let t="init";if(this.isContextual("get")||this.isContextual("set")){const e=this.lookahead();e.type!==d.name&&e.type!==d.string&&e.type!==d.num||(t=this.state.value,this.next())}const i=this.flowParseObjectTypeProperty(l,e,n,p,t,s,null!=r?r:!c);null===i?(h=!0,o=this.state.lastTokStart):a.properties.push(i)}this.flowObjectTypeSemicolon(),!o||this.match(d.braceR)||this.match(d.braceBarR)||this.raise(o,Bt.UnexpectedExplicitInexactInObject)}this.expect(o),s&&(a.inexact=h);const l=this.finishNode(a,"ObjectTypeAnnotation");return this.state.inType=n,l}flowParseObjectTypeProperty(t,e,s,i,r,n,a){if(this.eat(d.ellipsis)){const e=this.match(d.comma)||this.match(d.semi)||this.match(d.braceR)||this.match(d.braceBarR);return e?(n?a||this.raise(this.state.lastTokStart,Bt.InexactInsideExact):this.raise(this.state.lastTokStart,Bt.InexactInsideNonObject),i&&this.raise(i.start,Bt.InexactVariance),null):(n||this.raise(this.state.lastTokStart,Bt.UnexpectedSpreadType),null!=s&&this.unexpected(s),i&&this.raise(i.start,Bt.SpreadVariance),t.argument=this.flowParseType(),this.finishNode(t,"ObjectTypeSpreadProperty"))}{t.key=this.flowParseObjectPropertyKey(),t.static=e,t.proto=null!=s,t.kind=r;let n=!1;return this.isRelational("<")||this.match(d.parenL)?(t.method=!0,null!=s&&this.unexpected(s),i&&this.unexpected(i.start),t.value=this.flowParseObjectTypeMethodish(this.startNodeAt(t.start,t.loc.start)),"get"!==r&&"set"!==r||this.flowCheckGetterSetterParams(t)):("init"!==r&&this.unexpected(),t.method=!1,this.eat(d.question)&&(n=!0),t.value=this.flowParseTypeInitialiser(),t.variance=i),t.optional=n,this.finishNode(t,"ObjectTypeProperty")}}flowCheckGetterSetterParams(t){const e="get"===t.kind?0:1,s=t.start,i=t.value.params.length+(t.value.rest?1:0);i!==e&&("get"===t.kind?this.raise(s,ut.BadGetterArity):this.raise(s,ut.BadSetterArity)),"set"===t.kind&&t.value.rest&&this.raise(s,ut.BadSetterRestParameter)}flowObjectTypeSemicolon(){this.eat(d.semi)||this.eat(d.comma)||this.match(d.braceR)||this.match(d.braceBarR)||this.unexpected()}flowParseQualifiedTypeIdentifier(t,e,s){t=t||this.state.start,e=e||this.state.startLoc;let i=s||this.flowParseRestrictedIdentifier(!0);while(this.eat(d.dot)){const s=this.startNodeAt(t,e);s.qualification=i,s.id=this.flowParseRestrictedIdentifier(!0),i=this.finishNode(s,"QualifiedTypeIdentifier")}return i}flowParseGenericType(t,e,s){const i=this.startNodeAt(t,e);return i.typeParameters=null,i.id=this.flowParseQualifiedTypeIdentifier(t,e,s),this.isRelational("<")&&(i.typeParameters=this.flowParseTypeParameterInstantiation()),this.finishNode(i,"GenericTypeAnnotation")}flowParseTypeofType(){const t=this.startNode();return this.expect(d._typeof),t.argument=this.flowParsePrimaryType(),this.finishNode(t,"TypeofTypeAnnotation")}flowParseTupleType(){const t=this.startNode();t.types=[],this.expect(d.bracketL);while(this.state.possuper.parseFunctionBody(t,!0,s)):super.parseFunctionBody(t,!1,s)}parseFunctionBodyAndFinish(t,e,s=!1){if(this.match(d.colon)){const e=this.startNode();[e.typeAnnotation,t.predicate]=this.flowParseTypeAndPredicateInitialiser(),t.returnType=e.typeAnnotation?this.finishNode(e,"TypeAnnotation"):null}super.parseFunctionBodyAndFinish(t,e,s)}parseStatement(t,e){if(this.state.strict&&this.match(d.name)&&"interface"===this.state.value){const t=this.startNode();return this.next(),this.flowParseInterface(t)}if(this.shouldParseEnums()&&this.isContextual("enum")){const t=this.startNode();return this.next(),this.flowParseEnumDeclaration(t)}{const s=super.parseStatement(t,e);return void 0!==this.flowPragma||this.isValidDirective(s)||(this.flowPragma=null),s}}parseExpressionStatement(t,e){if("Identifier"===e.type)if("declare"===e.name){if(this.match(d._class)||this.match(d.name)||this.match(d._function)||this.match(d._var)||this.match(d._export))return this.flowParseDeclare(t)}else if(this.match(d.name)){if("interface"===e.name)return this.flowParseInterface(t);if("type"===e.name)return this.flowParseTypeAlias(t);if("opaque"===e.name)return this.flowParseOpaqueType(t,!1)}return super.parseExpressionStatement(t,e)}shouldParseExportDeclaration(){return this.isContextual("type")||this.isContextual("interface")||this.isContextual("opaque")||this.shouldParseEnums()&&this.isContextual("enum")||super.shouldParseExportDeclaration()}isExportDefaultSpecifier(){return(!this.match(d.name)||!("type"===this.state.value||"interface"===this.state.value||"opaque"===this.state.value||this.shouldParseEnums()&&"enum"===this.state.value))&&super.isExportDefaultSpecifier()}parseExportDefaultExpression(){if(this.shouldParseEnums()&&this.isContextual("enum")){const t=this.startNode();return this.next(),this.flowParseEnumDeclaration(t)}return super.parseExportDefaultExpression()}parseConditional(t,e,s,i,r){if(!this.match(d.question))return t;if(r){const n=this.tryParse(()=>super.parseConditional(t,e,s,i));return n.node?(n.error&&(this.state=n.failState),n.node):(r.start=n.error.pos||this.state.start,t)}this.expect(d.question);const n=this.state.clone(),a=this.state.noArrowAt,o=this.startNodeAt(s,i);let{consequent:c,failed:h}=this.tryParseConditionalConsequent(),[l,p]=this.getArrowLikeExpressions(c);if(h||p.length>0){const t=[...a];if(p.length>0){this.state=n,this.state.noArrowAt=t;for(let e=0;e1&&this.raise(n.start,Bt.AmbiguousConditionalArrow),h&&1===l.length&&(this.state=n,this.state.noArrowAt=t.concat(l[0].start),({consequent:c,failed:h}=this.tryParseConditionalConsequent()))}return this.getArrowLikeExpressions(c,!0),this.state.noArrowAt=a,this.expect(d.colon),o.test=t,o.consequent=c,o.alternate=this.forwardNoArrowParamsConversionAt(o,()=>this.parseMaybeAssign(e,void 0,void 0,void 0)),this.finishNode(o,"ConditionalExpression")}tryParseConditionalConsequent(){this.state.noArrowParamsConversionAt.push(this.state.start);const t=this.parseMaybeAssign(),e=!this.match(d.colon);return this.state.noArrowParamsConversionAt.pop(),{consequent:t,failed:e}}getArrowLikeExpressions(t,e){const s=[t],i=[];while(0!==s.length){const t=s.pop();"ArrowFunctionExpression"===t.type?(t.typeParameters||!t.returnType?this.finishArrowValidation(t):i.push(t),s.push(t.body)):"ConditionalExpression"===t.type&&(s.push(t.consequent),s.push(t.alternate))}return e?(i.forEach(t=>this.finishArrowValidation(t)),[i,[]]):zt(i,t=>t.params.every(t=>this.isAssignable(t,!0)))}finishArrowValidation(t){var e;this.toAssignableList(t.params,null==(e=t.extra)?void 0:e.trailingComma),this.scope.enter(y|g),super.checkParams(t,!1,!0),this.scope.exit()}forwardNoArrowParamsConversionAt(t,e){let s;return-1!==this.state.noArrowParamsConversionAt.indexOf(t.start)?(this.state.noArrowParamsConversionAt.push(this.state.start),s=e(),this.state.noArrowParamsConversionAt.pop()):s=e(),s}parseParenItem(t,e,s){if(t=super.parseParenItem(t,e,s),this.eat(d.question)&&(t.optional=!0,this.resetEndLocation(t)),this.match(d.colon)){const i=this.startNodeAt(e,s);return i.expression=t,i.typeAnnotation=this.flowParseTypeAnnotation(),this.finishNode(i,"TypeCastExpression")}return t}assertModuleNodeAllowed(t){"ImportDeclaration"===t.type&&("type"===t.importKind||"typeof"===t.importKind)||"ExportNamedDeclaration"===t.type&&"type"===t.exportKind||"ExportAllDeclaration"===t.type&&"type"===t.exportKind||super.assertModuleNodeAllowed(t)}parseExport(t){const e=super.parseExport(t);return"ExportNamedDeclaration"!==e.type&&"ExportAllDeclaration"!==e.type||(e.exportKind=e.exportKind||"value"),e}parseExportDeclaration(t){if(this.isContextual("type")){t.exportKind="type";const e=this.startNode();return this.next(),this.match(d.braceL)?(t.specifiers=this.parseExportSpecifiers(),this.parseExportFrom(t),null):this.flowParseTypeAlias(e)}if(this.isContextual("opaque")){t.exportKind="type";const e=this.startNode();return this.next(),this.flowParseOpaqueType(e,!1)}if(this.isContextual("interface")){t.exportKind="type";const e=this.startNode();return this.next(),this.flowParseInterface(e)}if(this.shouldParseEnums()&&this.isContextual("enum")){t.exportKind="value";const e=this.startNode();return this.next(),this.flowParseEnumDeclaration(e)}return super.parseExportDeclaration(t)}eatExportStar(t){return!!super.eatExportStar(...arguments)||!(!this.isContextual("type")||this.lookahead().type!==d.star)&&(t.exportKind="type",this.next(),this.next(),!0)}maybeParseExportNamespaceSpecifier(t){const e=this.state.start,s=super.maybeParseExportNamespaceSpecifier(t);return s&&"type"===t.exportKind&&this.unexpected(e),s}parseClassId(t,e,s){super.parseClassId(t,e,s),this.isRelational("<")&&(t.typeParameters=this.flowParseTypeParameterDeclaration())}parseClassMember(t,e,s,i){const r=this.state.start;if(this.isContextual("declare")){if(this.parseClassMemberFromModifier(t,e))return;e.declare=!0}super.parseClassMember(t,e,s,i),e.declare&&("ClassProperty"!==e.type&&"ClassPrivateProperty"!==e.type?this.raise(r,Bt.DeclareClassElement):e.value&&this.raise(e.value.start,Bt.DeclareClassFieldInitializer))}getTokenFromCode(t){const e=this.input.charCodeAt(this.state.pos+1);return 123===t&&124===e?this.finishOp(d.braceBarL,2):!this.state.inType||62!==t&&60!==t?jt(t,e)?(this.state.isIterator=!0,super.readWord()):super.getTokenFromCode(t):this.finishOp(d.relational,1)}isAssignable(t,e){switch(t.type){case"Identifier":case"ObjectPattern":case"ArrayPattern":case"AssignmentPattern":return!0;case"ObjectExpression":{const e=t.properties.length-1;return t.properties.every((t,s)=>"ObjectMethod"!==t.type&&(s===e||"SpreadElement"===t.type)&&this.isAssignable(t))}case"ObjectProperty":return this.isAssignable(t.value);case"SpreadElement":return this.isAssignable(t.argument);case"ArrayExpression":return t.elements.every(t=>this.isAssignable(t));case"AssignmentExpression":return"="===t.operator;case"ParenthesizedExpression":case"TypeCastExpression":return this.isAssignable(t.expression);case"MemberExpression":case"OptionalMemberExpression":return!e;default:return!1}}toAssignable(t){return"TypeCastExpression"===t.type?super.toAssignable(this.typeCastToParameter(t)):super.toAssignable(t)}toAssignableList(t,e){for(let s=0;s1||!e)&&this.raise(r.typeAnnotation.start,Bt.TypeCastInPattern)}return t}checkLVal(t,e=V,s,i){if("TypeCastExpression"!==t.type)return super.checkLVal(t,e,s,i)}parseClassProperty(t){return this.match(d.colon)&&(t.typeAnnotation=this.flowParseTypeAnnotation()),super.parseClassProperty(t)}parseClassPrivateProperty(t){return this.match(d.colon)&&(t.typeAnnotation=this.flowParseTypeAnnotation()),super.parseClassPrivateProperty(t)}isClassMethod(){return this.isRelational("<")||super.isClassMethod()}isClassProperty(){return this.match(d.colon)||super.isClassProperty()}isNonstaticConstructor(t){return!this.match(d.colon)&&super.isNonstaticConstructor(t)}pushClassMethod(t,e,s,i,r,n){e.variance&&this.unexpected(e.variance.start),delete e.variance,this.isRelational("<")&&(e.typeParameters=this.flowParseTypeParameterDeclaration()),super.pushClassMethod(t,e,s,i,r,n)}pushClassPrivateMethod(t,e,s,i){e.variance&&this.unexpected(e.variance.start),delete e.variance,this.isRelational("<")&&(e.typeParameters=this.flowParseTypeParameterDeclaration()),super.pushClassPrivateMethod(t,e,s,i)}parseClassSuper(t){if(super.parseClassSuper(t),t.superClass&&this.isRelational("<")&&(t.superTypeParameters=this.flowParseTypeParameterInstantiation()),this.isContextual("implements")){this.next();const e=t.implements=[];do{const t=this.startNode();t.id=this.flowParseRestrictedIdentifier(!0),this.isRelational("<")?t.typeParameters=this.flowParseTypeParameterInstantiation():t.typeParameters=null,e.push(this.finishNode(t,"ClassImplements"))}while(this.eat(d.comma))}}parsePropertyName(t,e){const s=this.flowParseVariance(),i=super.parsePropertyName(t,e);return t.variance=s,i}parseObjPropValue(t,e,s,i,r,n,a,o){let c;t.variance&&this.unexpected(t.variance.start),delete t.variance,this.isRelational("<")&&(c=this.flowParseTypeParameterDeclaration(),this.match(d.parenL)||this.unexpected()),super.parseObjPropValue(t,e,s,i,r,n,a,o),c&&((t.value||t).typeParameters=c)}parseAssignableListItemTypes(t){return this.eat(d.question)&&("Identifier"!==t.type&&this.raise(t.start,Bt.OptionalBindingPattern),t.optional=!0),this.match(d.colon)&&(t.typeAnnotation=this.flowParseTypeAnnotation()),this.resetEndLocation(t),t}parseMaybeDefault(t,e,s){const i=super.parseMaybeDefault(t,e,s);return"AssignmentPattern"===i.type&&i.typeAnnotation&&i.right.startsuper.parseMaybeAssign(t,e,s,i),a),!n.error)return n.node;const{context:r}=this.state;r[r.length-1]===gt.j_oTag?r.length-=2:r[r.length-1]===gt.j_expr&&(r.length-=1)}if((null==(r=n)?void 0:r.error)||this.isRelational("<")){var o,c,h;let r;a=a||this.state.clone();const l=this.tryParse(()=>{r=this.flowParseTypeParameterDeclaration();const n=this.forwardNoArrowParamsConversionAt(r,()=>super.parseMaybeAssign(t,e,s,i));return n.typeParameters=r,this.resetStartLocationFromNode(n,r),n},a),p="ArrowFunctionExpression"===(null==(o=l.node)?void 0:o.type)?l.node:null;if(!l.error&&p)return p;if(null==(c=n)?void 0:c.node)return this.state=n.failState,n.node;if(p)return this.state=l.failState,p;if(null==(h=n)?void 0:h.thrown)throw n.error;if(l.thrown)throw l.error;throw this.raise(r.start,Bt.UnexpectedTokenAfterTypeParameter)}return super.parseMaybeAssign(t,e,s,i)}parseArrow(t){if(this.match(d.colon)){const e=this.tryParse(()=>{const e=this.state.noAnonFunctionType;this.state.noAnonFunctionType=!0;const s=this.startNode();return[s.typeAnnotation,t.predicate]=this.flowParseTypeAndPredicateInitialiser(),this.state.noAnonFunctionType=e,this.canInsertSemicolon()&&this.unexpected(),this.match(d.arrow)||this.unexpected(),s});if(e.thrown)return null;e.error&&(this.state=e.failState),t.returnType=e.node.typeAnnotation?this.finishNode(e.node,"TypeAnnotation"):null}return super.parseArrow(t)}shouldParseArrow(){return this.match(d.colon)||super.shouldParseArrow()}setArrowFunctionParameters(t,e){-1!==this.state.noArrowParamsConversionAt.indexOf(t.start)?t.params=e:super.setArrowFunctionParameters(t,e)}checkParams(t,e,s){if(!s||-1===this.state.noArrowParamsConversionAt.indexOf(t.start))return super.checkParams(...arguments)}parseParenAndDistinguishExpression(t){return super.parseParenAndDistinguishExpression(t&&-1===this.state.noArrowAt.indexOf(this.state.start))}parseSubscripts(t,e,s,i){if("Identifier"===t.type&&"async"===t.name&&-1!==this.state.noArrowAt.indexOf(e)){this.next();const i=this.startNodeAt(e,s);i.callee=t,i.arguments=this.parseCallExpressionArguments(d.parenR,!1),t=this.finishNode(i,"CallExpression")}else if("Identifier"===t.type&&"async"===t.name&&this.isRelational("<")){const r=this.state.clone(),n=this.tryParse(t=>this.parseAsyncArrowWithTypeParameters(e,s)||t(),r);if(!n.error&&!n.aborted)return n.node;const a=this.tryParse(()=>super.parseSubscripts(t,e,s,i),r);if(a.node&&!a.error)return a.node;if(n.node)return this.state=n.failState,n.node;if(a.node)return this.state=a.failState,a.node;throw n.error||a.error}return super.parseSubscripts(t,e,s,i)}parseSubscript(t,e,s,i,r){if(this.match(d.questionDot)&&this.isLookaheadRelational("<")){if(r.optionalChainMember=!0,i)return r.stop=!0,t;this.next();const n=this.startNodeAt(e,s);return n.callee=t,n.typeArguments=this.flowParseTypeParameterInstantiation(),this.expect(d.parenL),n.arguments=this.parseCallExpressionArguments(d.parenR,!1),n.optional=!0,this.finishCallExpression(n,!0)}if(!i&&this.shouldParseTypes()&&this.isRelational("<")){const i=this.startNodeAt(e,s);i.callee=t;const n=this.tryParse(()=>(i.typeArguments=this.flowParseTypeParameterInstantiationCallOrNew(),this.expect(d.parenL),i.arguments=this.parseCallExpressionArguments(d.parenR,!1),r.optionalChainMember&&(i.optional=!1),this.finishCallExpression(i,r.optionalChainMember)));if(n.node)return n.error&&(this.state=n.failState),n.node}return super.parseSubscript(t,e,s,i,r)}parseNewArguments(t){let e=null;this.shouldParseTypes()&&this.isRelational("<")&&(e=this.tryParse(()=>this.flowParseTypeParameterInstantiationCallOrNew()).node),t.typeArguments=e,super.parseNewArguments(t)}parseAsyncArrowWithTypeParameters(t,e){const s=this.startNodeAt(t,e);if(this.parseFunctionParams(s),this.parseArrow(s))return this.parseArrowExpression(s,void 0,!0)}readToken_mult_modulo(t){const e=this.input.charCodeAt(this.state.pos+1);if(42===t&&47===e&&this.state.hasFlowComment)return this.state.hasFlowComment=!1,this.state.pos+=2,void this.nextToken();super.readToken_mult_modulo(t)}readToken_pipe_amp(t){const e=this.input.charCodeAt(this.state.pos+1);124!==t||125!==e?super.readToken_pipe_amp(t):this.finishOp(d.braceBarR,2)}parseTopLevel(t,e){const s=super.parseTopLevel(t,e);return this.state.hasFlowComment&&this.raise(this.state.pos,Bt.UnterminatedFlowComment),s}skipBlockComment(){if(this.hasPlugin("flowComments")&&this.skipFlowComment())return this.state.hasFlowComment&&this.unexpected(null,Bt.NestedFlowComment),this.hasFlowCommentCompletion(),this.state.pos+=this.skipFlowComment(),void(this.state.hasFlowComment=!0);if(this.state.hasFlowComment){const t=this.input.indexOf("*-/",this.state.pos+=2);if(-1===t)throw this.raise(this.state.pos-2,ut.UnterminatedComment);this.state.pos=t+3}else super.skipBlockComment()}skipFlowComment(){const{pos:t}=this.state;let e=2;while([32,9].includes(this.input.charCodeAt(t+e)))e++;const s=this.input.charCodeAt(e+t),i=this.input.charCodeAt(e+t+1);return 58===s&&58===i?e+2:"flow-include"===this.input.slice(e+t,e+t+12)?e+12:58===s&&58!==i&&e}hasFlowCommentCompletion(){const t=this.input.indexOf("*/",this.state.pos);if(-1===t)throw this.raise(this.state.pos,ut.UnterminatedComment)}flowEnumErrorBooleanMemberNotInitialized(t,{enumName:e,memberName:s}){this.raise(t,Bt.EnumBooleanMemberNotInitialized,s,e)}flowEnumErrorInvalidMemberName(t,{enumName:e,memberName:s}){const i=s[0].toUpperCase()+s.slice(1);this.raise(t,Bt.EnumInvalidMemberName,s,i,e)}flowEnumErrorDuplicateMemberName(t,{enumName:e,memberName:s}){this.raise(t,Bt.EnumDuplicateMemberName,s,e)}flowEnumErrorInconsistentMemberValues(t,{enumName:e}){this.raise(t,Bt.EnumInconsistentMemberValues,e)}flowEnumErrorInvalidExplicitType(t,{enumName:e,suppliedType:s}){return this.raise(t,null===s?Bt.EnumInvalidExplicitTypeUnknownSupplied:Bt.EnumInvalidExplicitType,e,s)}flowEnumErrorInvalidMemberInitializer(t,{enumName:e,explicitType:s,memberName:i}){let r=null;switch(s){case"boolean":case"number":case"string":r=Bt.EnumInvalidMemberInitializerPrimaryType;break;case"symbol":r=Bt.EnumInvalidMemberInitializerSymbolType;break;default:r=Bt.EnumInvalidMemberInitializerUnknownType}return this.raise(t,r,e,i,s)}flowEnumErrorNumberMemberNotInitialized(t,{enumName:e,memberName:s}){this.raise(t,Bt.EnumNumberMemberNotInitialized,e,s)}flowEnumErrorStringMemberInconsistentlyInitailized(t,{enumName:e}){this.raise(t,Bt.EnumStringMemberInconsistentlyInitailized,e)}flowEnumMemberInit(){const t=this.state.start,e=()=>this.match(d.comma)||this.match(d.braceR);switch(this.state.type){case d.num:{const s=this.parseLiteral(this.state.value,"NumericLiteral");return e()?{type:"number",pos:s.start,value:s}:{type:"invalid",pos:t}}case d.string:{const s=this.parseLiteral(this.state.value,"StringLiteral");return e()?{type:"string",pos:s.start,value:s}:{type:"invalid",pos:t}}case d._true:case d._false:{const s=this.parseBooleanLiteral();return e()?{type:"boolean",pos:s.start,value:s}:{type:"invalid",pos:t}}default:return{type:"invalid",pos:t}}}flowEnumMemberRaw(){const t=this.state.start,e=this.parseIdentifier(!0),s=this.eat(d.eq)?this.flowEnumMemberInit():{type:"none",pos:t};return{id:e,init:s}}flowEnumCheckExplicitTypeMismatch(t,e,s){const{explicitType:i}=e;null!==i&&i!==s&&this.flowEnumErrorInvalidMemberInitializer(t,e)}flowEnumMembers({enumName:t,explicitType:e}){const s=new Set,i={booleanMembers:[],numberMembers:[],stringMembers:[],defaultedMembers:[]};while(!this.match(d.braceR)){const r=this.startNode(),{id:n,init:a}=this.flowEnumMemberRaw(),o=n.name;if(""===o)continue;/^[a-z]/.test(o)&&this.flowEnumErrorInvalidMemberName(n.start,{enumName:t,memberName:o}),s.has(o)&&this.flowEnumErrorDuplicateMemberName(n.start,{enumName:t,memberName:o}),s.add(o);const c={enumName:t,explicitType:e,memberName:o};switch(r.id=n,a.type){case"boolean":this.flowEnumCheckExplicitTypeMismatch(a.pos,c,"boolean"),r.init=a.value,i.booleanMembers.push(this.finishNode(r,"EnumBooleanMember"));break;case"number":this.flowEnumCheckExplicitTypeMismatch(a.pos,c,"number"),r.init=a.value,i.numberMembers.push(this.finishNode(r,"EnumNumberMember"));break;case"string":this.flowEnumCheckExplicitTypeMismatch(a.pos,c,"string"),r.init=a.value,i.stringMembers.push(this.finishNode(r,"EnumStringMember"));break;case"invalid":throw this.flowEnumErrorInvalidMemberInitializer(a.pos,c);case"none":switch(e){case"boolean":this.flowEnumErrorBooleanMemberNotInitialized(a.pos,c);break;case"number":this.flowEnumErrorNumberMemberNotInitialized(a.pos,c);break;default:i.defaultedMembers.push(this.finishNode(r,"EnumDefaultedMember"))}}this.match(d.braceR)||this.expect(d.comma)}return i}flowEnumStringMembers(t,e,{enumName:s}){if(0===t.length)return e;if(0===e.length)return t;if(e.length>t.length){for(let e=0;e(t.members=[],this.expect(d.braceR),this.finishNode(t,"EnumStringBody"));t.explicitType=!1;const n=r.booleanMembers.length,a=r.numberMembers.length,o=r.stringMembers.length,c=r.defaultedMembers.length;if(n||a||o||c){if(n||a){if(!a&&!o&&n>=c){for(let t=0,s=r.defaultedMembers;t=c){for(let t=0,s=r.defaultedMembers;t",nbsp:" ",iexcl:"¡",cent:"¢",pound:"£",curren:"¤",yen:"¥",brvbar:"¦",sect:"§",uml:"¨",copy:"©",ordf:"ª",laquo:"«",not:"¬",shy:"­",reg:"®",macr:"¯",deg:"°",plusmn:"±",sup2:"²",sup3:"³",acute:"´",micro:"µ",para:"¶",middot:"·",cedil:"¸",sup1:"¹",ordm:"º",raquo:"»",frac14:"¼",frac12:"½",frac34:"¾",iquest:"¿",Agrave:"À",Aacute:"Á",Acirc:"Â",Atilde:"Ã",Auml:"Ä",Aring:"Å",AElig:"Æ",Ccedil:"Ç",Egrave:"È",Eacute:"É",Ecirc:"Ê",Euml:"Ë",Igrave:"Ì",Iacute:"Í",Icirc:"Î",Iuml:"Ï",ETH:"Ð",Ntilde:"Ñ",Ograve:"Ò",Oacute:"Ó",Ocirc:"Ô",Otilde:"Õ",Ouml:"Ö",times:"×",Oslash:"Ø",Ugrave:"Ù",Uacute:"Ú",Ucirc:"Û",Uuml:"Ü",Yacute:"Ý",THORN:"Þ",szlig:"ß",agrave:"à",aacute:"á",acirc:"â",atilde:"ã",auml:"ä",aring:"å",aelig:"æ",ccedil:"ç",egrave:"è",eacute:"é",ecirc:"ê",euml:"ë",igrave:"ì",iacute:"í",icirc:"î",iuml:"ï",eth:"ð",ntilde:"ñ",ograve:"ò",oacute:"ó",ocirc:"ô",otilde:"õ",ouml:"ö",divide:"÷",oslash:"ø",ugrave:"ù",uacute:"ú",ucirc:"û",uuml:"ü",yacute:"ý",thorn:"þ",yuml:"ÿ",OElig:"Œ",oelig:"œ",Scaron:"Š",scaron:"š",Yuml:"Ÿ",fnof:"ƒ",circ:"ˆ",tilde:"˜",Alpha:"Α",Beta:"Β",Gamma:"Γ",Delta:"Δ",Epsilon:"Ε",Zeta:"Ζ",Eta:"Η",Theta:"Θ",Iota:"Ι",Kappa:"Κ",Lambda:"Λ",Mu:"Μ",Nu:"Ν",Xi:"Ξ",Omicron:"Ο",Pi:"Π",Rho:"Ρ",Sigma:"Σ",Tau:"Τ",Upsilon:"Υ",Phi:"Φ",Chi:"Χ",Psi:"Ψ",Omega:"Ω",alpha:"α",beta:"β",gamma:"γ",delta:"δ",epsilon:"ε",zeta:"ζ",eta:"η",theta:"θ",iota:"ι",kappa:"κ",lambda:"λ",mu:"μ",nu:"ν",xi:"ξ",omicron:"ο",pi:"π",rho:"ρ",sigmaf:"ς",sigma:"σ",tau:"τ",upsilon:"υ",phi:"φ",chi:"χ",psi:"ψ",omega:"ω",thetasym:"ϑ",upsih:"ϒ",piv:"ϖ",ensp:" ",emsp:" ",thinsp:" ",zwnj:"‌",zwj:"‍",lrm:"‎",rlm:"‏",ndash:"–",mdash:"—",lsquo:"‘",rsquo:"’",sbquo:"‚",ldquo:"“",rdquo:"”",bdquo:"„",dagger:"†",Dagger:"‡",bull:"•",hellip:"…",permil:"‰",prime:"′",Prime:"″",lsaquo:"‹",rsaquo:"›",oline:"‾",frasl:"⁄",euro:"€",image:"ℑ",weierp:"℘",real:"ℜ",trade:"™",alefsym:"ℵ",larr:"←",uarr:"↑",rarr:"→",darr:"↓",harr:"↔",crarr:"↵",lArr:"⇐",uArr:"⇑",rArr:"⇒",dArr:"⇓",hArr:"⇔",forall:"∀",part:"∂",exist:"∃",empty:"∅",nabla:"∇",isin:"∈",notin:"∉",ni:"∋",prod:"∏",sum:"∑",minus:"−",lowast:"∗",radic:"√",prop:"∝",infin:"∞",ang:"∠",and:"∧",or:"∨",cap:"∩",cup:"∪",int:"∫",there4:"∴",sim:"∼",cong:"≅",asymp:"≈",ne:"≠",equiv:"≡",le:"≤",ge:"≥",sub:"⊂",sup:"⊃",nsub:"⊄",sube:"⊆",supe:"⊇",oplus:"⊕",otimes:"⊗",perp:"⊥",sdot:"⋅",lceil:"⌈",rceil:"⌉",lfloor:"⌊",rfloor:"⌋",lang:"〈",rang:"〉",loz:"◊",spades:"♠",clubs:"♣",hearts:"♥",diams:"♦"},Xt=/^[\da-fA-F]+$/,Gt=/^\d+$/,Yt=Object.freeze({AttributeIsEmpty:"JSX attributes must only be assigned a non-empty expression",MissingClosingTagFragment:"Expected corresponding JSX closing tag for <>",MissingClosingTagElement:"Expected corresponding JSX closing tag for <%0>",UnsupportedJsxValue:"JSX value should be either an expression or a quoted JSX text",UnterminatedJsxContent:"Unterminated JSX contents",UnwrappedAdjacentJSXElements:"Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...?"});function Jt(t){return!!t&&("JSXOpeningFragment"===t.type||"JSXClosingFragment"===t.type)}function Qt(t){if("JSXIdentifier"===t.type)return t.name;if("JSXNamespacedName"===t.type)return t.namespace.name+":"+t.name.name;if("JSXMemberExpression"===t.type)return Qt(t.object)+"."+Qt(t.property);throw new Error("Node had unexpected type: "+t.type)}gt.j_oTag=new yt("...",!0,!0),d.jsxName=new h("jsxName"),d.jsxText=new h("jsxText",{beforeExpr:!0}),d.jsxTagStart=new h("jsxTagStart",{startsExpr:!0}),d.jsxTagEnd=new h("jsxTagEnd"),d.jsxTagStart.updateContext=function(){this.state.context.push(gt.j_expr),this.state.context.push(gt.j_oTag),this.state.exprAllowed=!1},d.jsxTagEnd.updateContext=function(t){const e=this.state.context.pop();e===gt.j_oTag&&t===d.slash||e===gt.j_cTag?(this.state.context.pop(),this.state.exprAllowed=this.curContext()===gt.j_expr):this.state.exprAllowed=!0};var Zt=t=>class extends t{jsxReadToken(){let t="",e=this.state.pos;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,Yt.UnterminatedJsxContent);const s=this.input.charCodeAt(this.state.pos);switch(s){case 60:case 123:return this.state.pos===this.state.start?60===s&&this.state.exprAllowed?(++this.state.pos,this.finishToken(d.jsxTagStart)):super.getTokenFromCode(s):(t+=this.input.slice(e,this.state.pos),this.finishToken(d.jsxText,t));case 38:t+=this.input.slice(e,this.state.pos),t+=this.jsxReadEntity(),e=this.state.pos;break;default:it(s)?(t+=this.input.slice(e,this.state.pos),t+=this.jsxReadNewLine(!0),e=this.state.pos):++this.state.pos}}}jsxReadNewLine(t){const e=this.input.charCodeAt(this.state.pos);let s;return++this.state.pos,13===e&&10===this.input.charCodeAt(this.state.pos)?(++this.state.pos,s=t?"\n":"\r\n"):s=String.fromCharCode(e),++this.state.curLine,this.state.lineStart=this.state.pos,s}jsxReadString(t){let e="",s=++this.state.pos;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,ut.UnterminatedString);const i=this.input.charCodeAt(this.state.pos);if(i===t)break;38===i?(e+=this.input.slice(s,this.state.pos),e+=this.jsxReadEntity(),s=this.state.pos):it(i)?(e+=this.input.slice(s,this.state.pos),e+=this.jsxReadNewLine(!1),s=this.state.pos):++this.state.pos}return e+=this.input.slice(s,this.state.pos++),this.finishToken(d.string,e)}jsxReadEntity(){let t,e="",s=0,i=this.input[this.state.pos];const r=++this.state.pos;while(this.state.pos0}get allowSuper(){return(this.currentThisScope().flags&b)>0}get allowDirectSuper(){return(this.currentThisScope().flags&v)>0}get inClass(){return(this.currentThisScope().flags&w)>0}get inNonArrowFunction(){return(this.currentThisScope().flags&y)>0}get treatFunctionsAsVar(){return this.treatFunctionsAsVarInScope(this.currentScope())}createScope(t){return new te(t)}enter(t){this.scopeStack.push(this.createScope(t))}exit(){this.scopeStack.pop()}treatFunctionsAsVarInScope(t){return!!(t.flags&y||!this.inModule&&t.flags&m)}declareName(t,e,s){let i=this.currentScope();if(e&C||e&k)this.checkRedeclarationInScope(i,t,e,s),e&k?i.functions.push(t):i.lexical.push(t),e&C&&this.maybeExportDefined(i,t);else if(e&S)for(let r=this.scopeStack.length-1;r>=0;--r)if(i=this.scopeStack[r],this.checkRedeclarationInScope(i,t,e,s),i.var.push(t),this.maybeExportDefined(i,t),i.flags&T)break;this.inModule&&i.flags&m&&this.undefinedExports.delete(t)}maybeExportDefined(t,e){this.inModule&&t.flags&m&&this.undefinedExports.delete(e)}checkRedeclarationInScope(t,e,s,i){this.isRedeclaredInScope(t,e,s)&&this.raise(i,ut.VarRedeclaration,e)}isRedeclaredInScope(t,e,s){return!!(s&E)&&(s&C?t.lexical.indexOf(e)>-1||t.functions.indexOf(e)>-1||t.var.indexOf(e)>-1:s&k?t.lexical.indexOf(e)>-1||!this.treatFunctionsAsVarInScope(t)&&t.var.indexOf(e)>-1:t.lexical.indexOf(e)>-1&&!(t.flags&x&&t.lexical[0]===e)||!this.treatFunctionsAsVarInScope(t)&&t.functions.indexOf(e)>-1)}checkLocalExport(t){-1===this.scopeStack[0].lexical.indexOf(t.name)&&-1===this.scopeStack[0].var.indexOf(t.name)&&-1===this.scopeStack[0].functions.indexOf(t.name)&&this.undefinedExports.set(t.name,t.start)}currentScope(){return this.scopeStack[this.scopeStack.length-1]}currentVarScope(){for(let t=this.scopeStack.length-1;;t--){const e=this.scopeStack[t];if(e.flags&T)return e}}currentThisScope(){for(let t=this.scopeStack.length-1;;t--){const e=this.scopeStack[t];if((e.flags&T||e.flags&w)&&!(e.flags&g))return e}}}class se extends te{constructor(...t){super(...t),this.types=[],this.enums=[],this.constEnums=[],this.classes=[],this.exportOnlyBindings=[]}}class ie extends ee{createScope(t){return new se(t)}declareName(t,e,s){const i=this.currentScope();if(e&M)return this.maybeExportDefined(i,t),void i.exportOnlyBindings.push(t);super.declareName(...arguments),e&A&&(e&E||(this.checkRedeclarationInScope(i,t,e,s),this.maybeExportDefined(i,t)),i.types.push(t)),e&O&&i.enums.push(t),e&D&&i.constEnums.push(t),e&I&&i.classes.push(t)}isRedeclaredInScope(t,e,s){if(t.enums.indexOf(e)>-1){if(s&O){const i=!!(s&D),r=t.constEnums.indexOf(e)>-1;return i!==r}return!0}return s&I&&t.classes.indexOf(e)>-1?t.lexical.indexOf(e)>-1&&!!(s&E):!!(s&A&&t.types.indexOf(e)>-1)||super.isRedeclaredInScope(...arguments)}checkLocalExport(t){-1===this.scopeStack[0].types.indexOf(t.name)&&-1===this.scopeStack[0].exportOnlyBindings.indexOf(t.name)&&super.checkLocalExport(t)}}const re=0,ne=1,ae=2,oe=4;class ce{constructor(){this.stacks=[]}enter(t){this.stacks.push(t)}exit(){this.stacks.pop()}currentFlags(){return this.stacks[this.stacks.length-1]}get hasAwait(){return(this.currentFlags()&ae)>0}get hasYield(){return(this.currentFlags()&ne)>0}get hasReturn(){return(this.currentFlags()&oe)>0}}function he(t,e){return(t?ae:0)|(e?ne:0)}function le(t){if(null==t)throw new Error(`Unexpected ${t} value.`);return t}function pe(t){if(!t)throw new Error("Assert fail")}const ue=Object.freeze({ClassMethodHasDeclare:"Class methods cannot have the 'declare' modifier",ClassMethodHasReadonly:"Class methods cannot have the 'readonly' modifier",DeclareClassFieldHasInitializer:"'declare' class fields cannot have an initializer",DuplicateModifier:"Duplicate modifier: '%0'",EmptyHeritageClauseType:"'%0' list cannot be empty.",IndexSignatureHasAbstract:"Index signatures cannot have the 'abstract' modifier",IndexSignatureHasAccessibility:"Index signatures cannot have an accessibility modifier ('%0')",IndexSignatureHasStatic:"Index signatures cannot have the 'static' modifier",OptionalTypeBeforeRequired:"A required element cannot follow an optional element.",PatternIsOptional:"A binding pattern parameter cannot be optional in an implementation signature.",PrivateElementHasAbstract:"Private elements cannot have the 'abstract' modifier.",PrivateElementHasAccessibility:"Private elements cannot have an accessibility modifier ('%0')",TemplateTypeHasSubstitution:"Template literal types cannot have any substitution",TypeAnnotationAfterAssign:"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`",UnexpectedReadonly:"'readonly' type modifier is only permitted on array and tuple literal types.",UnexpectedTypeAnnotation:"Did not expect a type annotation here.",UnexpectedTypeCastInParameter:"Unexpected type cast in parameter position.",UnsupportedImportTypeArgument:"Argument in a type import must be a string literal",UnsupportedParameterPropertyKind:"A parameter property may not be declared using a binding pattern.",UnsupportedSignatureParameterKind:"Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got %0"});function de(t){switch(t){case"any":return"TSAnyKeyword";case"boolean":return"TSBooleanKeyword";case"bigint":return"TSBigIntKeyword";case"never":return"TSNeverKeyword";case"number":return"TSNumberKeyword";case"object":return"TSObjectKeyword";case"string":return"TSStringKeyword";case"symbol":return"TSSymbolKeyword";case"undefined":return"TSUndefinedKeyword";case"unknown":return"TSUnknownKeyword";default:return}}var fe=t=>class extends t{getScopeHandler(){return ie}tsIsIdentifier(){return this.match(d.name)}tsNextTokenCanFollowModifier(){return this.next(),!this.hasPrecedingLineBreak()&&!this.match(d.parenL)&&!this.match(d.parenR)&&!this.match(d.colon)&&!this.match(d.eq)&&!this.match(d.question)&&!this.match(d.bang)}tsParseModifier(t){if(!this.match(d.name))return;const e=this.state.value;return-1!==t.indexOf(e)&&this.tsTryParse(this.tsNextTokenCanFollowModifier.bind(this))?e:void 0}tsParseModifiers(t,e){for(;;){const s=this.state.start,i=this.tsParseModifier(e);if(!i)break;Object.hasOwnProperty.call(t,i)&&this.raise(s,ue.DuplicateModifier,i),t[i]=!0}}tsIsListTerminator(t){switch(t){case"EnumMembers":case"TypeMembers":return this.match(d.braceR);case"HeritageClauseElement":return this.match(d.braceL);case"TupleElementTypes":return this.match(d.bracketR);case"TypeParametersOrArguments":return this.isRelational(">")}throw new Error("Unreachable")}tsParseList(t,e){const s=[];while(!this.tsIsListTerminator(t))s.push(e());return s}tsParseDelimitedList(t,e){return le(this.tsParseDelimitedListWorker(t,e,!0))}tsParseDelimitedListWorker(t,e,s){const i=[];for(;;){if(this.tsIsListTerminator(t))break;const r=e();if(null==r)return;if(i.push(r),!this.eat(d.comma)){if(this.tsIsListTerminator(t))break;return void(s&&this.expect(d.comma))}}return i}tsParseBracketedList(t,e,s,i){i||(s?this.expect(d.bracketL):this.expectRelational("<"));const r=this.tsParseDelimitedList(t,e);return s?this.expect(d.bracketR):this.expectRelational(">"),r}tsParseImportType(){const t=this.startNode();return this.expect(d._import),this.expect(d.parenL),this.match(d.string)||this.raise(this.state.start,ue.UnsupportedImportTypeArgument),t.argument=this.parseExprAtom(),this.expect(d.parenR),this.eat(d.dot)&&(t.qualifier=this.tsParseEntityName(!0)),this.isRelational("<")&&(t.typeParameters=this.tsParseTypeArguments()),this.finishNode(t,"TSImportType")}tsParseEntityName(t){let e=this.parseIdentifier();while(this.eat(d.dot)){const s=this.startNodeAtNode(e);s.left=e,s.right=this.parseIdentifier(t),e=this.finishNode(s,"TSQualifiedName")}return e}tsParseTypeReference(){const t=this.startNode();return t.typeName=this.tsParseEntityName(!1),!this.hasPrecedingLineBreak()&&this.isRelational("<")&&(t.typeParameters=this.tsParseTypeArguments()),this.finishNode(t,"TSTypeReference")}tsParseThisTypePredicate(t){this.next();const e=this.startNodeAtNode(t);return e.parameterName=t,e.typeAnnotation=this.tsParseTypeAnnotation(!1),this.finishNode(e,"TSTypePredicate")}tsParseThisTypeNode(){const t=this.startNode();return this.next(),this.finishNode(t,"TSThisType")}tsParseTypeQuery(){const t=this.startNode();return this.expect(d._typeof),this.match(d._import)?t.exprName=this.tsParseImportType():t.exprName=this.tsParseEntityName(!0),this.finishNode(t,"TSTypeQuery")}tsParseTypeParameter(){const t=this.startNode();return t.name=this.parseIdentifierName(t.start),t.constraint=this.tsEatThenParseType(d._extends),t.default=this.tsEatThenParseType(d.eq),this.finishNode(t,"TSTypeParameter")}tsTryParseTypeParameters(){if(this.isRelational("<"))return this.tsParseTypeParameters()}tsParseTypeParameters(){const t=this.startNode();return this.isRelational("<")||this.match(d.jsxTagStart)?this.next():this.unexpected(),t.params=this.tsParseBracketedList("TypeParametersOrArguments",this.tsParseTypeParameter.bind(this),!1,!0),this.finishNode(t,"TSTypeParameterDeclaration")}tsTryNextParseConstantContext(){return this.lookahead().type===d._const?(this.next(),this.tsParseTypeReference()):null}tsFillSignature(t,e){const s=t===d.arrow;e.typeParameters=this.tsTryParseTypeParameters(),this.expect(d.parenL),e.parameters=this.tsParseBindingListForSignature(),(s||this.match(t))&&(e.typeAnnotation=this.tsParseTypeOrTypePredicateAnnotation(t))}tsParseBindingListForSignature(){return this.parseBindingList(d.parenR,41).map(t=>("Identifier"!==t.type&&"RestElement"!==t.type&&"ObjectPattern"!==t.type&&"ArrayPattern"!==t.type&&this.raise(t.start,ue.UnsupportedSignatureParameterKind,t.type),t))}tsParseTypeMemberSemicolon(){this.eat(d.comma)||this.semicolon()}tsParseSignatureMember(t,e){return this.tsFillSignature(d.colon,e),this.tsParseTypeMemberSemicolon(),this.finishNode(e,t)}tsIsUnambiguouslyIndexSignature(){return this.next(),this.eat(d.name)&&this.match(d.colon)}tsTryParseIndexSignature(t){if(!this.match(d.bracketL)||!this.tsLookAhead(this.tsIsUnambiguouslyIndexSignature.bind(this)))return;this.expect(d.bracketL);const e=this.parseIdentifier();e.typeAnnotation=this.tsParseTypeAnnotation(),this.resetEndLocation(e),this.expect(d.bracketR),t.parameters=[e];const s=this.tsTryParseTypeAnnotation();return s&&(t.typeAnnotation=s),this.tsParseTypeMemberSemicolon(),this.finishNode(t,"TSIndexSignature")}tsParsePropertyOrMethodSignature(t,e){this.eat(d.question)&&(t.optional=!0);const s=t;if(e||!this.match(d.parenL)&&!this.isRelational("<")){const t=s;e&&(t.readonly=!0);const i=this.tsTryParseTypeAnnotation();return i&&(t.typeAnnotation=i),this.tsParseTypeMemberSemicolon(),this.finishNode(t,"TSPropertySignature")}{const t=s;return this.tsFillSignature(d.colon,t),this.tsParseTypeMemberSemicolon(),this.finishNode(t,"TSMethodSignature")}}tsParseTypeMember(){const t=this.startNode();if(this.match(d.parenL)||this.isRelational("<"))return this.tsParseSignatureMember("TSCallSignatureDeclaration",t);if(this.match(d._new)){const e=this.startNode();return this.next(),this.match(d.parenL)||this.isRelational("<")?this.tsParseSignatureMember("TSConstructSignatureDeclaration",t):(t.key=this.createIdentifier(e,"new"),this.tsParsePropertyOrMethodSignature(t,!1))}const e=!!this.tsParseModifier(["readonly"]),s=this.tsTryParseIndexSignature(t);return s?(e&&(t.readonly=!0),s):(this.parsePropertyName(t,!1),this.tsParsePropertyOrMethodSignature(t,e))}tsParseTypeLiteral(){const t=this.startNode();return t.members=this.tsParseObjectTypeMembers(),this.finishNode(t,"TSTypeLiteral")}tsParseObjectTypeMembers(){this.expect(d.braceL);const t=this.tsParseList("TypeMembers",this.tsParseTypeMember.bind(this));return this.expect(d.braceR),t}tsIsStartOfMappedType(){return this.next(),this.eat(d.plusMin)?this.isContextual("readonly"):(this.isContextual("readonly")&&this.next(),!!this.match(d.bracketL)&&(this.next(),!!this.tsIsIdentifier()&&(this.next(),this.match(d._in))))}tsParseMappedTypeParameter(){const t=this.startNode();return t.name=this.parseIdentifierName(t.start),t.constraint=this.tsExpectThenParseType(d._in),this.finishNode(t,"TSTypeParameter")}tsParseMappedType(){const t=this.startNode();return this.expect(d.braceL),this.match(d.plusMin)?(t.readonly=this.state.value,this.next(),this.expectContextual("readonly")):this.eatContextual("readonly")&&(t.readonly=!0),this.expect(d.bracketL),t.typeParameter=this.tsParseMappedTypeParameter(),this.expect(d.bracketR),this.match(d.plusMin)?(t.optional=this.state.value,this.next(),this.expect(d.question)):this.eat(d.question)&&(t.optional=!0),t.typeAnnotation=this.tsTryParseType(),this.semicolon(),this.expect(d.braceR),this.finishNode(t,"TSMappedType")}tsParseTupleType(){const t=this.startNode();t.elementTypes=this.tsParseBracketedList("TupleElementTypes",this.tsParseTupleElementType.bind(this),!0,!1);let e=!1;return t.elementTypes.forEach(t=>{"TSOptionalType"===t.type?e=!0:e&&"TSRestType"!==t.type&&this.raise(t.start,ue.OptionalTypeBeforeRequired)}),this.finishNode(t,"TSTupleType")}tsParseTupleElementType(){if(this.match(d.ellipsis)){const t=this.startNode();return this.next(),t.typeAnnotation=this.tsParseType(),this.match(d.comma)&&93!==this.lookaheadCharCode()&&this.raiseRestNotLast(this.state.start),this.finishNode(t,"TSRestType")}const t=this.tsParseType();if(this.eat(d.question)){const e=this.startNodeAtNode(t);return e.typeAnnotation=t,this.finishNode(e,"TSOptionalType")}return t}tsParseParenthesizedType(){const t=this.startNode();return this.expect(d.parenL),t.typeAnnotation=this.tsParseType(),this.expect(d.parenR),this.finishNode(t,"TSParenthesizedType")}tsParseFunctionOrConstructorType(t){const e=this.startNode();return"TSConstructorType"===t&&this.expect(d._new),this.tsFillSignature(d.arrow,e),this.finishNode(e,t)}tsParseLiteralTypeNode(){const t=this.startNode();return t.literal=(()=>{switch(this.state.type){case d.num:case d.bigint:case d.string:case d._true:case d._false:return this.parseExprAtom();default:throw this.unexpected()}})(),this.finishNode(t,"TSLiteralType")}tsParseTemplateLiteralType(){const t=this.startNode(),e=this.parseTemplate(!1);return e.expressions.length>0&&this.raise(e.expressions[0].start,ue.TemplateTypeHasSubstitution),t.literal=e,this.finishNode(t,"TSLiteralType")}tsParseThisTypeOrThisTypePredicate(){const t=this.tsParseThisTypeNode();return this.isContextual("is")&&!this.hasPrecedingLineBreak()?this.tsParseThisTypePredicate(t):t}tsParseNonArrayType(){switch(this.state.type){case d.name:case d._void:case d._null:{const t=this.match(d._void)?"TSVoidKeyword":this.match(d._null)?"TSNullKeyword":de(this.state.value);if(void 0!==t&&46!==this.lookaheadCharCode()){const e=this.startNode();return this.next(),this.finishNode(e,t)}return this.tsParseTypeReference()}case d.string:case d.num:case d.bigint:case d._true:case d._false:return this.tsParseLiteralTypeNode();case d.plusMin:if("-"===this.state.value){const t=this.startNode(),e=this.lookahead();if(e.type!==d.num&&e.type!==d.bigint)throw this.unexpected();return t.literal=this.parseMaybeUnary(),this.finishNode(t,"TSLiteralType")}break;case d._this:return this.tsParseThisTypeOrThisTypePredicate();case d._typeof:return this.tsParseTypeQuery();case d._import:return this.tsParseImportType();case d.braceL:return this.tsLookAhead(this.tsIsStartOfMappedType.bind(this))?this.tsParseMappedType():this.tsParseTypeLiteral();case d.bracketL:return this.tsParseTupleType();case d.parenL:return this.tsParseParenthesizedType();case d.backQuote:return this.tsParseTemplateLiteralType()}throw this.unexpected()}tsParseArrayTypeOrHigher(){let t=this.tsParseNonArrayType();while(!this.hasPrecedingLineBreak()&&this.eat(d.bracketL))if(this.match(d.bracketR)){const e=this.startNodeAtNode(t);e.elementType=t,this.expect(d.bracketR),t=this.finishNode(e,"TSArrayType")}else{const e=this.startNodeAtNode(t);e.objectType=t,e.indexType=this.tsParseType(),this.expect(d.bracketR),t=this.finishNode(e,"TSIndexedAccessType")}return t}tsParseTypeOperator(t){const e=this.startNode();return this.expectContextual(t),e.operator=t,e.typeAnnotation=this.tsParseTypeOperatorOrHigher(),"readonly"===t&&this.tsCheckTypeAnnotationForReadOnly(e),this.finishNode(e,"TSTypeOperator")}tsCheckTypeAnnotationForReadOnly(t){switch(t.typeAnnotation.type){case"TSTupleType":case"TSArrayType":return;default:this.raise(t.start,ue.UnexpectedReadonly)}}tsParseInferType(){const t=this.startNode();this.expectContextual("infer");const e=this.startNode();return e.name=this.parseIdentifierName(e.start),t.typeParameter=this.finishNode(e,"TSTypeParameter"),this.finishNode(t,"TSInferType")}tsParseTypeOperatorOrHigher(){const t=["keyof","unique","readonly"].find(t=>this.isContextual(t));return t?this.tsParseTypeOperator(t):this.isContextual("infer")?this.tsParseInferType():this.tsParseArrayTypeOrHigher()}tsParseUnionOrIntersectionType(t,e,s){this.eat(s);let i=e();if(this.match(s)){const r=[i];while(this.eat(s))r.push(e());const n=this.startNodeAtNode(i);n.types=r,i=this.finishNode(n,t)}return i}tsParseIntersectionTypeOrHigher(){return this.tsParseUnionOrIntersectionType("TSIntersectionType",this.tsParseTypeOperatorOrHigher.bind(this),d.bitwiseAND)}tsParseUnionTypeOrHigher(){return this.tsParseUnionOrIntersectionType("TSUnionType",this.tsParseIntersectionTypeOrHigher.bind(this),d.bitwiseOR)}tsIsStartOfFunctionType(){return!!this.isRelational("<")||this.match(d.parenL)&&this.tsLookAhead(this.tsIsUnambiguouslyStartOfFunctionType.bind(this))}tsSkipParameterStart(){if(this.match(d.name)||this.match(d._this))return this.next(),!0;if(this.match(d.braceL)){let t=1;this.next();while(t>0)this.match(d.braceL)?++t:this.match(d.braceR)&&--t,this.next();return!0}if(this.match(d.bracketL)){let t=1;this.next();while(t>0)this.match(d.bracketL)?++t:this.match(d.bracketR)&&--t,this.next();return!0}return!1}tsIsUnambiguouslyStartOfFunctionType(){if(this.next(),this.match(d.parenR)||this.match(d.ellipsis))return!0;if(this.tsSkipParameterStart()){if(this.match(d.colon)||this.match(d.comma)||this.match(d.question)||this.match(d.eq))return!0;if(this.match(d.parenR)&&(this.next(),this.match(d.arrow)))return!0}return!1}tsParseTypeOrTypePredicateAnnotation(t){return this.tsInType(()=>{const e=this.startNode();this.expect(t);const s=this.tsTryParse(this.tsParseTypePredicateAsserts.bind(this));if(s&&this.match(d._this)){let t=this.tsParseThisTypeOrThisTypePredicate();if("TSThisType"===t.type){const s=this.startNodeAtNode(e);s.parameterName=t,s.asserts=!0,t=this.finishNode(s,"TSTypePredicate")}else t.asserts=!0;return e.typeAnnotation=t,this.finishNode(e,"TSTypeAnnotation")}const i=this.tsIsIdentifier()&&this.tsTryParse(this.tsParseTypePredicatePrefix.bind(this));if(!i){if(!s)return this.tsParseTypeAnnotation(!1,e);const t=this.startNodeAtNode(e);return t.parameterName=this.parseIdentifier(),t.asserts=s,e.typeAnnotation=this.finishNode(t,"TSTypePredicate"),this.finishNode(e,"TSTypeAnnotation")}const r=this.tsParseTypeAnnotation(!1),n=this.startNodeAtNode(e);return n.parameterName=i,n.typeAnnotation=r,n.asserts=s,e.typeAnnotation=this.finishNode(n,"TSTypePredicate"),this.finishNode(e,"TSTypeAnnotation")})}tsTryParseTypeOrTypePredicateAnnotation(){return this.match(d.colon)?this.tsParseTypeOrTypePredicateAnnotation(d.colon):void 0}tsTryParseTypeAnnotation(){return this.match(d.colon)?this.tsParseTypeAnnotation():void 0}tsTryParseType(){return this.tsEatThenParseType(d.colon)}tsParseTypePredicatePrefix(){const t=this.parseIdentifier();if(this.isContextual("is")&&!this.hasPrecedingLineBreak())return this.next(),t}tsParseTypePredicateAsserts(){if(!this.match(d.name)||"asserts"!==this.state.value||this.hasPrecedingLineBreak())return!1;const t=this.state.containsEsc;return this.next(),!(!this.match(d.name)&&!this.match(d._this))&&(t&&this.raise(this.state.lastTokStart,ut.InvalidEscapedReservedWord,"asserts"),!0)}tsParseTypeAnnotation(t=!0,e=this.startNode()){return this.tsInType(()=>{t&&this.expect(d.colon),e.typeAnnotation=this.tsParseType()}),this.finishNode(e,"TSTypeAnnotation")}tsParseType(){pe(this.state.inType);const t=this.tsParseNonConditionalType();if(this.hasPrecedingLineBreak()||!this.eat(d._extends))return t;const e=this.startNodeAtNode(t);return e.checkType=t,e.extendsType=this.tsParseNonConditionalType(),this.expect(d.question),e.trueType=this.tsParseType(),this.expect(d.colon),e.falseType=this.tsParseType(),this.finishNode(e,"TSConditionalType")}tsParseNonConditionalType(){return this.tsIsStartOfFunctionType()?this.tsParseFunctionOrConstructorType("TSFunctionType"):this.match(d._new)?this.tsParseFunctionOrConstructorType("TSConstructorType"):this.tsParseUnionTypeOrHigher()}tsParseTypeAssertion(){const t=this.startNode(),e=this.tsTryNextParseConstantContext();return t.typeAnnotation=e||this.tsNextThenParseType(),this.expectRelational(">"),t.expression=this.parseMaybeUnary(),this.finishNode(t,"TSTypeAssertion")}tsParseHeritageClause(t){const e=this.state.start,s=this.tsParseDelimitedList("HeritageClauseElement",this.tsParseExpressionWithTypeArguments.bind(this));return s.length||this.raise(e,ue.EmptyHeritageClauseType,t),s}tsParseExpressionWithTypeArguments(){const t=this.startNode();return t.expression=this.tsParseEntityName(!1),this.isRelational("<")&&(t.typeParameters=this.tsParseTypeArguments()),this.finishNode(t,"TSExpressionWithTypeArguments")}tsParseInterfaceDeclaration(t){t.id=this.parseIdentifier(),this.checkLVal(t.id,F,void 0,"typescript interface declaration"),t.typeParameters=this.tsTryParseTypeParameters(),this.eat(d._extends)&&(t.extends=this.tsParseHeritageClause("extends"));const e=this.startNode();return e.body=this.tsInType(this.tsParseObjectTypeMembers.bind(this)),t.body=this.finishNode(e,"TSInterfaceBody"),this.finishNode(t,"TSInterfaceDeclaration")}tsParseTypeAliasDeclaration(t){return t.id=this.parseIdentifier(),this.checkLVal(t.id,B,void 0,"typescript type alias"),t.typeParameters=this.tsTryParseTypeParameters(),t.typeAnnotation=this.tsExpectThenParseType(d.eq),this.semicolon(),this.finishNode(t,"TSTypeAliasDeclaration")}tsInNoContext(t){const e=this.state.context;this.state.context=[e[0]];try{return t()}finally{this.state.context=e}}tsInType(t){const e=this.state.inType;this.state.inType=!0;try{return t()}finally{this.state.inType=e}}tsEatThenParseType(t){return this.match(t)?this.tsNextThenParseType():void 0}tsExpectThenParseType(t){return this.tsDoThenParseType(()=>this.expect(t))}tsNextThenParseType(){return this.tsDoThenParseType(()=>this.next())}tsDoThenParseType(t){return this.tsInType(()=>(t(),this.tsParseType()))}tsParseEnumMember(){const t=this.startNode();return t.id=this.match(d.string)?this.parseExprAtom():this.parseIdentifier(!0),this.eat(d.eq)&&(t.initializer=this.parseMaybeAssign()),this.finishNode(t,"TSEnumMember")}tsParseEnumDeclaration(t,e){return e&&(t.const=!0),t.id=this.parseIdentifier(),this.checkLVal(t.id,e?z:U,void 0,"typescript enum declaration"),this.expect(d.braceL),t.members=this.tsParseDelimitedList("EnumMembers",this.tsParseEnumMember.bind(this)),this.expect(d.braceR),this.finishNode(t,"TSEnumDeclaration")}tsParseModuleBlock(){const t=this.startNode();return this.scope.enter(f),this.expect(d.braceL),this.parseBlockOrModuleBlockBody(t.body=[],void 0,!0,d.braceR),this.scope.exit(),this.finishNode(t,"TSModuleBlock")}tsParseModuleOrNamespaceDeclaration(t,e=!1){if(t.id=this.parseIdentifier(),e||this.checkLVal(t.id,W,null,"module or namespace declaration"),this.eat(d.dot)){const e=this.startNode();this.tsParseModuleOrNamespaceDeclaration(e,!0),t.body=e}else this.scope.enter(P),this.prodParam.enter(re),t.body=this.tsParseModuleBlock(),this.prodParam.exit(),this.scope.exit();return this.finishNode(t,"TSModuleDeclaration")}tsParseAmbientExternalModuleDeclaration(t){return this.isContextual("global")?(t.global=!0,t.id=this.parseIdentifier()):this.match(d.string)?t.id=this.parseExprAtom():this.unexpected(),this.match(d.braceL)?(this.scope.enter(P),this.prodParam.enter(re),t.body=this.tsParseModuleBlock(),this.prodParam.exit(),this.scope.exit()):this.semicolon(),this.finishNode(t,"TSModuleDeclaration")}tsParseImportEqualsDeclaration(t,e){return t.isExport=e||!1,t.id=this.parseIdentifier(),this.checkLVal(t.id,_,void 0,"import equals declaration"),this.expect(d.eq),t.moduleReference=this.tsParseModuleReference(),this.semicolon(),this.finishNode(t,"TSImportEqualsDeclaration")}tsIsExternalModuleReference(){return this.isContextual("require")&&40===this.lookaheadCharCode()}tsParseModuleReference(){return this.tsIsExternalModuleReference()?this.tsParseExternalModuleReference():this.tsParseEntityName(!1)}tsParseExternalModuleReference(){const t=this.startNode();if(this.expectContextual("require"),this.expect(d.parenL),!this.match(d.string))throw this.unexpected();return t.expression=this.parseExprAtom(),this.expect(d.parenR),this.finishNode(t,"TSExternalModuleReference")}tsLookAhead(t){const e=this.state.clone(),s=t();return this.state=e,s}tsTryParseAndCatch(t){const e=this.tryParse(e=>t()||e());if(!e.aborted&&e.node)return e.error&&(this.state=e.failState),e.node}tsTryParse(t){const e=this.state.clone(),s=t();return void 0!==s&&!1!==s?s:void(this.state=e)}tsTryParseDeclare(t){if(this.isLineTerminator())return;let e,s=this.state.type;switch(this.isContextual("let")&&(s=d._var,e="let"),s){case d._function:return this.parseFunctionStatement(t,!1,!0);case d._class:return t.declare=!0,this.parseClass(t,!0,!1);case d._const:if(this.match(d._const)&&this.isLookaheadContextual("enum"))return this.expect(d._const),this.expectContextual("enum"),this.tsParseEnumDeclaration(t,!0);case d._var:return e=e||this.state.value,this.parseVarStatement(t,e);case d.name:{const e=this.state.value;return"global"===e?this.tsParseAmbientExternalModuleDeclaration(t):this.tsParseDeclaration(t,e,!0)}}}tsTryParseExportDeclaration(){return this.tsParseDeclaration(this.startNode(),this.state.value,!0)}tsParseExpressionStatement(t,e){switch(e.name){case"declare":{const e=this.tsTryParseDeclare(t);if(e)return e.declare=!0,e;break}case"global":if(this.match(d.braceL)){this.scope.enter(P),this.prodParam.enter(re);const s=t;return s.global=!0,s.id=e,s.body=this.tsParseModuleBlock(),this.scope.exit(),this.prodParam.exit(),this.finishNode(s,"TSModuleDeclaration")}break;default:return this.tsParseDeclaration(t,e.name,!1)}}tsParseDeclaration(t,e,s){switch(e){case"abstract":if(this.tsCheckLineTerminatorAndMatch(d._class,s)){const e=t;return e.abstract=!0,s&&(this.next(),this.match(d._class)||this.unexpected(null,d._class)),this.parseClass(e,!0,!1)}break;case"enum":if(s||this.match(d.name))return s&&this.next(),this.tsParseEnumDeclaration(t,!1);break;case"interface":if(this.tsCheckLineTerminatorAndMatch(d.name,s))return s&&this.next(),this.tsParseInterfaceDeclaration(t);break;case"module":if(s&&this.next(),this.match(d.string))return this.tsParseAmbientExternalModuleDeclaration(t);if(this.tsCheckLineTerminatorAndMatch(d.name,s))return this.tsParseModuleOrNamespaceDeclaration(t);break;case"namespace":if(this.tsCheckLineTerminatorAndMatch(d.name,s))return s&&this.next(),this.tsParseModuleOrNamespaceDeclaration(t);break;case"type":if(this.tsCheckLineTerminatorAndMatch(d.name,s))return s&&this.next(),this.tsParseTypeAliasDeclaration(t);break}}tsCheckLineTerminatorAndMatch(t,e){return(e||this.match(t))&&!this.isLineTerminator()}tsTryParseGenericAsyncArrowFunction(t,e){if(!this.isRelational("<"))return;const s=this.state.maybeInArrowParameters,i=this.state.yieldPos,r=this.state.awaitPos;this.state.maybeInArrowParameters=!0,this.state.yieldPos=-1,this.state.awaitPos=-1;const n=this.tsTryParseAndCatch(()=>{const s=this.startNodeAt(t,e);return s.typeParameters=this.tsParseTypeParameters(),super.parseFunctionParams(s),s.returnType=this.tsTryParseTypeOrTypePredicateAnnotation(),this.expect(d.arrow),s});return this.state.maybeInArrowParameters=s,this.state.yieldPos=i,this.state.awaitPos=r,n?this.parseArrowExpression(n,null,!0):void 0}tsParseTypeArguments(){const t=this.startNode();return t.params=this.tsInType(()=>this.tsInNoContext(()=>(this.expectRelational("<"),this.tsParseDelimitedList("TypeParametersOrArguments",this.tsParseType.bind(this))))),this.state.exprAllowed=!1,this.expectRelational(">"),this.finishNode(t,"TSTypeParameterInstantiation")}tsIsDeclarationStart(){if(this.match(d.name))switch(this.state.value){case"abstract":case"declare":case"enum":case"interface":case"module":case"namespace":case"type":return!0}return!1}isExportDefaultSpecifier(){return!this.tsIsDeclarationStart()&&super.isExportDefaultSpecifier()}parseAssignableListItem(t,e){const s=this.state.start,i=this.state.startLoc;let r,n=!1;t&&(r=this.parseAccessModifier(),n=!!this.tsParseModifier(["readonly"]));const a=this.parseMaybeDefault();this.parseAssignableListItemTypes(a);const o=this.parseMaybeDefault(a.start,a.loc.start,a);if(r||n){const t=this.startNodeAt(s,i);return e.length&&(t.decorators=e),r&&(t.accessibility=r),n&&(t.readonly=n),"Identifier"!==o.type&&"AssignmentPattern"!==o.type&&this.raise(t.start,ue.UnsupportedParameterPropertyKind),t.parameter=o,this.finishNode(t,"TSParameterProperty")}return e.length&&(a.decorators=e),o}parseFunctionBodyAndFinish(t,e,s=!1){this.match(d.colon)&&(t.returnType=this.tsParseTypeOrTypePredicateAnnotation(d.colon));const i="FunctionDeclaration"===e?"TSDeclareFunction":"ClassMethod"===e?"TSDeclareMethod":void 0;i&&!this.match(d.braceL)&&this.isLineTerminator()?this.finishNode(t,i):super.parseFunctionBodyAndFinish(t,e,s)}registerFunctionStatementId(t){!t.body&&t.id?this.checkLVal(t.id,q,null,"function name"):super.registerFunctionStatementId(...arguments)}parseSubscript(t,e,s,i,r){if(!this.hasPrecedingLineBreak()&&this.match(d.bang)){this.state.exprAllowed=!1,this.next();const i=this.startNodeAt(e,s);return i.expression=t,this.finishNode(i,"TSNonNullExpression")}if(this.isRelational("<")){const n=this.tsTryParseAndCatch(()=>{if(!i&&this.atPossibleAsyncArrow(t)){const t=this.tsTryParseGenericAsyncArrowFunction(e,s);if(t)return t}const n=this.startNodeAt(e,s);n.callee=t;const a=this.tsParseTypeArguments();if(a){if(!i&&this.eat(d.parenL))return n.arguments=this.parseCallExpressionArguments(d.parenR,!1),n.typeParameters=a,this.finishCallExpression(n,r.optionalChainMember);if(this.match(d.backQuote))return this.parseTaggedTemplateExpression(e,s,t,r,a)}this.unexpected()});if(n)return n}return super.parseSubscript(t,e,s,i,r)}parseNewArguments(t){if(this.isRelational("<")){const e=this.tsTryParseAndCatch(()=>{const t=this.tsParseTypeArguments();return this.match(d.parenL)||this.unexpected(),t});e&&(t.typeParameters=e)}super.parseNewArguments(t)}parseExprOp(t,e,s,i,r){if(le(d._in.binop)>i&&!this.hasPrecedingLineBreak()&&this.isContextual("as")){const n=this.startNodeAt(e,s);n.expression=t;const a=this.tsTryNextParseConstantContext();return n.typeAnnotation=a||this.tsNextThenParseType(),this.finishNode(n,"TSAsExpression"),this.parseExprOp(n,e,s,i,r)}return super.parseExprOp(t,e,s,i,r)}checkReservedWord(t,e,s,i){}checkDuplicateExports(){}parseImport(t){if(this.match(d.name)||this.match(d.star)||this.match(d.braceL)){const e=this.lookahead();if(this.match(d.name)&&e.type===d.eq)return this.tsParseImportEqualsDeclaration(t);!this.isContextual("type")||e.type===d.comma||e.type===d.name&&"from"===e.value?t.importKind="value":(t.importKind="type",this.next())}const e=super.parseImport(t);return"type"===e.importKind&&e.specifiers.length>1&&"ImportDefaultSpecifier"===e.specifiers[0].type&&this.raise(e.start,"A type-only import can specify a default import or named bindings, but not both."),e}parseExport(t){if(this.match(d._import))return this.expect(d._import),this.tsParseImportEqualsDeclaration(t,!0);if(this.eat(d.eq)){const e=t;return e.expression=this.parseExpression(),this.semicolon(),this.finishNode(e,"TSExportAssignment")}if(this.eatContextual("as")){const e=t;return this.expectContextual("namespace"),e.id=this.parseIdentifier(),this.semicolon(),this.finishNode(e,"TSNamespaceExportDeclaration")}return this.isContextual("type")&&this.lookahead().type===d.braceL?(this.next(),t.exportKind="type"):t.exportKind="value",super.parseExport(t)}isAbstractClass(){return this.isContextual("abstract")&&this.lookahead().type===d._class}parseExportDefaultExpression(){if(this.isAbstractClass()){const t=this.startNode();return this.next(),this.parseClass(t,!0,!0),t.abstract=!0,t}if("interface"===this.state.value){const t=this.tsParseDeclaration(this.startNode(),this.state.value,!0);if(t)return t}return super.parseExportDefaultExpression()}parseStatementContent(t,e){if(this.state.type===d._const){const t=this.lookahead();if(t.type===d.name&&"enum"===t.value){const t=this.startNode();return this.expect(d._const),this.expectContextual("enum"),this.tsParseEnumDeclaration(t,!0)}}return super.parseStatementContent(t,e)}parseAccessModifier(){return this.tsParseModifier(["public","protected","private"])}parseClassMember(t,e,s,i){this.tsParseModifiers(e,["declare"]);const r=this.parseAccessModifier();r&&(e.accessibility=r),this.tsParseModifiers(e,["declare"]),super.parseClassMember(t,e,s,i)}parseClassMemberWithIsStatic(t,e,s,i,r){this.tsParseModifiers(e,["abstract","readonly","declare"]);const n=this.tsTryParseIndexSignature(e);if(n)return t.body.push(n),e.abstract&&this.raise(e.start,ue.IndexSignatureHasAbstract),i&&this.raise(e.start,ue.IndexSignatureHasStatic),void(e.accessibility&&this.raise(e.start,ue.IndexSignatureHasAccessibility,e.accessibility));super.parseClassMemberWithIsStatic(t,e,s,i,r)}parsePostMemberNameModifiers(t){const e=this.eat(d.question);e&&(t.optional=!0),t.readonly&&this.match(d.parenL)&&this.raise(t.start,ue.ClassMethodHasReadonly),t.declare&&this.match(d.parenL)&&this.raise(t.start,ue.ClassMethodHasDeclare)}parseExpressionStatement(t,e){const s="Identifier"===e.type?this.tsParseExpressionStatement(t,e):void 0;return s||super.parseExpressionStatement(t,e)}shouldParseExportDeclaration(){return!!this.tsIsDeclarationStart()||super.shouldParseExportDeclaration()}parseConditional(t,e,s,i,r){if(!r||!this.match(d.question))return super.parseConditional(t,e,s,i,r);const n=this.tryParse(()=>super.parseConditional(t,e,s,i));return n.node?(n.error&&(this.state=n.failState),n.node):(r.start=n.error.pos||this.state.start,t)}parseParenItem(t,e,s){if(t=super.parseParenItem(t,e,s),this.eat(d.question)&&(t.optional=!0,this.resetEndLocation(t)),this.match(d.colon)){const i=this.startNodeAt(e,s);return i.expression=t,i.typeAnnotation=this.tsParseTypeAnnotation(),this.finishNode(i,"TSTypeCastExpression")}return t}parseExportDeclaration(t){const e=this.state.start,s=this.state.startLoc,i=this.eatContextual("declare");let r;return this.match(d.name)&&(r=this.tsTryParseExportDeclaration()),r||(r=super.parseExportDeclaration(t)),r&&("TSInterfaceDeclaration"===r.type||"TSTypeAliasDeclaration"===r.type||i)&&(t.exportKind="type"),r&&i&&(this.resetStartLocation(r,e,s),r.declare=!0),r}parseClassId(t,e,s){if((!e||s)&&this.isContextual("implements"))return;super.parseClassId(t,e,s,t.declare?q:L);const i=this.tsTryParseTypeParameters();i&&(t.typeParameters=i)}parseClassPropertyAnnotation(t){!t.optional&&this.eat(d.bang)&&(t.definite=!0);const e=this.tsTryParseTypeAnnotation();e&&(t.typeAnnotation=e)}parseClassProperty(t){return this.parseClassPropertyAnnotation(t),t.declare&&this.match(d.equal)&&this.raise(this.state.start,ue.DeclareClassFieldHasInitializer),super.parseClassProperty(t)}parseClassPrivateProperty(t){return t.abstract&&this.raise(t.start,ue.PrivateElementHasAbstract),t.accessibility&&this.raise(t.start,ue.PrivateElementHasAccessibility,t.accessibility),this.parseClassPropertyAnnotation(t),super.parseClassPrivateProperty(t)}pushClassMethod(t,e,s,i,r,n){const a=this.tsTryParseTypeParameters();a&&(e.typeParameters=a),super.pushClassMethod(t,e,s,i,r,n)}pushClassPrivateMethod(t,e,s,i){const r=this.tsTryParseTypeParameters();r&&(e.typeParameters=r),super.pushClassPrivateMethod(t,e,s,i)}parseClassSuper(t){super.parseClassSuper(t),t.superClass&&this.isRelational("<")&&(t.superTypeParameters=this.tsParseTypeArguments()),this.eatContextual("implements")&&(t.implements=this.tsParseHeritageClause("implements"))}parseObjPropValue(t,...e){const s=this.tsTryParseTypeParameters();s&&(t.typeParameters=s),super.parseObjPropValue(t,...e)}parseFunctionParams(t,e){const s=this.tsTryParseTypeParameters();s&&(t.typeParameters=s),super.parseFunctionParams(t,e)}parseVarId(t,e){super.parseVarId(t,e),"Identifier"===t.id.type&&this.eat(d.bang)&&(t.definite=!0);const s=this.tsTryParseTypeAnnotation();s&&(t.id.typeAnnotation=s,this.resetEndLocation(t.id))}parseAsyncArrowFromCallExpression(t,e){return this.match(d.colon)&&(t.returnType=this.tsParseTypeAnnotation()),super.parseAsyncArrowFromCallExpression(t,e)}parseMaybeAssign(...t){var e,s,i,r,n,a,o;let c,h,l,p;if(this.match(d.jsxTagStart)){if(c=this.state.clone(),h=this.tryParse(()=>super.parseMaybeAssign(...t),c),!h.error)return h.node;const{context:e}=this.state;e[e.length-1]===gt.j_oTag?e.length-=2:e[e.length-1]===gt.j_expr&&(e.length-=1)}if(!(null==(e=h)?void 0:e.error)&&!this.isRelational("<"))return super.parseMaybeAssign(...t);c=c||this.state.clone();const u=this.tryParse(e=>{var s;p=this.tsParseTypeParameters();const i=super.parseMaybeAssign(...t);return("ArrowFunctionExpression"!==i.type||i.extra&&i.extra.parenthesized)&&e(),0!==(null==(s=p)?void 0:s.params.length)&&this.resetStartLocationFromNode(i,p),i.typeParameters=p,i},c);if(!u.error&&!u.aborted)return u.node;if(!h&&(pe(!this.hasPlugin("jsx")),l=this.tryParse(()=>super.parseMaybeAssign(...t),c),!l.error))return l.node;if(null==(s=h)?void 0:s.node)return this.state=h.failState,h.node;if(u.node)return this.state=u.failState,u.node;if(null==(i=l)?void 0:i.node)return this.state=l.failState,l.node;if(null==(r=h)?void 0:r.thrown)throw h.error;if(u.thrown)throw u.error;if(null==(n=l)?void 0:n.thrown)throw l.error;throw(null==(a=h)?void 0:a.error)||u.error||(null==(o=l)?void 0:o.error)}parseMaybeUnary(t){return!this.hasPlugin("jsx")&&this.isRelational("<")?this.tsParseTypeAssertion():super.parseMaybeUnary(t)}parseArrow(t){if(this.match(d.colon)){const e=this.tryParse(t=>{const e=this.tsParseTypeOrTypePredicateAnnotation(d.colon);return!this.canInsertSemicolon()&&this.match(d.arrow)||t(),e});if(e.aborted)return;e.thrown||(e.error&&(this.state=e.failState),t.returnType=e.node)}return super.parseArrow(t)}parseAssignableListItemTypes(t){this.eat(d.question)&&("Identifier"!==t.type&&this.raise(t.start,ue.PatternIsOptional),t.optional=!0);const e=this.tsTryParseTypeAnnotation();return e&&(t.typeAnnotation=e),this.resetEndLocation(t),t}toAssignable(t){switch(t.type){case"TSTypeCastExpression":return super.toAssignable(this.typeCastToParameter(t));case"TSParameterProperty":return super.toAssignable(t);case"TSAsExpression":case"TSNonNullExpression":case"TSTypeAssertion":return t.expression=this.toAssignable(t.expression),t;default:return super.toAssignable(t)}}checkLVal(t,e=V,s,i){switch(t.type){case"TSTypeCastExpression":return;case"TSParameterProperty":return void this.checkLVal(t.parameter,e,s,"parameter property");case"TSAsExpression":case"TSNonNullExpression":case"TSTypeAssertion":return void this.checkLVal(t.expression,e,s,i);default:return void super.checkLVal(t,e,s,i)}}parseBindingAtom(){switch(this.state.type){case d._this:return this.parseIdentifier(!0);default:return super.parseBindingAtom()}}parseMaybeDecoratorArguments(t){if(this.isRelational("<")){const e=this.tsParseTypeArguments();if(this.match(d.parenL)){const s=super.parseMaybeDecoratorArguments(t);return s.typeParameters=e,s}this.unexpected(this.state.start,d.parenL)}return super.parseMaybeDecoratorArguments(t)}isClassMethod(){return this.isRelational("<")||super.isClassMethod()}isClassProperty(){return this.match(d.bang)||this.match(d.colon)||super.isClassProperty()}parseMaybeDefault(...t){const e=super.parseMaybeDefault(...t);return"AssignmentPattern"===e.type&&e.typeAnnotation&&e.right.startthis.tsParseTypeArguments());e&&(t.typeParameters=e)}return super.jsxParseOpeningElementAfterName(t)}getGetterSetterExpectedParamCount(t){const e=super.getGetterSetterExpectedParamCount(t),s=t.params[0],i=s&&"Identifier"===s.type&&"this"===s.name;return i?e+1:e}};d.placeholder=new h("%%",{startsExpr:!0});var me=t=>class extends t{parsePlaceholder(t){if(this.match(d.placeholder)){const e=this.startNode();return this.next(),this.assertNoSpace("Unexpected space in placeholder."),e.name=super.parseIdentifier(!0),this.assertNoSpace("Unexpected space in placeholder."),this.expect(d.placeholder),this.finishPlaceholder(e,t)}}finishPlaceholder(t,e){const s=!(!t.expectedNode||"Placeholder"!==t.type);return t.expectedNode=e,s?t:this.finishNode(t,"Placeholder")}getTokenFromCode(t){return 37===t&&37===this.input.charCodeAt(this.state.pos+1)?this.finishOp(d.placeholder,2):super.getTokenFromCode(...arguments)}parseExprAtom(){return this.parsePlaceholder("Expression")||super.parseExprAtom(...arguments)}parseIdentifier(){return this.parsePlaceholder("Identifier")||super.parseIdentifier(...arguments)}checkReservedWord(t){void 0!==t&&super.checkReservedWord(...arguments)}parseBindingAtom(){return this.parsePlaceholder("Pattern")||super.parseBindingAtom(...arguments)}checkLVal(t){"Placeholder"!==t.type&&super.checkLVal(...arguments)}toAssignable(t){return t&&"Placeholder"===t.type&&"Expression"===t.expectedNode?(t.expectedNode="Pattern",t):super.toAssignable(...arguments)}verifyBreakContinue(t){t.label&&"Placeholder"===t.label.type||super.verifyBreakContinue(...arguments)}parseExpressionStatement(t,e){if("Placeholder"!==e.type||e.extra&&e.extra.parenthesized)return super.parseExpressionStatement(...arguments);if(this.match(d.colon)){const s=t;return s.label=this.finishPlaceholder(e,"Identifier"),this.next(),s.body=this.parseStatement("label"),this.finishNode(s,"LabeledStatement")}return this.semicolon(),t.name=e.name,this.finishPlaceholder(t,"Statement")}parseBlock(){return this.parsePlaceholder("BlockStatement")||super.parseBlock(...arguments)}parseFunctionId(){return this.parsePlaceholder("Identifier")||super.parseFunctionId(...arguments)}parseClass(t,e,s){const i=e?"ClassDeclaration":"ClassExpression";this.next(),this.takeDecorators(t);const r=this.parsePlaceholder("Identifier");if(r)if(this.match(d._extends)||this.match(d.placeholder)||this.match(d.braceL))t.id=r;else{if(s||!e)return t.id=null,t.body=this.finishPlaceholder(r,"ClassBody"),this.finishNode(t,i);this.unexpected(null,"A class name is required")}else this.parseClassId(t,e,s);return this.parseClassSuper(t),t.body=this.parsePlaceholder("ClassBody")||this.parseClassBody(!!t.superClass),this.finishNode(t,i)}parseExport(t){const e=this.parsePlaceholder("Identifier");if(!e)return super.parseExport(...arguments);if(!this.isContextual("from")&&!this.match(d.comma))return t.specifiers=[],t.source=null,t.declaration=this.finishPlaceholder(e,"Declaration"),this.finishNode(t,"ExportNamedDeclaration");this.expectPlugin("exportDefaultFrom");const s=this.startNode();return s.exported=e,t.specifiers=[this.finishNode(s,"ExportDefaultSpecifier")],super.parseExport(t)}isExportDefaultSpecifier(){if(this.match(d._default)){const t=this.nextTokenStart();if(this.isUnparsedContextual(t,"from")&&this.input.startsWith(d.placeholder.label,this.nextTokenStartSince(t+4)))return!0}return super.isExportDefaultSpecifier()}maybeParseExportDefaultSpecifier(t){return!!(t.specifiers&&t.specifiers.length>0)||super.maybeParseExportDefaultSpecifier(...arguments)}checkExport(t){const{specifiers:e}=t;(null==e?void 0:e.length)&&(t.specifiers=e.filter(t=>"Placeholder"===t.exported.type)),super.checkExport(t),t.specifiers=e}parseImport(t){const e=this.parsePlaceholder("Identifier");if(!e)return super.parseImport(...arguments);if(t.specifiers=[],!this.isContextual("from")&&!this.match(d.comma))return t.source=this.finishPlaceholder(e,"StringLiteral"),this.semicolon(),this.finishNode(t,"ImportDeclaration");const s=this.startNodeAtNode(e);if(s.local=e,this.finishNode(s,"ImportDefaultSpecifier"),t.specifiers.push(s),this.eat(d.comma)){const e=this.maybeParseStarImportSpecifier(t);e||this.parseNamedImportSpecifiers(t)}return this.expectContextual("from"),t.source=this.parseImportSource(),this.semicolon(),this.finishNode(t,"ImportDeclaration")}parseImportSource(){return this.parsePlaceholder("StringLiteral")||super.parseImportSource(...arguments)}},ye=t=>class extends t{parseV8Intrinsic(){if(this.match(d.modulo)){const t=this.state.start,e=this.startNode();if(this.eat(d.modulo),this.match(d.name)){const t=this.parseIdentifierName(this.state.start),s=this.createIdentifier(e,t);if(s.type="V8IntrinsicIdentifier",this.match(d.parenL))return s}this.unexpected(t)}}parseExprAtom(){return this.parseV8Intrinsic()||super.parseExprAtom(...arguments)}};function ge(t,e){return t.some(t=>Array.isArray(t)?t[0]===e:t===e)}function xe(t,e,s){const i=t.find(t=>Array.isArray(t)?t[0]===e:t===e);return i&&Array.isArray(i)?i[1][s]:null}const be=["minimal","smart","fsharp"],ve=["hash","bar"];function we(t){if(ge(t,"decorators")){if(ge(t,"decorators-legacy"))throw new Error("Cannot use the decorators and decorators-legacy plugin together");const e=xe(t,"decorators","decoratorsBeforeExport");if(null==e)throw new Error("The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean. If you are migrating from Babylon/Babel 6 or want to use the old decorators proposal, you should use the 'decorators-legacy' plugin instead of 'decorators'.");if("boolean"!==typeof e)throw new Error("'decoratorsBeforeExport' must be a boolean.")}if(ge(t,"flow")&&ge(t,"typescript"))throw new Error("Cannot combine flow and typescript plugins.");if(ge(t,"placeholders")&&ge(t,"v8intrinsic"))throw new Error("Cannot combine placeholders and v8intrinsic plugins.");if(ge(t,"pipelineOperator")&&!be.includes(xe(t,"pipelineOperator","proposal")))throw new Error("'pipelineOperator' requires 'proposal' option whose value should be one of: "+be.map(t=>`'${t}'`).join(", "));if(ge(t,"moduleAttributes")){const e=xe(t,"moduleAttributes","version");if("may-2020"!==e)throw new Error("The 'moduleAttributes' plugin requires a 'version' option, representing the last proposal update. Currently, the only supported value is 'may-2020'.")}if(ge(t,"recordAndTuple")&&!ve.includes(xe(t,"recordAndTuple","syntaxType")))throw new Error("'recordAndTuple' requires 'syntaxType' option whose value should be one of: "+ve.map(t=>`'${t}'`).join(", "))}const Pe={estree:mt,jsx:Zt,flow:Kt,typescript:fe,v8intrinsic:ye,placeholders:me},Te=Object.keys(Pe),Ee={sourceType:"script",sourceFilename:void 0,startLine:1,allowAwaitOutsideFunction:!1,allowReturnOutsideFunction:!1,allowImportExportEverywhere:!1,allowSuperOutsideMethod:!1,allowUndeclaredExports:!1,plugins:[],strictMode:null,ranges:!1,tokens:!1,createParenthesizedExpressions:!1,errorRecovery:!1};function Ae(t){const e={};for(let s=0,i=Object.keys(Ee);s=48&&t<=57};const ke=new Set(["g","m","s","i","y","u"]),Ne={decBinOct:[46,66,69,79,95,98,101,111],hex:[46,88,95,120]},Ie={bin:[48,49]};Ie.oct=[...Ie.bin,50,51,52,53,54,55],Ie.dec=[...Ie.oct,56,57],Ie.hex=[...Ie.dec,65,66,67,68,69,70,97,98,99,100,101,102];class Oe{constructor(t){this.type=t.type,this.value=t.value,this.start=t.start,this.end=t.end,this.loc=new ot(t.startLoc,t.endLoc)}}class De extends dt{constructor(t,e){super(),this.tokens=[],this.state=new Se,this.state.init(t),this.input=e,this.length=e.length,this.isLookahead=!1}pushToken(t){this.tokens.length=this.state.tokensLength,this.tokens.push(t),++this.state.tokensLength}next(){this.isLookahead||(this.checkKeywordEscapes(),this.options.tokens&&this.pushToken(new Oe(this.state))),this.state.lastTokEnd=this.state.end,this.state.lastTokStart=this.state.start,this.state.lastTokEndLoc=this.state.endLoc,this.state.lastTokStartLoc=this.state.startLoc,this.nextToken()}eat(t){return!!this.match(t)&&(this.next(),!0)}match(t){return this.state.type===t}lookahead(){const t=this.state;this.state=t.clone(!0),this.isLookahead=!0,this.next(),this.isLookahead=!1;const e=this.state;return this.state=t,e}nextTokenStart(){return this.nextTokenStartSince(this.state.pos)}nextTokenStartSince(t){rt.lastIndex=t;const e=rt.exec(this.input);return t+e[0].length}lookaheadCharCode(){return this.input.charCodeAt(this.nextTokenStart())}setStrict(t){if(this.state.strict=t,this.match(d.num)||this.match(d.string)){this.state.pos=this.state.start;while(this.state.pos=this.length)return void this.finishToken(d.eof);const e=null==t?void 0:t.override;e?e(this):this.getTokenFromCode(this.input.codePointAt(this.state.pos))}pushComment(t,e,s,i,r,n){const a={type:t?"CommentBlock":"CommentLine",value:e,start:s,end:i,loc:new ot(r,n)};this.options.tokens&&this.pushToken(a),this.state.comments.push(a),this.addComment(a)}skipBlockComment(){const t=this.state.curPosition(),e=this.state.pos,s=this.input.indexOf("*/",this.state.pos+2);if(-1===s)throw this.raise(e,ut.UnterminatedComment);let i;this.state.pos=s+2,st.lastIndex=e;while((i=st.exec(this.input))&&i.index=48&&e<=57)throw this.raise(this.state.pos,ut.UnexpectedDigitAfterHash);if(123===e||91===e&&this.hasPlugin("recordAndTuple")){if(this.expectPlugin("recordAndTuple"),"hash"!==this.getPluginOption("recordAndTuple","syntaxType"))throw this.raise(this.state.pos,123===e?ut.RecordExpressionHashIncorrectStartSyntaxType:ut.TupleExpressionHashIncorrectStartSyntaxType);123===e?this.finishToken(d.braceHashL):this.finishToken(d.bracketHashL),this.state.pos+=2}else this.finishOp(d.hash,1)}readToken_dot(){const t=this.input.charCodeAt(this.state.pos+1);t>=48&&t<=57?this.readNumber(!0):46===t&&46===this.input.charCodeAt(this.state.pos+2)?(this.state.pos+=3,this.finishToken(d.ellipsis)):(++this.state.pos,this.finishToken(d.dot))}readToken_slash(){if(this.state.exprAllowed&&!this.state.inType)return++this.state.pos,void this.readRegexp();const t=this.input.charCodeAt(this.state.pos+1);61===t?this.finishOp(d.assign,2):this.finishOp(d.slash,1)}readToken_interpreter(){if(0!==this.state.pos||this.length<2)return!1;let t=this.input.charCodeAt(this.state.pos+1);if(33!==t)return!1;const e=this.state.pos;this.state.pos+=1;while(!it(t)&&++this.state.pos=48&&e<=57?(++this.state.pos,this.finishToken(d.question)):(this.state.pos+=2,this.finishToken(d.questionDot)):61===e?this.finishOp(d.assign,3):this.finishOp(d.nullishCoalescing,2)}getTokenFromCode(t){switch(t){case 46:return void this.readToken_dot();case 40:return++this.state.pos,void this.finishToken(d.parenL);case 41:return++this.state.pos,void this.finishToken(d.parenR);case 59:return++this.state.pos,void this.finishToken(d.semi);case 44:return++this.state.pos,void this.finishToken(d.comma);case 91:if(this.hasPlugin("recordAndTuple")&&124===this.input.charCodeAt(this.state.pos+1)){if("bar"!==this.getPluginOption("recordAndTuple","syntaxType"))throw this.raise(this.state.pos,ut.TupleExpressionBarIncorrectStartSyntaxType);this.finishToken(d.bracketBarL),this.state.pos+=2}else++this.state.pos,this.finishToken(d.bracketL);return;case 93:return++this.state.pos,void this.finishToken(d.bracketR);case 123:if(this.hasPlugin("recordAndTuple")&&124===this.input.charCodeAt(this.state.pos+1)){if("bar"!==this.getPluginOption("recordAndTuple","syntaxType"))throw this.raise(this.state.pos,ut.RecordExpressionBarIncorrectStartSyntaxType);this.finishToken(d.braceBarL),this.state.pos+=2}else++this.state.pos,this.finishToken(d.braceL);return;case 125:return++this.state.pos,void this.finishToken(d.braceR);case 58:return void(this.hasPlugin("functionBind")&&58===this.input.charCodeAt(this.state.pos+1)?this.finishOp(d.doubleColon,2):(++this.state.pos,this.finishToken(d.colon)));case 63:return void this.readToken_question();case 96:return++this.state.pos,void this.finishToken(d.backQuote);case 48:{const t=this.input.charCodeAt(this.state.pos+1);if(120===t||88===t)return void this.readRadixNumber(16);if(111===t||79===t)return void this.readRadixNumber(8);if(98===t||66===t)return void this.readRadixNumber(2)}case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return void this.readNumber(!1);case 34:case 39:return void this.readString(t);case 47:return void this.readToken_slash();case 37:case 42:return void this.readToken_mult_modulo(t);case 124:case 38:return void this.readToken_pipe_amp(t);case 94:return void this.readToken_caret();case 43:case 45:return void this.readToken_plus_min(t);case 60:case 62:return void this.readToken_lt_gt(t);case 61:case 33:return void this.readToken_eq_excl(t);case 126:return void this.finishOp(d.tilde,1);case 64:return++this.state.pos,void this.finishToken(d.at);case 35:return void this.readToken_numberSign();case 92:return void this.readWord();default:if(At(t))return void this.readWord()}throw this.raise(this.state.pos,ut.InvalidOrUnexpectedToken,String.fromCodePoint(t))}finishOp(t,e){const s=this.input.slice(this.state.pos,this.state.pos+e);this.state.pos+=e,this.finishToken(t,s)}readRegexp(){const t=this.state.pos;let e,s;for(;;){if(this.state.pos>=this.length)throw this.raise(t,ut.UnterminatedRegExp);const i=this.input.charAt(this.state.pos);if(et.test(i))throw this.raise(t,ut.UnterminatedRegExp);if(e)e=!1;else{if("["===i)s=!0;else if("]"===i&&s)s=!1;else if("/"===i&&!s)break;e="\\"===i}++this.state.pos}const i=this.input.slice(t,this.state.pos);++this.state.pos;let r="";while(this.state.pos-1&&this.raise(this.state.pos+1,ut.DuplicateRegExpFlags);else{if(!St(e)&&92!==e)break;this.raise(this.state.pos+1,ut.MalformedRegExpFlags)}++this.state.pos,r+=t}this.finishToken(d.regexp,{pattern:i,flags:r})}readInt(t,e,s,i=!0){const r=this.state.pos,n=16===t?Ne.hex:Ne.decBinOct,a=16===t?Ie.hex:10===t?Ie.dec:8===t?Ie.oct:Ie.bin;let o=!1,c=0;for(let h=0,l=null==e?1/0:e;h-1||n.indexOf(e)>-1||Number.isNaN(e))&&this.raise(this.state.pos,ut.UnexpectedNumericSeparator),i||this.raise(this.state.pos,ut.NumericSeparatorInEscapeSequence),++this.state.pos}else{if(r=e>=97?e-97+10:e>=65?e-65+10:Ce(e)?e-48:1/0,r>=t)if(this.options.errorRecovery&&r<=9)r=0,this.raise(this.state.start+h+2,ut.InvalidDigit,t);else{if(!s)break;r=0,o=!0}++this.state.pos,c=c*t+r}}return this.state.pos===r||null!=e&&this.state.pos-r!==e||o?null:c}readRadixNumber(t){const e=this.state.pos;let s=!1;this.state.pos+=2;const i=this.readInt(t);null==i&&this.raise(this.state.start+2,ut.InvalidDigit,t);const r=this.input.charCodeAt(this.state.pos);if(95===r&&this.expectPlugin("numericSeparator",this.state.pos),110===r&&(++this.state.pos,s=!0),At(this.input.codePointAt(this.state.pos)))throw this.raise(this.state.pos,ut.NumberIdentifier);if(s){const t=this.input.slice(e,this.state.pos).replace(/[_n]/g,"");this.finishToken(d.bigint,t)}else this.finishToken(d.num,i)}readNumber(t){const e=this.state.pos;let s=!1,i=!1,r=!1;t||null!==this.readInt(10)||this.raise(e,ut.InvalidNumber);let n=this.state.pos-e>=2&&48===this.input.charCodeAt(e);n&&(this.state.strict&&this.raise(e,ut.StrictOctalLiteral),/[89]/.test(this.input.slice(e,this.state.pos))&&(n=!1,r=!0));let a=this.input.charCodeAt(this.state.pos);if(46!==a||n||(++this.state.pos,this.readInt(10),s=!0,a=this.input.charCodeAt(this.state.pos)),69!==a&&101!==a||n||(a=this.input.charCodeAt(++this.state.pos),43!==a&&45!==a||++this.state.pos,null===this.readInt(10)&&this.raise(e,ut.InvalidNumber),s=!0,a=this.input.charCodeAt(this.state.pos)),this.hasPlugin("numericSeparator")&&(n||r)){const t=this.input.slice(e,this.state.pos).indexOf("_");t>0&&this.raise(t+e,ut.ZeroDigitNumericSeparator)}if(95===a&&this.expectPlugin("numericSeparator",this.state.pos),110===a&&((s||n||r)&&this.raise(e,ut.InvalidBigIntLiteral),++this.state.pos,i=!0),At(this.input.codePointAt(this.state.pos)))throw this.raise(this.state.pos,ut.NumberIdentifier);const o=this.input.slice(e,this.state.pos).replace(/[_n]/g,"");if(i)return void this.finishToken(d.bigint,o);const c=n?parseInt(o,8):parseFloat(o);this.finishToken(d.num,c)}readCodePoint(t){const e=this.input.charCodeAt(this.state.pos);let s;if(123===e){const e=++this.state.pos;if(s=this.readHexChar(this.input.indexOf("}",this.state.pos)-this.state.pos,!0,t),++this.state.pos,null!==s&&s>1114111){if(!t)return null;this.raise(e,ut.InvalidCodePoint)}}else s=this.readHexChar(4,!1,t);return s}readString(t){let e="",s=++this.state.pos;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,ut.UnterminatedString);const i=this.input.charCodeAt(this.state.pos);if(i===t)break;if(92===i)e+=this.input.slice(s,this.state.pos),e+=this.readEscapedChar(!1),s=this.state.pos;else if(8232===i||8233===i)++this.state.pos,++this.state.curLine,this.state.lineStart=this.state.pos;else{if(it(i))throw this.raise(this.state.start,ut.UnterminatedString);++this.state.pos}}e+=this.input.slice(s,this.state.pos++),this.finishToken(d.string,e)}readTmplToken(){let t="",e=this.state.pos,s=!1;for(;;){if(this.state.pos>=this.length)throw this.raise(this.state.start,ut.UnterminatedTemplate);const i=this.input.charCodeAt(this.state.pos);if(96===i||36===i&&123===this.input.charCodeAt(this.state.pos+1))return this.state.pos===this.state.start&&this.match(d.template)?36===i?(this.state.pos+=2,void this.finishToken(d.dollarBraceL)):(++this.state.pos,void this.finishToken(d.backQuote)):(t+=this.input.slice(e,this.state.pos),void this.finishToken(d.template,s?null:t));if(92===i){t+=this.input.slice(e,this.state.pos);const i=this.readEscapedChar(!0);null===i?s=!0:t+=i,e=this.state.pos}else if(it(i)){switch(t+=this.input.slice(e,this.state.pos),++this.state.pos,i){case 13:10===this.input.charCodeAt(this.state.pos)&&++this.state.pos;case 10:t+="\n";break;default:t+=String.fromCharCode(i);break}++this.state.curLine,this.state.lineStart=this.state.pos,e=this.state.pos}else++this.state.pos}}readEscapedChar(t){const e=!t,s=this.input.charCodeAt(++this.state.pos);switch(++this.state.pos,s){case 110:return"\n";case 114:return"\r";case 120:{const t=this.readHexChar(2,!1,e);return null===t?null:String.fromCharCode(t)}case 117:{const t=this.readCodePoint(e);return null===t?null:String.fromCodePoint(t)}case 116:return"\t";case 98:return"\b";case 118:return"\v";case 102:return"\f";case 13:10===this.input.charCodeAt(this.state.pos)&&++this.state.pos;case 10:this.state.lineStart=this.state.pos,++this.state.curLine;case 8232:case 8233:return"";case 56:case 57:if(t)return null;default:if(s>=48&&s<=55){const e=this.state.pos-1,s=this.input.substr(this.state.pos-1,3).match(/^[0-7]+/);let i=s[0],r=parseInt(i,8);r>255&&(i=i.slice(0,-1),r=parseInt(i,8)),this.state.pos+=i.length-1;const n=this.input.charCodeAt(this.state.pos);if("0"!==i||56===n||57===n){if(t)return null;this.state.strict?this.raise(e,ut.StrictOctalLiteral):this.state.octalPositions.push(e)}return String.fromCharCode(r)}return String.fromCharCode(s)}}readHexChar(t,e,s){const i=this.state.pos,r=this.readInt(16,t,e,!1);return null===r&&(s?this.raise(i,ut.InvalidEscapeSequence):this.state.pos=i-1),r}readWord1(){let t="";this.state.containsEsc=!1;const e=this.state.pos;let s=this.state.pos;while(this.state.posthis.state.lastTokEnd&&this.raise(this.state.lastTokEnd,t)}unexpected(t,e="Unexpected token"){throw"string"!==typeof e&&(e=`Unexpected token, expected "${e.label}"`),this.raise(null!=t?t:this.state.start,e)}expectPlugin(t,e){if(!this.hasPlugin(t))throw this.raiseWithData(null!=e?e:this.state.start,{missingPlugin:[t]},`This experimental syntax requires enabling the parser plugin: '${t}'`);return!0}expectOnePlugin(t,e){if(!t.some(t=>this.hasPlugin(t)))throw this.raiseWithData(null!=e?e:this.state.start,{missingPlugin:t},`This experimental syntax requires enabling one of the following parser plugin(s): '${t.join(", ")}'`)}checkYieldAwaitInDefaultParams(){-1!==this.state.yieldPos&&(-1===this.state.awaitPos||this.state.yieldPos{throw s.node=t,s});if(this.state.errors.length>e.errors.length){const t=this.state;return this.state=e,{node:i,error:t.errors[e.errors.length],thrown:!1,aborted:!1,failState:t}}return{node:i,error:null,thrown:!1,aborted:!1,failState:null}}catch(i){const t=this.state;if(this.state=e,i instanceof SyntaxError)return{node:null,error:i,thrown:!0,aborted:!1,failState:t};if(i===s)return{node:s.node,error:null,thrown:!1,aborted:!0,failState:t};throw i}}checkExpressionErrors(t,e){if(!t)return!1;const{shorthandAssign:s,doubleProto:i}=t;if(!e)return s>=0||i>=0;s>=0&&this.unexpected(s),i>=0&&this.raise(i,ut.DuplicateProto)}isLiteralPropertyName(){return this.match(d.name)||!!this.state.type.keyword||this.match(d.string)||this.match(d.num)||this.match(d.bigint)}}class Le{constructor(){this.shorthandAssign=-1,this.doubleProto=-1}}class _e{constructor(t,e,s){this.type="",this.start=e,this.end=0,this.loc=new ot(s),(null==t?void 0:t.options.ranges)&&(this.range=[e,0]),(null==t?void 0:t.filename)&&(this.loc.filename=t.filename)}__clone(){const t=new _e,e=Object.keys(this);for(let s=0,i=e.length;s"ParenthesizedExpression"===t.type?je(t.expression):t;class Fe extends Re{toAssignable(t){var e,s;let i=void 0;switch(("ParenthesizedExpression"===t.type||(null==(e=t.extra)?void 0:e.parenthesized))&&(i=je(t),"Identifier"!==i.type&&"MemberExpression"!==i.type&&this.raise(t.start,ut.InvalidParenthesizedAssignment)),t.type){case"Identifier":case"ObjectPattern":case"ArrayPattern":case"AssignmentPattern":break;case"ObjectExpression":t.type="ObjectPattern";for(let e=0,s=t.properties.length,i=s-1;e=s.left.start&&(e.shorthandAssign=-1),this.checkLVal(o,void 0,void 0,"assignment expression"),this.next(),s.right=this.parseMaybeAssign(t),this.finishNode(s,"AssignmentExpression")}return a&&this.checkExpressionErrors(e,!0),o}parseMaybeConditional(t,e,s){const i=this.state.start,r=this.state.startLoc,n=this.state.potentialArrowAt,a=this.parseExprOps(t,e);return"ArrowFunctionExpression"===a.type&&a.start===n||this.checkExpressionErrors(e,!1)?a:this.parseConditional(a,t,i,r,s)}parseConditional(t,e,s,i,r){if(this.eat(d.question)){const r=this.startNodeAt(s,i);return r.test=t,r.consequent=this.parseMaybeAssign(),this.expect(d.colon),r.alternate=this.parseMaybeAssign(e),this.finishNode(r,"ConditionalExpression")}return t}parseExprOps(t,e){const s=this.state.start,i=this.state.startLoc,r=this.state.potentialArrowAt,n=this.parseMaybeUnary(e);return"ArrowFunctionExpression"===n.type&&n.start===r||this.checkExpressionErrors(e,!1)?n:this.parseExprOp(n,s,i,-1,t)}parseExprOp(t,e,s,i,r){let n=this.state.type.binop;if(null!=n&&(!r||!this.match(d._in))&&n>i){const a=this.state.value;if("|>"===a&&this.state.inFSharpPipelineDirectBody)return t;const o=this.startNodeAt(e,s);o.left=t,o.operator=a,"**"!==a||"UnaryExpression"!==t.type||!this.options.createParenthesizedExpressions&&t.extra&&t.extra.parenthesized||this.raise(t.argument.start,ut.UnexpectedTokenUnaryExponentiation);const c=this.state.type,h=c===d.logicalOR||c===d.logicalAND,l=c===d.nullishCoalescing;if(c===d.pipeline?(this.expectPlugin("pipelineOperator"),this.state.inPipeline=!0,this.checkPipelineAtInfixOperator(t,e)):l&&(n=d.logicalAND.binop),this.next(),c===d.pipeline&&"minimal"===this.getPluginOption("pipelineOperator","proposal")&&this.match(d.name)&&"await"===this.state.value&&this.prodParam.hasAwait)throw this.raise(this.state.start,ut.UnexpectedAwaitAfterPipelineBody);o.right=this.parseExprOpRightExpr(c,n,r),this.finishNode(o,h||l?"LogicalExpression":"BinaryExpression");const p=this.state.type;if(l&&(p===d.logicalOR||p===d.logicalAND)||h&&p===d.nullishCoalescing)throw this.raise(this.state.start,ut.MixingCoalesceWithLogical);return this.parseExprOp(o,e,s,i,r)}return t}parseExprOpRightExpr(t,e,s){const i=this.state.start,r=this.state.startLoc;switch(t){case d.pipeline:switch(this.getPluginOption("pipelineOperator","proposal")){case"smart":return this.withTopicPermittingContext(()=>this.parseSmartPipelineBody(this.parseExprOpBaseRightExpr(t,e,s),i,r));case"fsharp":return this.withSoloAwaitPermittingContext(()=>this.parseFSharpPipelineBody(e,s))}default:return this.parseExprOpBaseRightExpr(t,e,s)}}parseExprOpBaseRightExpr(t,e,s){const i=this.state.start,r=this.state.startLoc;return this.parseExprOp(this.parseMaybeUnary(),i,r,t.rightAssociative?e-1:e,s)}parseMaybeUnary(t){if(this.isContextual("await")&&this.isAwaitAllowed())return this.parseAwait();if(this.state.type.prefix){const e=this.startNode(),s=this.match(d.incDec);if(e.operator=this.state.value,e.prefix=!0,"throw"===e.operator&&this.expectPlugin("throwExpressions"),this.next(),e.argument=this.parseMaybeUnary(),this.checkExpressionErrors(t,!0),s)this.checkLVal(e.argument,void 0,void 0,"prefix operation");else if(this.state.strict&&"delete"===e.operator){const t=e.argument;"Identifier"===t.type?this.raise(e.start,ut.StrictDelete):"MemberExpression"!==t.type&&"OptionalMemberExpression"!==t.type||"PrivateName"!==t.property.type||this.raise(e.start,ut.DeletePrivateField)}return this.finishNode(e,s?"UpdateExpression":"UnaryExpression")}const e=this.state.start,s=this.state.startLoc;let i=this.parseExprSubscripts(t);if(this.checkExpressionErrors(t,!1))return i;while(this.state.type.postfix&&!this.canInsertSemicolon()){const t=this.startNodeAt(e,s);t.operator=this.state.value,t.prefix=!1,t.argument=i,this.checkLVal(i,void 0,void 0,"postfix operation"),this.next(),i=this.finishNode(t,"UpdateExpression")}return i}parseExprSubscripts(t){const e=this.state.start,s=this.state.startLoc,i=this.state.potentialArrowAt,r=this.parseExprAtom(t);return"ArrowFunctionExpression"===r.type&&r.start===i?r:this.parseSubscripts(r,e,s)}parseSubscripts(t,e,s,i){const r={optionalChainMember:!1,maybeAsyncArrow:this.atPossibleAsyncArrow(t),stop:!1};do{const n=this.state.maybeInAsyncArrowHead;r.maybeAsyncArrow&&(this.state.maybeInAsyncArrowHead=!0),t=this.parseSubscript(t,e,s,i,r),r.maybeAsyncArrow=!1,this.state.maybeInAsyncArrowHead=n}while(!r.stop);return t}parseSubscript(t,e,s,i,r){if(!i&&this.eat(d.doubleColon)){const n=this.startNodeAt(e,s);return n.object=t,n.callee=this.parseNoCallExpr(),r.stop=!0,this.parseSubscripts(this.finishNode(n,"BindExpression"),e,s,i)}let n=!1;if(this.match(d.questionDot)){if(r.optionalChainMember=n=!0,i&&40===this.lookaheadCharCode())return r.stop=!0,t;this.next()}const a=this.eat(d.bracketL);if(n&&!this.match(d.parenL)&&!this.match(d.backQuote)||a||this.eat(d.dot)){const i=this.startNodeAt(e,s);return i.object=t,i.property=a?this.parseExpression():this.parseMaybePrivateName(!0),i.computed=a,"PrivateName"===i.property.type&&("Super"===i.object.type&&this.raise(e,ut.SuperPrivateField),this.classScope.usePrivateName(i.property.id.name,i.property.start)),a&&this.expect(d.bracketR),r.optionalChainMember?(i.optional=n,this.finishNode(i,"OptionalMemberExpression")):this.finishNode(i,"MemberExpression")}if(!i&&this.match(d.parenL)){const i=this.state.maybeInArrowParameters,a=this.state.yieldPos,o=this.state.awaitPos;this.state.maybeInArrowParameters=!0,this.state.yieldPos=-1,this.state.awaitPos=-1,this.next();let c=this.startNodeAt(e,s);return c.callee=t,r.optionalChainMember&&(c.optional=n),c.arguments=n?this.parseCallExpressionArguments(d.parenR,!1):this.parseCallExpressionArguments(d.parenR,r.maybeAsyncArrow,"Import"===t.type,"Super"!==t.type,c),this.finishCallExpression(c,r.optionalChainMember),r.maybeAsyncArrow&&this.shouldParseAsyncArrow()&&!n?(r.stop=!0,c=this.parseAsyncArrowFromCallExpression(this.startNodeAt(e,s),c),this.checkYieldAwaitInDefaultParams(),this.state.yieldPos=a,this.state.awaitPos=o):(this.toReferencedListDeep(c.arguments),-1!==a&&(this.state.yieldPos=a),(this.isAwaitAllowed()||i)&&-1===o||(this.state.awaitPos=o)),this.state.maybeInArrowParameters=i,c}return this.match(d.backQuote)?this.parseTaggedTemplateExpression(e,s,t,r):(r.stop=!0,t)}parseTaggedTemplateExpression(t,e,s,i,r){const n=this.startNodeAt(t,e);return n.tag=s,n.quasi=this.parseTemplate(!0),r&&(n.typeParameters=r),i.optionalChainMember&&this.raise(t,ut.OptionalChainingNoTemplate),this.finishNode(n,"TaggedTemplateExpression")}atPossibleAsyncArrow(t){return"Identifier"===t.type&&"async"===t.name&&this.state.lastTokEnd===t.end&&!this.canInsertSemicolon()&&t.end-t.start===5&&t.start===this.state.potentialArrowAt}finishCallExpression(t,e){if("Import"===t.callee.type)if(2===t.arguments.length&&this.expectPlugin("moduleAttributes"),0===t.arguments.length||t.arguments.length>2)this.raise(t.start,ut.ImportCallArity,this.hasPlugin("moduleAttributes")?"one or two arguments":"one argument");else for(let s=0,i=t.arguments;s1?(i=this.startNodeAt(c,h),i.expressions=l,this.finishNodeAt(i,"SequenceExpression",g,x)):i=l[0],!this.options.createParenthesizedExpressions)return this.addExtra(i,"parenthesized",!0),this.addExtra(i,"parenStart",e),i;const v=this.startNodeAt(e,s);return v.expression=i,this.finishNode(v,"ParenthesizedExpression"),v}shouldParseArrow(){return!this.canInsertSemicolon()}parseArrow(t){if(this.eat(d.arrow))return t}parseParenItem(t,e,s){return t}parseNew(){const t=this.startNode();let e=this.startNode();if(this.next(),e=this.createIdentifier(e,"new"),this.eat(d.dot)){const s=this.parseMetaProperty(t,e,"target");if(!this.scope.inNonArrowFunction&&!this.scope.inClass){let t=ut.UnexpectedNewTarget;this.hasPlugin("classProperties")&&(t+=" or class properties"),this.raise(s.start,t)}return s}return t.callee=this.parseNoCallExpr(),"Import"===t.callee.type?this.raise(t.callee.start,ut.ImportCallNotNewExpression):"OptionalMemberExpression"===t.callee.type||"OptionalCallExpression"===t.callee.type?this.raise(this.state.lastTokEnd,ut.OptionalChainingNoNew):this.eat(d.questionDot)&&this.raise(this.state.start,ut.OptionalChainingNoNew),this.parseNewArguments(t),this.finishNode(t,"NewExpression")}parseNewArguments(t){if(this.eat(d.parenL)){const e=this.parseExprList(d.parenR);this.toReferencedList(e),t.arguments=e}else t.arguments=[]}parseTemplateElement(t){const e=this.startNode();return null===this.state.value&&(t||this.raise(this.state.start+1,ut.InvalidEscapeSequenceTemplate)),e.value={raw:this.input.slice(this.state.start,this.state.end).replace(/\r\n?/g,"\n"),cooked:this.state.value},this.next(),e.tail=this.match(d.backQuote),this.finishNode(e,"TemplateElement")}parseTemplate(t){const e=this.startNode();this.next(),e.expressions=[];let s=this.parseTemplateElement(t);e.quasis=[s];while(!s.tail)this.expect(d.dollarBraceL),e.expressions.push(this.parseExpression()),this.expect(d.braceR),e.quasis.push(s=this.parseTemplateElement(t));return this.next(),this.finishNode(e,"TemplateLiteral")}parseObj(t,e,s,i){const r=Object.create(null);let n=!0;const a=this.startNode();a.properties=[],this.next();while(!this.eat(t)){if(n)n=!1;else if(this.expect(d.comma),this.match(t)){this.addExtra(a,"trailingComma",this.state.lastTokStart),this.next();break}const o=this.parseObjectMember(e,i);e||this.checkProto(o,s,r,i),s&&"ObjectProperty"!==o.type&&"SpreadElement"!==o.type&&this.raise(o.start,ut.InvalidRecordProperty),o.shorthand&&this.addExtra(o,"shorthand",!0),a.properties.push(o)}let o="ObjectExpression";return e?o="ObjectPattern":s&&(o="RecordExpression"),this.finishNode(a,o)}isAsyncProp(t){return!t.computed&&"Identifier"===t.key.type&&"async"===t.key.name&&(this.isLiteralPropertyName()||this.match(d.bracketL)||this.match(d.star))&&!this.hasPrecedingLineBreak()}parseObjectMember(t,e){let s=[];if(this.match(d.at)){this.hasPlugin("decorators")&&this.raise(this.state.start,ut.UnsupportedPropertyDecorator);while(this.match(d.at))s.push(this.parseDecorator())}const i=this.startNode();let r,n,a=!1,o=!1;if(this.match(d.ellipsis))return s.length&&this.unexpected(),t?(this.next(),i.argument=this.parseIdentifier(),this.checkCommaAfterRest(125),this.finishNode(i,"RestElement")):this.parseSpread();s.length&&(i.decorators=s,s=[]),i.method=!1,(t||e)&&(r=this.state.start,n=this.state.startLoc),t||(a=this.eat(d.star));const c=this.state.containsEsc;return this.parsePropertyName(i,!1),t||c||a||!this.isAsyncProp(i)?o=!1:(o=!0,a=this.eat(d.star),this.parsePropertyName(i,!1)),this.parseObjPropValue(i,r,n,a,o,t,e,c),i}isGetterOrSetterMethod(t,e){return!e&&!t.computed&&"Identifier"===t.key.type&&("get"===t.key.name||"set"===t.key.name)&&(this.isLiteralPropertyName()||this.match(d.bracketL))}getGetterSetterExpectedParamCount(t){return"get"===t.kind?0:1}checkGetterSetterParams(t){const e=this.getGetterSetterExpectedParamCount(t),s=t.start;t.params.length!==e&&("get"===t.kind?this.raise(s,ut.BadGetterArity):this.raise(s,ut.BadSetterArity)),"set"===t.kind&&"RestElement"===t.params[t.params.length-1].type&&this.raise(s,ut.BadSetterRestParameter)}parseObjectMethod(t,e,s,i,r){return s||e||this.match(d.parenL)?(i&&this.unexpected(),t.kind="method",t.method=!0,this.parseMethod(t,e,s,!1,!1,"ObjectMethod")):!r&&this.isGetterOrSetterMethod(t,i)?((e||s)&&this.unexpected(),t.kind=t.key.name,this.parsePropertyName(t,!1),this.parseMethod(t,!1,!1,!1,!1,"ObjectMethod"),this.checkGetterSetterParams(t),t):void 0}parseObjectProperty(t,e,s,i,r){return t.shorthand=!1,this.eat(d.colon)?(t.value=i?this.parseMaybeDefault(this.state.start,this.state.startLoc):this.parseMaybeAssign(!1,r),this.finishNode(t,"ObjectProperty")):t.computed||"Identifier"!==t.key.type?void 0:(this.checkReservedWord(t.key.name,t.key.start,!0,!0),i?t.value=this.parseMaybeDefault(e,s,t.key.__clone()):this.match(d.eq)&&r?(-1===r.shorthandAssign&&(r.shorthandAssign=this.state.start),t.value=this.parseMaybeDefault(e,s,t.key.__clone())):t.value=t.key.__clone(),t.shorthand=!0,this.finishNode(t,"ObjectProperty"))}parseObjPropValue(t,e,s,i,r,n,a,o){const c=this.parseObjectMethod(t,i,r,n,o)||this.parseObjectProperty(t,e,s,n,a);return c||this.unexpected(),c}parsePropertyName(t,e){if(this.eat(d.bracketL))t.computed=!0,t.key=this.parseMaybeAssign(),this.expect(d.bracketR);else{const s=this.state.inPropertyName;this.state.inPropertyName=!0,t.key=this.match(d.num)||this.match(d.string)||this.match(d.bigint)?this.parseExprAtom():this.parseMaybePrivateName(e),"PrivateName"!==t.key.type&&(t.computed=!1),this.state.inPropertyName=s}return t.key}initFunction(t,e){t.id=null,t.generator=!1,t.async=!!e}parseMethod(t,e,s,i,r,n,a=!1){const o=this.state.yieldPos,c=this.state.awaitPos;this.state.yieldPos=-1,this.state.awaitPos=-1,this.initFunction(t,s),t.generator=!!e;const h=i;return this.scope.enter(y|b|(a?w:0)|(r?v:0)),this.prodParam.enter(he(s,t.generator)),this.parseFunctionParams(t,h),this.parseFunctionBodyAndFinish(t,n,!0),this.prodParam.exit(),this.scope.exit(),this.state.yieldPos=o,this.state.awaitPos=c,t}parseArrowExpression(t,e,s,i){this.scope.enter(y|g),this.prodParam.enter(he(s,!1)),this.initFunction(t,s);const r=this.state.maybeInArrowParameters,n=this.state.yieldPos,a=this.state.awaitPos;return e&&(this.state.maybeInArrowParameters=!0,this.setArrowFunctionParameters(t,e,i)),this.state.maybeInArrowParameters=!1,this.state.yieldPos=-1,this.state.awaitPos=-1,this.parseFunctionBody(t,!0),this.prodParam.exit(),this.scope.exit(),this.state.maybeInArrowParameters=r,this.state.yieldPos=n,this.state.awaitPos=a,this.finishNode(t,"ArrowFunctionExpression")}setArrowFunctionParameters(t,e,s){t.params=this.toAssignableList(e,s)}parseFunctionBodyAndFinish(t,e,s=!1){this.parseFunctionBody(t,!1,s),this.finishNode(t,e)}parseFunctionBody(t,e,s=!1){const i=e&&!this.match(d.braceL),r=this.state.inParameters;if(this.state.inParameters=!1,i)t.body=this.parseMaybeAssign(),this.checkParams(t,!1,e,!1);else{const i=this.state.strict,r=this.state.labels;this.state.labels=[],this.prodParam.enter(this.prodParam.currentFlags()|oe),t.body=this.parseBlock(!0,!1,r=>{const n=!this.isSimpleParamList(t.params);if(r&&n){const e="method"!==t.kind&&"constructor"!==t.kind||!t.key?t.start:t.key.end;this.raise(e,ut.IllegalLanguageModeDirective)}const a=!i&&this.state.strict;this.checkParams(t,!this.state.strict&&!e&&!s&&!n,e,a),this.state.strict&&t.id&&this.checkLVal(t.id,H,void 0,"function name",void 0,a)}),this.prodParam.exit(),this.state.labels=r}this.state.inParameters=r}isSimpleParamList(t){for(let e=0,s=t.length;e=1}topicReferenceWasUsedInCurrentTopicContext(){return null!=this.state.topicContext.maxTopicIndex&&this.state.topicContext.maxTopicIndex>=0}parseFSharpPipelineBody(t,e){const s=this.state.start,i=this.state.startLoc;this.state.potentialArrowAt=this.state.start;const r=this.state.inFSharpPipelineDirectBody;this.state.inFSharpPipelineDirectBody=!0;const n=this.parseExprOp(this.parseMaybeUnary(),s,i,t,e);return this.state.inFSharpPipelineDirectBody=r,n}}const Ue={kind:"loop"},qe={kind:"switch"},Ve=0,He=1,ze=2,We=4;class Ke extends Be{parseTopLevel(t,e){if(e.sourceType=this.options.sourceType,e.interpreter=this.parseInterpreterDirective(),this.parseBlockBody(e,!0,!0,d.eof),this.inModule&&!this.options.allowUndeclaredExports&&this.scope.undefinedExports.size>0)for(let s=0,i=Array.from(this.scope.undefinedExports);sthis.parseStatement("do")),this.state.labels.pop(),this.expect(d._while),t.test=this.parseHeaderExpression(),this.eat(d.semi),this.finishNode(t,"DoWhileStatement")}parseForStatement(t){this.next(),this.state.labels.push(Ue);let e=-1;if(this.isAwaitAllowed()&&this.eatContextual("await")&&(e=this.state.lastTokStart),this.scope.enter(f),this.expect(d.parenL),this.match(d.semi))return e>-1&&this.unexpected(e),this.parseFor(t,null);const s=this.isLet();if(this.match(d._var)||this.match(d._const)||s){const i=this.startNode(),r=s?"let":this.state.value;return this.next(),this.parseVar(i,!0,r),this.finishNode(i,"VariableDeclaration"),(this.match(d._in)||this.isContextual("of"))&&1===i.declarations.length?this.parseForIn(t,i,e):(e>-1&&this.unexpected(e),this.parseFor(t,i))}const i=new Le,r=this.parseExpression(!0,i);if(this.match(d._in)||this.isContextual("of")){this.toAssignable(r);const s=this.isContextual("of")?"for-of statement":"for-in statement";return this.checkLVal(r,void 0,void 0,s),this.parseForIn(t,r,e)}return this.checkExpressionErrors(i,!0),e>-1&&this.unexpected(e),this.parseFor(t,r)}parseFunctionStatement(t,e,s){return this.next(),this.parseFunction(t,He|(s?0:ze),e)}parseIfStatement(t){return this.next(),t.test=this.parseHeaderExpression(),t.consequent=this.parseStatement("if"),t.alternate=this.eat(d._else)?this.parseStatement("if"):null,this.finishNode(t,"IfStatement")}parseReturnStatement(t){return this.prodParam.hasReturn||this.options.allowReturnOutsideFunction||this.raise(this.state.start,ut.IllegalReturn),this.next(),this.isLineTerminator()?t.argument=null:(t.argument=this.parseExpression(),this.semicolon()),this.finishNode(t,"ReturnStatement")}parseSwitchStatement(t){this.next(),t.discriminant=this.parseHeaderExpression();const e=t.cases=[];let s,i;for(this.expect(d.braceL),this.state.labels.push(qe),this.scope.enter(f);!this.match(d.braceR);)if(this.match(d._case)||this.match(d._default)){const t=this.match(d._case);s&&this.finishNode(s,"SwitchCase"),e.push(s=this.startNode()),s.consequent=[],this.next(),t?s.test=this.parseExpression():(i&&this.raise(this.state.lastTokStart,ut.MultipleDefaultsInSwitch),i=!0,s.test=null),this.expect(d.colon)}else s?s.consequent.push(this.parseStatement(null)):this.unexpected();return this.scope.exit(),s&&this.finishNode(s,"SwitchCase"),this.next(),this.state.labels.pop(),this.finishNode(t,"SwitchStatement")}parseThrowStatement(t){return this.next(),et.test(this.input.slice(this.state.lastTokEnd,this.state.start))&&this.raise(this.state.lastTokEnd,ut.NewlineAfterThrow),t.argument=this.parseExpression(),this.semicolon(),this.finishNode(t,"ThrowStatement")}parseTryStatement(t){if(this.next(),t.block=this.parseBlock(),t.handler=null,this.match(d._catch)){const e=this.startNode();if(this.next(),this.match(d.parenL)){this.expect(d.parenL),e.param=this.parseBindingAtom();const t="Identifier"===e.param.type;this.scope.enter(t?x:0),this.checkLVal(e.param,_,null,"catch clause"),this.expect(d.parenR)}else e.param=null,this.scope.enter(f);e.body=this.withTopicForbiddingContext(()=>this.parseBlock(!1,!1)),this.scope.exit(),t.handler=this.finishNode(e,"CatchClause")}return t.finalizer=this.eat(d._finally)?this.parseBlock():null,t.handler||t.finalizer||this.raise(t.start,ut.NoCatchOrFinally),this.finishNode(t,"TryStatement")}parseVarStatement(t,e){return this.next(),this.parseVar(t,!1,e),this.semicolon(),this.finishNode(t,"VariableDeclaration")}parseWhileStatement(t){return this.next(),t.test=this.parseHeaderExpression(),this.state.labels.push(Ue),t.body=this.withTopicForbiddingContext(()=>this.parseStatement("while")),this.state.labels.pop(),this.finishNode(t,"WhileStatement")}parseWithStatement(t){return this.state.strict&&this.raise(this.state.start,ut.StrictWith),this.next(),t.object=this.parseHeaderExpression(),t.body=this.withTopicForbiddingContext(()=>this.parseStatement("with")),this.finishNode(t,"WithStatement")}parseEmptyStatement(t){return this.next(),this.finishNode(t,"EmptyStatement")}parseLabeledStatement(t,e,s,i){for(let n=0,a=this.state.labels;n=0;n--){const e=this.state.labels[n];if(e.statementStart!==t.start)break;e.statementStart=this.state.start,e.kind=r}return this.state.labels.push({name:e,kind:r,statementStart:this.state.start}),t.body=this.parseStatement(i?-1===i.indexOf("label")?i+"label":i:"label"),this.state.labels.pop(),t.label=s,this.finishNode(t,"LabeledStatement")}parseExpressionStatement(t,e){return t.expression=e,this.semicolon(),this.finishNode(t,"ExpressionStatement")}parseBlock(t=!1,e=!0,s){const i=this.startNode();return this.expect(d.braceL),e&&this.scope.enter(f),this.parseBlockBody(i,t,!1,d.braceR,s),e&&this.scope.exit(),this.finishNode(i,"BlockStatement")}isValidDirective(t){return"ExpressionStatement"===t.type&&"StringLiteral"===t.expression.type&&!t.expression.extra.parenthesized}parseBlockBody(t,e,s,i,r){const n=t.body=[],a=t.directives=[];this.parseBlockOrModuleBlockBody(n,e?a:void 0,s,i,r)}parseBlockOrModuleBlockBody(t,e,s,i,r){const n=[],a=this.state.strict;let o=!1,c=!1;while(!this.match(i)){!c&&this.state.octalPositions.length&&n.push(...this.state.octalPositions);const i=this.parseStatement(null,s);if(e&&!c&&this.isValidDirective(i)){const t=this.stmtToDirective(i);e.push(t),o||"use strict"!==t.value.value||(o=!0,this.setStrict(!0))}else c=!0,t.push(i)}if(this.state.strict&&n.length)for(let h=0;hthis.parseStatement("for")),this.scope.exit(),this.state.labels.pop(),this.finishNode(t,"ForStatement")}parseForIn(t,e,s){const i=this.match(d._in);return this.next(),i?s>-1&&this.unexpected(s):t.await=s>-1,"VariableDeclaration"!==e.type||null==e.declarations[0].init||i&&!this.state.strict&&"var"===e.kind&&"Identifier"===e.declarations[0].id.type?"AssignmentPattern"===e.type&&this.raise(e.start,ut.InvalidLhs,"for-loop"):this.raise(e.start,ut.ForInOfLoopInitializer,i?"for-in":"for-of"),t.left=e,t.right=i?this.parseExpression():this.parseMaybeAssign(),this.expect(d.parenR),t.body=this.withTopicForbiddingContext(()=>this.parseStatement("for")),this.scope.exit(),this.state.labels.pop(),this.finishNode(t,i?"ForInStatement":"ForOfStatement")}parseVar(t,e,s){const i=t.declarations=[],r=this.hasPlugin("typescript");for(t.kind=s;;){const t=this.startNode();if(this.parseVarId(t,s),this.eat(d.eq)?t.init=this.parseMaybeAssign(e):("const"!==s||this.match(d._in)||this.isContextual("of")?"Identifier"===t.id.type||e&&(this.match(d._in)||this.isContextual("of"))||this.raise(this.state.lastTokEnd,ut.DeclarationMissingInitializer,"Complex binding patterns"):r||this.unexpected(),t.init=null),i.push(this.finishNode(t,"VariableDeclarator")),!this.eat(d.comma))break}return t}parseVarId(t,e){t.id=this.parseBindingAtom(),this.checkLVal(t.id,"var"===e?R:_,void 0,"variable declaration","var"!==e)}parseFunction(t,e=Ve,s=!1){const i=e&He,r=e&ze,n=!!i&&!(e&We);this.initFunction(t,s),this.match(d.star)&&r&&this.raise(this.state.start,ut.GeneratorInSingleStatementContext),t.generator=this.eat(d.star),i&&(t.id=this.parseFunctionId(n));const a=this.state.maybeInArrowParameters,o=this.state.yieldPos,c=this.state.awaitPos;return this.state.maybeInArrowParameters=!1,this.state.yieldPos=-1,this.state.awaitPos=-1,this.scope.enter(y),this.prodParam.enter(he(s,t.generator)),i||(t.id=this.parseFunctionId()),this.parseFunctionParams(t),this.withTopicForbiddingContext(()=>{this.parseFunctionBodyAndFinish(t,i?"FunctionDeclaration":"FunctionExpression")}),this.prodParam.exit(),this.scope.exit(),i&&!r&&this.registerFunctionStatementId(t),this.state.maybeInArrowParameters=a,this.state.yieldPos=o,this.state.awaitPos=c,t}parseFunctionId(t){return t||this.match(d.name)?this.parseIdentifier():null}parseFunctionParams(t,e){const s=this.state.inParameters;this.state.inParameters=!0,this.expect(d.parenL),t.params=this.parseBindingList(d.parenR,41,!1,e),this.state.inParameters=s,this.checkYieldAwaitInDefaultParams()}registerFunctionStatementId(t){t.id&&this.scope.declareName(t.id.name,this.state.strict||t.generator||t.async?this.scope.treatFunctionsAsVar?R:_:j,t.id.start)}parseClass(t,e,s){this.next(),this.takeDecorators(t);const i=this.state.strict;return this.state.strict=!0,this.parseClassId(t,e,s),this.parseClassSuper(t),t.body=this.parseClassBody(!!t.superClass,i),this.state.strict=i,this.finishNode(t,e?"ClassDeclaration":"ClassExpression")}isClassProperty(){return this.match(d.eq)||this.match(d.semi)||this.match(d.braceR)}isClassMethod(){return this.match(d.parenL)}isNonstaticConstructor(t){return!t.computed&&!t.static&&("constructor"===t.key.name||"constructor"===t.key.value)}parseClassBody(t,e){this.classScope.enter();const s={hadConstructor:!1};let i=[];const r=this.startNode();if(r.body=[],this.expect(d.braceL),this.withTopicForbiddingContext(()=>{while(!this.match(d.braceR)){if(this.eat(d.semi)){if(i.length>0)throw this.raise(this.state.lastTokEnd,ut.DecoratorSemicolon);continue}if(this.match(d.at)){i.push(this.parseDecorator());continue}const e=this.startNode();i.length&&(e.decorators=i,this.resetStartLocationFromNode(e,i[0]),i=[]),this.parseClassMember(r,e,s,t),"constructor"===e.kind&&e.decorators&&e.decorators.length>0&&this.raise(e.start,ut.DecoratorConstructor)}}),e||(this.state.strict=!1),this.next(),i.length)throw this.raise(this.state.start,ut.TrailingDecorator);return this.classScope.exit(),this.finishNode(r,"ClassBody")}parseClassMemberFromModifier(t,e){const s=this.state.containsEsc,i=this.parseIdentifier(!0);if(this.isClassMethod()){const s=e;return s.kind="method",s.computed=!1,s.key=i,s.static=!1,this.pushClassMethod(t,s,!1,!1,!1,!1),!0}if(this.isClassProperty()){const s=e;return s.computed=!1,s.key=i,s.static=!1,t.body.push(this.parseClassProperty(s)),!0}if(s)throw this.unexpected();return!1}parseClassMember(t,e,s,i){const r=this.isContextual("static");r&&this.parseClassMemberFromModifier(t,e)||this.parseClassMemberWithIsStatic(t,e,s,r,i)}parseClassMemberWithIsStatic(t,e,s,i,r){const n=e,a=e,o=e,c=e,h=n,l=n;if(e.static=i,this.eat(d.star))return h.kind="method",this.parseClassPropertyName(h),"PrivateName"===h.key.type?void this.pushClassPrivateMethod(t,a,!0,!1):(this.isNonstaticConstructor(n)&&this.raise(n.key.start,ut.ConstructorIsGenerator),void this.pushClassMethod(t,n,!0,!1,!1,!1));const p=this.state.containsEsc,u=this.parseClassPropertyName(e),f="PrivateName"===u.type,m="Identifier"===u.type,y=this.state.start;if(this.parsePostMemberNameModifiers(l),this.isClassMethod()){if(h.kind="method",f)return void this.pushClassPrivateMethod(t,a,!1,!1);const e=this.isNonstaticConstructor(n);let i=!1;e&&(n.kind="constructor",s.hadConstructor&&!this.hasPlugin("typescript")&&this.raise(u.start,ut.DuplicateConstructor),s.hadConstructor=!0,i=r),this.pushClassMethod(t,n,!1,!1,e,i)}else if(this.isClassProperty())f?this.pushClassPrivateProperty(t,c):this.pushClassProperty(t,o);else if(!m||"async"!==u.name||p||this.isLineTerminator())!m||"get"!==u.name&&"set"!==u.name||p||this.match(d.star)&&this.isLineTerminator()?this.isLineTerminator()?f?this.pushClassPrivateProperty(t,c):this.pushClassProperty(t,o):this.unexpected():(h.kind=u.name,this.parseClassPropertyName(n),"PrivateName"===h.key.type?this.pushClassPrivateMethod(t,a,!1,!1):(this.isNonstaticConstructor(n)&&this.raise(n.key.start,ut.ConstructorIsAccessor),this.pushClassMethod(t,n,!1,!1,!1,!1)),this.checkGetterSetterParams(n));else{const e=this.eat(d.star);l.optional&&this.unexpected(y),h.kind="method",this.parseClassPropertyName(h),this.parsePostMemberNameModifiers(l),"PrivateName"===h.key.type?this.pushClassPrivateMethod(t,a,e,!0):(this.isNonstaticConstructor(n)&&this.raise(n.key.start,ut.ConstructorIsAsync),this.pushClassMethod(t,n,e,!0,!1,!1))}}parseClassPropertyName(t){const e=this.parsePropertyName(t,!0);return t.computed||!t.static||"prototype"!==e.name&&"prototype"!==e.value||this.raise(e.start,ut.StaticPrototype),"PrivateName"===e.type&&"constructor"===e.id.name&&this.raise(e.start,ut.ConstructorClassPrivateField),e}pushClassProperty(t,e){e.computed||"constructor"!==e.key.name&&"constructor"!==e.key.value||this.raise(e.key.start,ut.ConstructorClassField),t.body.push(this.parseClassProperty(e))}pushClassPrivateProperty(t,e){this.expectPlugin("classPrivateProperties",e.key.start);const s=this.parseClassPrivateProperty(e);t.body.push(s),this.classScope.declarePrivateName(s.key.id.name,tt,s.key.start)}pushClassMethod(t,e,s,i,r,n){t.body.push(this.parseMethod(e,s,i,r,n,"ClassMethod",!0))}pushClassPrivateMethod(t,e,s,i){this.expectPlugin("classPrivateMethods",e.key.start);const r=this.parseMethod(e,s,i,!1,!1,"ClassPrivateMethod",!0);t.body.push(r);const n="get"===r.kind?r.static?Y:Q:"set"===r.kind?r.static?J:Z:tt;this.classScope.declarePrivateName(r.key.id.name,n,r.key.start)}parsePostMemberNameModifiers(t){}parseAccessModifier(){}parseClassPrivateProperty(t){return this.scope.enter(w|b),this.prodParam.enter(re),t.value=this.eat(d.eq)?this.parseMaybeAssign():null,this.semicolon(),this.prodParam.exit(),this.scope.exit(),this.finishNode(t,"ClassPrivateProperty")}parseClassProperty(t){return t.typeAnnotation||this.expectPlugin("classProperties"),this.scope.enter(w|b),this.prodParam.enter(re),this.match(d.eq)?(this.expectPlugin("classProperties"),this.next(),t.value=this.parseMaybeAssign()):t.value=null,this.semicolon(),this.prodParam.exit(),this.scope.exit(),this.finishNode(t,"ClassProperty")}parseClassId(t,e,s,i=L){this.match(d.name)?(t.id=this.parseIdentifier(),e&&this.checkLVal(t.id,i,void 0,"class name")):s||!e?t.id=null:this.unexpected(null,ut.MissingClassName)}parseClassSuper(t){t.superClass=this.eat(d._extends)?this.parseExprSubscripts():null}parseExport(t){const e=this.maybeParseExportDefaultSpecifier(t),s=!e||this.eat(d.comma),i=s&&this.eatExportStar(t),r=i&&this.maybeParseExportNamespaceSpecifier(t),n=s&&(!r||this.eat(d.comma)),a=e||i;if(i&&!r)return e&&this.unexpected(),this.parseExportFrom(t,!0),this.finishNode(t,"ExportAllDeclaration");const o=this.maybeParseExportNamedSpecifiers(t);if(e&&s&&!i&&!o||r&&n&&!o)throw this.unexpected(null,d.braceL);let c;if(a||o?(c=!1,this.parseExportFrom(t,a)):c=this.maybeParseExportDeclaration(t),a||o||c)return this.checkExport(t,!0,!1,!!t.source),this.finishNode(t,"ExportNamedDeclaration");if(this.eat(d._default))return t.declaration=this.parseExportDefaultExpression(),this.checkExport(t,!0,!0),this.finishNode(t,"ExportDefaultDeclaration");throw this.unexpected(null,d.braceL)}eatExportStar(t){return this.eat(d.star)}maybeParseExportDefaultSpecifier(t){if(this.isExportDefaultSpecifier()){this.expectPlugin("exportDefaultFrom");const e=this.startNode();return e.exported=this.parseIdentifier(!0),t.specifiers=[this.finishNode(e,"ExportDefaultSpecifier")],!0}return!1}maybeParseExportNamespaceSpecifier(t){if(this.isContextual("as")){t.specifiers||(t.specifiers=[]);const e=this.startNodeAt(this.state.lastTokStart,this.state.lastTokStartLoc);return this.next(),e.exported=this.parseIdentifier(!0),t.specifiers.push(this.finishNode(e,"ExportNamespaceSpecifier")),!0}return!1}maybeParseExportNamedSpecifiers(t){return!!this.match(d.braceL)&&(t.specifiers||(t.specifiers=[]),t.specifiers.push(...this.parseExportSpecifiers()),t.source=null,t.declaration=null,!0)}maybeParseExportDeclaration(t){if(this.shouldParseExportDeclaration()){if(this.isContextual("async")){const t=this.nextTokenStart();this.isUnparsedContextual(t,"function")||this.unexpected(t,d._function)}return t.specifiers=[],t.source=null,t.declaration=this.parseExportDeclaration(t),!0}return!1}isAsyncFunction(){if(!this.isContextual("async"))return!1;const t=this.nextTokenStart();return!et.test(this.input.slice(this.state.pos,t))&&this.isUnparsedContextual(t,"function")}parseExportDefaultExpression(){const t=this.startNode(),e=this.isAsyncFunction();if(this.match(d._function)||e)return this.next(),e&&this.next(),this.parseFunction(t,He|We,e);if(this.match(d._class))return this.parseClass(t,!0,!0);if(this.match(d.at))return this.hasPlugin("decorators")&&this.getPluginOption("decorators","decoratorsBeforeExport")&&this.raise(this.state.start,ut.DecoratorBeforeExport),this.parseDecorators(!1),this.parseClass(t,!0,!0);if(this.match(d._const)||this.match(d._var)||this.isLet())throw this.raise(this.state.start,ut.UnsupportedDefaultExport);{const t=this.parseMaybeAssign();return this.semicolon(),t}}parseExportDeclaration(t){return this.parseStatement(null)}isExportDefaultSpecifier(){if(this.match(d.name)){const t=this.state.value;if("async"===t||"let"===t)return!1;if(("type"===t||"interface"===t)&&!this.state.containsEsc){const t=this.lookahead();if(t.type===d.name&&"from"!==t.value||t.type===d.braceL)return this.expectOnePlugin(["flow","typescript"]),!1}}else if(!this.match(d._default))return!1;const t=this.nextTokenStart(),e=this.isUnparsedContextual(t,"from");if(44===this.input.charCodeAt(t)||this.match(d.name)&&e)return!0;if(this.match(d._default)&&e){const e=this.input.charCodeAt(this.nextTokenStartSince(t+4));return 34===e||39===e}return!1}parseExportFrom(t,e){this.eatContextual("from")?(t.source=this.parseImportSource(),this.checkExport(t)):e?this.unexpected():t.source=null,this.semicolon()}shouldParseExportDeclaration(){if(this.match(d.at)&&(this.expectOnePlugin(["decorators","decorators-legacy"]),this.hasPlugin("decorators"))){if(!this.getPluginOption("decorators","decoratorsBeforeExport"))return!0;this.unexpected(this.state.start,ut.DecoratorBeforeExport)}return"var"===this.state.type.keyword||"const"===this.state.type.keyword||"function"===this.state.type.keyword||"class"===this.state.type.keyword||this.isLet()||this.isAsyncFunction()}checkExport(t,e,s,i){if(e)if(s){if(this.checkDuplicateExports(t,"default"),this.hasPlugin("exportDefaultFrom")){var r;const e=t.declaration;"Identifier"!==e.type||"from"!==e.name||e.end-e.start!==4||(null==(r=e.extra)?void 0:r.parenthesized)||this.raise(e.start,ut.ExportDefaultFromAsIdentifier)}}else if(t.specifiers&&t.specifiers.length)for(let a=0,o=t.specifiers;a-1&&this.raise(t.start,"default"===e?ut.DuplicateDefaultExport:ut.DuplicateExport,e),this.state.exportedIdentifiers.push(e)}parseExportSpecifiers(){const t=[];let e=!0;this.expect(d.braceL);while(!this.eat(d.braceR)){if(e)e=!1;else if(this.expect(d.comma),this.eat(d.braceR))break;const s=this.startNode();s.local=this.parseIdentifier(!0),s.exported=this.eatContextual("as")?this.parseIdentifier(!0):s.local.__clone(),t.push(this.finishNode(s,"ExportSpecifier"))}return t}parseImport(t){if(t.specifiers=[],!this.match(d.string)){const e=this.maybeParseDefaultImportSpecifier(t),s=!e||this.eat(d.comma),i=s&&this.maybeParseStarImportSpecifier(t);s&&!i&&this.parseNamedImportSpecifiers(t),this.expectContextual("from")}t.source=this.parseImportSource();const e=this.maybeParseModuleAttributes();return e&&(t.attributes=e),this.semicolon(),this.finishNode(t,"ImportDeclaration")}parseImportSource(){return this.match(d.string)||this.unexpected(),this.parseExprAtom()}shouldParseDefaultImport(t){return this.match(d.name)}parseImportSpecifierLocal(t,e,s,i){e.local=this.parseIdentifier(),this.checkLVal(e.local,_,void 0,i),t.specifiers.push(this.finishNode(e,s))}maybeParseModuleAttributes(){if(!this.match(d._with)||this.hasPrecedingLineBreak())return this.hasPlugin("moduleAttributes")?[]:null;this.expectPlugin("moduleAttributes"),this.next();const t=[],e=new Set;do{const s=this.startNode();if(s.key=this.parseIdentifier(!0),"type"!==s.key.name&&this.raise(s.key.start,ut.ModuleAttributeDifferentFromType,s.key.name),e.has(s.key.name)&&this.raise(s.key.start,ut.ModuleAttributesWithDuplicateKeys,s.key.name),e.add(s.key.name),this.expect(d.colon),!this.match(d.string))throw this.unexpected(this.state.start,ut.ModuleAttributeInvalidValue);s.value=this.parseLiteral(this.state.value,"StringLiteral"),this.finishNode(s,"ImportAttribute"),t.push(s)}while(this.eat(d.comma));return t}maybeParseDefaultImportSpecifier(t){return!!this.shouldParseDefaultImport(t)&&(this.parseImportSpecifierLocal(t,this.startNode(),"ImportDefaultSpecifier","default import specifier"),!0)}maybeParseStarImportSpecifier(t){if(this.match(d.star)){const e=this.startNode();return this.next(),this.expectContextual("as"),this.parseImportSpecifierLocal(t,e,"ImportNamespaceSpecifier","import namespace specifier"),!0}return!1}parseNamedImportSpecifiers(t){let e=!0;this.expect(d.braceL);while(!this.eat(d.braceR)){if(e)e=!1;else{if(this.eat(d.colon))throw this.raise(this.state.start,ut.DestructureNamedImport);if(this.expect(d.comma),this.eat(d.braceR))break}this.parseImportSpecifier(t)}}parseImportSpecifier(t){const e=this.startNode();e.imported=this.parseIdentifier(!0),this.eatContextual("as")?e.local=this.parseIdentifier():(this.checkReservedWord(e.imported.name,e.start,!0,!0),e.local=e.imported.__clone()),this.checkLVal(e.local,_,void 0,"import specifier"),t.specifiers.push(this.finishNode(e,"ImportSpecifier"))}}class $e{constructor(){this.privateNames=new Set,this.loneAccessors=new Map,this.undefinedPrivateNames=new Map}}class Xe{constructor(t){this.stack=[],this.undefinedPrivateNames=new Map,this.raise=t}current(){return this.stack[this.stack.length-1]}enter(){this.stack.push(new $e)}exit(){const t=this.stack.pop(),e=this.current();for(let s=0,i=Array.from(t.undefinedPrivateNames);sge(t,e)),s=e.join("/");let i=ts[s];if(!i){i=Ge;for(let t=0;t=51||!i((function(){var e=[],s=e.constructor={};return s[a]=function(){return{foo:1}},1!==e[t](Boolean).foo}))}},"21a1":function(t,e,s){(function(e){(function(e,s){t.exports=s()})(0,(function(){"use strict";"undefined"!==typeof window?window:"undefined"!==typeof e||"undefined"!==typeof self&&self;function t(t,e){return e={exports:{}},t(e,e.exports),e.exports}var s=t((function(t,e){(function(e,s){t.exports=s()})(0,(function(){function t(t){var e=t&&"object"===typeof t;return e&&"[object RegExp]"!==Object.prototype.toString.call(t)&&"[object Date]"!==Object.prototype.toString.call(t)}function e(t){return Array.isArray(t)?[]:{}}function s(s,i){var r=i&&!0===i.clone;return r&&t(s)?n(e(s),s,i):s}function i(e,i,r){var a=e.slice();return i.forEach((function(i,o){"undefined"===typeof a[o]?a[o]=s(i,r):t(i)?a[o]=n(e[o],i,r):-1===e.indexOf(i)&&a.push(s(i,r))})),a}function r(e,i,r){var a={};return t(e)&&Object.keys(e).forEach((function(t){a[t]=s(e[t],r)})),Object.keys(i).forEach((function(o){t(i[o])&&e[o]?a[o]=n(e[o],i[o],r):a[o]=s(i[o],r)})),a}function n(t,e,n){var a=Array.isArray(e),o=n||{arrayMerge:i},c=o.arrayMerge||i;return a?Array.isArray(t)?c(t,e,n):s(e,n):r(t,e,n)}return n.all=function(t,e){if(!Array.isArray(t)||t.length<2)throw new Error("first argument should be an array with at least two elements");return t.reduce((function(t,s){return n(t,s,e)}))},n}))}));function i(t){return t=t||Object.create(null),{on:function(e,s){(t[e]||(t[e]=[])).push(s)},off:function(e,s){t[e]&&t[e].splice(t[e].indexOf(s)>>>0,1)},emit:function(e,s){(t[e]||[]).map((function(t){t(s)})),(t["*"]||[]).map((function(t){t(e,s)}))}}}var r=t((function(t,e){var s={svg:{name:"xmlns",uri:"http://www.w3.org/2000/svg"},xlink:{name:"xmlns:xlink",uri:"http://www.w3.org/1999/xlink"}};e.default=s,t.exports=e.default})),n=function(t){return Object.keys(t).map((function(e){var s=t[e].toString().replace(/"/g,""");return e+'="'+s+'"'})).join(" ")},a=r.svg,o=r.xlink,c={};c[a.name]=a.uri,c[o.name]=o.uri;var h,l=function(t,e){void 0===t&&(t="");var i=s(c,e||{}),r=n(i);return""+t+""},p=r.svg,u=r.xlink,d={attrs:(h={style:["position: absolute","width: 0","height: 0"].join("; "),"aria-hidden":"true"},h[p.name]=p.uri,h[u.name]=u.uri,h)},f=function(t){this.config=s(d,t||{}),this.symbols=[]};f.prototype.add=function(t){var e=this,s=e.symbols,i=this.find(t.id);return i?(s[s.indexOf(i)]=t,!1):(s.push(t),!0)},f.prototype.remove=function(t){var e=this,s=e.symbols,i=this.find(t);return!!i&&(s.splice(s.indexOf(i),1),i.destroy(),!0)},f.prototype.find=function(t){return this.symbols.filter((function(e){return e.id===t}))[0]||null},f.prototype.has=function(t){return null!==this.find(t)},f.prototype.stringify=function(){var t=this.config,e=t.attrs,s=this.symbols.map((function(t){return t.stringify()})).join("");return l(s,e)},f.prototype.toString=function(){return this.stringify()},f.prototype.destroy=function(){this.symbols.forEach((function(t){return t.destroy()}))};var m=function(t){var e=t.id,s=t.viewBox,i=t.content;this.id=e,this.viewBox=s,this.content=i};m.prototype.stringify=function(){return this.content},m.prototype.toString=function(){return this.stringify()},m.prototype.destroy=function(){var t=this;["id","viewBox","content"].forEach((function(e){return delete t[e]}))};var y=function(t){var e=!!document.importNode,s=(new DOMParser).parseFromString(t,"image/svg+xml").documentElement;return e?document.importNode(s,!0):s},g=function(t){function e(){t.apply(this,arguments)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var s={isMounted:{}};return s.isMounted.get=function(){return!!this.node},e.createFromExistingNode=function(t){return new e({id:t.getAttribute("id"),viewBox:t.getAttribute("viewBox"),content:t.outerHTML})},e.prototype.destroy=function(){this.isMounted&&this.unmount(),t.prototype.destroy.call(this)},e.prototype.mount=function(t){if(this.isMounted)return this.node;var e="string"===typeof t?document.querySelector(t):t,s=this.render();return this.node=s,e.appendChild(s),s},e.prototype.render=function(){var t=this.stringify();return y(l(t)).childNodes[0]},e.prototype.unmount=function(){this.node.parentNode.removeChild(this.node)},Object.defineProperties(e.prototype,s),e}(m),x={autoConfigure:!0,mountTo:"body",syncUrlsWithBaseTag:!1,listenLocationChangeEvent:!0,locationChangeEvent:"locationChange",locationChangeAngularEmitter:!1,usagesToUpdate:"use[*|href]",moveGradientsOutsideSymbol:!1},b=function(t){return Array.prototype.slice.call(t,0)},v={isChrome:function(){return/chrome/i.test(navigator.userAgent)},isFirefox:function(){return/firefox/i.test(navigator.userAgent)},isIE:function(){return/msie/i.test(navigator.userAgent)||/trident/i.test(navigator.userAgent)},isEdge:function(){return/edge/i.test(navigator.userAgent)}},w=function(t,e){var s=document.createEvent("CustomEvent");s.initCustomEvent(t,!1,!1,e),window.dispatchEvent(s)},P=function(t){var e=[];return b(t.querySelectorAll("style")).forEach((function(t){t.textContent+="",e.push(t)})),e},T=function(t){return(t||window.location.href).split("#")[0]},E=function(t){angular.module("ng").run(["$rootScope",function(e){e.$on("$locationChangeSuccess",(function(e,s,i){w(t,{oldUrl:i,newUrl:s})}))}])},A="linearGradient, radialGradient, pattern, mask, clipPath",S=function(t,e){return void 0===e&&(e=A),b(t.querySelectorAll("symbol")).forEach((function(t){b(t.querySelectorAll(e)).forEach((function(e){t.parentNode.insertBefore(e,t)}))})),t};function C(t,e){var s=b(t).reduce((function(t,s){if(!s.attributes)return t;var i=b(s.attributes),r=e?i.filter(e):i;return t.concat(r)}),[]);return s}var k=r.xlink.uri,N="xlink:href",I=/[{}|\\\^\[\]`"<>]/g;function O(t){return t.replace(I,(function(t){return"%"+t[0].charCodeAt(0).toString(16).toUpperCase()}))}function D(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function M(t,e,s){return b(t).forEach((function(t){var i=t.getAttribute(N);if(i&&0===i.indexOf(e)){var r=i.replace(e,s);t.setAttributeNS(k,N,r)}})),t}var L,_=["clipPath","colorProfile","src","cursor","fill","filter","marker","markerStart","markerMid","markerEnd","mask","stroke","style"],R=_.map((function(t){return"["+t+"]"})).join(","),j=function(t,e,s,i){var r=O(s),n=O(i),a=t.querySelectorAll(R),o=C(a,(function(t){var e=t.localName,s=t.value;return-1!==_.indexOf(e)&&-1!==s.indexOf("url("+r)}));o.forEach((function(t){return t.value=t.value.replace(new RegExp(D(r),"g"),n)})),M(e,r,n)},F={MOUNT:"mount",SYMBOL_MOUNT:"symbol_mount"},B=function(t){function e(e){var r=this;void 0===e&&(e={}),t.call(this,s(x,e));var n=i();this._emitter=n,this.node=null;var a=this,o=a.config;if(o.autoConfigure&&this._autoConfigure(e),o.syncUrlsWithBaseTag){var c=document.getElementsByTagName("base")[0].getAttribute("href");n.on(F.MOUNT,(function(){return r.updateUrls("#",c)}))}var h=this._handleLocationChange.bind(this);this._handleLocationChange=h,o.listenLocationChangeEvent&&window.addEventListener(o.locationChangeEvent,h),o.locationChangeAngularEmitter&&E(o.locationChangeEvent),n.on(F.MOUNT,(function(t){o.moveGradientsOutsideSymbol&&S(t)})),n.on(F.SYMBOL_MOUNT,(function(t){o.moveGradientsOutsideSymbol&&S(t.parentNode),(v.isIE()||v.isEdge())&&P(t)}))}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={isMounted:{}};return r.isMounted.get=function(){return!!this.node},e.prototype._autoConfigure=function(t){var e=this,s=e.config;"undefined"===typeof t.syncUrlsWithBaseTag&&(s.syncUrlsWithBaseTag="undefined"!==typeof document.getElementsByTagName("base")[0]),"undefined"===typeof t.locationChangeAngularEmitter&&(s.locationChangeAngularEmitter="undefined"!==typeof window.angular),"undefined"===typeof t.moveGradientsOutsideSymbol&&(s.moveGradientsOutsideSymbol=v.isFirefox())},e.prototype._handleLocationChange=function(t){var e=t.detail,s=e.oldUrl,i=e.newUrl;this.updateUrls(s,i)},e.prototype.add=function(e){var s=this,i=t.prototype.add.call(this,e);return this.isMounted&&i&&(e.mount(s.node),this._emitter.emit(F.SYMBOL_MOUNT,e.node)),i},e.prototype.attach=function(t){var e=this,s=this;if(s.isMounted)return s.node;var i="string"===typeof t?document.querySelector(t):t;return s.node=i,this.symbols.forEach((function(t){t.mount(s.node),e._emitter.emit(F.SYMBOL_MOUNT,t.node)})),b(i.querySelectorAll("symbol")).forEach((function(t){var e=g.createFromExistingNode(t);e.node=t,s.add(e)})),this._emitter.emit(F.MOUNT,i),i},e.prototype.destroy=function(){var t=this,e=t.config,s=t.symbols,i=t._emitter;s.forEach((function(t){return t.destroy()})),i.off("*"),window.removeEventListener(e.locationChangeEvent,this._handleLocationChange),this.isMounted&&this.unmount()},e.prototype.mount=function(t,e){void 0===t&&(t=this.config.mountTo),void 0===e&&(e=!1);var s=this;if(s.isMounted)return s.node;var i="string"===typeof t?document.querySelector(t):t,r=s.render();return this.node=r,e&&i.childNodes[0]?i.insertBefore(r,i.childNodes[0]):i.appendChild(r),this._emitter.emit(F.MOUNT,r),r},e.prototype.render=function(){return y(this.stringify())},e.prototype.unmount=function(){this.node.parentNode.removeChild(this.node)},e.prototype.updateUrls=function(t,e){if(!this.isMounted)return!1;var s=document.querySelectorAll(this.config.usagesToUpdate);return j(this.node,s,T(t)+"#",T(e)+"#"),!0},Object.defineProperties(e.prototype,r),e}(f),U=t((function(t){ +/*! + * domready (c) Dustin Diaz 2014 - License MIT + */ +!function(e,s){t.exports=s()}(0,(function(){var t,e=[],s=document,i=s.documentElement.doScroll,r="DOMContentLoaded",n=(i?/^loaded|^c/:/^loaded|^i|^c/).test(s.readyState);return n||s.addEventListener(r,t=function(){s.removeEventListener(r,t),n=1;while(t=e.shift())t()}),function(t){n?setTimeout(t,0):e.push(t)}}))})),q="__SVG_SPRITE_NODE__",V="__SVG_SPRITE__",H=!!window[V];H?L=window[V]:(L=new B({attrs:{id:q}}),window[V]=L);var z=function(){var t=document.getElementById(q);t?L.attach(t):L.mount(document.body,!0)};document.body?z():U(z);var W=L;return W}))}).call(this,s("c8ba"))},"21a6":function(t,e,s){(function(s){var i,r,n;(function(s,a){r=[],i=a,n="function"===typeof i?i.apply(e,r):i,void 0===n||(t.exports=n)})(0,(function(){"use strict";function e(t,e){return"undefined"==typeof e?e={autoBom:!1}:"object"!=typeof e&&(console.warn("Deprecated: Expected third argument to be a object"),e={autoBom:!e}),e.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(t.type)?new Blob(["\ufeff",t],{type:t.type}):t}function i(t,e,s){var i=new XMLHttpRequest;i.open("GET",t),i.responseType="blob",i.onload=function(){o(i.response,e,s)},i.onerror=function(){console.error("could not download file")},i.send()}function r(t){var e=new XMLHttpRequest;e.open("HEAD",t,!1);try{e.send()}catch(t){}return 200<=e.status&&299>=e.status}function n(t){try{t.dispatchEvent(new MouseEvent("click"))}catch(i){var e=document.createEvent("MouseEvents");e.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),t.dispatchEvent(e)}}var a="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof s&&s.global===s?s:void 0,o=a.saveAs||("object"!=typeof window||window!==a?function(){}:"download"in HTMLAnchorElement.prototype?function(t,e,s){var o=a.URL||a.webkitURL,c=document.createElement("a");e=e||t.name||"download",c.download=e,c.rel="noopener","string"==typeof t?(c.href=t,c.origin===location.origin?n(c):r(c.href)?i(t,e,s):n(c,c.target="_blank")):(c.href=o.createObjectURL(t),setTimeout((function(){o.revokeObjectURL(c.href)}),4e4),setTimeout((function(){n(c)}),0))}:"msSaveOrOpenBlob"in navigator?function(t,s,a){if(s=s||t.name||"download","string"!=typeof t)navigator.msSaveOrOpenBlob(e(t,a),s);else if(r(t))i(t,s,a);else{var o=document.createElement("a");o.href=t,o.target="_blank",setTimeout((function(){n(o)}))}}:function(t,e,s,r){if(r=r||open("","_blank"),r&&(r.document.title=r.document.body.innerText="downloading..."),"string"==typeof t)return i(t,e,s);var n="application/octet-stream"===t.type,o=/constructor/i.test(a.HTMLElement)||a.safari,c=/CriOS\/[\d]+/.test(navigator.userAgent);if((c||n&&o)&&"object"==typeof FileReader){var h=new FileReader;h.onloadend=function(){var t=h.result;t=c?t:t.replace(/^data:[^;]*;/,"data:attachment/file;"),r?r.location.href=t:location=t,r=null},h.readAsDataURL(t)}else{var l=a.URL||a.webkitURL,p=l.createObjectURL(t);r?r.location=p:location.href=p,r=null,setTimeout((function(){l.revokeObjectURL(p)}),4e4)}});a.saveAs=o.saveAs=o,t.exports=o}))}).call(this,s("c8ba"))},2266:function(t,e,s){var i=s("825a"),r=s("e95a"),n=s("50c4"),a=s("0366"),o=s("35a1"),c=s("9bdd"),h=function(t,e){this.stopped=t,this.result=e},l=t.exports=function(t,e,s,l,p){var u,d,f,m,y,g,x,b=a(e,s,l?2:1);if(p)u=t;else{if(d=o(t),"function"!=typeof d)throw TypeError("Target is not iterable");if(r(d)){for(f=0,m=n(t.length);m>f;f++)if(y=l?b(i(x=t[f])[0],x[1]):b(t[f]),y&&y instanceof h)return y;return new h(!1)}u=d.call(t)}g=u.next;while(!(x=g.call(u)).done)if(y=c(u,b,x.value,l),"object"==typeof y&&y&&y instanceof h)return y;return new h(!1)};l.stop=function(t){return new h(!0,t)}},"23cb":function(t,e,s){var i=s("a691"),r=Math.max,n=Math.min;t.exports=function(t,e){var s=i(t);return s<0?r(s+e,0):n(s,e)}},"23e7":function(t,e,s){var i=s("da84"),r=s("06cf").f,n=s("9112"),a=s("6eeb"),o=s("ce4e"),c=s("e893"),h=s("94ca");t.exports=function(t,e){var s,l,p,u,d,f,m=t.target,y=t.global,g=t.stat;if(l=y?i:g?i[m]||o(m,{}):(i[m]||{}).prototype,l)for(p in e){if(d=e[p],t.noTargetGet?(f=r(l,p),u=f&&f.value):u=l[p],s=h(y?p:m+(g?".":"#")+p,t.forced),!s&&void 0!==u){if(typeof d===typeof u)continue;c(d,u)}(t.sham||u&&u.sham)&&n(d,"sham",!0),a(l,p,d,t)}}},"241c":function(t,e,s){var i=s("ca84"),r=s("7839"),n=r.concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return i(t,n)}},"25f0":function(t,e,s){"use strict";var i=s("6eeb"),r=s("825a"),n=s("d039"),a=s("ad6d"),o="toString",c=RegExp.prototype,h=c[o],l=n((function(){return"/a/b"!=h.call({source:"a",flags:"b"})})),p=h.name!=o;(l||p)&&i(RegExp.prototype,o,(function(){var t=r(this),e=String(t.source),s=t.flags,i=String(void 0===s&&t instanceof RegExp&&!("flags"in c)?a.call(t):s);return"/"+e+"/"+i}),{unsafe:!0})},2626:function(t,e,s){"use strict";var i=s("d066"),r=s("9bf2"),n=s("b622"),a=s("83ab"),o=n("species");t.exports=function(t){var e=i(t),s=r.f;a&&e&&!e[o]&&s(e,o,{configurable:!0,get:function(){return this}})}},2877:function(t,e,s){"use strict";function i(t,e,s,i,r,n,a,o){var c,h="function"===typeof t?t.options:t;if(e&&(h.render=e,h.staticRenderFns=s,h._compiled=!0),i&&(h.functional=!0),n&&(h._scopeId="data-v-"+n),a?(c=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"===typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),r&&r.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},h._ssrRegister=c):r&&(c=o?function(){r.call(this,(h.functional?this.parent:this).$root.$options.shadowRoot)}:r),c)if(h.functional){h._injectStyles=c;var l=h.render;h.render=function(t,e){return c.call(e),l(t,e)}}else{var p=h.beforeCreate;h.beforeCreate=p?[].concat(p,c):[c]}return{exports:t,options:h}}s.d(e,"a",(function(){return i}))},"28a0":function(t,e){"function"===typeof Object.create?t.exports=function(t,e){t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(t,e){t.super_=e;var s=function(){};s.prototype=e.prototype,t.prototype=new s,t.prototype.constructor=t}},"2cf4":function(t,e,s){var i,r,n,a=s("da84"),o=s("d039"),c=s("c6b6"),h=s("0366"),l=s("1be4"),p=s("cc12"),u=s("1cdc"),d=a.location,f=a.setImmediate,m=a.clearImmediate,y=a.process,g=a.MessageChannel,x=a.Dispatch,b=0,v={},w="onreadystatechange",P=function(t){if(v.hasOwnProperty(t)){var e=v[t];delete v[t],e()}},T=function(t){return function(){P(t)}},E=function(t){P(t.data)},A=function(t){a.postMessage(t+"",d.protocol+"//"+d.host)};f&&m||(f=function(t){var e=[],s=1;while(arguments.length>s)e.push(arguments[s++]);return v[++b]=function(){("function"==typeof t?t:Function(t)).apply(void 0,e)},i(b),b},m=function(t){delete v[t]},"process"==c(y)?i=function(t){y.nextTick(T(t))}:x&&x.now?i=function(t){x.now(T(t))}:g&&!u?(r=new g,n=r.port2,r.port1.onmessage=E,i=h(n.postMessage,n,1)):!a.addEventListener||"function"!=typeof postMessage||a.importScripts||o(A)||"file:"===d.protocol?i=w in p("script")?function(t){l.appendChild(p("script"))[w]=function(){l.removeChild(this),P(t)}}:function(t){setTimeout(T(t),0)}:(i=A,a.addEventListener("message",E,!1))),t.exports={set:f,clear:m}},"2d00":function(t,e,s){var i,r,n=s("da84"),a=s("342f"),o=n.process,c=o&&o.versions,h=c&&c.v8;h?(i=h.split("."),r=i[0]+i[1]):a&&(i=a.match(/Edge\/(\d+)/),(!i||i[1]>=74)&&(i=a.match(/Chrome\/(\d+)/),i&&(r=i[1]))),t.exports=r&&+r},3022:function(t,e,s){(function(t){var i=Object.getOwnPropertyDescriptors||function(t){for(var e=Object.keys(t),s={},i=0;i=n)return t;switch(t){case"%s":return String(i[s++]);case"%d":return Number(i[s++]);case"%j":try{return JSON.stringify(i[s++])}catch(e){return"[Circular]"}default:return t}})),c=i[s];s=3&&(i.depth=arguments[2]),arguments.length>=4&&(i.colors=arguments[3]),x(s)?i.showHidden=s:s&&e._extend(i,s),E(i.showHidden)&&(i.showHidden=!1),E(i.depth)&&(i.depth=2),E(i.colors)&&(i.colors=!1),E(i.customInspect)&&(i.customInspect=!0),i.colors&&(i.stylize=c),p(i,t,i.depth)}function c(t,e){var s=o.styles[e];return s?"["+o.colors[s][0]+"m"+t+"["+o.colors[s][1]+"m":t}function h(t,e){return t}function l(t){var e={};return t.forEach((function(t,s){e[t]=!0})),e}function p(t,s,i){if(t.customInspect&&s&&N(s.inspect)&&s.inspect!==e.inspect&&(!s.constructor||s.constructor.prototype!==s)){var r=s.inspect(i,t);return P(r)||(r=p(t,r,i)),r}var n=u(t,s);if(n)return n;var a=Object.keys(s),o=l(a);if(t.showHidden&&(a=Object.getOwnPropertyNames(s)),k(s)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return d(s);if(0===a.length){if(N(s)){var c=s.name?": "+s.name:"";return t.stylize("[Function"+c+"]","special")}if(A(s))return t.stylize(RegExp.prototype.toString.call(s),"regexp");if(C(s))return t.stylize(Date.prototype.toString.call(s),"date");if(k(s))return d(s)}var h,x="",b=!1,v=["{","}"];if(g(s)&&(b=!0,v=["[","]"]),N(s)){var w=s.name?": "+s.name:"";x=" [Function"+w+"]"}return A(s)&&(x=" "+RegExp.prototype.toString.call(s)),C(s)&&(x=" "+Date.prototype.toUTCString.call(s)),k(s)&&(x=" "+d(s)),0!==a.length||b&&0!=s.length?i<0?A(s)?t.stylize(RegExp.prototype.toString.call(s),"regexp"):t.stylize("[Object]","special"):(t.seen.push(s),h=b?f(t,s,i,o,a):a.map((function(e){return m(t,s,i,o,e,b)})),t.seen.pop(),y(h,x,v)):v[0]+x+v[1]}function u(t,e){if(E(e))return t.stylize("undefined","undefined");if(P(e)){var s="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(s,"string")}return w(e)?t.stylize(""+e,"number"):x(e)?t.stylize(""+e,"boolean"):b(e)?t.stylize("null","null"):void 0}function d(t){return"["+Error.prototype.toString.call(t)+"]"}function f(t,e,s,i,r){for(var n=[],a=0,o=e.length;a-1&&(o=n?o.split("\n").map((function(t){return" "+t})).join("\n").substr(2):"\n"+o.split("\n").map((function(t){return" "+t})).join("\n"))):o=t.stylize("[Circular]","special")),E(a)){if(n&&r.match(/^\d+$/))return o;a=JSON.stringify(""+r),a.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=t.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=t.stylize(a,"string"))}return a+": "+o}function y(t,e,s){var i=t.reduce((function(t,e){return e.indexOf("\n")>=0&&0,t+e.replace(/\u001b\[\d\d?m/g,"").length+1}),0);return i>60?s[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+s[1]:s[0]+e+" "+t.join(", ")+" "+s[1]}function g(t){return Array.isArray(t)}function x(t){return"boolean"===typeof t}function b(t){return null===t}function v(t){return null==t}function w(t){return"number"===typeof t}function P(t){return"string"===typeof t}function T(t){return"symbol"===typeof t}function E(t){return void 0===t}function A(t){return S(t)&&"[object RegExp]"===O(t)}function S(t){return"object"===typeof t&&null!==t}function C(t){return S(t)&&"[object Date]"===O(t)}function k(t){return S(t)&&("[object Error]"===O(t)||t instanceof Error)}function N(t){return"function"===typeof t}function I(t){return null===t||"boolean"===typeof t||"number"===typeof t||"string"===typeof t||"symbol"===typeof t||"undefined"===typeof t}function O(t){return Object.prototype.toString.call(t)}function D(t){return t<10?"0"+t.toString(10):t.toString(10)}e.debuglog=function(s){if(E(n)&&(n=Object({NODE_ENV:"production",BASE_URL:"/form-generator/"}).NODE_DEBUG||""),s=s.toUpperCase(),!a[s])if(new RegExp("\\b"+s+"\\b","i").test(n)){var i=t.pid;a[s]=function(){var t=e.format.apply(e,arguments);console.error("%s %d: %s",s,i,t)}}else a[s]=function(){};return a[s]},e.inspect=o,o.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},o.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},e.isArray=g,e.isBoolean=x,e.isNull=b,e.isNullOrUndefined=v,e.isNumber=w,e.isString=P,e.isSymbol=T,e.isUndefined=E,e.isRegExp=A,e.isObject=S,e.isDate=C,e.isError=k,e.isFunction=N,e.isPrimitive=I,e.isBuffer=s("d60a");var M=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function L(){var t=new Date,e=[D(t.getHours()),D(t.getMinutes()),D(t.getSeconds())].join(":");return[t.getDate(),M[t.getMonth()],e].join(" ")}function _(t,e){return Object.prototype.hasOwnProperty.call(t,e)}e.log=function(){console.log("%s - %s",L(),e.format.apply(e,arguments))},e.inherits=s("28a0"),e._extend=function(t,e){if(!e||!S(e))return t;var s=Object.keys(e),i=s.length;while(i--)t[s[i]]=e[s[i]];return t};var R="undefined"!==typeof Symbol?Symbol("util.promisify.custom"):void 0;function j(t,e){if(!t){var s=new Error("Promise was rejected with a falsy value");s.reason=t,t=s}return e(t)}function F(e){if("function"!==typeof e)throw new TypeError('The "original" argument must be of type Function');function s(){for(var s=[],i=0;i=h?t?"":void 0:(n=o.charCodeAt(c),n<55296||n>56319||c+1===h||(a=o.charCodeAt(c+1))<56320||a>57343?t?o.charAt(c):n:t?o.slice(c,c+2):a-56320+(n-55296<<10)+65536)}}},"0390":function(t,e,s){"use strict";var i=s("02f4")(!0);t.exports=function(t,e,s){return e+(s?i(t,e).length:1)}},"0bfb":function(t,e,s){"use strict";var i=s("cb7c");t.exports=function(){var t=i(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},"0d58":function(t,e,s){var i=s("ce10"),r=s("e11e");t.exports=Object.keys||function(t){return i(t,r)}},1495:function(t,e,s){var i=s("86cc"),r=s("cb7c"),n=s("0d58");t.exports=s("9e1e")?Object.defineProperties:function(t,e){r(t);var s,a=n(e),o=a.length,c=0;while(o>c)i.f(t,s=a[c++],e[s]);return t}},"214f":function(t,e,s){"use strict";s("b0c5");var i=s("2aba"),r=s("32e9"),n=s("79e5"),a=s("be13"),o=s("2b4c"),c=s("520a"),h=o("species"),l=!n((function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:"7"},t},"7"!=="".replace(t,"$")})),p=function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var s="ab".split(t);return 2===s.length&&"a"===s[0]&&"b"===s[1]}();t.exports=function(t,e,s){var u=o(t),d=!n((function(){var e={};return e[u]=function(){return 7},7!=""[t](e)})),f=d?!n((function(){var e=!1,s=/a/;return s.exec=function(){return e=!0,null},"split"===t&&(s.constructor={},s.constructor[h]=function(){return s}),s[u](""),!e})):void 0;if(!d||!f||"replace"===t&&!l||"split"===t&&!p){var m=/./[u],y=s(a,u,""[t],(function(t,e,s,i,r){return e.exec===c?d&&!r?{done:!0,value:m.call(e,s,i)}:{done:!0,value:t.call(s,e,i)}:{done:!1}})),g=y[0],x=y[1];i(String.prototype,t,g),r(RegExp.prototype,u,2==e?function(t,e){return x.call(t,this,e)}:function(t){return x.call(t,this)})}}},"230e":function(t,e,s){var i=s("d3f4"),r=s("7726").document,n=i(r)&&i(r.createElement);t.exports=function(t){return n?r.createElement(t):{}}},"23c6":function(t,e,s){var i=s("2d95"),r=s("2b4c")("toStringTag"),n="Arguments"==i(function(){return arguments}()),a=function(t,e){try{return t[e]}catch(s){}};t.exports=function(t){var e,s,o;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(s=a(e=Object(t),r))?s:n?i(e):"Object"==(o=i(e))&&"function"==typeof e.callee?"Arguments":o}},2621:function(t,e){e.f=Object.getOwnPropertySymbols},"2aba":function(t,e,s){var i=s("7726"),r=s("32e9"),n=s("69a8"),a=s("ca5a")("src"),o=s("fa5b"),c="toString",h=(""+o).split(c);s("8378").inspectSource=function(t){return o.call(t)},(t.exports=function(t,e,s,o){var c="function"==typeof s;c&&(n(s,"name")||r(s,"name",e)),t[e]!==s&&(c&&(n(s,a)||r(s,a,t[e]?""+t[e]:h.join(String(e)))),t===i?t[e]=s:o?t[e]?t[e]=s:r(t,e,s):(delete t[e],r(t,e,s)))})(Function.prototype,c,(function(){return"function"==typeof this&&this[a]||o.call(this)}))},"2aeb":function(t,e,s){var i=s("cb7c"),r=s("1495"),n=s("e11e"),a=s("613b")("IE_PROTO"),o=function(){},c="prototype",h=function(){var t,e=s("230e")("iframe"),i=n.length,r="<",a=">";e.style.display="none",s("fab2").appendChild(e),e.src="javascript:",t=e.contentWindow.document,t.open(),t.write(r+"script"+a+"document.F=Object"+r+"/script"+a),t.close(),h=t.F;while(i--)delete h[c][n[i]];return h()};t.exports=Object.create||function(t,e){var s;return null!==t?(o[c]=i(t),s=new o,o[c]=null,s[a]=t):s=h(),void 0===e?s:r(s,e)}},"2b4c":function(t,e,s){var i=s("5537")("wks"),r=s("ca5a"),n=s("7726").Symbol,a="function"==typeof n,o=t.exports=function(t){return i[t]||(i[t]=a&&n[t]||(a?n:r)("Symbol."+t))};o.store=i},"2d00":function(t,e){t.exports=!1},"2d95":function(t,e){var s={}.toString;t.exports=function(t){return s.call(t).slice(8,-1)}},"2fdb":function(t,e,s){"use strict";var i=s("5ca1"),r=s("d2c8"),n="includes";i(i.P+i.F*s("5147")(n),"String",{includes:function(t){return!!~r(this,t,n).indexOf(t,arguments.length>1?arguments[1]:void 0)}})},"32e9":function(t,e,s){var i=s("86cc"),r=s("4630");t.exports=s("9e1e")?function(t,e,s){return i.f(t,e,r(1,s))}:function(t,e,s){return t[e]=s,t}},"38fd":function(t,e,s){var i=s("69a8"),r=s("4bf8"),n=s("613b")("IE_PROTO"),a=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=r(t),i(t,n)?t[n]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?a:null}},"41a0":function(t,e,s){"use strict";var i=s("2aeb"),r=s("4630"),n=s("7f20"),a={};s("32e9")(a,s("2b4c")("iterator"),(function(){return this})),t.exports=function(t,e,s){t.prototype=i(a,{next:r(1,s)}),n(t,e+" Iterator")}},"456d":function(t,e,s){var i=s("4bf8"),r=s("0d58");s("5eda")("keys",(function(){return function(t){return r(i(t))}}))},4588:function(t,e){var s=Math.ceil,i=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?i:s)(t)}},4630:function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},"4bf8":function(t,e,s){var i=s("be13");t.exports=function(t){return Object(i(t))}},5147:function(t,e,s){var i=s("2b4c")("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(s){try{return e[i]=!1,!"/./"[t](e)}catch(r){}}return!0}},"520a":function(t,e,s){"use strict";var i=s("0bfb"),r=RegExp.prototype.exec,n=String.prototype.replace,a=r,o="lastIndex",c=function(){var t=/a/,e=/b*/g;return r.call(t,"a"),r.call(e,"a"),0!==t[o]||0!==e[o]}(),h=void 0!==/()??/.exec("")[1],l=c||h;l&&(a=function(t){var e,s,a,l,p=this;return h&&(s=new RegExp("^"+p.source+"$(?!\\s)",i.call(p))),c&&(e=p[o]),a=r.call(p,t),c&&a&&(p[o]=p.global?a.index+a[0].length:e),h&&a&&a.length>1&&n.call(a[0],s,(function(){for(l=1;l1?arguments[1]:void 0)}}),s("9c6c")("includes")},6821:function(t,e,s){var i=s("626a"),r=s("be13");t.exports=function(t){return i(r(t))}},"69a8":function(t,e){var s={}.hasOwnProperty;t.exports=function(t,e){return s.call(t,e)}},"6a99":function(t,e,s){var i=s("d3f4");t.exports=function(t,e){if(!i(t))return t;var s,r;if(e&&"function"==typeof(s=t.toString)&&!i(r=s.call(t)))return r;if("function"==typeof(s=t.valueOf)&&!i(r=s.call(t)))return r;if(!e&&"function"==typeof(s=t.toString)&&!i(r=s.call(t)))return r;throw TypeError("Can't convert object to primitive value")}},7333:function(t,e,s){"use strict";var i=s("9e1e"),r=s("0d58"),n=s("2621"),a=s("52a7"),o=s("4bf8"),c=s("626a"),h=Object.assign;t.exports=!h||s("79e5")((function(){var t={},e={},s=Symbol(),i="abcdefghijklmnopqrst";return t[s]=7,i.split("").forEach((function(t){e[t]=t})),7!=h({},t)[s]||Object.keys(h({},e)).join("")!=i}))?function(t,e){var s=o(t),h=arguments.length,l=1,p=n.f,u=a.f;while(h>l){var d,f=c(arguments[l++]),m=p?r(f).concat(p(f)):r(f),y=m.length,g=0;while(y>g)d=m[g++],i&&!u.call(f,d)||(s[d]=f[d])}return s}:h},7726:function(t,e){var s=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=s)},"77f1":function(t,e,s){var i=s("4588"),r=Math.max,n=Math.min;t.exports=function(t,e){return t=i(t),t<0?r(t+e,0):n(t,e)}},"79e5":function(t,e){t.exports=function(t){try{return!!t()}catch(e){return!0}}},"7f20":function(t,e,s){var i=s("86cc").f,r=s("69a8"),n=s("2b4c")("toStringTag");t.exports=function(t,e,s){t&&!r(t=s?t:t.prototype,n)&&i(t,n,{configurable:!0,value:e})}},8378:function(t,e){var s=t.exports={version:"2.6.11"};"number"==typeof __e&&(__e=s)},"84f2":function(t,e){t.exports={}},"86cc":function(t,e,s){var i=s("cb7c"),r=s("c69a"),n=s("6a99"),a=Object.defineProperty;e.f=s("9e1e")?Object.defineProperty:function(t,e,s){if(i(t),e=n(e,!0),i(s),r)try{return a(t,e,s)}catch(o){}if("get"in s||"set"in s)throw TypeError("Accessors not supported!");return"value"in s&&(t[e]=s.value),t}},"9b43":function(t,e,s){var i=s("d8e8");t.exports=function(t,e,s){if(i(t),void 0===e)return t;switch(s){case 1:return function(s){return t.call(e,s)};case 2:return function(s,i){return t.call(e,s,i)};case 3:return function(s,i,r){return t.call(e,s,i,r)}}return function(){return t.apply(e,arguments)}}},"9c6c":function(t,e,s){var i=s("2b4c")("unscopables"),r=Array.prototype;void 0==r[i]&&s("32e9")(r,i,{}),t.exports=function(t){r[i][t]=!0}},"9def":function(t,e,s){var i=s("4588"),r=Math.min;t.exports=function(t){return t>0?r(i(t),9007199254740991):0}},"9e1e":function(t,e,s){t.exports=!s("79e5")((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}))},a352:function(t,e){t.exports=s("aa47")},a481:function(t,e,s){"use strict";var i=s("cb7c"),r=s("4bf8"),n=s("9def"),a=s("4588"),o=s("0390"),c=s("5f1b"),h=Math.max,l=Math.min,p=Math.floor,u=/\$([$&`']|\d\d?|<[^>]*>)/g,d=/\$([$&`']|\d\d?)/g,f=function(t){return void 0===t?t:String(t)};s("214f")("replace",2,(function(t,e,s,m){return[function(i,r){var n=t(this),a=void 0==i?void 0:i[e];return void 0!==a?a.call(i,n,r):s.call(String(n),i,r)},function(t,e){var r=m(s,t,this,e);if(r.done)return r.value;var p=i(t),u=String(this),d="function"===typeof e;d||(e=String(e));var g=p.global;if(g){var x=p.unicode;p.lastIndex=0}var b=[];while(1){var v=c(p,u);if(null===v)break;if(b.push(v),!g)break;var w=String(v[0]);""===w&&(p.lastIndex=o(u,n(p.lastIndex),x))}for(var P="",T=0,E=0;E=T&&(P+=u.slice(T,S)+O,T=S+A.length)}return P+u.slice(T)}];function y(t,e,i,n,a,o){var c=i+t.length,h=n.length,l=d;return void 0!==a&&(a=r(a),l=u),s.call(o,l,(function(s,r){var o;switch(r.charAt(0)){case"$":return"$";case"&":return t;case"`":return e.slice(0,i);case"'":return e.slice(c);case"<":o=a[r.slice(1,-1)];break;default:var l=+r;if(0===l)return s;if(l>h){var u=p(l/10);return 0===u?s:u<=h?void 0===n[u-1]?r.charAt(1):n[u-1]+r.charAt(1):s}o=n[l-1]}return void 0===o?"":o}))}}))},aae3:function(t,e,s){var i=s("d3f4"),r=s("2d95"),n=s("2b4c")("match");t.exports=function(t){var e;return i(t)&&(void 0!==(e=t[n])?!!e:"RegExp"==r(t))}},ac6a:function(t,e,s){for(var i=s("cadf"),r=s("0d58"),n=s("2aba"),a=s("7726"),o=s("32e9"),c=s("84f2"),h=s("2b4c"),l=h("iterator"),p=h("toStringTag"),u=c.Array,d={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},f=r(d),m=0;ml)if(o=c[l++],o!=o)return!0}else for(;h>l;l++)if((t||l in c)&&c[l]===s)return t||l||0;return!t&&-1}}},c649:function(t,e,s){"use strict";(function(t){s.d(e,"c",(function(){return h})),s.d(e,"a",(function(){return o})),s.d(e,"b",(function(){return r})),s.d(e,"d",(function(){return c}));s("a481");function i(){return"undefined"!==typeof window?window.console:t.console}var r=i();function n(t){var e=Object.create(null);return function(s){var i=e[s];return i||(e[s]=t(s))}}var a=/-(\w)/g,o=n((function(t){return t.replace(a,(function(t,e){return e?e.toUpperCase():""}))}));function c(t){null!==t.parentElement&&t.parentElement.removeChild(t)}function h(t,e,s){var i=0===s?t.children[0]:t.children[s-1].nextSibling;t.insertBefore(e,i)}}).call(this,s("c8ba"))},c69a:function(t,e,s){t.exports=!s("9e1e")&&!s("79e5")((function(){return 7!=Object.defineProperty(s("230e")("div"),"a",{get:function(){return 7}}).a}))},c8ba:function(t,e){var s;s=function(){return this}();try{s=s||new Function("return this")()}catch(i){"object"===typeof window&&(s=window)}t.exports=s},ca5a:function(t,e){var s=0,i=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++s+i).toString(36))}},cadf:function(t,e,s){"use strict";var i=s("9c6c"),r=s("d53b"),n=s("84f2"),a=s("6821");t.exports=s("01f9")(Array,"Array",(function(t,e){this._t=a(t),this._i=0,this._k=e}),(function(){var t=this._t,e=this._k,s=this._i++;return!t||s>=t.length?(this._t=void 0,r(1)):r(0,"keys"==e?s:"values"==e?t[s]:[s,t[s]])}),"values"),n.Arguments=n.Array,i("keys"),i("values"),i("entries")},cb7c:function(t,e,s){var i=s("d3f4");t.exports=function(t){if(!i(t))throw TypeError(t+" is not an object!");return t}},ce10:function(t,e,s){var i=s("69a8"),r=s("6821"),n=s("c366")(!1),a=s("613b")("IE_PROTO");t.exports=function(t,e){var s,o=r(t),c=0,h=[];for(s in o)s!=a&&i(o,s)&&h.push(s);while(e.length>c)i(o,s=e[c++])&&(~n(h,s)||h.push(s));return h}},d2c8:function(t,e,s){var i=s("aae3"),r=s("be13");t.exports=function(t,e,s){if(i(e))throw TypeError("String#"+s+" doesn't accept regex!");return String(r(t))}},d3f4:function(t,e){t.exports=function(t){return"object"===typeof t?null!==t:"function"===typeof t}},d53b:function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},d8e8:function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},e11e:function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},f559:function(t,e,s){"use strict";var i=s("5ca1"),r=s("9def"),n=s("d2c8"),a="startsWith",o=""[a];i(i.P+i.F*s("5147")(a),"String",{startsWith:function(t){var e=n(this,t,a),s=r(Math.min(arguments.length>1?arguments[1]:void 0,e.length)),i=String(t);return o?o.call(e,i,s):e.slice(s,s+i.length)===i}})},f6fd:function(t,e){(function(t){var e="currentScript",s=t.getElementsByTagName("script");e in t||Object.defineProperty(t,e,{get:function(){try{throw new Error}catch(i){var t,e=(/.*at [^\(]*\((.*):.+:.+\)$/gi.exec(i.stack)||[!1])[1];for(t in s)if(s[t].src==e||"interactive"==s[t].readyState)return s[t];return null}}})})(document)},f751:function(t,e,s){var i=s("5ca1");i(i.S+i.F,"Object",{assign:s("7333")})},fa5b:function(t,e,s){t.exports=s("5537")("native-function-to-string",Function.toString)},fab2:function(t,e,s){var i=s("7726").document;t.exports=i&&i.documentElement},fb15:function(t,e,s){"use strict";var i;(s.r(e),"undefined"!==typeof window)&&(s("f6fd"),(i=window.document.currentScript)&&(i=i.src.match(/(.+\/)[^/]+\.js(\?.*)?$/))&&(s.p=i[1]));s("f751"),s("f559"),s("ac6a"),s("cadf"),s("456d");function r(t){if(Array.isArray(t))return t}function n(t,e){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(t)){var s=[],i=!0,r=!1,n=void 0;try{for(var a,o=t[Symbol.iterator]();!(i=(a=o.next()).done);i=!0)if(s.push(a.value),e&&s.length===e)break}catch(c){r=!0,n=c}finally{try{i||null==o["return"]||o["return"]()}finally{if(r)throw n}}return s}}function a(t,e){(null==e||e>t.length)&&(e=t.length);for(var s=0,i=new Array(e);s=n?r.length:r.indexOf(t)}));return s?a.filter((function(t){return-1!==t})):a}function v(t,e){var s=this;this.$nextTick((function(){return s.$emit(t.toLowerCase(),e)}))}function w(t){var e=this;return function(s){null!==e.realList&&e["onDrag"+t](s),v.call(e,t,s)}}function P(t){return["transition-group","TransitionGroup"].includes(t)}function T(t){if(!t||1!==t.length)return!1;var e=h(t,1),s=e[0].componentOptions;return!!s&&P(s.tag)}function E(t,e,s){return t[s]||(e[s]?e[s]():void 0)}function A(t,e,s){var i=0,r=0,n=E(e,s,"header");n&&(i=n.length,t=t?[].concat(d(n),d(t)):d(n));var a=E(e,s,"footer");return a&&(r=a.length,t=t?[].concat(d(t),d(a)):d(a)),{children:t,headerOffset:i,footerOffset:r}}function S(t,e){var s=null,i=function(t,e){s=g(s,t,e)},r=Object.keys(t).filter((function(t){return"id"===t||t.startsWith("data-")})).reduce((function(e,s){return e[s]=t[s],e}),{});if(i("attrs",r),!e)return s;var n=e.on,a=e.props,o=e.attrs;return i("on",n),i("props",a),Object.assign(s.attrs,o),s}var C=["Start","Add","Remove","Update","End"],k=["Choose","Unchoose","Sort","Filter","Clone"],N=["Move"].concat(C,k).map((function(t){return"on"+t})),I=null,O={options:Object,list:{type:Array,required:!1,default:null},value:{type:Array,required:!1,default:null},noTransitionOnDrag:{type:Boolean,default:!1},clone:{type:Function,default:function(t){return t}},element:{type:String,default:"div"},tag:{type:String,default:null},move:{type:Function,default:null},componentData:{type:Object,required:!1,default:null}},D={name:"draggable",inheritAttrs:!1,props:O,data:function(){return{transitionMode:!1,noneFunctionalComponentMode:!1}},render:function(t){var e=this.$slots.default;this.transitionMode=T(e);var s=A(e,this.$slots,this.$scopedSlots),i=s.children,r=s.headerOffset,n=s.footerOffset;this.headerOffset=r,this.footerOffset=n;var a=S(this.$attrs,this.componentData);return t(this.getTag(),a,i)},created:function(){null!==this.list&&null!==this.value&&y["b"].error("Value and list props are mutually exclusive! Please set one or another."),"div"!==this.element&&y["b"].warn("Element props is deprecated please use tag props instead. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#element-props"),void 0!==this.options&&y["b"].warn("Options props is deprecated, add sortable options directly as vue.draggable item, or use v-bind. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#options-props")},mounted:function(){var t=this;if(this.noneFunctionalComponentMode=this.getTag().toLowerCase()!==this.$el.nodeName.toLowerCase()&&!this.getIsFunctional(),this.noneFunctionalComponentMode&&this.transitionMode)throw new Error("Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ".concat(this.getTag()));var e={};C.forEach((function(s){e["on"+s]=w.call(t,s)})),k.forEach((function(s){e["on"+s]=v.bind(t,s)}));var s=Object.keys(this.$attrs).reduce((function(e,s){return e[Object(y["a"])(s)]=t.$attrs[s],e}),{}),i=Object.assign({},this.options,s,e,{onMove:function(e,s){return t.onDragMove(e,s)}});!("draggable"in i)&&(i.draggable=">*"),this._sortable=new m.a(this.rootContainer,i),this.computeIndexes()},beforeDestroy:function(){void 0!==this._sortable&&this._sortable.destroy()},computed:{rootContainer:function(){return this.transitionMode?this.$el.children[0]:this.$el},realList:function(){return this.list?this.list:this.value}},watch:{options:{handler:function(t){this.updateOptions(t)},deep:!0},$attrs:{handler:function(t){this.updateOptions(t)},deep:!0},realList:function(){this.computeIndexes()}},methods:{getIsFunctional:function(){var t=this._vnode.fnOptions;return t&&t.functional},getTag:function(){return this.tag||this.element},updateOptions:function(t){for(var e in t){var s=Object(y["a"])(e);-1===N.indexOf(s)&&this._sortable.option(s,t[e])}},getChildrenNodes:function(){if(this.noneFunctionalComponentMode)return this.$children[0].$slots.default;var t=this.$slots.default;return this.transitionMode?t[0].child.$slots.default:t},computeIndexes:function(){var t=this;this.$nextTick((function(){t.visibleIndexes=b(t.getChildrenNodes(),t.rootContainer.children,t.transitionMode,t.footerOffset)}))},getUnderlyingVm:function(t){var e=x(this.getChildrenNodes()||[],t);if(-1===e)return null;var s=this.realList[e];return{index:e,element:s}},getUnderlyingPotencialDraggableComponent:function(t){var e=t.__vue__;return e&&e.$options&&P(e.$options._componentTag)?e.$parent:!("realList"in e)&&1===e.$children.length&&"realList"in e.$children[0]?e.$children[0]:e},emitChanges:function(t){var e=this;this.$nextTick((function(){e.$emit("change",t)}))},alterList:function(t){if(this.list)t(this.list);else{var e=d(this.value);t(e),this.$emit("input",e)}},spliceList:function(){var t=arguments,e=function(e){return e.splice.apply(e,d(t))};this.alterList(e)},updatePosition:function(t,e){var s=function(s){return s.splice(e,0,s.splice(t,1)[0])};this.alterList(s)},getRelatedContextFromMoveEvent:function(t){var e=t.to,s=t.related,i=this.getUnderlyingPotencialDraggableComponent(e);if(!i)return{component:i};var r=i.realList,n={list:r,component:i};if(e!==s&&r&&i.getUnderlyingVm){var a=i.getUnderlyingVm(s);if(a)return Object.assign(a,n)}return n},getVmIndex:function(t){var e=this.visibleIndexes,s=e.length;return t>s-1?s:e[t]},getComponent:function(){return this.$slots.default[0].componentInstance},resetTransitionData:function(t){if(this.noTransitionOnDrag&&this.transitionMode){var e=this.getChildrenNodes();e[t].data=null;var s=this.getComponent();s.children=[],s.kept=void 0}},onDragStart:function(t){this.context=this.getUnderlyingVm(t.item),t.item._underlying_vm_=this.clone(this.context.element),I=t.item},onDragAdd:function(t){var e=t.item._underlying_vm_;if(void 0!==e){Object(y["d"])(t.item);var s=this.getVmIndex(t.newIndex);this.spliceList(s,0,e),this.computeIndexes();var i={element:e,newIndex:s};this.emitChanges({added:i})}},onDragRemove:function(t){if(Object(y["c"])(this.rootContainer,t.item,t.oldIndex),"clone"!==t.pullMode){var e=this.context.index;this.spliceList(e,1);var s={element:this.context.element,oldIndex:e};this.resetTransitionData(e),this.emitChanges({removed:s})}else Object(y["d"])(t.clone)},onDragUpdate:function(t){Object(y["d"])(t.item),Object(y["c"])(t.from,t.item,t.oldIndex);var e=this.context.index,s=this.getVmIndex(t.newIndex);this.updatePosition(e,s);var i={element:this.context.element,oldIndex:e,newIndex:s};this.emitChanges({moved:i})},updateProperty:function(t,e){t.hasOwnProperty(e)&&(t[e]+=this.headerOffset)},computeFutureIndex:function(t,e){if(!t.element)return 0;var s=d(e.to.children).filter((function(t){return"none"!==t.style["display"]})),i=s.indexOf(e.related),r=t.component.getVmIndex(i),n=-1!==s.indexOf(I);return n||!e.willInsertAfter?r:r+1},onDragMove:function(t,e){var s=this.move;if(!s||!this.realList)return!0;var i=this.getRelatedContextFromMoveEvent(t),r=this.context,n=this.computeFutureIndex(i,t);Object.assign(r,{futureIndex:n});var a=Object.assign({},t,{relatedContext:i,draggedContext:r});return s(a,e)},onDragEnd:function(){this.computeIndexes(),I=null}}};"undefined"!==typeof window&&"Vue"in window&&window.Vue.component("draggable",D);var M=D;e["default"]=M}})["default"]},"342f":function(t,e,s){var i=s("d066");t.exports=i("navigator","userAgent")||""},"35a1":function(t,e,s){var i=s("f5df"),r=s("3f8c"),n=s("b622"),a=n("iterator");t.exports=function(t){if(void 0!=t)return t[a]||t["@@iterator"]||r[i(t)]}},"37e8":function(t,e,s){var i=s("83ab"),r=s("9bf2"),n=s("825a"),a=s("df75");t.exports=i?Object.defineProperties:function(t,e){n(t);var s,i=a(e),o=i.length,c=0;while(o>c)r.f(t,s=i[c++],e[s]);return t}},"3bbe":function(t,e,s){var i=s("861d");t.exports=function(t){if(!i(t)&&null!==t)throw TypeError("Can't set "+String(t)+" as a prototype");return t}},"3ca3":function(t,e,s){"use strict";var i=s("6547").charAt,r=s("69f3"),n=s("7dd0"),a="String Iterator",o=r.set,c=r.getterFor(a);n(String,"String",(function(t){o(this,{type:a,string:String(t),index:0})}),(function(){var t,e=c(this),s=e.string,r=e.index;return r>=s.length?{value:void 0,done:!0}:(t=i(s,r),e.index+=t.length,{value:t,done:!1})}))},"3f8c":function(t,e){t.exports={}},4160:function(t,e,s){"use strict";var i=s("23e7"),r=s("17c2");i({target:"Array",proto:!0,forced:[].forEach!=r},{forEach:r})},"428f":function(t,e,s){var i=s("da84");t.exports=i},4362:function(t,e,s){e.nextTick=function(t){var e=Array.prototype.slice.call(arguments);e.shift(),setTimeout((function(){t.apply(null,e)}),0)},e.platform=e.arch=e.execPath=e.title="browser",e.pid=1,e.browser=!0,e.env={},e.argv=[],e.binding=function(t){throw new Error("No such module. (Possibly not yet loaded)")},function(){var t,i="/";e.cwd=function(){return i},e.chdir=function(e){t||(t=s("df7c")),i=t.resolve(e,i)}}(),e.exit=e.kill=e.umask=e.dlopen=e.uptime=e.memoryUsage=e.uvCounters=function(){},e.features={}},"44ad":function(t,e,s){var i=s("d039"),r=s("c6b6"),n="".split;t.exports=i((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==r(t)?n.call(t,""):Object(t)}:Object},"44d2":function(t,e,s){var i=s("b622"),r=s("7c73"),n=s("9bf2"),a=i("unscopables"),o=Array.prototype;void 0==o[a]&&n.f(o,a,{configurable:!0,value:r(null)}),t.exports=function(t){o[a][t]=!0}},"44de":function(t,e,s){var i=s("da84");t.exports=function(t,e){var s=i.console;s&&s.error&&(1===arguments.length?s.error(t):s.error(t,e))}},"44e7":function(t,e,s){var i=s("861d"),r=s("c6b6"),n=s("b622"),a=n("match");t.exports=function(t){var e;return i(t)&&(void 0!==(e=t[a])?!!e:"RegExp"==r(t))}},"45fc":function(t,e,s){"use strict";var i=s("23e7"),r=s("b727").some,n=s("a640"),a=s("ae40"),o=n("some"),c=a("some");i({target:"Array",proto:!0,forced:!o||!c},{some:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}})},4840:function(t,e,s){var i=s("825a"),r=s("1c0b"),n=s("b622"),a=n("species");t.exports=function(t,e){var s,n=i(t).constructor;return void 0===n||void 0==(s=i(n)[a])?e:r(s)}},4930:function(t,e,s){var i=s("d039");t.exports=!!Object.getOwnPropertySymbols&&!i((function(){return!String(Symbol())}))},"4d63":function(t,e,s){var i=s("83ab"),r=s("da84"),n=s("94ca"),a=s("7156"),o=s("9bf2").f,c=s("241c").f,h=s("44e7"),l=s("ad6d"),p=s("9f7f"),u=s("6eeb"),d=s("d039"),f=s("69f3").set,m=s("2626"),y=s("b622"),g=y("match"),x=r.RegExp,b=x.prototype,v=/a/g,w=/a/g,P=new x(v)!==v,T=p.UNSUPPORTED_Y,E=i&&n("RegExp",!P||T||d((function(){return w[g]=!1,x(v)!=v||x(w)==w||"/a/i"!=x(v,"i")})));if(E){var A=function(t,e){var s,i=this instanceof A,r=h(t),n=void 0===e;if(!i&&r&&t.constructor===A&&n)return t;P?r&&!n&&(t=t.source):t instanceof A&&(n&&(e=l.call(t)),t=t.source),T&&(s=!!e&&e.indexOf("y")>-1,s&&(e=e.replace(/y/g,"")));var o=a(P?new x(t,e):x(t,e),i?this:b,A);return T&&s&&f(o,{sticky:s}),o},S=function(t){t in A||o(A,t,{configurable:!0,get:function(){return x[t]},set:function(e){x[t]=e}})},C=c(x),k=0;while(C.length>k)S(C[k++]);b.constructor=A,A.prototype=b,u(r,"RegExp",A)}m("RegExp")},"4d64":function(t,e,s){var i=s("fc6a"),r=s("50c4"),n=s("23cb"),a=function(t){return function(e,s,a){var o,c=i(e),h=r(c.length),l=n(a,h);if(t&&s!=s){while(h>l)if(o=c[l++],o!=o)return!0}else for(;h>l;l++)if((t||l in c)&&c[l]===s)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},"4de4":function(t,e,s){"use strict";var i=s("23e7"),r=s("b727").filter,n=s("1dde"),a=s("ae40"),o=n("filter"),c=a("filter");i({target:"Array",proto:!0,forced:!o||!c},{filter:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}})},"50c4":function(t,e,s){var i=s("a691"),r=Math.min;t.exports=function(t){return t>0?r(i(t),9007199254740991):0}},5135:function(t,e){var s={}.hasOwnProperty;t.exports=function(t,e){return s.call(t,e)}},5319:function(t,e,s){"use strict";var i=s("d784"),r=s("825a"),n=s("7b0b"),a=s("50c4"),o=s("a691"),c=s("1d80"),h=s("8aa5"),l=s("14c3"),p=Math.max,u=Math.min,d=Math.floor,f=/\$([$&'`]|\d\d?|<[^>]*>)/g,m=/\$([$&'`]|\d\d?)/g,y=function(t){return void 0===t?t:String(t)};i("replace",2,(function(t,e,s,i){var g=i.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,x=i.REPLACE_KEEPS_$0,b=g?"$":"$0";return[function(s,i){var r=c(this),n=void 0==s?void 0:s[t];return void 0!==n?n.call(s,r,i):e.call(String(r),s,i)},function(t,i){if(!g&&x||"string"===typeof i&&-1===i.indexOf(b)){var n=s(e,t,this,i);if(n.done)return n.value}var c=r(t),d=String(this),f="function"===typeof i;f||(i=String(i));var m=c.global;if(m){var w=c.unicode;c.lastIndex=0}var P=[];while(1){var T=l(c,d);if(null===T)break;if(P.push(T),!m)break;var E=String(T[0]);""===E&&(c.lastIndex=h(d,a(c.lastIndex),w))}for(var A="",S=0,C=0;C=S&&(A+=d.slice(S,N)+L,S=N+k.length)}return A+d.slice(S)}];function v(t,s,i,r,a,o){var c=i+t.length,h=r.length,l=m;return void 0!==a&&(a=n(a),l=f),e.call(o,l,(function(e,n){var o;switch(n.charAt(0)){case"$":return"$";case"&":return t;case"`":return s.slice(0,i);case"'":return s.slice(c);case"<":o=a[n.slice(1,-1)];break;default:var l=+n;if(0===l)return e;if(l>h){var p=d(l/10);return 0===p?e:p<=h?void 0===r[p-1]?n.charAt(1):r[p-1]+n.charAt(1):e}o=r[l-1]}return void 0===o?"":o}))}}))},"53ca":function(t,e,s){"use strict";s.d(e,"a",(function(){return i}));s("a4d3"),s("e01a"),s("d28b"),s("d3b7"),s("3ca3"),s("ddb0");function i(t){return i="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"===typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i(t)}},5530:function(t,e,s){"use strict";s.d(e,"a",(function(){return n}));s("a4d3"),s("4de4"),s("4160"),s("e439"),s("dbb4"),s("b64b"),s("159b");var i=s("ade3");function r(t,e){var s=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),s.push.apply(s,i)}return s}function n(t){for(var e=1;el){var d,f=h(arguments[l++]),m=p?n(f).concat(p(f)):n(f),y=m.length,g=0;while(y>g)d=m[g++],i&&!u.call(f,d)||(s[d]=f[d])}return s}:l},6547:function(t,e,s){var i=s("a691"),r=s("1d80"),n=function(t){return function(e,s){var n,a,o=String(r(e)),c=i(s),h=o.length;return c<0||c>=h?t?"":void 0:(n=o.charCodeAt(c),n<55296||n>56319||c+1===h||(a=o.charCodeAt(c+1))<56320||a>57343?t?o.charAt(c):n:t?o.slice(c,c+2):a-56320+(n-55296<<10)+65536)}};t.exports={codeAt:n(!1),charAt:n(!0)}},"65f0":function(t,e,s){var i=s("861d"),r=s("e8b5"),n=s("b622"),a=n("species");t.exports=function(t,e){var s;return r(t)&&(s=t.constructor,"function"!=typeof s||s!==Array&&!r(s.prototype)?i(s)&&(s=s[a],null===s&&(s=void 0)):s=void 0),new(void 0===s?Array:s)(0===e?0:e)}},"69f3":function(t,e,s){var i,r,n,a=s("7f9a"),o=s("da84"),c=s("861d"),h=s("9112"),l=s("5135"),p=s("f772"),u=s("d012"),d=o.WeakMap,f=function(t){return n(t)?r(t):i(t,{})},m=function(t){return function(e){var s;if(!c(e)||(s=r(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return s}};if(a){var y=new d,g=y.get,x=y.has,b=y.set;i=function(t,e){return b.call(y,t,e),e},r=function(t){return g.call(y,t)||{}},n=function(t){return x.call(y,t)}}else{var v=p("state");u[v]=!0,i=function(t,e){return h(t,v,e),e},r=function(t){return l(t,v)?t[v]:{}},n=function(t){return l(t,v)}}t.exports={set:i,get:r,has:n,enforce:f,getterFor:m}},"6eeb":function(t,e,s){var i=s("da84"),r=s("9112"),n=s("5135"),a=s("ce4e"),o=s("8925"),c=s("69f3"),h=c.get,l=c.enforce,p=String(String).split("String");(t.exports=function(t,e,s,o){var c=!!o&&!!o.unsafe,h=!!o&&!!o.enumerable,u=!!o&&!!o.noTargetGet;"function"==typeof s&&("string"!=typeof e||n(s,"name")||r(s,"name",e),l(s).source=p.join("string"==typeof e?e:"")),t!==i?(c?!u&&t[e]&&(h=!0):delete t[e],h?t[e]=s:r(t,e,s)):h?t[e]=s:a(e,s)})(Function.prototype,"toString",(function(){return"function"==typeof this&&h(this).source||o(this)}))},7156:function(t,e,s){var i=s("861d"),r=s("d2bb");t.exports=function(t,e,s){var n,a;return r&&"function"==typeof(n=e.constructor)&&n!==s&&i(a=n.prototype)&&a!==s.prototype&&r(t,a),t}},7418:function(t,e){e.f=Object.getOwnPropertySymbols},"746f":function(t,e,s){var i=s("428f"),r=s("5135"),n=s("e538"),a=s("9bf2").f;t.exports=function(t){var e=i.Symbol||(i.Symbol={});r(e,t)||a(e,t,{value:n.f(t)})}},7839:function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},"7b0b":function(t,e,s){var i=s("1d80");t.exports=function(t){return Object(i(t))}},"7c73":function(t,e,s){var i,r=s("825a"),n=s("37e8"),a=s("7839"),o=s("d012"),c=s("1be4"),h=s("cc12"),l=s("f772"),p=">",u="<",d="prototype",f="script",m=l("IE_PROTO"),y=function(){},g=function(t){return u+f+p+t+u+"/"+f+p},x=function(t){t.write(g("")),t.close();var e=t.parentWindow.Object;return t=null,e},b=function(){var t,e=h("iframe"),s="java"+f+":";return e.style.display="none",c.appendChild(e),e.src=String(s),t=e.contentWindow.document,t.open(),t.write(g("document.F=Object")),t.close(),t.F},v=function(){try{i=document.domain&&new ActiveXObject("htmlfile")}catch(e){}v=i?x(i):b();var t=a.length;while(t--)delete v[d][a[t]];return v()};o[m]=!0,t.exports=Object.create||function(t,e){var s;return null!==t?(y[d]=r(t),s=new y,y[d]=null,s[m]=t):s=v(),void 0===e?s:n(s,e)}},"7db0":function(t,e,s){"use strict";var i=s("23e7"),r=s("b727").find,n=s("44d2"),a=s("ae40"),o="find",c=!0,h=a(o);o in[]&&Array(1)[o]((function(){c=!1})),i({target:"Array",proto:!0,forced:c||!h},{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),n(o)},"7dd0":function(t,e,s){"use strict";var i=s("23e7"),r=s("9ed3"),n=s("e163"),a=s("d2bb"),o=s("d44e"),c=s("9112"),h=s("6eeb"),l=s("b622"),p=s("c430"),u=s("3f8c"),d=s("ae93"),f=d.IteratorPrototype,m=d.BUGGY_SAFARI_ITERATORS,y=l("iterator"),g="keys",x="values",b="entries",v=function(){return this};t.exports=function(t,e,s,l,d,w,P){r(s,e,l);var T,E,A,S=function(t){if(t===d&&O)return O;if(!m&&t in N)return N[t];switch(t){case g:return function(){return new s(this,t)};case x:return function(){return new s(this,t)};case b:return function(){return new s(this,t)}}return function(){return new s(this)}},C=e+" Iterator",k=!1,N=t.prototype,I=N[y]||N["@@iterator"]||d&&N[d],O=!m&&I||S(d),D="Array"==e&&N.entries||I;if(D&&(T=n(D.call(new t)),f!==Object.prototype&&T.next&&(p||n(T)===f||(a?a(T,f):"function"!=typeof T[y]&&c(T,y,v)),o(T,C,!0,!0),p&&(u[C]=v))),d==x&&I&&I.name!==x&&(k=!0,O=function(){return I.call(this)}),p&&!P||N[y]===O||c(N,y,O),u[e]=O,d)if(E={values:S(x),keys:w?O:S(g),entries:S(b)},P)for(A in E)(m||k||!(A in N))&&h(N,A,E[A]);else i({target:e,proto:!0,forced:m||k},E);return E}},"7f9a":function(t,e,s){var i=s("da84"),r=s("8925"),n=i.WeakMap;t.exports="function"===typeof n&&/native code/.test(r(n))},"825a":function(t,e,s){var i=s("861d");t.exports=function(t){if(!i(t))throw TypeError(String(t)+" is not an object");return t}},"83ab":function(t,e,s){var i=s("d039");t.exports=!i((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},8418:function(t,e,s){"use strict";var i=s("c04e"),r=s("9bf2"),n=s("5c6c");t.exports=function(t,e,s){var a=i(e);a in t?r.f(t,a,n(0,s)):t[a]=s}},"861d":function(t,e){t.exports=function(t){return"object"===typeof t?null!==t:"function"===typeof t}},8925:function(t,e,s){var i=s("c6cd"),r=Function.toString;"function"!=typeof i.inspectSource&&(i.inspectSource=function(t){return r.call(t)}),t.exports=i.inspectSource},"8a79":function(t,e,s){"use strict";var i=s("23e7"),r=s("06cf").f,n=s("50c4"),a=s("5a34"),o=s("1d80"),c=s("ab13"),h=s("c430"),l="".endsWith,p=Math.min,u=c("endsWith"),d=!h&&!u&&!!function(){var t=r(String.prototype,"endsWith");return t&&!t.writable}();i({target:"String",proto:!0,forced:!d&&!u},{endsWith:function(t){var e=String(o(this));a(t);var s=arguments.length>1?arguments[1]:void 0,i=n(e.length),r=void 0===s?i:p(n(s),i),c=String(t);return l?l.call(e,c,r):e.slice(r-c.length,r)===c}})},"8aa5":function(t,e,s){"use strict";var i=s("6547").charAt;t.exports=function(t,e,s){return e+(s?i(t,e).length:1)}},"90e3":function(t,e){var s=0,i=Math.random();t.exports=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++s+i).toString(36)}},9112:function(t,e,s){var i=s("83ab"),r=s("9bf2"),n=s("5c6c");t.exports=i?function(t,e,s){return r.f(t,e,n(1,s))}:function(t,e,s){return t[e]=s,t}},9263:function(t,e,s){"use strict";var i=s("ad6d"),r=s("9f7f"),n=RegExp.prototype.exec,a=String.prototype.replace,o=n,c=function(){var t=/a/,e=/b*/g;return n.call(t,"a"),n.call(e,"a"),0!==t.lastIndex||0!==e.lastIndex}(),h=r.UNSUPPORTED_Y||r.BROKEN_CARET,l=void 0!==/()??/.exec("")[1],p=c||l||h;p&&(o=function(t){var e,s,r,o,p=this,u=h&&p.sticky,d=i.call(p),f=p.source,m=0,y=t;return u&&(d=d.replace("y",""),-1===d.indexOf("g")&&(d+="g"),y=String(t).slice(p.lastIndex),p.lastIndex>0&&(!p.multiline||p.multiline&&"\n"!==t[p.lastIndex-1])&&(f="(?: "+f+")",y=" "+y,m++),s=new RegExp("^(?:"+f+")",d)),l&&(s=new RegExp("^"+f+"$(?!\\s)",d)),c&&(e=p.lastIndex),r=n.call(u?s:p,y),u?r?(r.input=r.input.slice(m),r[0]=r[0].slice(m),r.index=p.lastIndex,p.lastIndex+=r[0].length):p.lastIndex=0:c&&r&&(p.lastIndex=p.global?r.index+r[0].length:e),l&&r&&r.length>1&&a.call(r[0],s,(function(){for(o=1;o=51||!r((function(){var t=[];return t[f]=!1,t.concat()[0]!==t})),x=p("concat"),b=function(t){if(!a(t))return!1;var e=t[f];return void 0!==e?!!e:n(t)},v=!g||!x;i({target:"Array",proto:!0,forced:v},{concat:function(t){var e,s,i,r,n,a=o(this),p=l(a,0),u=0;for(e=-1,i=arguments.length;em)throw TypeError(y);for(s=0;s=m)throw TypeError(y);h(p,u++,n)}return p.length=u,p}})},"9bdd":function(t,e,s){var i=s("825a");t.exports=function(t,e,s,r){try{return r?e(i(s)[0],s[1]):e(s)}catch(a){var n=t["return"];throw void 0!==n&&i(n.call(t)),a}}},"9bf2":function(t,e,s){var i=s("83ab"),r=s("0cfb"),n=s("825a"),a=s("c04e"),o=Object.defineProperty;e.f=i?o:function(t,e,s){if(n(t),e=a(e,!0),n(s),r)try{return o(t,e,s)}catch(i){}if("get"in s||"set"in s)throw TypeError("Accessors not supported");return"value"in s&&(t[e]=s.value),t}},"9ed3":function(t,e,s){"use strict";var i=s("ae93").IteratorPrototype,r=s("7c73"),n=s("5c6c"),a=s("d44e"),o=s("3f8c"),c=function(){return this};t.exports=function(t,e,s){var h=e+" Iterator";return t.prototype=r(i,{next:n(1,s)}),a(t,h,!1,!0),o[h]=c,t}},"9f7f":function(t,e,s){"use strict";var i=s("d039");function r(t,e){return RegExp(t,e)}e.UNSUPPORTED_Y=i((function(){var t=r("a","y");return t.lastIndex=2,null!=t.exec("abcd")})),e.BROKEN_CARET=i((function(){var t=r("^r","gy");return t.lastIndex=2,null!=t.exec("str")}))},a15b:function(t,e,s){"use strict";var i=s("23e7"),r=s("44ad"),n=s("fc6a"),a=s("a640"),o=[].join,c=r!=Object,h=a("join",",");i({target:"Array",proto:!0,forced:c||!h},{join:function(t){return o.call(n(this),void 0===t?",":t)}})},a434:function(t,e,s){"use strict";var i=s("23e7"),r=s("23cb"),n=s("a691"),a=s("50c4"),o=s("7b0b"),c=s("65f0"),h=s("8418"),l=s("1dde"),p=s("ae40"),u=l("splice"),d=p("splice",{ACCESSORS:!0,0:0,1:2}),f=Math.max,m=Math.min,y=9007199254740991,g="Maximum allowed length exceeded";i({target:"Array",proto:!0,forced:!u||!d},{splice:function(t,e){var s,i,l,p,u,d,x=o(this),b=a(x.length),v=r(t,b),w=arguments.length;if(0===w?s=i=0:1===w?(s=0,i=b-v):(s=w-2,i=m(f(n(e),0),b-v)),b+s-i>y)throw TypeError(g);for(l=c(x,i),p=0;pb-i+s;p--)delete x[p-1]}else if(s>i)for(p=b-i;p>v;p--)u=p+i-1,d=p+s-1,u in x?x[d]=x[u]:delete x[d];for(p=0;pn)r.push(arguments[n++]);if(i=e,(d(e)||void 0!==t)&&!ot(t))return u(e)||(e=function(t,e){if("function"==typeof i&&(e=i.call(this,t,e)),!ot(e))return e}),r[1]=e,$.apply(null,r)}})}K[q][V]||C(K[q],V,K[q].valueOf),R(K,U),O[B]=!0},a640:function(t,e,s){"use strict";var i=s("d039");t.exports=function(t,e){var s=[][t];return!!s&&i((function(){s.call(null,e||function(){throw 1},1)}))}},a691:function(t,e){var s=Math.ceil,i=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?i:s)(t)}},a79d:function(t,e,s){"use strict";var i=s("23e7"),r=s("c430"),n=s("fea9"),a=s("d039"),o=s("d066"),c=s("4840"),h=s("cdf9"),l=s("6eeb"),p=!!n&&a((function(){n.prototype["finally"].call({then:function(){}},(function(){}))}));i({target:"Promise",proto:!0,real:!0,forced:p},{finally:function(t){var e=c(this,o("Promise")),s="function"==typeof t;return this.then(s?function(s){return h(e,t()).then((function(){return s}))}:t,s?function(s){return h(e,t()).then((function(){throw s}))}:t)}}),r||"function"!=typeof n||n.prototype["finally"]||l(n.prototype,"finally",o("Promise").prototype["finally"])},aa47:function(t,e,s){"use strict"; +/**! + * Sortable 1.10.2 + * @author RubaXa + * @author owenm + * @license MIT + */ +function i(t){return i="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"===typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i(t)}function r(t,e,s){return e in t?Object.defineProperty(t,e,{value:s,enumerable:!0,configurable:!0,writable:!0}):t[e]=s,t}function n(){return n=Object.assign||function(t){for(var e=1;e=0||(r[s]=t[s]);return r}function c(t,e){if(null==t)return{};var s,i,r=o(t,e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(t,s)&&(r[s]=t[s])}return r}function h(t){return l(t)||p(t)||u()}function l(t){if(Array.isArray(t)){for(var e=0,s=new Array(t.length);e"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(s){return!1}return!1}}function A(t){return t.host&&t!==document&&t.host.nodeType?t.host:t.parentNode}function S(t,e,s,i){if(t){s=s||document;do{if(null!=e&&(">"===e[0]?t.parentNode===s&&E(t,e):E(t,e))||i&&t===s)return t;if(t===s)break}while(t=A(t))}return null}var C,k=/\s+/g;function N(t,e,s){if(t&&e)if(t.classList)t.classList[s?"add":"remove"](e);else{var i=(" "+t.className+" ").replace(k," ").replace(" "+e+" "," ");t.className=(i+(s?" "+e:"")).replace(k," ")}}function I(t,e,s){var i=t&&t.style;if(i){if(void 0===s)return document.defaultView&&document.defaultView.getComputedStyle?s=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(s=t.currentStyle),void 0===e?s:s[e];e in i||-1!==e.indexOf("webkit")||(e="-webkit-"+e),i[e]=s+("string"===typeof s?"":"px")}}function O(t,e){var s="";if("string"===typeof t)s=t;else do{var i=I(t,"transform");i&&"none"!==i&&(s=i+" "+s)}while(!e&&(t=t.parentNode));var r=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return r&&new r(s)}function D(t,e,s){if(t){var i=t.getElementsByTagName(e),r=0,n=i.length;if(s)for(;r=n:r<=n,!a)return i;if(i===M())break;i=q(i,!1)}return!1}function R(t,e,s){var i=0,r=0,n=t.children;while(r2&&void 0!==arguments[2]?arguments[2]:{},i=s.evt,r=c(s,["evt"]);st.pluginEvent.bind(Qt)(t,e,a({dragEl:at,parentEl:ot,ghostEl:ct,rootEl:ht,nextEl:lt,lastDownEl:pt,cloneEl:ut,cloneHidden:dt,dragStarted:St,putSortable:bt,activeSortable:Qt.active,originalEvent:i,oldIndex:ft,oldDraggableIndex:yt,newIndex:mt,newDraggableIndex:gt,hideGhostForTarget:Xt,unhideGhostForTarget:Gt,cloneNowHidden:function(){dt=!0},cloneNowShown:function(){dt=!1},dispatchSortableEvent:function(t){nt({sortable:e,name:t,originalEvent:i})}},r))};function nt(t){it(a({putSortable:bt,cloneEl:ut,targetEl:at,rootEl:ht,oldIndex:ft,oldDraggableIndex:yt,newIndex:mt,newDraggableIndex:gt},t))}var at,ot,ct,ht,lt,pt,ut,dt,ft,mt,yt,gt,xt,bt,vt,wt,Pt,Tt,Et,At,St,Ct,kt,Nt,It,Ot=!1,Dt=!1,Mt=[],Lt=!1,_t=!1,Rt=[],jt=!1,Ft=[],Bt="undefined"!==typeof document,Ut=b,qt=y||m?"cssFloat":"float",Vt=Bt&&!v&&!b&&"draggable"in document.createElement("div"),Ht=function(){if(Bt){if(m)return!1;var t=document.createElement("x");return t.style.cssText="pointer-events:auto","auto"===t.style.pointerEvents}}(),zt=function(t,e){var s=I(t),i=parseInt(s.width)-parseInt(s.paddingLeft)-parseInt(s.paddingRight)-parseInt(s.borderLeftWidth)-parseInt(s.borderRightWidth),r=R(t,0,e),n=R(t,1,e),a=r&&I(r),o=n&&I(n),c=a&&parseInt(a.marginLeft)+parseInt(a.marginRight)+L(r).width,h=o&&parseInt(o.marginLeft)+parseInt(o.marginRight)+L(n).width;if("flex"===s.display)return"column"===s.flexDirection||"column-reverse"===s.flexDirection?"vertical":"horizontal";if("grid"===s.display)return s.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(r&&a["float"]&&"none"!==a["float"]){var l="left"===a["float"]?"left":"right";return!n||"both"!==o.clear&&o.clear!==l?"horizontal":"vertical"}return r&&("block"===a.display||"flex"===a.display||"table"===a.display||"grid"===a.display||c>=i&&"none"===s[qt]||n&&"none"===s[qt]&&c+h>i)?"vertical":"horizontal"},Wt=function(t,e,s){var i=s?t.left:t.top,r=s?t.right:t.bottom,n=s?t.width:t.height,a=s?e.left:e.top,o=s?e.right:e.bottom,c=s?e.width:e.height;return i===a||r===o||i+n/2===a+c/2},Kt=function(t,e){var s;return Mt.some((function(i){if(!j(i)){var r=L(i),n=i[Y].options.emptyInsertThreshold,a=t>=r.left-n&&t<=r.right+n,o=e>=r.top-n&&e<=r.bottom+n;return n&&a&&o?s=i:void 0}})),s},$t=function(t){function e(t,s){return function(i,r,n,a){var o=i.options.group.name&&r.options.group.name&&i.options.group.name===r.options.group.name;if(null==t&&(s||o))return!0;if(null==t||!1===t)return!1;if(s&&"clone"===t)return t;if("function"===typeof t)return e(t(i,r,n,a),s)(i,r,n,a);var c=(s?i:r).options.group.name;return!0===t||"string"===typeof t&&t===c||t.join&&t.indexOf(c)>-1}}var s={},r=t.group;r&&"object"==i(r)||(r={name:r}),s.name=r.name,s.checkPull=e(r.pull,!0),s.checkPut=e(r.put),s.revertClone=r.revertClone,t.group=s},Xt=function(){!Ht&&ct&&I(ct,"display","none")},Gt=function(){!Ht&&ct&&I(ct,"display","")};Bt&&document.addEventListener("click",(function(t){if(Dt)return t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),Dt=!1,!1}),!0);var Yt=function(t){if(at){t=t.touches?t.touches[0]:t;var e=Kt(t.clientX,t.clientY);if(e){var s={};for(var i in t)t.hasOwnProperty(i)&&(s[i]=t[i]);s.target=s.rootEl=e,s.preventDefault=void 0,s.stopPropagation=void 0,e[Y]._onDragOver(s)}}},Jt=function(t){at&&at.parentNode[Y]._isOutsideThisEl(t.target)};function Qt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=n({},e),t[Y]=this;var s={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return zt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Qt.supportPointer&&"PointerEvent"in window,emptyInsertThreshold:5};for(var i in st.initializePlugins(this,t,s),s)!(i in e)&&(e[i]=s[i]);for(var r in $t(e),this)"_"===r.charAt(0)&&"function"===typeof this[r]&&(this[r]=this[r].bind(this));this.nativeDraggable=!e.forceFallback&&Vt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?P(t,"pointerdown",this._onTapStart):(P(t,"mousedown",this._onTapStart),P(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(P(t,"dragover",this),P(t,"dragenter",this)),Mt.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),n(this,J())}function Zt(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move"),t.cancelable&&t.preventDefault()}function te(t,e,s,i,r,n,a,o){var c,h,l=t[Y],p=l.options.onMove;return!window.CustomEvent||m||y?(c=document.createEvent("Event"),c.initEvent("move",!0,!0)):c=new CustomEvent("move",{bubbles:!0,cancelable:!0}),c.to=e,c.from=t,c.dragged=s,c.draggedRect=i,c.related=r||e,c.relatedRect=n||L(e),c.willInsertAfter=o,c.originalEvent=a,t.dispatchEvent(c),p&&(h=p.call(l,c,a)),h}function ee(t){t.draggable=!1}function se(){jt=!1}function ie(t,e,s){var i=L(j(s.el,s.options.draggable)),r=10;return e?t.clientX>i.right+r||t.clientX<=i.right&&t.clientY>i.bottom&&t.clientX>=i.left:t.clientX>i.right&&t.clientY>i.top||t.clientX<=i.right&&t.clientY>i.bottom+r}function re(t,e,s,i,r,n,a,o){var c=i?t.clientY:t.clientX,h=i?s.height:s.width,l=i?s.top:s.left,p=i?s.bottom:s.right,u=!1;if(!a)if(o&&Ntl+h*n/2:cp-Nt)return-kt}else if(c>l+h*(1-r)/2&&cp-h*n/2)?c>l+h/2?1:-1:0}function ne(t){return F(at)=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){at&&ee(at),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;T(t,"mouseup",this._disableDelayedDrag),T(t,"touchend",this._disableDelayedDrag),T(t,"touchcancel",this._disableDelayedDrag),T(t,"mousemove",this._delayedDragTouchMoveHandler),T(t,"touchmove",this._delayedDragTouchMoveHandler),T(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?P(document,"pointermove",this._onTouchMove):P(document,e?"touchmove":"mousemove",this._onTouchMove):(P(at,"dragend",this),P(ht,"dragstart",this._onDragStart));try{document.selection?ce((function(){document.selection.empty()})):window.getSelection().removeAllRanges()}catch(s){}},_dragStarted:function(t,e){if(Ot=!1,ht&&at){rt("dragStarted",this,{evt:e}),this.nativeDraggable&&P(document,"dragover",Jt);var s=this.options;!t&&N(at,s.dragClass,!1),N(at,s.ghostClass,!0),Qt.active=this,t&&this._appendGhost(),nt({sortable:this,name:"start",originalEvent:e})}else this._nulling()},_emulateDragOver:function(){if(wt){this._lastX=wt.clientX,this._lastY=wt.clientY,Xt();var t=document.elementFromPoint(wt.clientX,wt.clientY),e=t;while(t&&t.shadowRoot){if(t=t.shadowRoot.elementFromPoint(wt.clientX,wt.clientY),t===e)break;e=t}if(at.parentNode[Y]._isOutsideThisEl(t),e)do{if(e[Y]){var s=void 0;if(s=e[Y]._onDragOver({clientX:wt.clientX,clientY:wt.clientY,target:t,rootEl:e}),s&&!this.options.dragoverBubble)break}t=e}while(e=e.parentNode);Gt()}},_onTouchMove:function(t){if(vt){var e=this.options,s=e.fallbackTolerance,i=e.fallbackOffset,r=t.touches?t.touches[0]:t,n=ct&&O(ct,!0),a=ct&&n&&n.a,o=ct&&n&&n.d,c=Ut&&It&&B(It),h=(r.clientX-vt.clientX+i.x)/(a||1)+(c?c[0]-Rt[0]:0)/(a||1),l=(r.clientY-vt.clientY+i.y)/(o||1)+(c?c[1]-Rt[1]:0)/(o||1);if(!Qt.active&&!Ot){if(s&&Math.max(Math.abs(r.clientX-this._lastX),Math.abs(r.clientY-this._lastY))=0&&(nt({rootEl:ot,name:"add",toEl:ot,fromEl:ht,originalEvent:t}),nt({sortable:this,name:"remove",toEl:ot,originalEvent:t}),nt({rootEl:ot,name:"sort",toEl:ot,fromEl:ht,originalEvent:t}),nt({sortable:this,name:"sort",toEl:ot,originalEvent:t})),bt&&bt.save()):mt!==ft&&mt>=0&&(nt({sortable:this,name:"update",toEl:ot,originalEvent:t}),nt({sortable:this,name:"sort",toEl:ot,originalEvent:t})),Qt.active&&(null!=mt&&-1!==mt||(mt=ft,gt=yt),nt({sortable:this,name:"end",toEl:ot,originalEvent:t}),this.save())))),this._nulling()},_nulling:function(){rt("nulling",this),ht=at=ot=ct=lt=ut=pt=dt=vt=wt=St=mt=gt=ft=yt=Ct=kt=bt=xt=Qt.dragged=Qt.ghost=Qt.clone=Qt.active=null,Ft.forEach((function(t){t.checked=!0})),Ft.length=Pt=Tt=0},handleEvent:function(t){switch(t.type){case"drop":case"dragend":this._onDrop(t);break;case"dragenter":case"dragover":at&&(this._onDragOver(t),Zt(t));break;case"selectstart":t.preventDefault();break}},toArray:function(){for(var t,e=[],s=this.el.children,i=0,r=s.length,n=this.options;i1&&(Me.forEach((function(t){i.addAnimationState({target:t,rect:Re?L(t):r}),G(t),t.fromRect=r,e.removeAnimationState(t)})),Re=!1,Be(!this.options.removeCloneOnHide,s))},dragOverCompleted:function(t){var e=t.sortable,s=t.isOwner,i=t.insertion,r=t.activeSortable,n=t.parentEl,a=t.putSortable,o=this.options;if(i){if(s&&r._hideClone(),_e=!1,o.animation&&Me.length>1&&(Re||!s&&!r.options.sort&&!a)){var c=L(Ie,!1,!0,!0);Me.forEach((function(t){t!==Ie&&(X(t,c),n.appendChild(t))})),Re=!0}if(!s)if(Re||qe(),Me.length>1){var h=De;r._showClone(e),r.options.animation&&!De&&h&&Le.forEach((function(t){r.addAnimationState({target:t,rect:Oe}),t.fromRect=Oe,t.thisAnimationDuration=null}))}else r._showClone(e)}},dragOverAnimationCapture:function(t){var e=t.dragRect,s=t.isOwner,i=t.activeSortable;if(Me.forEach((function(t){t.thisAnimationDuration=null})),i.options.animation&&!s&&i.multiDrag.isMultiDrag){Oe=n({},e);var r=O(Ie,!0);Oe.top-=r.f,Oe.left-=r.e}},dragOverAnimationComplete:function(){Re&&(Re=!1,qe())},drop:function(t){var e=t.originalEvent,s=t.rootEl,i=t.parentEl,r=t.sortable,n=t.dispatchSortableEvent,a=t.oldIndex,o=t.putSortable,c=o||this.sortable;if(e){var h=this.options,l=i.children;if(!je)if(h.multiDragKey&&!this.multiDragKeyDown&&this._deselectMultiDrag(),N(Ie,h.selectedClass,!~Me.indexOf(Ie)),~Me.indexOf(Ie))Me.splice(Me.indexOf(Ie),1),ke=null,it({sortable:r,rootEl:s,name:"deselect",targetEl:Ie,originalEvt:e});else{if(Me.push(Ie),it({sortable:r,rootEl:s,name:"select",targetEl:Ie,originalEvt:e}),e.shiftKey&&ke&&r.el.contains(ke)){var p,u,d=F(ke),f=F(Ie);if(~d&&~f&&d!==f)for(f>d?(u=d,p=f):(u=f,p=d+1);u1){var m=L(Ie),y=F(Ie,":not(."+this.options.selectedClass+")");if(!_e&&h.animation&&(Ie.thisAnimationDuration=null),c.captureAnimationState(),!_e&&(h.animation&&(Ie.fromRect=m,Me.forEach((function(t){if(t.thisAnimationDuration=null,t!==Ie){var e=Re?L(t):m;t.fromRect=e,c.addAnimationState({target:t,rect:e})}}))),qe(),Me.forEach((function(t){l[y]?i.insertBefore(t,l[y]):i.appendChild(t),y++})),a===F(Ie))){var g=!1;Me.forEach((function(t){t.sortableIndex===F(t)||(g=!0)})),g&&n("update")}Me.forEach((function(t){G(t)})),c.animateAll()}Ne=c}(s===i||o&&"clone"!==o.lastPutMode)&&Le.forEach((function(t){t.parentNode&&t.parentNode.removeChild(t)}))}},nullingGlobal:function(){this.isMultiDrag=je=!1,Le.length=0},destroyGlobal:function(){this._deselectMultiDrag(),T(document,"pointerup",this._deselectMultiDrag),T(document,"mouseup",this._deselectMultiDrag),T(document,"touchend",this._deselectMultiDrag),T(document,"keydown",this._checkKeyDown),T(document,"keyup",this._checkKeyUp)},_deselectMultiDrag:function(t){if(("undefined"===typeof je||!je)&&Ne===this.sortable&&(!t||!S(t.target,this.options.draggable,this.sortable.el,!1))&&(!t||0===t.button))while(Me.length){var e=Me[0];N(e,this.options.selectedClass,!1),Me.shift(),it({sortable:this.sortable,rootEl:this.sortable.el,name:"deselect",targetEl:e,originalEvt:t})}},_checkKeyDown:function(t){t.key===this.options.multiDragKey&&(this.multiDragKeyDown=!0)},_checkKeyUp:function(t){t.key===this.options.multiDragKey&&(this.multiDragKeyDown=!1)}},n(t,{pluginName:"multiDrag",utils:{select:function(t){var e=t.parentNode[Y];e&&e.options.multiDrag&&!~Me.indexOf(t)&&(Ne&&Ne!==e&&(Ne.multiDrag._deselectMultiDrag(),Ne=e),N(t,e.options.selectedClass,!0),Me.push(t))},deselect:function(t){var e=t.parentNode[Y],s=Me.indexOf(t);e&&e.options.multiDrag&&~s&&(N(t,e.options.selectedClass,!1),Me.splice(s,1))}},eventProperties:function(){var t=this,e=[],s=[];return Me.forEach((function(i){var r;e.push({multiDragElement:i,index:i.sortableIndex}),r=Re&&i!==Ie?-1:Re?F(i,":not(."+t.options.selectedClass+")"):F(i),s.push({multiDragElement:i,index:r})})),{items:h(Me),clones:[].concat(Le),oldIndicies:e,newIndicies:s}},optionListeners:{multiDragKey:function(t){return t=t.toLowerCase(),"ctrl"===t?t="Control":t.length>1&&(t=t.charAt(0).toUpperCase()+t.substr(1)),t}}})}function Be(t,e){Me.forEach((function(s,i){var r=e.children[s.sortableIndex+(t?Number(i):0)];r?e.insertBefore(s,r):e.appendChild(s)}))}function Ue(t,e){Le.forEach((function(s,i){var r=e.children[s.sortableIndex+(t?Number(i):0)];r?e.insertBefore(s,r):e.appendChild(s)}))}function qe(){Me.forEach((function(t){t!==Ie&&t.parentNode&&t.parentNode.removeChild(t)}))}Qt.mount(new xe),Qt.mount(Ae,Ee),e["default"]=Qt},ab13:function(t,e,s){var i=s("b622"),r=i("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(s){try{return e[r]=!1,"/./"[t](e)}catch(i){}}return!1}},ac1f:function(t,e,s){"use strict";var i=s("23e7"),r=s("9263");i({target:"RegExp",proto:!0,forced:/./.exec!==r},{exec:r})},ad6d:function(t,e,s){"use strict";var i=s("825a");t.exports=function(){var t=i(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.dotAll&&(e+="s"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},ade3:function(t,e,s){"use strict";function i(t,e,s){return e in t?Object.defineProperty(t,e,{value:s,enumerable:!0,configurable:!0,writable:!0}):t[e]=s,t}s.d(e,"a",(function(){return i}))},ae40:function(t,e,s){var i=s("83ab"),r=s("d039"),n=s("5135"),a=Object.defineProperty,o={},c=function(t){throw t};t.exports=function(t,e){if(n(o,t))return o[t];e||(e={});var s=[][t],h=!!n(e,"ACCESSORS")&&e.ACCESSORS,l=n(e,0)?e[0]:c,p=n(e,1)?e[1]:void 0;return o[t]=!!s&&!r((function(){if(h&&!i)return!0;var t={length:-1};h?a(t,1,{enumerable:!0,get:c}):t[1]=1,s.call(t,l,p)}))}},ae93:function(t,e,s){"use strict";var i,r,n,a=s("e163"),o=s("9112"),c=s("5135"),h=s("b622"),l=s("c430"),p=h("iterator"),u=!1,d=function(){return this};[].keys&&(n=[].keys(),"next"in n?(r=a(a(n)),r!==Object.prototype&&(i=r)):u=!0),void 0==i&&(i={}),l||c(i,p)||o(i,p,d),t.exports={IteratorPrototype:i,BUGGY_SAFARI_ITERATORS:u}},b041:function(t,e,s){"use strict";var i=s("00ee"),r=s("f5df");t.exports=i?{}.toString:function(){return"[object "+r(this)+"]"}},b0c0:function(t,e,s){var i=s("83ab"),r=s("9bf2").f,n=Function.prototype,a=n.toString,o=/^\s*function ([^ (]*)/,c="name";i&&!(c in n)&&r(n,c,{configurable:!0,get:function(){try{return a.call(this).match(o)[1]}catch(t){return""}}})},b311:function(t,e,s){ +/*! + * clipboard.js v2.0.6 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +(function(e,s){t.exports=s()})(0,(function(){return function(t){var e={};function s(i){if(e[i])return e[i].exports;var r=e[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,s),r.l=!0,r.exports}return s.m=t,s.c=e,s.d=function(t,e,i){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},s.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(s.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)s.d(i,r,function(e){return t[e]}.bind(null,r));return i},s.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=6)}([function(t,e){function s(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var s=t.hasAttribute("readonly");s||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),s||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var i=window.getSelection(),r=document.createRange();r.selectNodeContents(t),i.removeAllRanges(),i.addRange(r),e=i.toString()}return e}t.exports=s},function(t,e){function s(){}s.prototype={on:function(t,e,s){var i=this.e||(this.e={});return(i[t]||(i[t]=[])).push({fn:e,ctx:s}),this},once:function(t,e,s){var i=this;function r(){i.off(t,r),e.apply(s,arguments)}return r._=e,this.on(t,r,s)},emit:function(t){var e=[].slice.call(arguments,1),s=((this.e||(this.e={}))[t]||[]).slice(),i=0,r=s.length;for(i;i0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var s=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=s+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=r()(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=r()(this.target),this.copyText()}},{key:"copyText",value:function(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==("undefined"===typeof t?"undefined":n(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),t}(),h=c,l=s(1),p=s.n(l),u=s(2),d=s.n(u),f="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"===typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},m=function(){function t(t,e){for(var s=0;s0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"===typeof t.action?t.action:this.defaultAction,this.target="function"===typeof t.target?t.target:this.defaultTarget,this.text="function"===typeof t.text?t.text:this.defaultText,this.container="object"===f(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=d()(t,"click",(function(t){return e.onClick(t)}))}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new h({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return v("action",t)}},{key:"defaultTarget",value:function(t){var e=v("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return v("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"===typeof t?[t]:t,s=!!document.queryCommandSupported;return e.forEach((function(t){s=s&&!!document.queryCommandSupported(t)})),s}}]),e}(p.a);function v(t,e){var s="data-clipboard-"+t;if(e.hasAttribute(s))return e.getAttribute(s)}e["default"]=b}])["default"]}))},b575:function(t,e,s){var i,r,n,a,o,c,h,l,p=s("da84"),u=s("06cf").f,d=s("c6b6"),f=s("2cf4").set,m=s("1cdc"),y=p.MutationObserver||p.WebKitMutationObserver,g=p.process,x=p.Promise,b="process"==d(g),v=u(p,"queueMicrotask"),w=v&&v.value;w||(i=function(){var t,e;b&&(t=g.domain)&&t.exit();while(r){e=r.fn,r=r.next;try{e()}catch(s){throw r?a():n=void 0,s}}n=void 0,t&&t.enter()},b?a=function(){g.nextTick(i)}:y&&!m?(o=!0,c=document.createTextNode(""),new y(i).observe(c,{characterData:!0}),a=function(){c.data=o=!o}):x&&x.resolve?(h=x.resolve(void 0),l=h.then,a=function(){l.call(h,i)}):a=function(){f.call(p,i)}),t.exports=w||function(t){var e={fn:t,next:void 0};n&&(n.next=e),r||(r=e,a()),n=e}},b622:function(t,e,s){var i=s("da84"),r=s("5692"),n=s("5135"),a=s("90e3"),o=s("4930"),c=s("fdbf"),h=r("wks"),l=i.Symbol,p=c?l:l&&l.withoutSetter||a;t.exports=function(t){return n(h,t)||(o&&n(l,t)?h[t]=l[t]:h[t]=p("Symbol."+t)),h[t]}},b64b:function(t,e,s){var i=s("23e7"),r=s("7b0b"),n=s("df75"),a=s("d039"),o=a((function(){n(1)}));i({target:"Object",stat:!0,forced:o},{keys:function(t){return n(r(t))}})},b727:function(t,e,s){var i=s("0366"),r=s("44ad"),n=s("7b0b"),a=s("50c4"),o=s("65f0"),c=[].push,h=function(t){var e=1==t,s=2==t,h=3==t,l=4==t,p=6==t,u=5==t||p;return function(d,f,m,y){for(var g,x,b=n(d),v=r(b),w=i(f,m,3),P=a(v.length),T=0,E=y||o,A=e?E(d,P):s?E(d,0):void 0;P>T;T++)if((u||T in v)&&(g=v[T],x=w(g,T,b),t))if(e)A[T]=x;else if(x)switch(t){case 3:return!0;case 5:return g;case 6:return T;case 2:c.call(A,g)}else if(l)return!1;return p?-1:h||l?l:A}};t.exports={forEach:h(0),map:h(1),filter:h(2),some:h(3),every:h(4),find:h(5),findIndex:h(6)}},c04e:function(t,e,s){var i=s("861d");t.exports=function(t,e){if(!i(t))return t;var s,r;if(e&&"function"==typeof(s=t.toString)&&!i(r=s.call(t)))return r;if("function"==typeof(s=t.valueOf)&&!i(r=s.call(t)))return r;if(!e&&"function"==typeof(s=t.toString)&&!i(r=s.call(t)))return r;throw TypeError("Can't convert object to primitive value")}},c430:function(t,e){t.exports=!1},c6b6:function(t,e){var s={}.toString;t.exports=function(t){return s.call(t).slice(8,-1)}},c6cd:function(t,e,s){var i=s("da84"),r=s("ce4e"),n="__core-js_shared__",a=i[n]||r(n,{});t.exports=a},c740:function(t,e,s){"use strict";var i=s("23e7"),r=s("b727").findIndex,n=s("44d2"),a=s("ae40"),o="findIndex",c=!0,h=a(o);o in[]&&Array(1)[o]((function(){c=!1})),i({target:"Array",proto:!0,forced:c||!h},{findIndex:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),n(o)},c8ba:function(t,e){var s;s=function(){return this}();try{s=s||new Function("return this")()}catch(i){"object"===typeof window&&(s=window)}t.exports=s},c975:function(t,e,s){"use strict";var i=s("23e7"),r=s("4d64").indexOf,n=s("a640"),a=s("ae40"),o=[].indexOf,c=!!o&&1/[1].indexOf(1,-0)<0,h=n("indexOf"),l=a("indexOf",{ACCESSORS:!0,1:0});i({target:"Array",proto:!0,forced:c||!h||!l},{indexOf:function(t){return c?o.apply(this,arguments)||0:r(this,t,arguments.length>1?arguments[1]:void 0)}})},ca84:function(t,e,s){var i=s("5135"),r=s("fc6a"),n=s("4d64").indexOf,a=s("d012");t.exports=function(t,e){var s,o=r(t),c=0,h=[];for(s in o)!i(a,s)&&i(o,s)&&h.push(s);while(e.length>c)i(o,s=e[c++])&&(~n(h,s)||h.push(s));return h}},caad:function(t,e,s){"use strict";var i=s("23e7"),r=s("4d64").includes,n=s("44d2"),a=s("ae40"),o=a("indexOf",{ACCESSORS:!0,1:0});i({target:"Array",proto:!0,forced:!o},{includes:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),n("includes")},cc06:function(t,e,s){"use strict";function i(t,e,s,i){var r,n=!1,a=0;function o(){r&&clearTimeout(r)}function c(){o(),n=!0}function h(){for(var c=arguments.length,h=new Array(c),l=0;lt?d():!0!==e&&(r=setTimeout(i?f:d,void 0===i?t-u:t)))}return"boolean"!==typeof e&&(i=s,s=e,e=void 0),h.cancel=c,h}function r(t,e,s){return void 0===s?i(t,e,!1):i(t,s,!1!==e)}s.d(e,"a",(function(){return r}))},cc12:function(t,e,s){var i=s("da84"),r=s("861d"),n=i.document,a=r(n)&&r(n.createElement);t.exports=function(t){return a?n.createElement(t):{}}},cca6:function(t,e,s){var i=s("23e7"),r=s("60da");i({target:"Object",stat:!0,forced:Object.assign!==r},{assign:r})},cdf9:function(t,e,s){var i=s("825a"),r=s("861d"),n=s("f069");t.exports=function(t,e){if(i(t),r(e)&&e.constructor===t)return e;var s=n.f(t),a=s.resolve;return a(e),s.promise}},ce4e:function(t,e,s){var i=s("da84"),r=s("9112");t.exports=function(t,e){try{r(i,t,e)}catch(s){i[t]=e}return e}},d012:function(t,e){t.exports={}},d039:function(t,e){t.exports=function(t){try{return!!t()}catch(e){return!0}}},d066:function(t,e,s){var i=s("428f"),r=s("da84"),n=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?n(i[t])||n(r[t]):i[t]&&i[t][e]||r[t]&&r[t][e]}},d1e7:function(t,e,s){"use strict";var i={}.propertyIsEnumerable,r=Object.getOwnPropertyDescriptor,n=r&&!i.call({1:2},1);e.f=n?function(t){var e=r(this,t);return!!e&&e.enumerable}:i},d28b:function(t,e,s){var i=s("746f");i("iterator")},d2bb:function(t,e,s){var i=s("825a"),r=s("3bbe");t.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var t,e=!1,s={};try{t=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set,t.call(s,[]),e=s instanceof Array}catch(n){}return function(s,n){return i(s),r(n),e?t.call(s,n):s.__proto__=n,s}}():void 0)},d3b7:function(t,e,s){var i=s("00ee"),r=s("6eeb"),n=s("b041");i||r(Object.prototype,"toString",n,{unsafe:!0})},d44e:function(t,e,s){var i=s("9bf2").f,r=s("5135"),n=s("b622"),a=n("toStringTag");t.exports=function(t,e,s){t&&!r(t=s?t:t.prototype,a)&&i(t,a,{configurable:!0,value:e})}},d60a:function(t,e){t.exports=function(t){return t&&"object"===typeof t&&"function"===typeof t.copy&&"function"===typeof t.fill&&"function"===typeof t.readUInt8}},d784:function(t,e,s){"use strict";s("ac1f");var i=s("6eeb"),r=s("d039"),n=s("b622"),a=s("9263"),o=s("9112"),c=n("species"),h=!r((function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:"7"},t},"7"!=="".replace(t,"$")})),l=function(){return"$0"==="a".replace(/./,"$0")}(),p=n("replace"),u=function(){return!!/./[p]&&""===/./[p]("a","$0")}(),d=!r((function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var s="ab".split(t);return 2!==s.length||"a"!==s[0]||"b"!==s[1]}));t.exports=function(t,e,s,p){var f=n(t),m=!r((function(){var e={};return e[f]=function(){return 7},7!=""[t](e)})),y=m&&!r((function(){var e=!1,s=/a/;return"split"===t&&(s={},s.constructor={},s.constructor[c]=function(){return s},s.flags="",s[f]=/./[f]),s.exec=function(){return e=!0,null},s[f](""),!e}));if(!m||!y||"replace"===t&&(!h||!l||u)||"split"===t&&!d){var g=/./[f],x=s(f,""[t],(function(t,e,s,i,r){return e.exec===a?m&&!r?{done:!0,value:g.call(e,s,i)}:{done:!0,value:t.call(s,e,i)}:{done:!1}}),{REPLACE_KEEPS_$0:l,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:u}),b=x[0],v=x[1];i(String.prototype,t,b),i(RegExp.prototype,f,2==e?function(t,e){return v.call(t,this,e)}:function(t){return v.call(t,this)})}p&&o(RegExp.prototype[f],"sham",!0)}},d81d:function(t,e,s){"use strict";var i=s("23e7"),r=s("b727").map,n=s("1dde"),a=s("ae40"),o=n("map"),c=a("map");i({target:"Array",proto:!0,forced:!o||!c},{map:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}})},da84:function(t,e,s){(function(e){var s=function(t){return t&&t.Math==Math&&t};t.exports=s("object"==typeof globalThis&&globalThis)||s("object"==typeof window&&window)||s("object"==typeof self&&self)||s("object"==typeof e&&e)||Function("return this")()}).call(this,s("c8ba"))},dbb4:function(t,e,s){var i=s("23e7"),r=s("83ab"),n=s("56ef"),a=s("fc6a"),o=s("06cf"),c=s("8418");i({target:"Object",stat:!0,sham:!r},{getOwnPropertyDescriptors:function(t){var e,s,i=a(t),r=o.f,h=n(i),l={},p=0;while(h.length>p)s=r(i,e=h[p++]),void 0!==s&&c(l,e,s);return l}})},ddb0:function(t,e,s){var i=s("da84"),r=s("fdbc"),n=s("e260"),a=s("9112"),o=s("b622"),c=o("iterator"),h=o("toStringTag"),l=n.values;for(var p in r){var u=i[p],d=u&&u.prototype;if(d){if(d[c]!==l)try{a(d,c,l)}catch(m){d[c]=l}if(d[h]||a(d,h,p),r[p])for(var f in n)if(d[f]!==n[f])try{a(d,f,n[f])}catch(m){d[f]=n[f]}}}},df75:function(t,e,s){var i=s("ca84"),r=s("7839");t.exports=Object.keys||function(t){return i(t,r)}},df7c:function(t,e,s){(function(t){function s(t,e){for(var s=0,i=t.length-1;i>=0;i--){var r=t[i];"."===r?t.splice(i,1):".."===r?(t.splice(i,1),s++):s&&(t.splice(i,1),s--)}if(e)for(;s--;s)t.unshift("..");return t}function i(t){"string"!==typeof t&&(t+="");var e,s=0,i=-1,r=!0;for(e=t.length-1;e>=0;--e)if(47===t.charCodeAt(e)){if(!r){s=e+1;break}}else-1===i&&(r=!1,i=e+1);return-1===i?"":t.slice(s,i)}function r(t,e){if(t.filter)return t.filter(e);for(var s=[],i=0;i=-1&&!i;n--){var a=n>=0?arguments[n]:t.cwd();if("string"!==typeof a)throw new TypeError("Arguments to path.resolve must be strings");a&&(e=a+"/"+e,i="/"===a.charAt(0))}return e=s(r(e.split("/"),(function(t){return!!t})),!i).join("/"),(i?"/":"")+e||"."},e.normalize=function(t){var i=e.isAbsolute(t),a="/"===n(t,-1);return t=s(r(t.split("/"),(function(t){return!!t})),!i).join("/"),t||i||(t="."),t&&a&&(t+="/"),(i?"/":"")+t},e.isAbsolute=function(t){return"/"===t.charAt(0)},e.join=function(){var t=Array.prototype.slice.call(arguments,0);return e.normalize(r(t,(function(t,e){if("string"!==typeof t)throw new TypeError("Arguments to path.join must be strings");return t})).join("/"))},e.relative=function(t,s){function i(t){for(var e=0;e=0;s--)if(""!==t[s])break;return e>s?[]:t.slice(e,s-e+1)}t=e.resolve(t).substr(1),s=e.resolve(s).substr(1);for(var r=i(t.split("/")),n=i(s.split("/")),a=Math.min(r.length,n.length),o=a,c=0;c=1;--n)if(e=t.charCodeAt(n),47===e){if(!r){i=n;break}}else r=!1;return-1===i?s?"/":".":s&&1===i?"/":t.slice(0,i)},e.basename=function(t,e){var s=i(t);return e&&s.substr(-1*e.length)===e&&(s=s.substr(0,s.length-e.length)),s},e.extname=function(t){"string"!==typeof t&&(t+="");for(var e=-1,s=0,i=-1,r=!0,n=0,a=t.length-1;a>=0;--a){var o=t.charCodeAt(a);if(47!==o)-1===i&&(r=!1,i=a+1),46===o?-1===e?e=a:1!==n&&(n=1):-1!==e&&(n=-1);else if(!r){s=a+1;break}}return-1===e||-1===i||0===n||1===n&&e===i-1&&e===s+1?"":t.slice(e,i)};var n="b"==="ab".substr(-1)?function(t,e,s){return t.substr(e,s)}:function(t,e,s){return e<0&&(e=t.length+e),t.substr(e,s)}}).call(this,s("4362"))},e017:function(t,e,s){(function(e){(function(e,s){t.exports=s()})(0,(function(){"use strict";var t=function(t){var e=t.id,s=t.viewBox,i=t.content;this.id=e,this.viewBox=s,this.content=i};t.prototype.stringify=function(){return this.content},t.prototype.toString=function(){return this.stringify()},t.prototype.destroy=function(){var t=this;["id","viewBox","content"].forEach((function(e){return delete t[e]}))};var s=function(t){var e=!!document.importNode,s=(new DOMParser).parseFromString(t,"image/svg+xml").documentElement;return e?document.importNode(s,!0):s};"undefined"!==typeof window?window:"undefined"!==typeof e||"undefined"!==typeof self&&self;function i(t,e){return e={exports:{}},t(e,e.exports),e.exports}var r=i((function(t,e){(function(e,s){t.exports=s()})(0,(function(){function t(t){var e=t&&"object"===typeof t;return e&&"[object RegExp]"!==Object.prototype.toString.call(t)&&"[object Date]"!==Object.prototype.toString.call(t)}function e(t){return Array.isArray(t)?[]:{}}function s(s,i){var r=i&&!0===i.clone;return r&&t(s)?n(e(s),s,i):s}function i(e,i,r){var a=e.slice();return i.forEach((function(i,o){"undefined"===typeof a[o]?a[o]=s(i,r):t(i)?a[o]=n(e[o],i,r):-1===e.indexOf(i)&&a.push(s(i,r))})),a}function r(e,i,r){var a={};return t(e)&&Object.keys(e).forEach((function(t){a[t]=s(e[t],r)})),Object.keys(i).forEach((function(o){t(i[o])&&e[o]?a[o]=n(e[o],i[o],r):a[o]=s(i[o],r)})),a}function n(t,e,n){var a=Array.isArray(e),o=n||{arrayMerge:i},c=o.arrayMerge||i;return a?Array.isArray(t)?c(t,e,n):s(e,n):r(t,e,n)}return n.all=function(t,e){if(!Array.isArray(t)||t.length<2)throw new Error("first argument should be an array with at least two elements");return t.reduce((function(t,s){return n(t,s,e)}))},n}))})),n=i((function(t,e){var s={svg:{name:"xmlns",uri:"http://www.w3.org/2000/svg"},xlink:{name:"xmlns:xlink",uri:"http://www.w3.org/1999/xlink"}};e.default=s,t.exports=e.default})),a=function(t){return Object.keys(t).map((function(e){var s=t[e].toString().replace(/"/g,""");return e+'="'+s+'"'})).join(" ")},o=n.svg,c=n.xlink,h={};h[o.name]=o.uri,h[c.name]=c.uri;var l=function(t,e){void 0===t&&(t="");var s=r(h,e||{}),i=a(s);return""+t+""},p=function(t){function e(){t.apply(this,arguments)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var i={isMounted:{}};return i.isMounted.get=function(){return!!this.node},e.createFromExistingNode=function(t){return new e({id:t.getAttribute("id"),viewBox:t.getAttribute("viewBox"),content:t.outerHTML})},e.prototype.destroy=function(){this.isMounted&&this.unmount(),t.prototype.destroy.call(this)},e.prototype.mount=function(t){if(this.isMounted)return this.node;var e="string"===typeof t?document.querySelector(t):t,s=this.render();return this.node=s,e.appendChild(s),s},e.prototype.render=function(){var t=this.stringify();return s(l(t)).childNodes[0]},e.prototype.unmount=function(){this.node.parentNode.removeChild(this.node)},Object.defineProperties(e.prototype,i),e}(t);return p}))}).call(this,s("c8ba"))},e01a:function(t,e,s){"use strict";var i=s("23e7"),r=s("83ab"),n=s("da84"),a=s("5135"),o=s("861d"),c=s("9bf2").f,h=s("e893"),l=n.Symbol;if(r&&"function"==typeof l&&(!("description"in l.prototype)||void 0!==l().description)){var p={},u=function(){var t=arguments.length<1||void 0===arguments[0]?void 0:String(arguments[0]),e=this instanceof u?new l(t):void 0===t?l():l(t);return""===t&&(p[e]=!0),e};h(u,l);var d=u.prototype=l.prototype;d.constructor=u;var f=d.toString,m="Symbol(test)"==String(l("test")),y=/^Symbol\((.*)\)[^)]+$/;c(d,"description",{configurable:!0,get:function(){var t=o(this)?this.valueOf():this,e=f.call(t);if(a(p,t))return"";var s=m?e.slice(7,-1):e.replace(y,"$1");return""===s?void 0:s}}),i({global:!0,forced:!0},{Symbol:u})}},e163:function(t,e,s){var i=s("5135"),r=s("7b0b"),n=s("f772"),a=s("e177"),o=n("IE_PROTO"),c=Object.prototype;t.exports=a?Object.getPrototypeOf:function(t){return t=r(t),i(t,o)?t[o]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?c:null}},e177:function(t,e,s){var i=s("d039");t.exports=!i((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}))},e260:function(t,e,s){"use strict";var i=s("fc6a"),r=s("44d2"),n=s("3f8c"),a=s("69f3"),o=s("7dd0"),c="Array Iterator",h=a.set,l=a.getterFor(c);t.exports=o(Array,"Array",(function(t,e){h(this,{type:c,target:i(t),index:0,kind:e})}),(function(){var t=l(this),e=t.target,s=t.kind,i=t.index++;return!e||i>=e.length?(t.target=void 0,{value:void 0,done:!0}):"keys"==s?{value:i,done:!1}:"values"==s?{value:e[i],done:!1}:{value:[i,e[i]],done:!1}}),"values"),n.Arguments=n.Array,r("keys"),r("values"),r("entries")},e2cc:function(t,e,s){var i=s("6eeb");t.exports=function(t,e,s){for(var r in e)i(t,r,e[r],s);return t}},e439:function(t,e,s){var i=s("23e7"),r=s("d039"),n=s("fc6a"),a=s("06cf").f,o=s("83ab"),c=r((function(){a(1)})),h=!o||c;i({target:"Object",stat:!0,forced:h,sham:!o},{getOwnPropertyDescriptor:function(t,e){return a(n(t),e)}})},e538:function(t,e,s){var i=s("b622");e.f=i},e667:function(t,e){t.exports=function(t){try{return{error:!1,value:t()}}catch(e){return{error:!0,value:e}}}},e6cf:function(t,e,s){"use strict";var i,r,n,a,o=s("23e7"),c=s("c430"),h=s("da84"),l=s("d066"),p=s("fea9"),u=s("6eeb"),d=s("e2cc"),f=s("d44e"),m=s("2626"),y=s("861d"),g=s("1c0b"),x=s("19aa"),b=s("c6b6"),v=s("8925"),w=s("2266"),P=s("1c7e"),T=s("4840"),E=s("2cf4").set,A=s("b575"),S=s("cdf9"),C=s("44de"),k=s("f069"),N=s("e667"),I=s("69f3"),O=s("94ca"),D=s("b622"),M=s("2d00"),L=D("species"),_="Promise",R=I.get,j=I.set,F=I.getterFor(_),B=p,U=h.TypeError,q=h.document,V=h.process,H=l("fetch"),z=k.f,W=z,K="process"==b(V),$=!!(q&&q.createEvent&&h.dispatchEvent),X="unhandledrejection",G="rejectionhandled",Y=0,J=1,Q=2,Z=1,tt=2,et=O(_,(function(){var t=v(B)!==String(B);if(!t){if(66===M)return!0;if(!K&&"function"!=typeof PromiseRejectionEvent)return!0}if(c&&!B.prototype["finally"])return!0;if(M>=51&&/native code/.test(B))return!1;var e=B.resolve(1),s=function(t){t((function(){}),(function(){}))},i=e.constructor={};return i[L]=s,!(e.then((function(){}))instanceof s)})),st=et||!P((function(t){B.all(t)["catch"]((function(){}))})),it=function(t){var e;return!(!y(t)||"function"!=typeof(e=t.then))&&e},rt=function(t,e,s){if(!e.notified){e.notified=!0;var i=e.reactions;A((function(){var r=e.value,n=e.state==J,a=0;while(i.length>a){var o,c,h,l=i[a++],p=n?l.ok:l.fail,u=l.resolve,d=l.reject,f=l.domain;try{p?(n||(e.rejection===tt&&ct(t,e),e.rejection=Z),!0===p?o=r:(f&&f.enter(),o=p(r),f&&(f.exit(),h=!0)),o===l.promise?d(U("Promise-chain cycle")):(c=it(o))?c.call(o,u,d):u(o)):d(r)}catch(m){f&&!h&&f.exit(),d(m)}}e.reactions=[],e.notified=!1,s&&!e.rejection&&at(t,e)}))}},nt=function(t,e,s){var i,r;$?(i=q.createEvent("Event"),i.promise=e,i.reason=s,i.initEvent(t,!1,!0),h.dispatchEvent(i)):i={promise:e,reason:s},(r=h["on"+t])?r(i):t===X&&C("Unhandled promise rejection",s)},at=function(t,e){E.call(h,(function(){var s,i=e.value,r=ot(e);if(r&&(s=N((function(){K?V.emit("unhandledRejection",i,t):nt(X,t,i)})),e.rejection=K||ot(e)?tt:Z,s.error))throw s.value}))},ot=function(t){return t.rejection!==Z&&!t.parent},ct=function(t,e){E.call(h,(function(){K?V.emit("rejectionHandled",t):nt(G,t,e.value)}))},ht=function(t,e,s,i){return function(r){t(e,s,r,i)}},lt=function(t,e,s,i){e.done||(e.done=!0,i&&(e=i),e.value=s,e.state=Q,rt(t,e,!0))},pt=function(t,e,s,i){if(!e.done){e.done=!0,i&&(e=i);try{if(t===s)throw U("Promise can't be resolved itself");var r=it(s);r?A((function(){var i={done:!1};try{r.call(s,ht(pt,t,i,e),ht(lt,t,i,e))}catch(n){lt(t,i,n,e)}})):(e.value=s,e.state=J,rt(t,e,!1))}catch(n){lt(t,{done:!1},n,e)}}};et&&(B=function(t){x(this,B,_),g(t),i.call(this);var e=R(this);try{t(ht(pt,this,e),ht(lt,this,e))}catch(s){lt(this,e,s)}},i=function(t){j(this,{type:_,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:Y,value:void 0})},i.prototype=d(B.prototype,{then:function(t,e){var s=F(this),i=z(T(this,B));return i.ok="function"!=typeof t||t,i.fail="function"==typeof e&&e,i.domain=K?V.domain:void 0,s.parent=!0,s.reactions.push(i),s.state!=Y&&rt(this,s,!1),i.promise},catch:function(t){return this.then(void 0,t)}}),r=function(){var t=new i,e=R(t);this.promise=t,this.resolve=ht(pt,t,e),this.reject=ht(lt,t,e)},k.f=z=function(t){return t===B||t===n?new r(t):W(t)},c||"function"!=typeof p||(a=p.prototype.then,u(p.prototype,"then",(function(t,e){var s=this;return new B((function(t,e){a.call(s,t,e)})).then(t,e)}),{unsafe:!0}),"function"==typeof H&&o({global:!0,enumerable:!0,forced:!0},{fetch:function(t){return S(B,H.apply(h,arguments))}}))),o({global:!0,wrap:!0,forced:et},{Promise:B}),f(B,_,!1,!0),m(_),n=l(_),o({target:_,stat:!0,forced:et},{reject:function(t){var e=z(this);return e.reject.call(void 0,t),e.promise}}),o({target:_,stat:!0,forced:c||et},{resolve:function(t){return S(c&&this===n?B:this,t)}}),o({target:_,stat:!0,forced:st},{all:function(t){var e=this,s=z(e),i=s.resolve,r=s.reject,n=N((function(){var s=g(e.resolve),n=[],a=0,o=1;w(t,(function(t){var c=a++,h=!1;n.push(void 0),o++,s.call(e,t).then((function(t){h||(h=!0,n[c]=t,--o||i(n))}),r)})),--o||i(n)}));return n.error&&r(n.value),s.promise},race:function(t){var e=this,s=z(e),i=s.reject,r=N((function(){var r=g(e.resolve);w(t,(function(t){r.call(e,t).then(s.resolve,i)}))}));return r.error&&i(r.value),s.promise}})},e893:function(t,e,s){var i=s("5135"),r=s("56ef"),n=s("06cf"),a=s("9bf2");t.exports=function(t,e){for(var s=r(e),o=a.f,c=n.f,h=0;h'});l.a.add(c);t["default"]=c},"064a":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-select",use:"icon-select-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"0f05":function(e,t,a){},"0f88":function(e,t,a){"use strict";a.r(t),t["default"]={"list-type":function(e,t,a){var o=[],n=t.__config__;return"picture-card"===t["list-type"]?o.push(e("i",{class:"el-icon-plus"})):o.push(e("el-button",{attrs:{size:"small",type:"primary",icon:"el-icon-upload"}},[n.buttonText])),n.showTip&&o.push(e("div",{slot:"tip",class:"el-upload__tip"},["只能上传不超过 ",n.fileSize,n.sizeUnit," 的",t.accept,"文件"])),o}}},"128d":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-textarea",use:"icon-textarea-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"167d":function(e,t,a){"use strict";a.r(t),t["default"]={prepend:function(e,t,a){return e("template",{slot:"prepend"},[t.__slot__[a]])},append:function(e,t,a){return e("template",{slot:"append"},[t.__slot__[a]])}}},"1fce":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-number",use:"icon-number-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"235f":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-date",use:"icon-date-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},2384:function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-switch",use:"icon-switch-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"2a3d":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-password",use:"icon-password-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"2cfa":function(e,t,a){"use strict";a.r(t);a("4160"),a("159b");t["default"]={options:function(e,t,a){var o=[];return t.__slot__.options.forEach((function(a){"button"===t.__config__.optionType?o.push(e("el-radio-button",{attrs:{label:a.value}},[a.label])):o.push(e("el-radio",{attrs:{label:a.value,border:t.border}},[a.label]))})),o}}},"2db0":function(e,t,a){},"2dba":function(e,t,a){"use strict";var o=a("6f47"),n=a.n(o);n.a},"31c6":function(e,t,a){"use strict";var o,n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("textarea",{staticStyle:{visibility:"hidden"},attrs:{id:e.tinymceId}})},i=[],l=(a("99af"),a("d3b7"),a("25f0"),a("c88b")),c=a("5f72"),r=a.n(c);function s(e){if(o)e(o);else{var t=r.a.Loading.service({fullscreen:!0,lock:!0,text:"富文本资源加载中...",spinner:"el-icon-loading",background:"rgba(255, 255, 255, 0.5)"});Object(l["a"])("https://lib.baomitu.com/tinymce/5.3.2/tinymce.min.js",(function(){t.close(),o=tinymce,e(o)}))}}var u=["advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount"],d=["code searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote removeformat subscript superscript codesample hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen"],_=a("cc06"),p=1,m={props:{id:{type:String,default:function(){return 1e4===p&&(p=1),"tinymce".concat(+new Date).concat(p++)}},value:{default:""}},data:function(){return{tinymceId:this.id}},mounted:function(){var e=this;s((function(t){a("afc4");var o={selector:"#".concat(e.tinymceId),language:"zh_CN",menubar:"file edit insert view format table",plugins:u,toolbar:d,height:300,branding:!1,object_resizing:!1,end_container_on_empty_block:!0,powerpaste_word_import:"clean",code_dialog_height:450,code_dialog_width:1e3,advlist_bullet_styles:"square",advlist_number_styles:"default",default_link_target:"_blank",link_title:!1,nonbreaking_force_tab:!0};o=Object.assign(o,e.$attrs),o.init_instance_callback=function(t){e.value&&t.setContent(e.value),e.vModel(t)},t.init(o)}))},destroyed:function(){this.destroyTinymce()},methods:{vModel:function(e){var t=this,a=Object(_["a"])(250,e.setContent);this.$watch("value",(function(t,o){e&&t!==o&&t!==e.getContent()&&("string"!==typeof t&&(t=t.toString()),a.call(e,t))})),e.on("change keyup undo redo",(function(){t.$emit("input",e.getContent())}))},destroyTinymce:function(){if(window.tinymce){var e=window.tinymce.get(this.tinymceId);e&&e.destroy()}}}},f=m,v=a("2877"),h=Object(v["a"])(f,n,i,!1,null,null,null);t["a"]=h.exports},"3add":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-time",use:"icon-time-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},4758:function(e,t,a){"use strict";a("4160"),a("b64b"),a("d3b7"),a("ac1f"),a("5319"),a("159b"),a("ddb0");var o=a("5530"),n=a("ed08"),i={},l=a("9977"),c=l.keys()||[];function r(e,t){var a=this;e.props.value=t,e.on.input=function(e){a.$emit("input",e)}}function s(e,t,a){var o=i[t.__config__.tag];o&&Object.keys(o).forEach((function(n){var i=o[n];t.__slot__&&t.__slot__[n]&&a.push(i(e,t,n))}))}function u(e){var t=this;["on","nativeOn"].forEach((function(a){var o=Object.keys(e[a]||{});o.forEach((function(o){var n=e[a][o];"string"===typeof n&&(e[a][o]=function(e){return t.$emit(n,e)})}))}))}function d(e,t){var a=this;Object.keys(e).forEach((function(n){var i=e[n];"__vModel__"===n?r.call(a,t,e.__config__.defaultValue):t[n]?t[n]=Object(o["a"])(Object(o["a"])({},t[n]),i):t.attrs[n]=i})),_(t)}function _(e){delete e.attrs.__config__,delete e.attrs.__slot__,delete e.attrs.__methods__}function p(){return{attrs:{},props:{},nativeOn:{},on:{},style:{}}}c.forEach((function(e){var t=e.replace(/^\.\/(.*)\.\w+$/,"$1"),a=l(e).default;i[t]=a})),t["a"]={props:{conf:{type:Object,required:!0}},render:function(e){var t=p(),a=Object(n["b"])(this.conf),o=[];return s.call(this,e,a,o),u.call(this,a),d.call(this,a,t),e(this.conf.__config__.tag,t,o)}}},"475a":function(e,t,a){},"4ed4":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-button",use:"icon-button-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"51ff":function(e,t,a){var o={"./button.svg":"4ed4","./cascader.svg":"a393","./checkbox.svg":"8963","./color.svg":"03ab","./component.svg":"56d6","./date-range.svg":"e6df","./date.svg":"235f","./input.svg":"81d6","./number.svg":"1fce","./password.svg":"2a3d","./radio.svg":"d8dc","./rate.svg":"6786","./rich-text.svg":"c630","./row.svg":"c95d","./select.svg":"064a","./slider.svg":"eb1c","./switch.svg":"2384","./textarea.svg":"128d","./time-range.svg":"861c","./time.svg":"3add","./upload.svg":"9d82"};function n(e){var t=i(e);return a(t)}function i(e){if(!a.o(o,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return o[e]}n.keys=function(){return Object.keys(o)},n.resolve=i,e.exports=n,n.id="51ff"},"56d6":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-component",use:"icon-component-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"5f72":function(e,t){e.exports=ELEMENT},"627e":function(e,t,a){},6389:function(e,t){e.exports=VueRouter},"66a2":function(e,t,a){"use strict";var o=a("475a"),n=a.n(o);n.a},6786:function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-rate",use:"icon-rate-usage",viewBox:"0 0 1069 1024",content:''});l.a.add(c);t["default"]=c},6828:function(e,t,a){"use strict";var o=a("627e"),n=a.n(o);n.a},"6f47":function(e,t,a){},"7f29":function(e,t,a){"use strict";a.r(t);a("4160"),a("159b");t["default"]={options:function(e,t,a){var o=[];return t.__slot__.options.forEach((function(t){o.push(e("el-option",{attrs:{label:t.label,value:t.value,disabled:t.disabled}}))})),o}}},"80e9":function(e,t,a){"use strict";var o=a("fca0"),n=a.n(o);n.a},"81d6":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-input",use:"icon-input-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"861c":function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-time-range",use:"icon-time-range-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},8963:function(e,t,a){"use strict";a.r(t);var o=a("e017"),n=a.n(o),i=a("21a1"),l=a.n(i),c=new n.a({id:"icon-checkbox",use:"icon-checkbox-usage",viewBox:"0 0 1024 1024",content:''});l.a.add(c);t["default"]=c},"8a8a":function(e,t,a){"use strict";a.r(t);a("e260"),a("e6cf"),a("cca6"),a("a79d");var o,n,i=a("8bbf"),l=a.n(i),c=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",[a("router-view")],1)},r=[],s={mounted:function(){var e=document.querySelector("#pre-loader");e.style.display="none",document.body.ondrop=function(e){e.preventDefault(),e.stopPropagation()}}},u=s,d=a("2877"),_=Object(d["a"])(u,c,r,!1,null,null,null),p=_.exports,m=(a("d3b7"),a("6389")),f=a.n(m),v=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",{staticClass:"container"},[a("div",{staticClass:"left-board"},[a("div",{staticClass:"logo-wrapper"},[a("div",{staticClass:"logo"},[a("img",{attrs:{src:e.logo,alt:"logo"}}),e._v(" 表单构建 ")])]),a("el-scrollbar",{staticClass:"left-scrollbar"},[a("div",{staticClass:"components-list"},e._l(e.leftComponents,(function(t,o){return a("div",{key:o},[a("div",{staticClass:"components-title"},[a("svg-icon",{attrs:{"icon-class":"component"}}),e._v(" "+e._s(t.title)+" ")],1),a("draggable",{staticClass:"components-draggable",attrs:{list:t.list,group:{name:"componentsGroup",pull:"clone",put:!1},clone:e.cloneComponent,draggable:".components-item",sort:!1},on:{end:e.onEnd}},e._l(t.list,(function(t,o){return a("div",{key:o,staticClass:"components-item",on:{click:function(a){return e.addComponent(t)}}},[a("div",{staticClass:"components-body"},[a("svg-icon",{attrs:{"icon-class":t.__config__.tagIcon}}),e._v(" "+e._s(t.__config__.label)+" ")],1)])})),0)],1)})),0)])],1),a("div",{staticClass:"center-board"},[a("div",{staticClass:"action-bar"},[a("el-button",{attrs:{icon:"el-icon-video-play",type:"text"},on:{click:e.run}},[e._v(" 运行 ")]),a("el-button",{attrs:{icon:"el-icon-view",type:"text"},on:{click:e.showJson}},[e._v(" 查看json ")]),a("el-button",{attrs:{icon:"el-icon-download",type:"text"},on:{click:e.download}},[e._v(" 导出vue文件 ")]),a("el-button",{staticClass:"copy-btn-main",attrs:{icon:"el-icon-document-copy",type:"text"},on:{click:e.copy}},[e._v(" 复制代码 ")]),a("el-button",{staticClass:"delete-btn",attrs:{icon:"el-icon-delete",type:"text"},on:{click:e.empty}},[e._v(" 清空 ")])],1),a("el-scrollbar",{staticClass:"center-scrollbar"},[a("el-row",{staticClass:"center-board-row",attrs:{gutter:e.formConf.gutter}},[a("el-form",{attrs:{size:e.formConf.size,"label-position":e.formConf.labelPosition,disabled:e.formConf.disabled,"label-width":e.formConf.labelWidth+"px"}},[a("draggable",{staticClass:"drawing-board",attrs:{list:e.drawingList,animation:340,group:"componentsGroup"}},e._l(e.drawingList,(function(t,o){return a("draggable-item",{key:t.renderKey,attrs:{"drawing-list":e.drawingList,element:t,index:o,"active-id":e.activeId,"form-conf":e.formConf},on:{activeItem:e.activeFormItem,copyItem:e.drawingItemCopy,deleteItem:e.drawingItemDelete}})})),1),a("div",{directives:[{name:"show",rawName:"v-show",value:!e.drawingList.length,expression:"!drawingList.length"}],staticClass:"empty-info"},[e._v(" 从左侧拖入或点选组件进行表单设计 ")])],1)],1)],1)],1),a("right-panel",{attrs:{"active-data":e.activeData,"form-conf":e.formConf,"show-field":!!e.drawingList.length},on:{"tag-change":e.tagChange}}),a("form-drawer",{attrs:{visible:e.drawerVisible,"form-data":e.formData,size:"100%","generate-conf":e.generateConf},on:{"update:visible":function(t){e.drawerVisible=t}}}),a("json-drawer",{attrs:{size:"60%",visible:e.jsonDrawerVisible,"json-str":JSON.stringify(e.formData)},on:{"update:visible":function(t){e.jsonDrawerVisible=t},refresh:e.refreshJson}}),a("code-type-dialog",{attrs:{visible:e.dialogVisible,title:"选择生成类型","show-file-name":e.showFileName},on:{"update:visible":function(t){e.dialogVisible=t},confirm:e.generate}}),a("input",{attrs:{id:"copyNode",type:"hidden"}})],1)},h=[],b=(a("c740"),a("4160"),a("d81d"),a("a434"),a("b64b"),a("ac1f"),a("5319"),a("159b"),a("53ca")),g=a("5530"),w=a("310e"),y=a.n(w),D=a("cc06"),x=a("21a6"),k=a("b311"),C=a.n(k),O=a("4758"),M=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",[a("el-drawer",e._g(e._b({on:{opened:e.onOpen,close:e.onClose}},"el-drawer",e.$attrs,!1),e.$listeners),[a("div",{staticStyle:{height:"100%"}},[a("el-row",{staticStyle:{height:"100%",overflow:"auto"}},[a("el-col",{staticClass:"left-editor",attrs:{md:24,lg:12}},[a("div",{staticClass:"setting",attrs:{title:"资源引用"},on:{click:e.showResource}},[a("el-badge",{staticClass:"item",attrs:{"is-dot":!!e.resources.length}},[a("i",{staticClass:"el-icon-setting"})])],1),a("el-tabs",{staticClass:"editor-tabs",attrs:{type:"card"},model:{value:e.activeTab,callback:function(t){e.activeTab=t},expression:"activeTab"}},[a("el-tab-pane",{attrs:{name:"html"}},[a("span",{attrs:{slot:"label"},slot:"label"},["html"===e.activeTab?a("i",{staticClass:"el-icon-edit"}):a("i",{staticClass:"el-icon-document"}),e._v(" template ")])]),a("el-tab-pane",{attrs:{name:"js"}},[a("span",{attrs:{slot:"label"},slot:"label"},["js"===e.activeTab?a("i",{staticClass:"el-icon-edit"}):a("i",{staticClass:"el-icon-document"}),e._v(" script ")])]),a("el-tab-pane",{attrs:{name:"css"}},[a("span",{attrs:{slot:"label"},slot:"label"},["css"===e.activeTab?a("i",{staticClass:"el-icon-edit"}):a("i",{staticClass:"el-icon-document"}),e._v(" css ")])])],1),a("div",{directives:[{name:"show",rawName:"v-show",value:"html"===e.activeTab,expression:"activeTab==='html'"}],staticClass:"tab-editor",attrs:{id:"editorHtml"}}),a("div",{directives:[{name:"show",rawName:"v-show",value:"js"===e.activeTab,expression:"activeTab==='js'"}],staticClass:"tab-editor",attrs:{id:"editorJs"}}),a("div",{directives:[{name:"show",rawName:"v-show",value:"css"===e.activeTab,expression:"activeTab==='css'"}],staticClass:"tab-editor",attrs:{id:"editorCss"}})],1),a("el-col",{staticClass:"right-preview",attrs:{md:24,lg:12}},[a("div",{staticClass:"action-bar",style:{"text-align":"left"}},[a("span",{staticClass:"bar-btn",on:{click:e.runCode}},[a("i",{staticClass:"el-icon-refresh"}),e._v(" 刷新 ")]),a("span",{staticClass:"bar-btn",on:{click:e.exportFile}},[a("i",{staticClass:"el-icon-download"}),e._v(" 导出vue文件 ")]),a("span",{ref:"copyBtn",staticClass:"bar-btn copy-btn"},[a("i",{staticClass:"el-icon-document-copy"}),e._v(" 复制代码 ")]),a("span",{staticClass:"bar-btn delete-btn",on:{click:function(t){return e.$emit("update:visible",!1)}}},[a("i",{staticClass:"el-icon-circle-close"}),e._v(" 关闭 ")])]),a("iframe",{directives:[{name:"show",rawName:"v-show",value:e.isIframeLoaded,expression:"isIframeLoaded"}],ref:"previewPage",staticClass:"result-wrapper",attrs:{frameborder:"0",src:"preview.html"},on:{load:e.iframeLoad}}),a("div",{directives:[{name:"show",rawName:"v-show",value:!e.isIframeLoaded,expression:"!isIframeLoaded"},{name:"loading",rawName:"v-loading",value:!0,expression:"true"}],staticClass:"result-wrapper"})])],1)],1)]),a("resource-dialog",{attrs:{visible:e.resourceVisible,"origin-resource":e.resources},on:{"update:visible":function(t){e.resourceVisible=t},save:e.setResource}})],1)},E=[],I=(a("99af"),a("8a79"),a("1861")),L=(a("a15b"),a("45fc"),a("b0c0"),a("beaa"));function j(e){return'\n '.concat(e,'\n
\n 取消\n 确定\n
\n
')}function T(e){return"")}function z(e){return"
\ No newline at end of file diff --git a/stop.sh b/stop.sh new file mode 100644 index 0000000..6dd9dc4 --- /dev/null +++ b/stop.sh @@ -0,0 +1,4 @@ +#!/bin/bash +killall go-admin # kill go-admin service +echo "stop go-admin success" +ps -aux | grep go-admin \ No newline at end of file diff --git a/template/api_migrate.template b/template/api_migrate.template new file mode 100644 index 0000000..6f39164 --- /dev/null +++ b/template/api_migrate.template @@ -0,0 +1,326 @@ +package version + +import ( + "gorm.io/gorm" + "runtime" + "time" + + "github.com/go-admin-team/go-admin-core/sdk/pkg" + + "go-admin/cmd/migrate/migration" + common "go-admin/common/models" +) + +type Menu struct { + MenuId int `json:"menuId" gorm:"primaryKey;autoIncrement"` + MenuName string `json:"menuName" gorm:"size:128;"` + Title string `json:"title" gorm:"size:128;"` + Icon string `json:"icon" gorm:"size:128;"` + Path string `json:"path" gorm:"size:128;"` + Paths string `json:"paths" gorm:"size:128;"` + MenuType string `json:"menuType" gorm:"size:1;"` + Action string `json:"action" gorm:"size:16;"` + Permission string `json:"permission" gorm:"size:255;"` + ParentId int `json:"parentId" gorm:"size:11;"` + NoCache bool `json:"noCache" gorm:"size:8;"` + Breadcrumb string `json:"breadcrumb" gorm:"size:255;"` + Component string `json:"component" gorm:"size:255;"` + Sort int `json:"sort" gorm:"size:4;"` + Visible string `json:"visible" gorm:"size:1;"` + CreateBy string `json:"createBy" gorm:"size:128;"` + UpdateBy string `json:"updateBy" gorm:"size:128;"` + IsFrame string `json:"isFrame" gorm:"size:1;DEFAULT:0;"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt *time.Time `json:"deletedAt"` +} + +func (Menu) TableName() string { + return "sys_menu" +} + +func init() { + _, fileName, _, _ := runtime.Caller(0) + migration.Migrate.SetVersion(migration.GetFilename(fileName), _{{.GenerateTime}}Test) +} + +func _{{.GenerateTime}}Test(db *gorm.DB, version string) error { + return db.Transaction(func(tx *gorm.DB) error { + + timeNow := pkg.GetCurrentTime() + Mmenu := Menu{} + Mmenu.MenuName = "{{.TBName}}Manage" + Mmenu.Title = "{{.TableComment}}" + Mmenu.Icon = "pass" + Mmenu.Path = "/{{.TBName}}" + Mmenu.MenuType = "M" + Mmenu.Action = "无" + Mmenu.ParentId = 0 + Mmenu.NoCache = false + Mmenu.Component = "Layout" + Mmenu.Sort = 0 + Mmenu.Visible = "0" + Mmenu.IsFrame = "0" + Mmenu.CreateBy = "1" + Mmenu.UpdateBy = "1" + Mmenu.CreatedAt = timeNow + Mmenu.UpdatedAt = timeNow + // Mmenu.MenuId, err = Mmenu.Create(db) + err := tx.Create(&Mmenu).Error + if err != nil { + return err + } + Cmenu := Menu{} + Cmenu.MenuName = "{{.TBName}}" + Cmenu.Title = "{{.TableComment}}" + Cmenu.Icon = "pass" + Cmenu.Path = "{{.TBName}}" + Cmenu.MenuType = "C" + Cmenu.Action = "无" + Cmenu.Permission = "{{.PackageName}}:{{.BusinessName}}:list" + Cmenu.ParentId = Mmenu.MenuId + Cmenu.NoCache = false + Cmenu.Component = "/{{.BusinessName}}/index" + Cmenu.Sort = 0 + Cmenu.Visible = "0" + Cmenu.IsFrame = "0" + Cmenu.CreateBy = "1" + Cmenu.UpdateBy = "1" + Cmenu.CreatedAt = timeNow + Cmenu.UpdatedAt = timeNow + // Cmenu.MenuId, err = Cmenu.Create(db) + err = tx.Create(&Cmenu).Error + if err != nil { + return err + } + + MList := Menu{} + MList.MenuName = "" + MList.Title = "分页获取{{.TableComment}}" + MList.Icon = "" + MList.Path = "{{.TBName}}" + MList.MenuType = "F" + MList.Action = "无" + MList.Permission = "{{.PackageName}}:{{.BusinessName}}:query" + MList.ParentId = Cmenu.MenuId + MList.NoCache = false + MList.Sort = 0 + MList.Visible = "0" + MList.IsFrame = "0" + MList.CreateBy = "1" + MList.UpdateBy = "1" + MList.CreatedAt = timeNow + MList.UpdatedAt = timeNow + // MList.MenuId, err = MList.Create(db) + err = tx.Create(&MList).Error + if err != nil { + return err + } + + MCreate := Menu{} + MCreate.MenuName = "" + MCreate.Title = "创建{{.TableComment}}" + MCreate.Icon = "" + MCreate.Path = "{{.TBName}}" + MCreate.MenuType = "F" + MCreate.Action = "无" + MCreate.Permission = "{{.PackageName}}:{{.BusinessName}}:add" + MCreate.ParentId = Cmenu.MenuId + MCreate.NoCache = false + MCreate.Sort = 0 + MCreate.Visible = "0" + MCreate.IsFrame = "0" + MCreate.CreateBy = "1" + MCreate.UpdateBy = "1" + MCreate.CreatedAt = timeNow + MCreate.UpdatedAt = timeNow + // MCreate.MenuId, err = MCreate.Create(db) + err = tx.Create(&MCreate).Error + if err != nil { + return err + } + + MUpdate := Menu{} + MUpdate.MenuName = "" + MUpdate.Title = "修改{{.TableComment}}" + MUpdate.Icon = "" + MUpdate.Path = "{{.TBName}}" + MUpdate.MenuType = "F" + MUpdate.Action = "无" + MUpdate.Permission ="{{.PackageName}}:{{.BusinessName}}:edit" + MUpdate.ParentId = Cmenu.MenuId + MUpdate.NoCache = false + MUpdate.Sort = 0 + MUpdate.Visible = "0" + MUpdate.IsFrame = "0" + MUpdate.CreateBy = "1" + MUpdate.UpdateBy = "1" + MUpdate.CreatedAt = timeNow + MUpdate.UpdatedAt = timeNow + // MUpdate.MenuId, err = MUpdate.Create(db) + err = tx.Create(&MUpdate).Error + if err != nil { + return err + } + + MDelete := Menu{} + MDelete.MenuName = "" + MDelete.Title = "删除{{.TableComment}}" + MDelete.Icon = "" + MDelete.Path = "{{.TBName}}" + MDelete.MenuType = "F" + MDelete.Action = "无" + MDelete.Permission = "{{.PackageName}}:{{.BusinessName}}:remove" + MDelete.ParentId = Cmenu.MenuId + MDelete.NoCache = false + MDelete.Sort = 0 + MDelete.Visible = "0" + MDelete.IsFrame = "0" + MDelete.CreateBy = "1" + MDelete.UpdateBy = "1" + MDelete.CreatedAt = timeNow + MDelete.UpdatedAt = timeNow + // MDelete.MenuId, err = MDelete.Create(db) + err = tx.Create(&MDelete).Error + if err != nil { + return err + } + + var InterfaceId = 63 + Amenu := Menu{} + Amenu.MenuName = "{{.TBName}}" + Amenu.Title = "{{.TableComment}}" + Amenu.Icon = "bug" + Amenu.Path = "{{.TBName}}" + Amenu.MenuType = "M" + Amenu.Action = "无" + Amenu.ParentId = InterfaceId + Amenu.NoCache = false + Amenu.Sort = 0 + Amenu.Visible = "1" + Amenu.IsFrame = "0" + Amenu.CreateBy = "1" + Amenu.UpdateBy = "1" + Amenu.CreatedAt = timeNow + Amenu.UpdatedAt = timeNow + // Amenu.MenuId, err = Amenu.Create(db) + err = tx.Create(&Amenu).Error + if err != nil { + return err + } + + AList := Menu{} + AList.MenuName = "" + AList.Title = "分页获取{{.TableComment}}" + AList.Icon = "bug" + AList.Path = "/api/v1/{{.ModuleName}}" + AList.MenuType = "A" + AList.Action = "GET" + AList.ParentId = Amenu.MenuId + AList.NoCache = false + AList.Sort = 0 + AList.Visible = "1" + AList.IsFrame = "0" + AList.CreateBy = "1" + AList.UpdateBy = "1" + AList.CreatedAt = timeNow + AList.UpdatedAt = timeNow + // AList.MenuId, err = AList.Create(db) + err = tx.Create(&AList).Error + if err != nil { + return err + } + + AGet := Menu{} + AGet.MenuName = "" + AGet.Title = "根据id获取{{.TableComment}}" + AGet.Icon = "bug" + AGet.Path = "/api/v1/{{.ModuleName}}/:id" + AGet.MenuType = "A" + AGet.Action = "GET" + AGet.ParentId = Amenu.MenuId + AGet.NoCache = false + AGet.Sort = 0 + AGet.Visible = "1" + AGet.IsFrame = "0" + AGet.CreateBy = "1" + AGet.UpdateBy = "1" + AGet.CreatedAt = timeNow + AGet.UpdatedAt = timeNow + // AGet.MenuId, err = AGet.Create(db) + err = tx.Create(&AGet).Error + if err != nil { + return err + } + + ACreate := Menu{} + ACreate.MenuName = "" + ACreate.Title = "创建{{.TableComment}}" + ACreate.Icon = "bug" + ACreate.Path = "/api/v1/{{.ModuleName}}" + ACreate.MenuType = "A" + ACreate.Action = "POST" + ACreate.ParentId = Amenu.MenuId + ACreate.NoCache = false + ACreate.Sort = 0 + ACreate.Visible = "1" + ACreate.IsFrame = "0" + ACreate.CreateBy = "1" + ACreate.UpdateBy = "1" + ACreate.CreatedAt = timeNow + ACreate.UpdatedAt = timeNow + // ACreate.MenuId, err = ACreate.Create(db) + err = tx.Create(&ACreate).Error + if err != nil { + return err + } + + AUpdate := Menu{} + AUpdate.MenuName = "" + AUpdate.Title = "修改{{.TableComment}}" + AUpdate.Icon = "bug" + AUpdate.Path = "/api/v1/{{.ModuleName}}/:id" + AUpdate.MenuType = "A" + AUpdate.Action = "PUT" + AUpdate.ParentId = Amenu.MenuId + AUpdate.NoCache = false + AUpdate.Sort = 0 + AUpdate.Visible = "1" + AUpdate.IsFrame = "0" + AUpdate.CreateBy = "1" + AUpdate.UpdateBy = "1" + AUpdate.CreatedAt = timeNow + AUpdate.UpdatedAt = timeNow + // AUpdate.MenuId, err = AUpdate.Create(db) + err = tx.Create(&AUpdate).Error + if err != nil { + return err + } + + ADelete := Menu{} + ADelete.MenuName = "" + ADelete.Title = "删除{{.TableComment}}" + ADelete.Icon = "bug" + ADelete.Path = "/api/v1/{{.ModuleName}}" + ADelete.MenuType = "A" + ADelete.Action = "DELETE" + ADelete.ParentId = Amenu.MenuId + ADelete.NoCache = false + ADelete.Sort = 0 + ADelete.Visible = "1" + ADelete.IsFrame = "0" + ADelete.CreateBy = "1" + ADelete.UpdateBy = "1" + ADelete.CreatedAt = timeNow + ADelete.UpdatedAt = timeNow + //ADelete.MenuId, err = ADelete.Create(db) + err = tx.Create(&ADelete).Error + if err != nil { + return err + } + + return tx.Create(&common.Migration{ + Version: version, + }).Error + }) +} \ No newline at end of file diff --git a/template/cmd_api.template b/template/cmd_api.template new file mode 100644 index 0000000..f58e37f --- /dev/null +++ b/template/cmd_api.template @@ -0,0 +1,8 @@ +package api + +import "go-admin/app/{{.appName}}/router" + +func init() { + //注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法 + AppRouters = append(AppRouters, router.InitRouter) +} \ No newline at end of file diff --git a/template/migrate.template b/template/migrate.template new file mode 100644 index 0000000..f30de78 --- /dev/null +++ b/template/migrate.template @@ -0,0 +1,40 @@ +package {{.Package}} + +import ( + "gorm.io/gorm" + "runtime" + + "go-admin/cmd/migrate/migration" + common "go-admin/common/models" +) + +func init() { + _, fileName, _, _ := runtime.Caller(0) + migration.Migrate.SetVersion(migration.GetFilename(fileName), _{{.GenerateTime}}Test) +} + +func _{{.GenerateTime}}Test(db *gorm.DB, version string) error { + return db.Transaction(func(tx *gorm.DB) error { + + // TODO: 这里开始写入要变更的内容 + + // TODO: 例如 修改表字段 使用过程中请删除此段代码 + //err := tx.Migrator().RenameColumn(&models.SysConfig{}, "config_id", "id") + //if err != nil { + // return err + //} + + // TODO: 例如 新增表结构 使用过程中请删除此段代码 + //err = tx.Debug().Migrator().AutoMigrate( + // new(models.CasbinRule), + // ) + //if err != nil { + // return err + //} + + + return tx.Create(&common.Migration{ + Version: version, + }).Error + }) +} diff --git a/template/router.template b/template/router.template new file mode 100644 index 0000000..b11e9b9 --- /dev/null +++ b/template/router.template @@ -0,0 +1,75 @@ +package router + + +import ( + "github.com/gin-gonic/gin" + _ "github.com/gin-gonic/gin" + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-admin-team/go-admin-core/sdk" + // "github.com/go-admin-team/go-admin-core/sdk/pkg" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + common "go-admin/common/middleware" + "os" +) + +var ( + routerNoCheckRole = make([]func(*gin.RouterGroup), 0) + routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0) +) + +// InitRouter 路由初始化 +func InitRouter() { + var r *gin.Engine + h := sdk.Runtime.GetEngine() + if h == nil { + h = gin.New() + sdk.Runtime.SetEngine(h) + } + switch h.(type) { + case *gin.Engine: + r = h.(*gin.Engine) + default: + log.Fatal("not support other engine") + os.Exit(-1) + } + + // the jwt middleware + authMiddleware, err := common.AuthInit() + if err != nil { + log.Fatalf("JWT Init Error, %s", err.Error()) + } + + // 注册业务路由 + InitBusinessRouter(r, authMiddleware) +} + +func InitBusinessRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine { + + // 无需认证的路由 + noCheckRoleRouter(r) + // 需要认证的路由 + checkRoleRouter(r, authMiddleware) + + return r +} + +// noCheckRoleRouter 无需认证的路由 +func noCheckRoleRouter(r *gin.Engine) { + // 可根据业务需求来设置接口版本 + v := r.Group("/api/v1") + + for _, f := range routerNoCheckRole { + f(v) + } +} + +// checkRoleRouter 需要认证的路由 +func checkRoleRouter(r *gin.Engine, authMiddleware *jwtauth.GinJWTMiddleware) { + // 可根据业务需求来设置接口版本 + v := r.Group("/api/v1") + + for _, f := range routerCheckRole { + f(v, authMiddleware) + } +} diff --git a/template/v4/actions/router_check_role.go.template b/template/v4/actions/router_check_role.go.template new file mode 100644 index 0000000..3c3c069 --- /dev/null +++ b/template/v4/actions/router_check_role.go.template @@ -0,0 +1,31 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/{{.PackageName}}/models" + "go-admin/app/{{.PackageName}}/service/dto" + "go-admin/common/actions" + "go-admin/common/middleware" +) + +func init() { + routerCheckRole = append(routerCheckRole, register{{.ClassName}}Router) +} + +// 需认证的路由代码 +func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + model := &models.{{.ClassName}}{} + r.GET("", actions.PermissionAction(), actions.IndexAction(model, new(dto.{{.ClassName}}Search), func() interface{} { + list := make([]models.{{.ClassName}}, 0) + return &list + })) + r.GET("/:id", actions.PermissionAction(), actions.ViewAction(new(dto.{{.ClassName}}ById), nil)) + r.POST("", actions.CreateAction(new(dto.{{.ClassName}}Control))) + r.PUT("/:id", actions.PermissionAction(), actions.UpdateAction(new(dto.{{.ClassName}}Control))) + r.DELETE("", actions.PermissionAction(), actions.DeleteAction(new(dto.{{.ClassName}}ById))) + } +} diff --git a/template/v4/actions/router_no_check_role.go.template b/template/v4/actions/router_no_check_role.go.template new file mode 100644 index 0000000..0154557 --- /dev/null +++ b/template/v4/actions/router_no_check_role.go.template @@ -0,0 +1,30 @@ +package router + +import ( + "github.com/gin-gonic/gin" + + "go-admin/app/{{.PackageName}}/middleware" + "go-admin/app/{{.PackageName}}/models" + "go-admin/app/{{.PackageName}}/service/dto" + "go-admin/common/actions" +) + +func init() { + routerNoCheckRole = append(routerNoCheckRole, register{{.ClassName}}Router) +} + +// 无需认证的路由代码 +func register{{.ClassName}}Router(v1 *gin.RouterGroup) { + r := v1.Group("/{{.ModuleName}}") + { + model := &models.{{.ClassName}}{} + r.GET("", actions.IndexAction(model, new(dto.{{.ClassName}}Search), func() interface{} { + list := make([]models.{{.ClassName}}, 0) + return &list + })) + r.GET("/:id", actions.ViewAction(new(dto.{{.ClassName}}ById), nil)) + r.POST("", actions.CreateAction(new(dto.{{.ClassName}}Control))) + r.PUT("/:id", actions.UpdateAction(new(dto.{{.ClassName}}Control))) + r.DELETE("", actions.DeleteAction(new(dto.{{.ClassName}}ById))) + } +} diff --git a/template/v4/dto.go.template b/template/v4/dto.go.template new file mode 100644 index 0000000..428b89a --- /dev/null +++ b/template/v4/dto.go.template @@ -0,0 +1,151 @@ +package dto + +import ( + {{- $bb := false -}} + {{- range .Columns -}} + {{- $z := .IsQuery -}} + {{- if ($z) -}} + {{- if eq .GoType "time.Time" -}}{{- $bb = true -}}{{- end -}} + {{- end -}} + {{- end -}} + {{- range .Columns -}} + {{- if eq .GoField "CreatedAt" -}} + {{- else if eq .GoField "UpdatedAt" -}} + {{- else if eq .GoField "DeletedAt" -}} + {{- else -}} + {{- if eq .GoType "time.Time" -}}{{- $bb = true -}}{{- end -}} + {{- end -}} + {{- end -}} + {{- if eq $bb true }} + "time" + {{- end }} + + "go-admin/app/{{.PackageName}}/models" + "go-admin/common/dto" + common "go-admin/common/models" +) + +type {{.ClassName}}GetPageReq struct { + dto.Pagination `search:"-"` + {{- $tablename := .TBName -}} + {{- range .Columns -}} + {{$z := .IsQuery}} + {{- if ($z) }} + {{.GoField}} {{.GoType}} `form:"{{.JsonField}}" search:"type:{{if eq .QueryType "EQ"}}exact{{ else if eq .QueryType "NE"}}iexact{{ else if eq .QueryType "LIKE"}}contains{{ else if eq .QueryType "GT"}}gt{{ else if eq .QueryType "GTE"}}gte{{ else if eq .QueryType "LT"}}lt{{ else if eq .QueryType "LTE"}}lte{{- end }};column:{{.ColumnName}};table:{{$tablename}}" comment:"{{.ColumnComment}}"` + {{- end }} + {{- end }} + {{.ClassName}}Order +} + +type {{.ClassName}}Order struct { + {{ $tablename := .TBName }} + {{- range .Columns -}} + {{.GoField}} string `form:"{{.JsonField}}Order" search:"type:order;column:{{.ColumnName}};table:{{$tablename}}"` + {{ end }} +} + +func (m *{{.ClassName}}GetPageReq) GetNeedSearch() interface{} { + return *m +} + +type {{.ClassName}}InsertReq struct { + {{- range .Columns -}} + {{$x := .Pk}} + {{- if ($x) }} + {{.GoField}} {{.GoType}} `json:"-" comment:"{{.ColumnComment}}"` // {{.ColumnComment}} + {{- else if eq .GoField "CreatedAt" -}} + {{- else if eq .GoField "UpdatedAt" -}} + {{- else if eq .GoField "DeletedAt" -}} + {{- else if eq .GoField "CreateBy" -}} + {{- else if eq .GoField "UpdateBy" -}} + {{- else }} + {{.GoField}} {{.GoType}} `json:"{{.JsonField}}" comment:"{{.ColumnComment}}"` + {{- end -}} + {{- end }} + common.ControlBy +} + +func (s *{{.ClassName}}InsertReq) Generate(model *models.{{.ClassName}}) { + {{- range .Columns -}} + {{$x := .Pk}} + {{- if ($x) }} + if s.{{.GoField}} == 0 { + model.Model = common.Model{ {{.GoField}}: s.{{.GoField}} } + } + {{- else if eq .GoField "CreatedAt" -}} + {{- else if eq .GoField "UpdatedAt" -}} + {{- else if eq .GoField "DeletedAt" -}} + {{- else if eq .GoField "CreateBy"}} + model.{{.GoField}} = s.{{.GoField}} // 添加这而,需要记录是被谁创建的 + {{- else if eq .GoField "UpdateBy" -}} + {{- else }} + model.{{.GoField}} = s.{{.GoField}} + {{- end -}} + {{- end }} +} + +func (s *{{.ClassName}}InsertReq) GetId() interface{} { + return s.{{.PkGoField}} +} + +type {{.ClassName}}UpdateReq struct { + {{- range .Columns -}} + {{$x := .Pk}} + {{- if ($x) }} + {{.GoField}} {{.GoType}} `uri:"{{.JsonField}}" comment:"{{.ColumnComment}}"` // {{.ColumnComment}} + {{- else if eq .GoField "CreatedAt" -}} + {{- else if eq .GoField "UpdatedAt" -}} + {{- else if eq .GoField "DeletedAt" -}} + {{- else if eq .GoField "CreateBy" -}} + {{- else if eq .GoField "UpdateBy" -}} + {{- else }} + {{.GoField}} {{.GoType}} `json:"{{.JsonField}}" comment:"{{.ColumnComment}}"` + {{- end -}} + {{- end }} + common.ControlBy +} + +func (s *{{.ClassName}}UpdateReq) Generate(model *models.{{.ClassName}}) { + {{- range .Columns -}} + {{$x := .Pk}} + {{- if ($x) }} + if s.{{.GoField}} == 0 { + model.Model = common.Model{ {{.GoField}}: s.{{.GoField}} } + } + {{- else if eq .GoField "CreatedAt" -}} + {{- else if eq .GoField "UpdatedAt" -}} + {{- else if eq .GoField "DeletedAt" -}} + {{- else if eq .GoField "CreateBy" -}} + {{- else if eq .GoField "UpdateBy"}} + model.{{.GoField}} = s.{{.GoField}} // 添加这而,需要记录是被谁更新的 + {{- else }} + model.{{.GoField}} = s.{{.GoField}} + {{- end -}} + {{- end }} +} + +func (s *{{.ClassName}}UpdateReq) GetId() interface{} { + return s.{{.PkGoField}} +} + +// {{.ClassName}}GetReq 功能获取请求参数 +type {{.ClassName}}GetReq struct { + {{- range .Columns -}} + {{$x := .Pk}} + {{- if ($x) }} + {{.GoField}} {{.GoType}} `uri:"{{.JsonField}}"` + {{- end }} + {{- end }} +} +func (s *{{.ClassName}}GetReq) GetId() interface{} { + return s.{{.PkGoField}} +} + +// {{.ClassName}}DeleteReq 功能删除请求参数 +type {{.ClassName}}DeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *{{.ClassName}}DeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/template/v4/js.go.template b/template/v4/js.go.template new file mode 100644 index 0000000..db3d4a2 --- /dev/null +++ b/template/v4/js.go.template @@ -0,0 +1,47 @@ +import request from '@/utils/request' + +// 查询{{.ClassName}}列表 +export function list{{.ClassName}}(query) { + return request({ + url: '/api/v1/{{.ModuleName}}', + method: 'get', + params: query + }) +} + +// 查询{{.ClassName}}详细 +export function get{{.ClassName}} ({{.PkJsonField}}) { + return request({ + url: '/api/v1/{{.ModuleName}}/' + {{.PkJsonField}}, + method: 'get' + }) +} + + +// 新增{{.ClassName}} +export function add{{.ClassName}}(data) { + return request({ + url: '/api/v1/{{.ModuleName}}', + method: 'post', + data: data + }) +} + +// 修改{{.ClassName}} +export function update{{.ClassName}}(data) { + return request({ + url: '/api/v1/{{.ModuleName}}/'+data.{{.PkJsonField}}, + method: 'put', + data: data + }) +} + +// 删除{{.ClassName}} +export function del{{.ClassName}}(data) { + return request({ + url: '/api/v1/{{.ModuleName}}', + method: 'delete', + data: data + }) +} + diff --git a/template/v4/model.go.template b/template/v4/model.go.template new file mode 100644 index 0000000..2f56123 --- /dev/null +++ b/template/v4/model.go.template @@ -0,0 +1,55 @@ +package models + +import ( + {{- $bb := false -}} + {{- range .Columns -}} + {{- $z := .IsQuery -}} + {{- if ($z) -}} + {{- if eq .GoType "time.Time" -}}{{- $bb = true -}}{{- end -}} + {{- end -}} + {{- end -}} + {{- range .Columns -}} + {{- if eq .GoField "CreatedAt" -}} + {{- else if eq .GoField "UpdatedAt" -}} + {{- else if eq .GoField "DeletedAt" -}} + {{- else -}} + {{- if eq .GoType "time.Time" -}}{{- $bb = true -}}{{- end -}} + {{- end -}} + {{- end -}} + {{- if eq $bb true }} + "time" + {{- end }} + + "go-admin/common/models" + +) + +type {{.ClassName}} struct { + models.Model + {{ range .Columns -}} + {{$x := .Pk}} + {{- if ($x) }} + {{- else if eq .GoField "CreatedAt" -}} + {{- else if eq .GoField "UpdatedAt" -}} + {{- else if eq .GoField "DeletedAt" -}} + {{- else if eq .GoField "CreateBy" -}} + {{- else if eq .GoField "UpdateBy" -}} + {{- else }} + {{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"type:{{.ColumnType}};comment:{{- if eq .ColumnComment "" -}}{{.GoField}}{{- else -}}{{.ColumnComment}}{{end -}}"` {{end -}} + {{- end }} + models.ModelTime + models.ControlBy +} + +func ({{.ClassName}}) TableName() string { + return "{{.TBName}}" +} + +func (e *{{.ClassName}}) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *{{.ClassName}}) GetId() interface{} { + return e.{{.PkGoField}} +} \ No newline at end of file diff --git a/template/v4/no_actions/apis.go.template b/template/v4/no_actions/apis.go.template new file mode 100644 index 0000000..7878776 --- /dev/null +++ b/template/v4/no_actions/apis.go.template @@ -0,0 +1,198 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/{{.PackageName}}/models" + "go-admin/app/{{.PackageName}}/service" + "go-admin/app/{{.PackageName}}/service/dto" + "go-admin/common/actions" +) + +type {{.ClassName}} struct { + api.Api +} + +// GetPage 获取{{.TableComment}}列表 +// @Summary 获取{{.TableComment}}列表 +// @Description 获取{{.TableComment}}列表 +// @Tags {{.TableComment}} +{{- $tablename := .TBName -}} +{{- range .Columns -}} +{{$z := .IsQuery}} +{{- if ($z) }} +// @Param {{.JsonField}} query {{.GoType}} false "{{.ColumnComment}}" +{{- end -}} +{{- end }} +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.{{.ClassName}}}} "{"code": 200, "data": [...]}" +// @Router /api/v1/{{.ModuleName}} [get] +// @Security Bearer +func (e {{.ClassName}}) GetPage(c *gin.Context) { + req := dto.{{.ClassName}}GetPageReq{} + s := service.{{.ClassName}}{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]models.{{.ClassName}}, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取{{.TableComment}}失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取{{.TableComment}} +// @Summary 获取{{.TableComment}} +// @Description 获取{{.TableComment}} +// @Tags {{.TableComment}} +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.{{.ClassName}}} "{"code": 200, "data": [...]}" +// @Router /api/v1/{{.ModuleName}}/{id} [get] +// @Security Bearer +func (e {{.ClassName}}) Get(c *gin.Context) { + req := dto.{{.ClassName}}GetReq{} + s := service.{{.ClassName}}{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.{{.ClassName}} + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取{{.TableComment}}失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK( object, "查询成功") +} + +// Insert 创建{{.TableComment}} +// @Summary 创建{{.TableComment}} +// @Description 创建{{.TableComment}} +// @Tags {{.TableComment}} +// @Accept application/json +// @Product application/json +// @Param data body dto.{{.ClassName}}InsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/{{.ModuleName}} [post] +// @Security Bearer +func (e {{.ClassName}}) Insert(c *gin.Context) { + req := dto.{{.ClassName}}InsertReq{} + s := service.{{.ClassName}}{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建{{.TableComment}}失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改{{.TableComment}} +// @Summary 修改{{.TableComment}} +// @Description 修改{{.TableComment}} +// @Tags {{.TableComment}} +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.{{.ClassName}}UpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/{{.ModuleName}}/{id} [put] +// @Security Bearer +func (e {{.ClassName}}) Update(c *gin.Context) { + req := dto.{{.ClassName}}UpdateReq{} + s := service.{{.ClassName}}{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改{{.TableComment}}失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "修改成功") +} + +// Delete 删除{{.TableComment}} +// @Summary 删除{{.TableComment}} +// @Description 删除{{.TableComment}} +// @Tags {{.TableComment}} +// @Param data body dto.{{.ClassName}}DeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/{{.ModuleName}} [delete] +// @Security Bearer +func (e {{.ClassName}}) Delete(c *gin.Context) { + s := service.{{.ClassName}}{} + req := dto.{{.ClassName}}DeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除{{.TableComment}}失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "删除成功") +} diff --git a/template/v4/no_actions/router_check_role.go.template b/template/v4/no_actions/router_check_role.go.template new file mode 100644 index 0000000..f8a3c3a --- /dev/null +++ b/template/v4/no_actions/router_check_role.go.template @@ -0,0 +1,27 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/{{.PackageName}}/apis" + "go-admin/common/middleware" + "go-admin/common/actions" +) + +func init() { + routerCheckRole = append(routerCheckRole, register{{.ClassName}}Router) +} + +// register{{.ClassName}}Router +func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.{{.ClassName}}{} + r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/template/v4/no_actions/router_no_check_role.go.template b/template/v4/no_actions/router_no_check_role.go.template new file mode 100644 index 0000000..fc26fe6 --- /dev/null +++ b/template/v4/no_actions/router_no_check_role.go.template @@ -0,0 +1,25 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/{{.PackageName}}/apis" +) + +func init() { + routerCheckRole = append(routerCheckRole, register{{.ClassName}}Router) +} + +// register{{.ClassName}}Router +func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.{{.ClassName}}{} + r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc()) + { + r.GET("", api.GetPage) + r.GET("/:id", api.Get) + r.POST("", api.Insert) + r.PUT("/:id", api.Update) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/template/v4/no_actions/service.go.template b/template/v4/no_actions/service.go.template new file mode 100644 index 0000000..84e8886 --- /dev/null +++ b/template/v4/no_actions/service.go.template @@ -0,0 +1,109 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/{{.PackageName}}/models" + "go-admin/app/{{.PackageName}}/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" +) + +type {{.ClassName}} struct { + service.Service +} + +// GetPage 获取{{.ClassName}}列表 +func (e *{{.ClassName}}) GetPage(c *dto.{{.ClassName}}GetPageReq, p *actions.DataPermission, list *[]models.{{.ClassName}}, count *int64) error { + var err error + var data models.{{.ClassName}} + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("{{.ClassName}}Service GetPage error:%s \r\n", err) + return err + } + return nil +} + +// Get 获取{{.ClassName}}对象 +func (e *{{.ClassName}}) Get(d *dto.{{.ClassName}}GetReq, p *actions.DataPermission, model *models.{{.ClassName}}) error { + var data models.{{.ClassName}} + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service Get{{.ClassName}} error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建{{.ClassName}}对象 +func (e *{{.ClassName}}) Insert(c *dto.{{.ClassName}}InsertReq) error { + var err error + var data models.{{.ClassName}} + c.Generate(&data) + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("{{.ClassName}}Service Insert error:%s \r\n", err) + return err + } + return nil +} + +// Update 修改{{.ClassName}}对象 +func (e *{{.ClassName}}) Update(c *dto.{{.ClassName}}UpdateReq, p *actions.DataPermission) error { + var err error + var data = models.{{.ClassName}}{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("{{.ClassName}}Service Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// Remove 删除{{.ClassName}} +func (e *{{.ClassName}}) Remove(d *dto.{{.ClassName}}DeleteReq, p *actions.DataPermission) error { + var data models.{{.ClassName}} + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service Remove{{.ClassName}} error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} diff --git a/template/v4/vue.go.template b/template/v4/vue.go.template new file mode 100644 index 0000000..ff70016 --- /dev/null +++ b/template/v4/vue.go.template @@ -0,0 +1,485 @@ +{{$tableComment:=.TableComment}} + + + diff --git a/test/api.go.template b/test/api.go.template new file mode 100644 index 0000000..1ae26ca --- /dev/null +++ b/test/api.go.template @@ -0,0 +1,126 @@ +package apis + +import ( +"github.com/gin-gonic/gin" +"github.com/gin-gonic/gin/binding" +"go-admin/models" +"github.com/go-admin-team/go-admin-core/sdk/pkg" +"go-admin/utils" +"net/http" +) + +// @Summary 配置列表数据 +// @Description 获取JSON +// @Tags 配置 +// @Param configKey query string false "configKey" +// @Param configName query string false "configName" +// @Param configType query string false "configType" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} app.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/configList [get] +// @Security Bearer +func Get{{.ClassName}}List(c *gin.Context) { +var data models.{{.ClassName}} +var err error +var pageSize = 10 +var pageIndex = 1 + +if size := c.Request.FormValue("pageSize"); size != "" { +pageSize = pkg.StrToInt(err, size) +} + +if index := c.Request.FormValue("pageIndex"); index != "" { +pageIndex = pkg.StrToInt(err, index) +} + +{{ range .Columns -}} + {{$z := .IsQuery}} + {{- if ($z) -}} + data.{{.GoField}} = c.Request.FormValue("{{.JsonField}}") + {{ end }} +{{- end -}} + +data.DataScope = utils.GetUserIdStr(c) +result, count, err := data.GetPage(pageSize, pageIndex) +pkg.HasError(err, "", -1) + +var mp = make(map[string]interface{}, 3) +mp["list"] = result +mp["count"] = count +mp["pageIndex"] = pageIndex +mp["pageIndex"] = pageSize + +var res app.Response +res.Data = mp + +c.JSON(http.StatusOK, res.ReturnOK()) +} + +// @Summary 获取配置 +// @Description 获取JSON +// @Tags 配置 +// @Param configId path int true "配置编码" +// @Success 200 {object} app.Response "{"code": 200, "data": [...]}" +// @Router /api/v1/config/{configId} [get] +// @Security Bearer +func Get{{.ClassName}}(c *gin.Context) { +var data models.{{.ClassName}} +data.{{.PkGoField}}, _ = utils.StringToInt(c.Param("{{.PkJsonField}}")) +result, err := data.Get() +pkg.HasError(err, "抱歉未找到相关信息", -1) + +var res app.Response +res.Data = result + +c.JSON(http.StatusOK, res.ReturnOK()) +} + +// @Summary 添加配置 +// @Description 获取JSON +// @Tags 配置 +// @Accept application/json +// @Product application/json +// @Param data body models.{{.ClassName}} true "data" +// @Success 200 {string} string "{"code": 200, "message": "添加成功"}" +// @Success 200 {string} string "{"code": -1, "message": "添加失败"}" +// @Router /api/v1/dict/data [post] +// @Security Bearer +func Insert{{.ClassName}}(c *gin.Context) { +var data models.{{.ClassName}} +err := c.BindWith(&data, binding.JSON) +data.CreateBy = utils.GetUserIdStr(c) +pkg.HasError(err, "", 500) +result, err := data.Create() +pkg.HasError(err, "", -1) + +var res app.Response +res.Data = result +c.JSON(http.StatusOK, res.ReturnOK()) + +} + +func Update{{.ClassName}}(c *gin.Context) { +var data models.{{.ClassName}} +err := c.BindWith(&data, binding.JSON) +pkg.HasError(err, "数据解析失败", -1) +data.UpdateBy = utils.GetUserIdStr(c) +result, err := data.Update(data.{{.PkGoField}}) +pkg.HasError(err, "", -1) + +var res app.Response +res.Data = result +c.JSON(http.StatusOK, res.ReturnOK()) +} + +func Delete{{.ClassName}}(c *gin.Context) { +var data models.{{.ClassName}} +id, err := utils.StringToInt(c.Param("{{.PkJsonField}}")) +data.UpdateBy = utils.GetUserIdStr(c) +_, err = data.Delete(id) +pkg.HasError(err, "修改失败", 500) + +var res app.Response +res.Msg = "删除成功" +c.JSON(http.StatusOK, res.ReturnOK()) +} diff --git a/test/gen_test.go b/test/gen_test.go new file mode 100644 index 0000000..99a5c74 --- /dev/null +++ b/test/gen_test.go @@ -0,0 +1,47 @@ +package test + +import ( + //"go-admin/models/tools" + //"os" + "testing" + //"text/template" +) + +func TestGoModelTemplate(t *testing.T) { + //t1, err := template.ParseFiles("model.go.template") + //if err != nil { + // t.Error(err) + //} + //table := tools.SysTables{} + //table.TBName = "sys_tables" + //tab, err := table.Get() + //if err != nil { + // t.Error(err) + //} + //file, err := os.Create("models/" + table.PackageName + ".go") + //if err != nil { + // t.Error(err) + //} + //defer file.Close() + // + //_ = t1.Execute(file, tab) + t.Log("") +} + +func TestGoApiTemplate(t *testing.T) { + //t1, err := template.ParseFiles("api.go.template") + //if err != nil { + // t.Error(err) + //} + //table := tools.SysTables{} + //table.TBName = "sys_tables" + //tab, _ := table.Get() + //file, err := os.Create("apis/" + table.PackageName + ".go") + //if err != nil { + // t.Error(err) + //} + //defer file.Close() + // + //_ = t1.Execute(file, tab) + t.Log("") +} diff --git a/test/model.go.template b/test/model.go.template new file mode 100644 index 0000000..6d9eaaa --- /dev/null +++ b/test/model.go.template @@ -0,0 +1,103 @@ +package models + +import ( +orm "go-admin/global" +"go-admin/utils" +"time" +) + +type {{.ClassName}} struct { + +{{ range .Columns -}} + {{$x := .Pk}} + // {{.ColumnComment}} + {{if ($x)}}{{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"column:{{.ColumnName}};primary_key"`{{else}}{{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"column:{{.ColumnName}};"`{{end}} +{{ end -}} +} + +// 创建{{.ClassName}} +func (e *{{.ClassName}}) Create() ({{.ClassName}}, error) { +var doc {{.ClassName}} +doc.IsDel = "0" +e.CreateTime = time.Now().String() +result := orm.Eloquent.Table("{{.TableName}}").Create(&e) +if result.Error != nil { +err := result.Error +return doc, err +} +doc = *e +return doc, nil +} + +// 获取{{.ClassName}} +func (e *{{.ClassName}}) Get() ({{.ClassName}}, error) { +var doc {{.ClassName}} + +table := orm.Eloquent.Table("{{.TableName}}") +{{ range .Columns -}} + {{$z := .IsQuery}} + {{- if ($z) -}}if e.{{.GoField}} != "" { + table = table.Where("{{.ColumnName}} = ?", e.{{.GoField}}) + } + {{ end }} +{{- end -}} + +if err := table.First(&doc).Error; err != nil { +return doc, err +} +return doc, nil +} + +// 获取{{.ClassName}}带分页 +func (e *{{.ClassName}}) GetPage(pageSize int, pageIndex int) ([]{{.ClassName}}, int32, error) { +var doc []{{.ClassName}} + +table := orm.Eloquent.Table("{{.TableName}}") +{{ range .Columns -}} + {{$z := .IsQuery}} + {{- if ($z) -}}if e.{{.GoField}} != "" { + table = table.Where("{{.ColumnName}} = ?", e.{{.GoField}}) + } + {{ end }} +{{- end -}} + +// 数据权限控制 +dataPermission := new(DataPermission) +dataPermission.UserId, _ = utils.StringToInt(e.DataScope) +table,err := dataPermission.GetDataScope("{{.TableName}}", table) +if err != nil { +return nil, 0, err +} +var count int32 +table = table.Offset((pageIndex - 1) * pageSize).Limit(pageSize) +if err := table.Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil { +return nil, 0, err +} +return doc, count, nil +} + +// 更新{{.ClassName}} +func (e *{{.ClassName}}) Update(id int) (update {{.ClassName}}, err error) { +if err = orm.Eloquent.Table("{{.TableName}}").Where("{{.PkColumn}} = ?", id).First(&update).Error; err != nil { +return +} + +//参数1:是要修改的数据 +//参数2:是修改的数据 +if err = orm.Eloquent.Table("{{.TableName}}").Model(&update).Updates(&e).Error; err != nil { +return +} +return +} + +// 删除{{.ClassName}} +func (e *{{.ClassName}}) Delete(id int) (success bool, err error) { + +if err = orm.Eloquent.Table("{{.TableName}}").Where("{{.PkColumn}} = ?", id).Delete(&{{.ClassName}}{}).Error; err != nil { +success = false +return +} +success = true +return +} + diff --git a/utils/httphelper/http_helper.go b/utils/httphelper/http_helper.go new file mode 100644 index 0000000..cf6496a --- /dev/null +++ b/utils/httphelper/http_helper.go @@ -0,0 +1,145 @@ +package httphelper + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +// HTTPClient 定义一个通用的 HTTP 客户端结构 +type HTTPClient struct { + Client *http.Client // 底层的 http.Client 实例 + BaseURL string // 基础 URL,所有请求将基于此 URL + Headers map[string]string // 默认请求头 +} + +// NewHTTPClient 创建一个新的 HTTPClient 实例 +// timeout: 请求超时时间,例如 10 * time.Second +// baseURL: 基础 URL,例如 "https://api.example.com" +// defaultHeaders: 默认请求头,例如 {"Content-Type": "application/json"} +func NewHTTPClient(timeout time.Duration, baseURL string, defaultHeaders map[string]string) *HTTPClient { + return &HTTPClient{ + Client: &http.Client{ + Timeout: timeout, + }, + BaseURL: baseURL, + Headers: defaultHeaders, + } +} + +// applyHeaders 为请求应用默认和自定义请求头 +func (c *HTTPClient) applyHeaders(req *http.Request, customHeaders map[string]string) { + // 应用默认请求头 + for key, value := range c.Headers { + req.Header.Set(key, value) + } + // 应用自定义请求头(覆盖默认请求头) + for key, value := range customHeaders { + req.Header.Set(key, value) + } +} + +// doRequest 执行实际的 HTTP 请求 +// method: HTTP 方法 (GET, POST, PUT, DELETE等) +// path: 请求路径,将与 BaseURL 拼接 +// requestBody: 请求体数据,如果为 GET/DELETE 请求则为 nil +// customHeaders: 自定义请求头,将覆盖默认请求头 +// responseData: 用于存储响应数据的目标结构体(指针类型) +func (c *HTTPClient) doRequest( + method, path string, + requestBody interface{}, + customHeaders map[string]string, + responseData interface{}, +) error { + // 拼接完整的 URL + url := c.BaseURL + path + + var reqBodyReader io.Reader + if requestBody != nil { + // 将请求体编码为 JSON + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("json marshal request body failed: %w", err) + } + reqBodyReader = bytes.NewBuffer(jsonBody) + } + + // 创建新的 HTTP 请求 + req, err := http.NewRequest(method, url, reqBodyReader) + if err != nil { + return fmt.Errorf("create http request failed: %w", err) + } + + // 应用请求头 + c.applyHeaders(req, customHeaders) + + // 发送请求 + resp, err := c.Client.Do(req) + if err != nil { + return fmt.Errorf("send http request failed: %w", err) + } + defer resp.Body.Close() + + // 检查 HTTP 状态码 + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest { + bodyBytes, _ := io.ReadAll(resp.Body) // 读取错误响应体 + return fmt.Errorf("http request failed with status: %d, body: %s", resp.StatusCode, string(bodyBytes)) + } + + // 如果提供了 responseData,则解析响应体 + if responseData != nil { + err = json.NewDecoder(resp.Body).Decode(responseData) + if err != nil { + return fmt.Errorf("json decode response body failed: %w", err) + } + } + + return nil +} + +// Get 发送 GET 请求 +// path: 请求路径 +// customHeaders: 自定义请求头 +// responseData: 用于存储响应数据的目标结构体(指针类型) +func (c *HTTPClient) Get(path string, customHeaders map[string]string, responseData interface{}) error { + return c.doRequest(http.MethodGet, path, nil, customHeaders, responseData) +} + +// Post 发送 POST 请求 +// path: 请求路径 +// requestBody: 请求体数据 +// customHeaders: 自定义请求头 +// responseData: 用于存储响应数据的目标结构体(指针类型) +func (c *HTTPClient) Post(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error { + return c.doRequest(http.MethodPost, path, requestBody, customHeaders, responseData) +} + +// Put 发送 PUT 请求 +// path: 请求路径 +// requestBody: 请求体数据 +// customHeaders: 自定义请求头 +// responseData: 用于存储响应数据的目标结构体(指针类型) +func (c *HTTPClient) Put(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error { + return c.doRequest(http.MethodPut, path, requestBody, customHeaders, responseData) +} + +// Delete 发送 DELETE 请求 +// path: 请求路径 +// customHeaders: 自定义请求头 +// responseData: 用于存储响应数据的目标结构体(指针类型) +func (c *HTTPClient) Delete(path string, customHeaders map[string]string, responseData interface{}) error { + // DELETE 请求通常没有请求体,但某些 RESTful API 可能支持 + return c.doRequest(http.MethodDelete, path, nil, customHeaders, responseData) +} + +// Patch 发送 PATCH 请求 +// path: 请求路径 +// requestBody: 请求体数据 +// customHeaders: 自定义请求头 +// responseData: 用于存储响应数据的目标结构体(指针类型) +func (c *HTTPClient) Patch(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error { + return c.doRequest(http.MethodPatch, path, requestBody, customHeaders, responseData) +} diff --git a/utils/redishelper/redis_helper.go b/utils/redishelper/redis_helper.go new file mode 100644 index 0000000..c1bb54b --- /dev/null +++ b/utils/redishelper/redis_helper.go @@ -0,0 +1,796 @@ +package redishelper + +import ( + "context" + "errors" + "fmt" + "log" + "math" + "reflect" + "strconv" + "time" + + "github.com/bytedance/sonic" + "github.com/go-redis/redis/v8" +) + +// RedisHelper 结构体封装了 Redis 客户端及上下文 +type RedisHelper struct { + client *redis.Client // Redis 客户端 + ctx context.Context // 上下文 + emptyCacheValue string // 缓存空值的标志 +} + +var DefaultRedis *RedisHelper + +// 初始化默认链接 +func InitDefaultRedis(addr, password string, db int) { + if DefaultRedis == nil { + DefaultRedis = NewRedisHelper(addr, password, db) + } + + log.Printf("初始化redis链接") +} + +// NewRedisHelper 创建一个新的 RedisHelper 实例 +func NewRedisHelper(addr, password string, db int) *RedisHelper { + rdb := redis.NewClient(&redis.Options{ + Addr: addr, // Redis 服务器地址 + Password: password, // Redis 密码 + DB: db, // 使用的数据库编号 + PoolSize: 50, + MinIdleConns: 10, + DialTimeout: 10 * time.Second, // 调整连接超时时间 + ReadTimeout: 10 * time.Second, // 调整读超时时间 + WriteTimeout: 10 * time.Second, // 调整写超时时间 + }) + + return &RedisHelper{ + client: rdb, + ctx: context.Background(), // 创建背景上下文 + } +} + +// 测试连接 +func (r *RedisHelper) Ping() error { + return r.client.Ping(r.ctx).Err() +} + +// SetString 设置字符串值 +func (r *RedisHelper) SetString(key, value string) error { + return r.client.Set(r.ctx, key, value, 0).Err() // 将值存储到指定的键 +} + +// 批量设置 +func (r *RedisHelper) BatchSet(maps *map[string]string) error { + pipe := r.client.Pipeline() + + for key, val := range *maps { + pipe.Set(r.ctx, key, val, 0) + } + + _, err := pipe.Exec(r.ctx) + + return err +} + +// SetString 设置字符串值 +func (r *RedisHelper) SetStringExpire(key, value string, expireTime time.Duration) error { + return r.client.Set(r.ctx, key, value, expireTime).Err() // 将值存储到指定的键 +} + +// SetString 设置字符串值 +func (r *RedisHelper) SetAdd(key, value string, expireTime time.Duration) error { + // 存储到 SET 中 + result, err := r.client.SAdd(r.ctx, key, value).Result() + if err != nil { + return err + } + + if result == 1 { + // 设置 SET 的过期时间 + err = r.client.Expire(r.ctx, key, expireTime).Err() + if err != nil { + return errors.New("设置过期时间失败:" + err.Error()) + } + + return nil + } else { + return errors.New("key已存在") + } +} + +// 设置对象 +func SetObjString[T any](r *RedisHelper, key string, value T) error { + keyValue, err := sonic.Marshal(value) + + if err != nil { + return err + } + + return r.SetString(key, string(keyValue)) +} + +// 获取对象 +func GetObjString[T any](r *RedisHelper, key string) (T, error) { + var result T + value, err := r.GetString(key) + + if err != nil { + return result, err + } + + err = sonic.Unmarshal([]byte(value), &result) + + if err != nil { + return result, err + } + + return result, nil +} + +func (r *RedisHelper) Get(key string) *redis.StringCmd { + return r.client.Get(r.ctx, key) +} + +/* +获取剩余时间 + - @key redis key +*/ +func (r *RedisHelper) TTL(key string) *redis.DurationCmd { + return r.client.TTL(r.ctx, key) +} + +// GetString 获取字符串值 +func (r *RedisHelper) GetString(key string) (string, error) { + return r.client.Get(r.ctx, key).Result() // 从指定的键获取值 +} + +// DeleteString 删除字符串键 +func (r *RedisHelper) DeleteString(key string) error { + return r.client.Del(r.ctx, key).Err() // 删除指定的键 +} + +// DeleteString 删除目录下所有key +func (r *RedisHelper) DeleteAll(key string) error { + keys, err := r.ScanKeys(key) + + if err != nil { + return err + } + + _, err = r.BatchDeleteKeys(keys) + return err +} + +/* +递增 + - @key rediskey +*/ +func (r *RedisHelper) Incr(key string) *redis.IntCmd { + return r.client.Incr(r.ctx, key) +} + +func (r *RedisHelper) IncrBy(key string, value int64) *redis.IntCmd { + return r.client.IncrBy(r.ctx, key, value) +} + +func (r *RedisHelper) Decr(key string) *redis.IntCmd { + return r.client.Decr(r.ctx, key) +} + +func (r *RedisHelper) DecrBy(key string, value int64) *redis.IntCmd { + return r.client.DecrBy(r.ctx, key, value) +} + +/* +设置过期时间 + - @key redis key + - @expiration 过期时间 +*/ +func (r *RedisHelper) Expire(key string, expiration time.Duration) *redis.BoolCmd { + return r.client.Expire(r.ctx, key, expiration) +} + +/* +批量删除 + + - @keys 键数组 +*/ +func (r *RedisHelper) BatchDeleteKeys(keys []string) (int, error) { + if r.client == nil { + return 0, errors.New("Redis client is nil") + } + if len(keys) == 0 { + return 0, nil + } + + deletedCount := 0 + batchSize := 1000 // 每批次删除的键数量 + for i := 0; i < len(keys); i += batchSize { + end := i + batchSize + if end > len(keys) { + end = len(keys) + } + batch := keys[i:end] + + _, err := r.client.Pipelined(r.ctx, func(pipe redis.Pipeliner) error { + for _, key := range batch { + pipe.Del(r.ctx, key) + deletedCount++ + } + return nil + }) + if err != nil { + return deletedCount, fmt.Errorf("failed to delete keys in batch: %v", err) + } + } + + return deletedCount, nil +} + +// DeleteKeysByPrefix 删除指定前缀的键 +func (r *RedisHelper) DeleteKeysByPrefix(prefixes ...string) error { + ctx := context.Background() + // 遍历每个前缀 + for _, prefix := range prefixes { + var cursor uint64 + var keys []string + + // 使用 SCAN 命令查找匹配的键 + for { + var err error + keys, cursor, err = r.client.Scan(ctx, cursor, prefix+"*", 1000).Result() + if err != nil { + return err + } + + // 删除匹配的键 + if len(keys) > 0 { + _, err := r.client.Del(ctx, keys...).Result() + if err != nil { + return err + } + fmt.Printf("Deleted keys with prefix '%s': %v\n", prefix, keys) + } + + // 如果游标为 0,表示迭代结束 + if cursor == 0 { + break + } + } + } + return nil +} + +// 查找所有value +func (r *RedisHelper) GetAllKeysAndValues(pattern string) ([]string, error) { + var cursor uint64 + var result = []string{} + + for { + // 使用 SCAN 命令获取匹配的键 + keys, nextCursor, err := r.client.Scan(r.ctx, cursor, pattern+"*", 1000).Result() + if err != nil { + log.Printf("Error scanning keys: %v", err) + return nil, err + } + + // 处理匹配到的键 + for _, key := range keys { + value, err := r.client.Get(r.ctx, key).Result() + if err != nil { + if err == redis.Nil { + fmt.Printf("Key %s does not exist\n", key) + } else { + fmt.Printf("Error getting value for key %s: %v", key, err) + } + } else { + result = append(result, value) + } + } + + // 如果 cursor 为 0,表示扫描完成 + if nextCursor == 0 { + break + } + cursor = nextCursor + } + + return result, nil +} + +// LPushList 将一个或多个值插入到列表的头部 +func (r *RedisHelper) LPushList(key string, values ...string) error { + return r.client.LPush(r.ctx, key, values).Err() // 将值插入到列表的头部 +} + +// RPushList 将一个或多个值插入到列表的尾部 +func (r *RedisHelper) RPushList(key string, values ...string) error { + return r.client.RPush(r.ctx, key, values).Err() // 将值插入到列表的尾部 +} + +// LPopList 从列表的头部弹出一个元素 +func (r *RedisHelper) LPopList(key string) (string, error) { + return r.client.LPop(r.ctx, key).Result() // 从列表的头部移除并返回第一个元素 +} + +// RPopList 从列表的尾部弹出一个元素 +func (r *RedisHelper) RPopList(key string) (string, error) { + return r.client.RPop(r.ctx, key).Result() // 从列表的尾部移除并返回最后一个元素 +} + +// LRangeList 获取列表中指定范围的元素 +func (r *RedisHelper) LRangeList(key string, start, stop int64) ([]string, error) { + return r.client.LRange(r.ctx, key, start, stop).Result() // 获取列表中指定范围的元素 +} + +// GetAllList 获取列表中的所有元素 +func (r *RedisHelper) GetAllList(key string) ([]string, error) { + values, err := r.client.LRange(r.ctx, key, 0, -1).Result() + if err == redis.Nil { + return nil, nil + } else if err != nil { + return nil, err + } + + // 检查是否包含空值标志 + if len(values) == 1 && values[0] == r.emptyCacheValue { + return nil, nil + } + + return values, nil +} + +func (r *RedisHelper) LRem(key, val string) (int64, error) { + count := 0 // 删除所有与 valueToRemove 相等的元素 + result, err := r.client.LRem(r.ctx, key, int64(count), val).Result() + if err != nil { + fmt.Printf("删除元素失败: %v\n", err) + } + + return result, nil +} + +func (r *RedisHelper) IsElementInList(key string, element string) (bool, error) { + var cursor int64 = 0 + const batchSize int64 = 1000 // 每批次获取的元素数量 + + for { + // 分批次获取列表元素 + elements, err := r.client.LRange(r.ctx, key, cursor, cursor+batchSize-1).Result() + if err != nil { + return false, err + } + if len(elements) == 0 { + break // 没有更多数据 + } + + // 遍历当前批次的元素 + for _, e := range elements { + if e == element { + return true, nil + } + } + + cursor += batchSize // 移动到下一批次 + } + + return false, nil +} + +/* +SetListCache 重新设置列表缓存 + - @expiration 0-过期 1-过期时间 +*/ +func (r *RedisHelper) SetListCache(key string, expiration time.Duration, values ...string) error { + tempKey := key + ":temp" + + // 使用事务来确保操作的原子性 + pipe := r.client.TxPipeline() + + // 将新数据插入到临时列表中 + pipe.RPush(r.ctx, tempKey, values) + + // 重命名临时列表为目标列表 + pipe.Rename(r.ctx, tempKey, key) + + if expiration > 0 { + // 设置目标列表的过期时间 + pipe.Expire(r.ctx, key, expiration) + } + + // 执行事务 + _, err := pipe.Exec(r.ctx) + return err +} + +// SetEmptyListCache 设置空值缓存 +func (r *RedisHelper) SetEmptyListCache(key string, expiration time.Duration) error { + // 使用一个特殊标志值表示列表为空 + _, err := r.client.RPush(r.ctx, key, r.emptyCacheValue).Result() + if err != nil { + return err + } + + // 设置列表的过期时间 + return r.client.Expire(r.ctx, key, expiration).Err() +} + +// scanKeys 使用 SCAN 命令获取所有匹配的键 +func (r *RedisHelper) ScanKeys(pattern string) ([]string, error) { + + var cursor uint64 + var keys []string + for { + var newKeys []string + var err error + + // SCAN 命令每次返回部分匹配的键 + newKeys, cursor, err = r.client.Scan(r.ctx, cursor, pattern, 1000).Result() + if err != nil { + return nil, err + } + keys = append(keys, newKeys...) + if cursor == 0 { + break + } + } + return keys, nil +} + +// 泛型函数,用于获取所有键的列表数据并合并为一个数组 +func GetAndMergeLists[T any](r *RedisHelper, keys []string) ([]T, error) { + var combinedList []T + for _, key := range keys { + // 获取每个键的列表数据 + listData, err := r.client.LRange(r.ctx, key, 0, -1).Result() + if err != nil { + return nil, err + } + + // 解码每个数据项为类型 T,并添加到结果列表中 + for _, data := range listData { + var item T + if err := sonic.Unmarshal([]byte(data), &item); err != nil { + return nil, err + } + combinedList = append(combinedList, item) + } + } + return combinedList, nil +} + +// SetNX 实现类似于 Redis 的 SETNX 命令 +func (r *RedisHelper) SetNX(key string, value interface{}, expiration time.Duration) (bool, error) { + result, err := r.client.Set(r.ctx, key, value, expiration).Result() + if err != nil { + return false, err + } + + // 如果键不存在则 result 会等于 "OK" + return result == "OK", nil +} + +func getFieldsFromStruct(obj interface{}) map[string]interface{} { + fields := make(map[string]interface{}) + val := reflect.ValueOf(obj) + typ := reflect.TypeOf(obj) + + for i := 0; i < val.NumField(); i++ { + field := typ.Field(i) + tag := field.Tag.Get("redis") + if tag != "" { + fieldVal := val.Field(i) + if fieldVal.Kind() == reflect.Slice || fieldVal.Kind() == reflect.Map { + // 处理切片或映射类型 + // 对于切片,使用索引作为字段名 + if fieldVal.Kind() == reflect.Slice { + for j := 0; j < fieldVal.Len(); j++ { + elem := fieldVal.Index(j).Interface() + fields[fmt.Sprintf("%s_%d", tag, j)] = elem + } + } else if fieldVal.Kind() == reflect.Map { + // 对于映射,使用键作为字段名 + for _, key := range fieldVal.MapKeys() { + elem := fieldVal.MapIndex(key).Interface() + fields[fmt.Sprintf("%s_%v", tag, key.Interface())] = elem + } + } + } else { + fields[tag] = fieldVal.Interface() + } + } + } + + return fields +} + +func (r *RedisHelper) SetHashWithTags(key string, obj interface{}) error { + fields := getFieldsFromStruct(obj) + _, err := r.client.HSet(r.ctx, key, fields).Result() + return err +} + +// HSetField 设置哈希中的一个字段 +func (r *RedisHelper) HSetField(key, field string, value interface{}) error { + _, err := r.client.HSet(r.ctx, key, field, value).Result() + if err != nil { + log.Printf("Error setting field %s in hash %s: %v", field, key, err) + return err + } + return nil +} + +// HSetMultipleFields 设置哈希中的多个字段 +func (r *RedisHelper) HSetMultipleFields(key string, fields map[string]interface{}) error { + _, err := r.client.HSet(r.ctx, key, fields).Result() + if err != nil { + log.Printf("Error setting multiple fields in hash %s: %v", key, err) + return err + } + return nil +} + +// HGetField 获取哈希中某个字段的值 +func (r *RedisHelper) HGetField(key, field string) (string, error) { + val, err := r.client.HGet(r.ctx, key, field).Result() + if err != nil { + if err == redis.Nil { + return "", nil // Field does not exist + } + log.Printf("Error getting field %s from hash %s: %v", field, key, err) + return "", err + } + return val, nil +} + +// HGetAllFields 获取哈希中所有字段的值 +func (r *RedisHelper) HGetAllFields(key string) (map[string]string, error) { + fields, err := r.client.HGetAll(r.ctx, key).Result() + if err != nil { + log.Printf("Error getting all fields from hash %s: %v", key, err) + return nil, err + } + return fields, nil +} + +// HDelField 删除哈希中的某个字段 +func (r *RedisHelper) HDelField(key, field string) error { + _, err := r.client.HDel(r.ctx, key, field).Result() + if err != nil { + log.Printf("Error deleting field %s from hash %s: %v", field, key, err) + return err + } + return nil +} + +// 删除哈希 +func (r *RedisHelper) HDelAll(key string) error { + _, err := r.client.Del(r.ctx, key).Result() + if err != nil { + log.Printf("Error deleting from hash %s: %v", key, err) + return err + } + return nil +} + +// HKeys 获取哈希中所有字段的名字 +func (r *RedisHelper) HKeys(key string) ([]string, error) { + fields, err := r.client.HKeys(r.ctx, key).Result() + if err != nil { + log.Printf("Error getting keys from hash %s: %v", key, err) + return nil, err + } + return fields, nil +} + +func (r *RedisHelper) HExists(key, field, value string) (bool, error) { + exists, err := r.client.HExists(r.ctx, key, field).Result() + if err != nil { + return false, fmt.Errorf("check existence failed: %v", err) + } + if !exists { + return false, nil + } + + storedValue, err := r.client.HGet(r.ctx, key, field).Result() + if err != nil { + return false, fmt.Errorf("get value failed: %v", err) + } + + // 如果值是 JSON,比较前反序列化 + var storedObj, inputObj interface{} + if err := sonic.UnmarshalString(storedValue, &storedObj); err != nil { + return false, fmt.Errorf("unmarshal stored value failed: %v", err) + } + if err := sonic.UnmarshalString(value, &inputObj); err != nil { + return false, fmt.Errorf("unmarshal input value failed: %v", err) + } + + // 比较两个对象(需要根据实际类型调整) + return fmt.Sprintf("%v", storedObj) == fmt.Sprintf("%v", inputObj), nil +} + +// DelSet 从集合中删除元素 +func (r *RedisHelper) DelSet(key string, value string) error { + _, err := r.client.SRem(r.ctx, key, value).Result() + if err != nil { + log.Printf("Error del value from set %s: %v", key, err) + return err + } + return nil +} + +func (r *RedisHelper) Sismember(key string, value string) (bool, error) { + result, err := r.client.SIsMember(r.ctx, key, value).Result() + if err != nil { + log.Printf("Error Sismember value from set %s: %v", key, err) + } + return result, err +} + +// sort set start +// 批量添加 +func (r *RedisHelper) BatchSortSet(key string, array []*redis.Z) error { + pipe := r.client.Pipeline() + for _, val := range array { + pipe.ZAdd(r.ctx, key, val) + } + + _, err := pipe.Exec(r.ctx) + return err +} + +// 单一写入 sort set +func (e *RedisHelper) SignelAdd(key string, score float64, member string) error { + // 先删除具有相同 score 的所有成员 + scoreStr := strconv.FormatFloat(score, 'g', -1, 64) + _, err := e.client.ZRemRangeByScore(e.ctx, key, scoreStr, scoreStr).Result() + + if err != nil { + fmt.Printf("删除score失败,err:%s", err.Error()) + } + _, err = e.client.ZAdd(e.ctx, key, &redis.Z{ + Score: score, + Member: member, + }).Result() + + if err != nil { + return err + } + + return nil +} + +// 写入数据 +func (e *RedisHelper) AddSortSet(key string, score float64, member string) error { + _, err := e.client.ZAdd(e.ctx, key, &redis.Z{ + Score: score, + Member: member, + }).Result() + + if err != nil { + return err + } + + return nil +} + +// 删除指定元素 +func (e *RedisHelper) DelSortSet(key, member string) error { + return e.client.ZRem(e.ctx, key, member).Err() +} + +// RemoveBeforeScore 移除 Sorted Set 中分数小于等于指定值的数据 +// key: Sorted Set 的键 +// score: 分数上限,所有小于等于此分数的元素将被移除 +// 返回值: 移除的元素数量和可能的错误 +func (e *RedisHelper) RemoveBeforeScore(key string, score float64) (int64, error) { + if key == "" { + return 0, errors.New("key 不能为空") + } + if math.IsNaN(score) || math.IsInf(score, 0) { + return 0, errors.New("score 必须是有效数字") + } + + // 使用 ZRemRangeByScore 移除数据 + count, err := e.client.ZRemRangeByScore(e.ctx, key, "-inf", strconv.FormatFloat(score, 'f', -1, 64)).Result() + if err != nil { + return 0, fmt.Errorf("移除 Sorted Set 数据失败, key: %s, score: %f, err: %v", key, score, err) + } + + return count, nil +} + +// GetNextAfterScore 获取指定分数及之后的第一条数据(包含指定分数) +func (e *RedisHelper) GetNextAfterScore(key string, score float64) (string, error) { + // 使用 ZRangeByScore 获取大于等于 score 的第一条数据 + zs, err := e.client.ZRangeByScoreWithScores(e.ctx, key, &redis.ZRangeBy{ + Min: fmt.Sprintf("%f", score), // 包含指定分数 + Max: "+inf", // 上限为正无穷 + Offset: 0, // 从第 0 条开始 + Count: 1, // 只取 1 条 + }).Result() + + if err != nil { + return "", fmt.Errorf("获取数据失败: %v", err) + } + if len(zs) == 0 { + return "", nil // 没有符合条件的元素 + } + return zs[0].Member.(string), nil +} + +/* +获取sort set 所有数据 +*/ +func (e *RedisHelper) GetAllSortSet(key string) ([]string, error) { + return e.client.ZRange(e.ctx, key, 0, -1).Result() +} + +/* +获取sort set 所有数据和score +*/ +func (e *RedisHelper) GetRevRangeScoresSortSet(key string) ([]redis.Z, error) { + return e.client.ZRevRangeWithScores(e.ctx, key, 0, -1).Result() +} + +// 获取最后一条数据 +func (e *RedisHelper) GetLastSortSet(key string) ([]redis.Z, error) { + // 获取最后一个元素及其分数 + results, err := e.client.ZRevRangeWithScores(e.ctx, key, 0, 0).Result() + if err != nil { + return nil, fmt.Errorf("failed to get last member: %w", err) + } + + // 如果没有数据,返回空 + if len(results) == 0 { + return []redis.Z{}, nil + } + + return results, nil +} + +// 获取指定区间数据 +func (e *RedisHelper) GetSortSetMembers(key string, start, stop int64) ([]string, error) { + return e.client.ZRange(e.ctx, key, start, stop).Result() +} + +// 获取最后N条数据 +func (e *RedisHelper) GetLastSortSetMembers(key string, num int64) ([]string, error) { + return e.client.ZRevRange(e.ctx, key, 0, num).Result() +} + +// func (e *RedisHelper) DelSortSet(key,) + +// 根据索引范围删除 +func (e *RedisHelper) DelByRank(key string, start, stop int64) error { + return e.client.ZRemRangeByRank(e.ctx, key, start, stop).Err() +} + +// sort set end + +// GetUserLoginPwdErrFre 获取用户登录密码错误频次 +func (e *RedisHelper) GetUserLoginPwdErrFre(key string) (total int, wait time.Duration, err error) { + total, _ = e.client.Get(e.ctx, key).Int() + wait = e.client.TTL(e.ctx, key).Val() + return +} + +// SetUserLoginPwdErrFre 设置用户登录密码错误频次 +func (e *RedisHelper) SetUserLoginPwdErrFre(key string, expire time.Duration) (val int64, err error) { + val, err = e.client.Incr(e.ctx, key).Result() + if err != nil { + return + } + if err = e.client.Expire(e.ctx, key, expire).Err(); err != nil { + return + } + return +} + +// SetKeyExpiration 为指定的key设置过期时间 +func (r *RedisHelper) SetKeyExpiration(key string, expiration time.Duration) error { + return r.client.Expire(r.ctx, key, expiration).Err() +} diff --git a/utils/redishelper/redis_lock.go b/utils/redishelper/redis_lock.go new file mode 100644 index 0000000..87840c5 --- /dev/null +++ b/utils/redishelper/redis_lock.go @@ -0,0 +1,195 @@ +package redishelper + +import ( + "context" + "errors" + "fmt" + "go-admin/utils/utility" + "math/rand" + "strconv" + "sync" + "sync/atomic" + "time" + + log "github.com/go-admin-team/go-admin-core/logger" + "github.com/go-redis/redis/v8" +) + +const ( + tolerance = 500 // milliseconds + millisPerSecond = 1000 + lockCommand = `if redis.call("GET", KEYS[1]) == ARGV[1] then + redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2]) + return "OK" +else + return redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) +end` + delCommand = `if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("DEL", KEYS[1]) +else + return 0 +end` + touchCommand = `if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("PEXPIRE", KEYS[1], ARGV[2]) +else + return 0 +end` +) + +var ( + clientRedisLock *redis.Client + onece sync.Once + ErrFailed = errors.New("redsync: failed to acquire lock") +) + +// InitLockRedisConn 初始化 Redis 连接 +func InitLockRedisConn(host, password, dbIndex string) { + onece.Do(func() { + dbIndexInt, err := strconv.Atoi(dbIndex) + if err != nil { + dbIndexInt = 0 + } + clientRedisLock = redis.NewClient(&redis.Options{ + Addr: host, + Password: password, + DB: dbIndexInt, + }) + + // 测试连接 + if _, err := clientRedisLock.Ping(context.Background()).Result(); err != nil { + log.Errorf("Failed to connect to Redis :%v", err) + panic(err) + } + + fmt.Println("redis lock初始化完毕") + }) +} + +// RedisLock 分布式锁结构 +type RedisLock struct { + redisClient *redis.Client + key string + id string + expiry time.Duration + retryCount int // 重试次数 + retryInterval time.Duration // 重试间隔时间 + seconds uint32 +} + +// NewRedisLock 创建一个新的 Redis 锁 +func NewRedisLock(key string, timeout uint32, retryCount int, retryInterval time.Duration) *RedisLock { + return &RedisLock{ + redisClient: clientRedisLock, + key: key, + id: utility.GetXid(), + expiry: time.Duration(timeout) * time.Second, + retryCount: retryCount, + retryInterval: retryInterval, + seconds: timeout, + } +} + +// Acquire 获取锁 +func (rl *RedisLock) Acquire() (bool, error) { + return rl.acquireCtx(context.Background()) +} + +// AcquireWait 获取锁,支持重试和超时 +func (rl *RedisLock) AcquireWait(ctx context.Context) (bool, error) { + if ctx == nil { + ctx = context.Background() + } + + for i := 0; i < rl.retryCount; i++ { + if i > 0 { + // 指数退避 + baseInterval := time.Duration(int64(rl.retryInterval) * (1 << i)) // 指数增长 + if baseInterval > time.Second { + baseInterval = time.Second + } + + if baseInterval <= 0 { + baseInterval = time.Millisecond * 100 // 至少 100ms + } + // 随机退避 + retryInterval := time.Duration(rand.Int63n(int64(baseInterval))) // 随机退避 + if retryInterval < time.Millisecond*100 { + retryInterval = time.Millisecond * 100 // 至少 100ms + } + select { + case <-ctx.Done(): + return false, ctx.Err() + case <-time.After(retryInterval): + } + } + + ok, err := rl.acquireCtx(ctx) + if ok { + return true, nil + } + if err != nil { + log.Errorf("Failed to acquire lock %s:%v", rl.key, err) + } + } + return false, ErrFailed +} + +func safeRandomDuration(max time.Duration) time.Duration { + if max <= 0 { + return 100 * time.Millisecond // fallback default + } + return time.Duration(rand.Int63n(int64(max))) +} + +// Release 释放锁 +func (rl *RedisLock) Release() (bool, error) { + return rl.releaseCtx(context.Background()) +} + +// Touch 续期锁 +func (rl *RedisLock) Touch() (bool, error) { + return rl.touchCtx(context.Background()) +} + +// acquireCtx 获取锁的核心逻辑 +func (rl *RedisLock) acquireCtx(ctx context.Context) (bool, error) { + resp, err := rl.redisClient.Eval(ctx, lockCommand, []string{rl.key}, []string{ + rl.id, strconv.Itoa(int(rl.seconds)*millisPerSecond + tolerance), + }).Result() + if err == redis.Nil { + return false, nil + } else if err != nil { + log.Error("Error acquiring lock key:%s %v", rl.key, err) + return false, err + } + + reply, ok := resp.(string) + return ok && reply == "OK", nil +} + +// releaseCtx 释放锁的核心逻辑 +func (rl *RedisLock) releaseCtx(ctx context.Context) (bool, error) { + resp, err := rl.redisClient.Eval(ctx, delCommand, []string{rl.key}, []string{rl.id}).Result() + if err != nil { + log.Error("Error releasing lock key:%s %v", rl.key, err) + return false, err + } + + reply, ok := resp.(int64) + return ok && reply == 1, nil +} + +// touchCtx 续期锁的核心逻辑 +func (rl *RedisLock) touchCtx(ctx context.Context) (bool, error) { + seconds := atomic.LoadUint32(&rl.seconds) + resp, err := rl.redisClient.Eval(ctx, touchCommand, []string{rl.key}, []string{ + rl.id, strconv.Itoa(int(seconds)*millisPerSecond + tolerance), + }).Result() + if err != nil { + log.Error("Error touching lock key:%s %v", rl.key, err) + return false, err + } + + reply, ok := resp.(int64) + return ok && reply == 1, nil +} diff --git a/utils/utility/id_helper.go b/utils/utility/id_helper.go new file mode 100644 index 0000000..4616231 --- /dev/null +++ b/utils/utility/id_helper.go @@ -0,0 +1,81 @@ +package utility + +import ( + "strings" + + "github.com/rs/xid" + "go.uber.org/zap" + + cryptoRand "crypto/rand" + "fmt" + "math" + "math/big" + "math/rand" + "time" + + log "github.com/go-admin-team/go-admin-core/logger" +) + +const base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + +// GetXid Package xid is a globally unique id generator library +// 包xid是一个全局唯一的id生成器库 +func GetXid() string { + return xid.New().String() +} + +// GetRandIntStr 生成len位的随机数字 +func GetRandIntStr(len int, prefix string) string { + rand.Seed(time.Now().UnixNano()) + + num := rand.Int31n(int32(math.Pow(10, float64(len)))) + x := fmt.Sprintf("%s%0*d", prefix, len, num) + return x +} + +// GenerateRandString 生成指定位数的字符串 +// 虽然繁琐 但理解之后就觉得很精妙 +func GenerateRandString(length int) string { + var chars = []byte(`ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`) // 长度:(1,256) + rand.Seed(time.Now().UnixNano()) + clen := len(chars) + maxRb := 255 - (256 % clen) // [-1,255] 255 - (256%36) = 251 避免模偏倚 为了每个字符被取到的几率相等 + b := make([]byte, length) + r := make([]byte, length+(length/4)) // storage for random bytes. 存储随机字节 + + for i := 0; ; { + // 将随机的byte值填充到byte数组中 以供使用 + if _, err := rand.Read(r); err != nil { + log.Error(`GenerateRandString`, zap.Error(err)) + return `` + } + for _, rb := range r { + c := int(rb) + if c > maxRb { + // Skip this number to avoid modulo bias.跳过这个数字以避免模偏倚 + continue + } + b[i] = chars[c%clen] + i++ + if i == length { // 直到取到合适的长度 + return string(b) + } + } + } +} + +// GenerateBase62Key 生成指定长度的随机 Base62(数字 + 大小写字母)字符串 +func GenerateBase62Key(length int) (string, error) { + var b strings.Builder + b.Grow(length) + + for i := 0; i < length; i++ { + n, err := cryptoRand.Int(cryptoRand.Reader, big.NewInt(int64(len(base62Chars)))) + if err != nil { + return "", err + } + b.WriteByte(base62Chars[n.Int64()]) + } + + return b.String(), nil +} diff --git a/utils/utility/slice.go b/utils/utility/slice.go new file mode 100644 index 0000000..5bee83b --- /dev/null +++ b/utils/utility/slice.go @@ -0,0 +1,29 @@ +package utility + +// SplitSlice 将 []string 切片根据最大数量分割成二维数组 +func SplitSlice[T any](slice []T, maxSize int) [][]T { + var result [][]T + + // 遍历切片,每次取 maxSize 个元素 + for i := 0; i < len(slice); i += maxSize { + end := i + maxSize + // 如果 end 超出切片长度,则取到切片末尾 + if end > len(slice) { + end = len(slice) + } + // 将当前段添加到结果中 + result = append(result, slice[i:end]) + } + + return result +} + +// ContainsInt []int 包含元素? +func ContainsInt(arr []int, v int) bool { + for _, a := range arr { + if a == v { + return true + } + } + return false +} diff --git a/utils/utility/string_helper.go b/utils/utility/string_helper.go new file mode 100644 index 0000000..1fa4d2d --- /dev/null +++ b/utils/utility/string_helper.go @@ -0,0 +1,63 @@ +package utility + +import "strings" + +// DesensitizeGeneric 通用脱敏函数: +// startReserveCount: 从字符串开头保留的字符数 +// endReserveCount: 从字符串末尾保留的字符数 +// asteriskChar: 用于替换的字符 (例如 '*') +// 例如:DesensitizeGeneric("这是一个秘密信息", 2, 2, '*') -> 这**信息 +func DesensitizeGeneric(text string, startReserveCount int, endReserveCount int, asteriskChar rune) string { + if text == "" { + return "" + } + runes := []rune(text) + length := len(runes) + + // 计算实际需要保留的总字符数 + totalReservedLength := startReserveCount + endReserveCount + + // 如果需要保留的字符数大于等于总长度,则不脱敏 + if totalReservedLength >= length { + return text + } + + // 确保保留位数不为负数 + if startReserveCount < 0 { + startReserveCount = 0 + } + if endReserveCount < 0 { + endReserveCount = 0 + } + + // 如果保留总长度为0,且字符串不为空,则全部脱敏 + if totalReservedLength == 0 && length > 0 { + return strings.Repeat(string(asteriskChar), length) + } + + // 确保保留的长度不超过总长度 + if startReserveCount > length { + startReserveCount = length + } + if endReserveCount > length-startReserveCount { + endReserveCount = length - startReserveCount + } + + // 构造脱敏字符串 + var sb strings.Builder + // 写入前缀 + if startReserveCount > 0 { + sb.WriteString(string(runes[0:startReserveCount])) + } + // 写入星号 + asteriskCount := length - startReserveCount - endReserveCount + if asteriskCount > 0 { + sb.WriteString(strings.Repeat(string(asteriskChar), asteriskCount)) + } + // 写入后缀 + if endReserveCount > 0 && length-endReserveCount >= startReserveCount { // 确保后缀不与前缀重叠 + sb.WriteString(string(runes[length-endReserveCount:])) + } + + return sb.String() +}