diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..3729ff0c
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/.docs/README.md b/.docs/README.md
new file mode 100644
index 00000000..c7aaa452
--- /dev/null
+++ b/.docs/README.md
@@ -0,0 +1,2 @@
+BlogCore官方文档仓库地址已经迁移到:
+https://gitee.com/laozhangIsPhi/Blog.Core.E-Book
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..7711e946
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,4 @@
+[*.cs]
+
+# IDE0005: Using 指令是不需要的。
+dotnet_diagnostic.IDE0005.severity = warning
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..7c3b4241
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: http://apk.neters.club/laozhangisphigood.jpg
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..dd84ea78
--- /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 00000000..96dd2c8f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,22 @@
+blank_issues_enabled: false
+contact_links:
+ - name: 🚨 Bug report | Bug 提交
+ url: https://github.com/anjoy8/Blog.Core/issues/new
+ about: |
+ Please report bugs here.
+ 请在此提交 Bug。
+ - name: 🙋 Feature request | 新功能提案
+ url: https://github.com/anjoy8/Blog.Core/issues/new
+ about: |
+ Please request features here.
+ 请在此提交新功能提案。
+ - name: 🤔 Consulting from the Blog.Core team | 咨询 作者
+ url: https://github.com/anjoy8/Blog.Core/issues/new
+ about: |
+ Get technical support, project audits, app deployments, and custom development from the core Blog.Core team.
+ 咨询核心 Blog.Core 团队以获得技术支持,项目审核,应用程序部署以及自定义开发等方面上的帮助。
+ - name: ❗️ All other issues | 其他问题
+ url: https://github.com/anjoy8/Blog.Core/issues/new
+ about: |
+ Please create all other issues here.
+ 请在此创建其他类型问题。
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..bbcbbe7d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..3df0ef21
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,70 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ master ]
+ schedule:
+ - cron: '32 13 * * 2'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp', 'javascript' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ 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@v2
+
+ # ℹ️ 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@v2
diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
new file mode 100644
index 00000000..f11fee1f
--- /dev/null
+++ b/.github/workflows/dotnetcore.yml
@@ -0,0 +1,23 @@
+name: .NET Core
+
+on: [push]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Setup .NET Core
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: 8.0.x
+ - name: Build with dotnet
+ run: dotnet build --configuration Release
+ - name: Build image
+ run: docker build -f "Dockerfile" --force-rm -t laozhangisphi/apkimg .
+ - name: Log into registry
+ run: echo "${{ secrets.ACCESS_TOKEN }}" | docker login -u laozhangisphi --password-stdin
+ - name: Push image
+ run: docker push laozhangisphi/apkimg
diff --git a/.gitignore b/.gitignore
index e53b3602..99804f89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,9 @@ bld/
# Visual Studio 2017 auto generated files
Generated\ Files/
+# Visual Studio Code
+.vscode
+
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
@@ -343,6 +346,17 @@ healthchecksdb
# wwwroot/images
*images/
-Blog.Core/WMBlog.db
.1YourProject
-!Blog.Core.Webapi.Template.1.0.0.nupkg
+.PublishFiles
+!.template.config/*.nupkg
+!Blog.Core.Webapi.Template.*.nupkg
+Blog.Core/WMBlog.db
+.docs/contents/.vuepress/dist/*
+Blog.Core/Blog.Core*.xml
+Blog.Core.Api/WMBlog.db
+Blog.Core.Api/wwwroot/ui/
+Blog.Core.Api/Logs
+*.db
+/Blog.Core.Api/WMBlog.db-journal
+.docs/.vuepress/dist/
+Blog.Core.Api/wwwroot/Temp/Sessions
diff --git a/Blog.Core.Webapi.Template.1.0.0.nupkg b/.template.config/Blog.Core.Webapi.Template.2.5.2.nupkg
similarity index 85%
rename from Blog.Core.Webapi.Template.1.0.0.nupkg
rename to .template.config/Blog.Core.Webapi.Template.2.5.2.nupkg
index 9bff74e6..1e04c646 100644
Binary files a/Blog.Core.Webapi.Template.1.0.0.nupkg and b/.template.config/Blog.Core.Webapi.Template.2.5.2.nupkg differ
diff --git a/Blog.Core.Api/.config/dotnet-tools.json b/Blog.Core.Api/.config/dotnet-tools.json
new file mode 100644
index 00000000..98091c92
--- /dev/null
+++ b/Blog.Core.Api/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "6.0.8",
+ "commands": [
+ "dotnet-ef"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Blog.Core.Api.csproj b/Blog.Core.Api/Blog.Core.Api.csproj
new file mode 100644
index 00000000..8bc327ab
--- /dev/null
+++ b/Blog.Core.Api/Blog.Core.Api.csproj
@@ -0,0 +1,122 @@
+
+
+
+ Exe
+ enable
+
+ Linux
+ true
+ default
+
+
+
+ ..\Blog.Core.Api\Blog.Core.xml
+ 1701;1702;1591
+
+
+
+ ..\Blog.Core\Blog.Core.xml
+ 1701;1702;1591
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ PreserveNewest
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Blog.Core.Api/Blog.Core.Model.xml b/Blog.Core.Api/Blog.Core.Model.xml
new file mode 100644
index 00000000..00b4c5be
--- /dev/null
+++ b/Blog.Core.Api/Blog.Core.Model.xml
@@ -0,0 +1,3407 @@
+
+
+
+ Blog.Core.Model
+
+
+
+
+ 无任何权限
+
+
+
+
+ 自定义权限
+
+
+
+
+ 本部门
+
+
+
+
+ 本部门及以下
+
+
+
+
+ 仅自己
+
+
+
+
+ 所有
+
+
+
+
+ 以下model 来自ids4项目,多库模式,为了调取ids4数据
+ 角色表
+
+
+
+
+ 排序
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 以下model 来自ids4项目,多库模式,为了调取ids4数据
+ 用户表
+
+
+
+
+ 这是爱
+
+
+
+
+ id
+
+
+
+
+ 姓名
+
+
+
+
+ 年龄
+
+
+
+
+ 通用返回信息类
+
+
+
+
+ 状态码
+
+
+
+
+ 操作是否成功
+
+
+
+
+ 返回信息
+
+
+
+
+ 开发者信息
+
+
+
+
+ 返回数据集合
+
+
+
+
+ 返回成功
+
+ 消息
+
+
+
+
+ 返回成功
+
+ 消息
+ 数据
+
+
+
+
+ 返回失败
+
+ 消息
+
+
+
+
+ 返回失败
+
+ 消息
+ 数据
+
+
+
+
+ 返回消息
+
+ 失败/成功
+ 消息
+ 数据
+
+
+
+
+ 状态码
+
+
+
+
+ 操作是否成功
+
+
+
+
+ 返回信息
+
+
+
+
+ 返回数据集合
+
+
+
+
+ 用户访问趋势日志
+
+
+
+
+ 用户
+
+
+
+
+ 次数
+
+
+
+
+ 更新时间
+
+
+
+
+ 广告图片
+
+
+
+
+ 广告标题
+
+
+
+
+ 广告链接
+
+
+
+
+ 备注
+
+
+
+
+ 创建时间
+
+
+
+
+ 博客文章
+
+
+
+
+ 主键
+
+ 这里之所以没用RootEntity,是想保持和之前的数据库一致,主键是bID,不是Id
+
+
+
+ 创建人
+
+
+
+
+ 标题blog
+
+
+
+
+ 类别
+
+
+
+
+ 内容
+
+
+
+
+ 访问量
+
+
+
+
+ 评论数量
+
+
+
+
+ 修改时间
+
+
+
+
+ 创建时间
+
+
+
+
+ 备注
+
+
+
+
+ 逻辑删除
+
+
+
+
+ 评论
+
+
+
+
+ 博客文章 评论
+
+
+
+
+ 部门表
+
+
+
+
+ Desc:部门关系编码
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:部门名称
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:负责人
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:排序
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:部门状态(0正常 1停用)
+ Default:0
+ Nullable:True
+
+
+
+
+ Desc:删除标志(0代表存在 2代表删除)
+ Default:0
+ Nullable:True
+
+
+
+
+ Desc:创建者
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:创建时间
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:更新者
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:更新时间
+ Default:
+ Nullable:True
+
+
+
+
+ 用户团队表
+
+
+
+
+ ID
+
+
+
+
+ HttpContext.TraceIdentifier 事件链路ID(获取或设置一个唯一标识符,用于在跟踪日志中表示此请求。)
+
+
+
+
+ 时间
+
+
+
+
+ 线程
+
+
+
+
+ 等级
+
+
+
+
+ 记录器
+
+
+
+
+ 日志类型
+
+
+
+
+ 数据类型
+
+
+
+
+ 错误信息
+
+
+
+
+ 异常
+
+
+
+ 博客ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 手机
+
+
+
+
+ qq
+
+
+
+
+ 留言内容
+
+
+
+
+ ip地址
+
+
+
+
+ 是否显示在前台,0否1是
+
+
+
+
+
+ 接口API地址信息表
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 名称
+
+
+
+
+ 菜单链接地址
+
+
+
+
+ 区域名称
+
+
+
+
+ 控制器名称
+
+
+
+
+ Action名称
+
+
+
+
+ 图标
+
+
+
+
+ 菜单编号
+
+
+
+
+ 排序
+
+
+
+
+ /描述
+
+
+
+
+ 是否是右侧菜单
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 日志记录
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 区域名
+
+
+
+
+ 区域控制器名
+
+
+
+
+ Action名称
+
+
+
+
+ IP地址
+
+
+
+
+ 描述
+
+
+
+
+ 登录时间
+
+
+
+
+ 登录名称
+
+
+
+
+ 用户ID
+
+
+
+
+ 密码库表
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 路由菜单表
+
+
+
+
+ 菜单执行Action名
+
+
+
+
+ 菜单显示名(如用户页、编辑(按钮)、删除(按钮))
+
+
+
+
+ 是否是按钮
+
+
+
+
+ 是否是隐藏菜单
+
+
+
+
+ 是否keepAlive
+
+
+
+
+ 按钮事件
+
+
+
+
+ 排序
+
+
+
+
+ 菜单图标
+
+
+
+
+ 菜单图标新
+
+
+
+
+ 菜单描述
+
+
+
+
+ 激活状态
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 角色表
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 角色名
+
+
+
+
+ 描述
+
+
+
+
+ 排序
+
+
+
+
+ 自定义权限的部门ids
+
+
+
+
+ 权限范围
+ -1 无任何权限;1 自定义权限;2 本部门;3 本部门及以下;4 仅自己;9 全部;
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 按钮跟权限关联表
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 状态
+ 中立字段,某些表可使用某些表不使用
+
+
+
+
+ 中立字段,某些表可使用某些表不使用
+ 逻辑上的删除,非物理删除
+ 例如:单据删除并非直接删除
+
+
+
+
+ 中立字段
+ 是否内置数据
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 更新者
+
+
+
+
+ 修改日期
+
+
+
+
+ 数据版本
+
+
+
+
+ 软删除 过滤器
+
+
+
+
+ 系统租户表
+ 根据TenantType 分为两种方案:
+ 1.按租户字段区分
+ 2.按租户分库
+
+
+
+ 注意:
+ 使用租户Id方案,无需配置分库的连接
+
+
+
+
+ 名称
+
+
+
+
+ 租户类型
+
+
+
+
+ 数据库/租户标识 不可重复
+ 使用Id方案,可无需配置
+
+
+
+
+ 主机
+ 使用Id方案,可无需配置
+
+
+
+
+ 数据库类型
+ 使用Id方案,可无需配置
+
+
+
+
+ 数据库连接
+ 使用Id方案,可无需配置
+
+
+
+
+ 状态
+
+
+
+
+ 备注
+
+
+
+
+ 用户信息表
+
+
+
+
+ 登录账号
+
+
+
+
+ 登录密码
+
+
+
+
+ 真实姓名
+
+
+
+
+ 状态
+
+
+
+
+ 部门
+
+
+
+
+ 备注
+
+
+
+
+ 创建时间
+
+
+
+
+ 更新时间
+
+
+
+
+ 关键业务修改时间
+
+
+
+
+ 最后异常时间
+
+
+
+
+ 错误次数
+
+
+
+
+ 登录账号
+
+
+
+
+ 租户Id
+
+
+
+
+ 任务日志表
+
+
+
+
+ 任务ID
+
+
+
+
+ 任务耗时
+
+
+
+
+ 执行结果(0-失败 1-成功)
+
+
+
+
+ 运行时间
+
+
+
+
+ 结束时间
+
+
+
+
+ 执行参数
+
+
+
+
+ 异常信息
+
+
+
+
+ 异常堆栈
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 任务名称
+
+
+
+
+ 任务分组
+
+
+
+
+ 任务计划表
+
+
+
+
+ 任务名称
+
+
+
+
+ 任务分组
+
+
+
+
+ 任务运行时间表达式
+
+
+
+
+ 任务所在DLL对应的程序集名称
+
+
+
+
+ 任务所在类
+
+
+
+
+ 任务描述
+
+
+
+
+ 执行次数
+
+
+
+
+ 开始时间
+
+
+
+
+ 结束时间
+
+
+
+
+ 触发器类型(0、simple 1、cron)
+
+
+
+
+ 执行间隔时间, 秒为单位
+
+
+
+
+ 循环执行次数
+
+
+
+
+ 已循环次数
+
+
+
+
+ 是否启动
+
+
+
+
+ 执行传参
+
+
+
+
+ 创建时间
+
+
+
+
+ 任务内存中的状态
+
+
+
+
+ 业务数据
+ 多租户 (Id 隔离)
+
+
+
+
+ 无需手动赋值
+
+
+
+
+ 名称
+
+
+
+
+ 金额
+
+
+
+
+ 多租户-多表方案 业务表 子表
+
+
+
+
+ 多租户-多表方案 业务表
+
+
+
+
+ 名称
+
+
+
+
+ 金额
+
+
+
+
+ 多租户-多库方案 业务表
+ 公共库无需标记[MultiTenant]特性
+
+
+
+
+ 名称
+
+
+
+
+ 金额
+
+
+
+
+ Tibug 类别
+
+
+
+
+ Tibug 博文
+
+
+
+
+ 用户跟角色关联表
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 公司ID
+
+
+
+
+ 公司名称
+
+
+
+
+ 公司IP
+
+
+
+
+ 公司备注
+
+
+
+
+ api地址
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 微信公众号唯一标识
+
+
+
+
+ 微信公众号名称
+
+
+
+
+ 微信账号
+
+
+
+
+ 微信名称
+
+
+
+
+ 应用ID
+
+
+
+
+ 应用秘钥
+
+
+
+
+ 公众号推送token
+
+
+
+
+ 验证秘钥(验证消息是否真实)
+
+
+
+
+ 微信公众号token过期时间
+
+
+
+
+ 备注
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 推送ID
+
+
+
+
+ 来自谁
+
+
+
+
+ 推送IP
+
+
+
+
+ 推送客户
+
+
+
+
+ 推送用户
+
+
+
+
+ 推送模板ID
+
+
+
+
+ 推送内容
+
+
+
+
+ 推送时间
+
+
+
+
+ 推送状态(Y/N)
+
+
+
+
+ 备注
+
+
+
+
+ 推送OpenID
+
+
+
+
+ 推送微信公众号
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 主键id,ticket
+
+
+
+
+ 需要绑定的公司
+
+
+
+
+ 需要绑定的员工id
+
+
+
+
+ 需要绑定的员工昵称
+
+
+
+
+ 创建时间
+
+
+
+
+ 关联的公众号
+
+
+
+
+ 是否已使用
+
+
+
+
+ 使用时间
+
+
+
+
+ 关联的微信用户id
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 来自哪个公众号
+
+
+
+
+ 绑定公司id
+
+
+
+
+ 绑定员工id
+
+
+
+
+ 绑定微信id
+
+
+
+
+ 绑定微信联合id
+
+
+
+
+ 绑定时间
+
+
+
+
+ 更新时间
+
+
+
+
+ 备注
+
+
+
+
+ 是否已解绑
+
+
+
+
+ 上次绑定微信id
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 文件ID
+
+
+
+
+ 文件名称
+
+
+
+
+ 文件大小
+
+
+
+
+ 文件类型
+
+
+
+
+ 文件拓展名
+
+
+
+
+ 文件位置
+
+
+
+
+ 文件上传时间
+
+
+
+
+ 文件备注
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+ 部门表
+
+
+
+
+ 上一级(0表示无上一级)
+
+
+
+
+ 接口API地址信息表
+ 父类
+
+
+
+
+ 父ID
+
+
+
+
+ 路由菜单表
+
+
+
+
+ 上一级菜单(0表示上一级无菜单)
+
+
+
+
+ 接口api
+
+
+
+
+ 按钮跟权限关联表
+ 父类
+
+
+
+
+ 角色ID
+
+
+
+
+ 菜单ID
+
+
+
+
+ api ID
+
+
+
+
+ ID
+ 泛型主键Tkey
+
+
+
+
+ 用户信息表
+
+
+
+
+ Id
+ 泛型主键Tkey
+
+
+
+
+ Tibug 博文
+
+
+
+
+ 用户跟角色关联表
+ 父类
+
+
+
+
+ 用户ID
+
+
+
+
+ 角色ID
+
+
+
+
+ 通用分页信息类
+
+
+
+
+ 当前页标
+
+
+
+
+ 总页数
+
+
+
+
+ 数据总数
+
+
+
+
+ 每页大小
+
+
+
+
+ 返回数据
+
+
+
+
+ 所需分页参数
+ 作者:胡丁文
+ 时间:2020-4-3 20:31:26
+
+
+
+
+ 当前页
+
+
+
+
+ 每页大小
+
+
+
+
+ 排序字段(例如:id desc,time asc)
+
+
+
+
+ 查询条件( 例如:id = 1 and name = 小明)
+
+
+
+
+ 无权限
+
+
+
+
+ 找不到指定资源
+
+
+
+
+ 找不到指定资源
+
+
+
+
+ 数据库读取类型
+
+
+
+
+ 表格数据,支持分页
+
+
+
+
+ 返回编码
+
+
+
+
+ 返回信息
+
+
+
+
+ 记录总数
+
+
+
+
+ 返回数据集
+
+
+
+
+ 租户模型接口
+
+
+
+
+ 租户Id
+
+
+
+
+ 标识 多租户 的业务表
+ 默认设置是多库
+ 公共表无需区分 直接使用主库 各自业务在各自库中
+
+
+
+
+ 租户隔离方案
+
+
+
+
+ Id隔离
+
+
+
+
+ 库隔离
+
+
+
+
+ 表隔离
+
+
+
+
+ 广告类
+
+
+
+
+ 分类ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 广告图片
+
+
+
+
+ 广告标题
+
+
+
+
+ 广告链接
+
+
+
+
+ 备注
+
+
+
+
+ 博客信息展示类
+
+
+
+
+
+
+
+
+ 创建人
+
+
+
+
+ 博客标题
+
+
+
+
+ 摘要
+
+
+
+
+
+ 上一篇
+
+
+
+
+ 上一篇id
+
+
+
+
+ 下一篇
+
+
+
+
+ 下一篇id
+
+
+
+ 类别
+
+
+
+
+ 内容
+
+
+
+
+
+ 访问量
+
+
+
+
+ 评论数量
+
+
+
+ 修改时间
+
+
+
+
+
+ 创建时间
+
+
+
+ 备注
+
+
+
+
+
+ Type Description balabala
+
+
+
+
+ 留言信息展示类
+
+
+
+ 留言表
+
+
+
+
+ 博客ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 手机
+
+
+
+
+ qq
+
+
+
+
+ 留言内容
+
+
+
+
+ ip地址
+
+
+
+
+ 是否显示在前台,0否1是
+
+
+
+
+
+ 商户号
+
+
+
+
+ 柜台号
+
+
+
+
+ 分行号
+
+
+
+
+ 集团商户信息
+
+
+
+
+ 交易码
+
+
+
+
+ 商户类型
+
+
+
+
+ 终端编号 1
+
+
+
+
+ 终端编号 2
+
+
+
+
+ 订单号
+
+
+
+
+ 码信息(一维码、二维码)
+
+
+
+
+ 订单金额,单位:元
+
+
+
+
+ 商品名称
+
+
+
+
+ 备注 1
+
+
+
+
+ 备注 2
+
+
+
+
+ 分账信息一
+
+
+
+
+ 分账信息二
+
+
+
+
+ 子商户公众账号 ID
+
+
+
+
+ 返回信息位图
+
+
+
+
+ 实名支付
+
+
+
+
+ 商品详情
+
+
+
+
+ 订单优惠标记
+
+
+
+
+ 公钥
+
+
+
+
+ 请求地址
+
+
+
+
+ 是否删除空值
+
+
+
+
+ 退款参数
+
+
+
+
+ 订单ID
+
+
+
+
+ 商品名称
+
+
+
+
+ 支付金额(小数点最多两位)
+
+
+
+
+ 二维码/条码信息
+
+
+
+
+ 备注信息1
+
+
+
+
+ 备注信息2
+
+
+
+
+ 订单参数
+
+
+
+
+ 订单号
+
+
+
+
+ 退款金额
+
+
+
+
+ 退款流水号(可选)
+
+
+
+
+ 退款返回消息
+
+
+
+
+ 序列号
+
+
+
+
+ 商户号
+
+
+
+
+ 交易码
+
+
+
+
+ 返回码
+
+
+
+
+ 返回码说明
+
+
+
+
+ 语言
+
+
+
+
+ 订单信息
+
+
+
+
+ 订单信息
+
+
+
+
+ 订单号
+
+
+
+
+ 支付金额
+
+
+
+
+ 退款金额
+
+
+
+
+ 备注1
+
+
+
+
+ 备注2
+
+
+
+
+ 退款返回结果消息
+
+
+
+
+ 订单号
+
+
+
+
+ 支付金额
+
+
+
+
+ 退款金额
+
+
+
+
+ 序列号
+
+
+
+
+ 商户号
+
+
+
+
+ 交易码
+
+
+
+
+ 返回码
+
+
+
+
+ 返回码说明
+
+
+
+
+ 语言
+
+
+
+
+ 支付结果dto
+
+
+
+
+ 支付结果
+ Y:成功
+ N:失败
+ U:不确定
+ Q:待轮询
+
+
+
+
+ 订单ID
+
+
+
+
+ 支付金额
+
+
+
+
+ 二维码类型
+ 1:龙支付
+ 2:微信
+ 3:支付宝
+ 4:银联
+
+
+
+
+ 等待时间-轮询等待时间
+
+
+
+
+ 全局事件跟踪号-建行交易流水号
+
+
+
+
+ 错误码
+
+
+
+
+ 错误信息
+
+
+
+
+ 验证签名-防止伪造攻击
+
+
+
+
+ 返回支付结果
+
+
+
+
+ 发起的订单ID
+
+
+
+
+ 返回支付的金额
+
+
+
+
+ 返回支付的类型 1:龙支付 2:微信 3:支付宝 4:银联
+
+
+
+
+ 返回建行的流水号
+
+
+
+
+ 错误代码
+
+
+
+
+ 错误信息
+
+
+
+
+ 实现IJob的类
+
+
+
+
+ 命名空间
+
+
+
+
+ 类名
+
+
+
+
+ 备注
+
+
+
+
+ 服务器VM
+
+
+
+
+ 环境变量
+
+
+
+
+ 系统架构
+
+
+
+
+ ContentRootPath
+
+
+
+
+ WebRootPath
+
+
+
+
+ .NET Core版本
+
+
+
+
+ 内存占用
+
+
+
+
+ 启动时间
+
+
+
+
+ 菜单展示model
+
+
+
+
+ 调度任务触发器信息实体
+
+
+
+
+ 任务ID
+
+
+
+
+ 任务名称
+
+
+
+
+ 任务分组
+
+
+
+
+ 触发器ID
+
+
+
+
+ 触发器名称
+
+
+
+
+ 触发器分组
+
+
+
+
+ 触发器状态
+
+
+
+
+ 用来测试 RestSharp Get 请求
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 用来测试 RestSharp Post 请求
+
+
+
+
+ 留言排名展示类
+
+
+
+ 博客ID
+
+
+
+
+
+ 评论数量
+
+
+
+ 博客标题
+
+
+
+
+
+ 微信接口消息DTO
+ 作者:胡丁文
+ 时间:2020-03-25
+
+
+
+
+ 微信公众号ID(数据库查询)
+
+
+
+
+ 错误代码
+
+
+
+
+ 错误信息
+
+
+
+
+ token
+
+
+
+
+ 过期时间(秒)
+
+
+
+
+ 用户关注数
+
+
+
+
+ 获取用户数量
+
+
+
+
+ 获取用户OpenIDs
+
+
+
+
+ 下一个关注用户
+
+
+
+
+ 微信消息模板列表
+
+
+
+
+ 微信菜单
+
+
+
+
+ 二维码票据
+
+
+
+
+ 二维码过期时间
+
+
+
+
+ 二维码地址
+
+
+
+
+ 关注状态
+
+
+
+
+ 用户微信ID
+
+
+
+
+ 昵称
+
+
+
+
+ 性别
+
+
+
+
+ 语言
+
+
+
+
+ 城市
+
+
+
+
+ 省份
+
+
+
+
+ 城市
+
+
+
+
+ 头像地址
+
+
+
+
+ 微信推送消息Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
+
+
+
+
+ 推送关键信息
+
+
+
+
+ 推送卡片消息Dto
+
+
+
+
+ 微信推送消息Dto
+ 作者:胡丁文
+ 时间:2020-11-23 16:29:05
+
+
+
+
+ 推送关键信息
+
+
+
+
+ 推送卡片消息Dto
+
+
+
+
+ 消息模板dto(如何填写数据,请参考微信模板即可)
+ 作者:胡丁文
+ 时间:2020-4-1 09:32:16
+
+
+
+
+ 消息模板
+
+
+
+
+ 标题
+
+
+
+
+ 标题颜色(颜色代码都必须为#开头的16进制代码)
+
+
+
+
+ 内容1
+
+
+
+
+ 内容1颜色
+
+
+
+
+ 内容2
+
+
+
+
+ 内容2颜色
+
+
+
+
+ 内容3
+
+
+
+
+ 内容3颜色
+
+
+
+
+ 内容4
+
+
+
+
+ 内容4颜色
+
+
+
+
+ 内容5
+
+
+
+
+ 内容5颜色
+
+
+
+
+ 备注信息
+
+
+
+
+ 备注信息颜色
+
+
+
+
+ 跳转连接
+
+
+
+
+ 获取微信菜单DTO,用于存放具体菜单内容
+
+
+
+
+ 获取微信菜单DTO
+
+
+
+
+ 按钮列表(最多三个)
+
+
+
+
+ 微信OpenID列表Dto
+
+
+
+
+ 推送详细数据
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
+
+
+
+
+ 推送给微信所需Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
+
+
+
+
+ 推送微信用户ID
+
+
+
+
+ 推送的模板ID
+
+
+
+
+ 推送URL地址
+
+
+
+
+ 推送的数据
+
+
+
+
+ 微信keyword所需Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:18:08
+
+
+
+
+ 内容
+
+
+
+
+ 文字颜色
+
+
+
+
+ 图文链接标题
+
+
+
+
+ 图文描述
+
+
+
+
+ 访问URL
+
+
+
+
+ 图片URL
+
+
+
+
+ 图片mediaID
+
+
+
+
+ 推送模拟消息Dto
+ 作者:胡丁文
+ 时间:2020-4-24 14:52:44
+
+
+
+
+ 当前选中的微信公众号
+
+
+
+
+ 当前选中的操作集合
+
+
+
+
+ 当前选中的绑定还是订阅
+
+
+
+
+ 当前选中的微信客户
+
+
+
+
+ 当前选中的消息类型
+
+
+
+
+ 当前选中要发送的用户
+
+
+
+
+ 文本消息
+
+
+
+
+ 图片消息
+
+
+
+
+ 语音消息
+
+
+
+
+ 视频消息
+
+
+
+
+ 链接消息
+
+
+
+
+ 文字消息
+
+
+
+
+ 视频标题
+
+
+
+
+ 视频封面mediaID
+
+
+
+
+ 视频mediaID
+
+
+
+
+ 语音mediaID
+
+
+
+
+ 微信二维码预装发送信息dto
+
+
+
+
+ 微信二维码预装具体消息
+
+
+
+
+ 微信二维码预装信息DTO
+
+
+
+
+ 返回给调用者的Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:52:06
+
+
+
+
+ 微信公众号ID
+
+
+
+
+ 公司代码
+
+
+
+
+ 数据
+
+
+
+
+ 微信消息模板Dto
+
+
+
+
+ 微信推送所需信息(公司版本)
+ 作者:胡丁文
+ 时间:2020-4-8 09:04:36
+
+
+
+
+ 微信公众号ID
+
+
+
+
+ 公司代码
+
+
+
+
+ 用户id
+
+
+
+
+ 用户昵称
+
+
+
+
+ 微信推送所需信息(OpenID版本)
+ 作者:胡丁文
+ 时间:2020-11-23 16:27:29
+
+
+
+
+ 微信公众号ID
+
+
+
+
+ 微信OpenID
+
+
+
+
+ 微信验证Dto
+ 作者:胡丁文
+ 时间:2020-4-1 21:34:07
+
+
+
+
+ 微信公众号唯一标识
+
+
+
+
+ 验证成功后返回给微信的字符串
+
+
+
+
+ 签名
+
+
+
+
+ 时间戳
+
+
+
+
+ 随机数
+
+
+
+
+ 微信XmlDto
+ 作者:胡丁文
+ 时间:2020-4-3 20:31:26
+
+
+
+
+ 微信公众号唯一表示
+
+
+
+
+ 微信开发者
+
+
+
+
+ 来自谁
+
+
+
+
+ 创建时间
+
+
+
+
+ 消息类型
+
+
+
+
+ 文字内容
+
+
+
+
+ 消息ID
+
+
+
+
+ 消息事件
+
+
+
+
+ 事件key值
+
+
+
+
+ 图片地址
+
+
+
+
+ 多媒体ID
+
+
+
+
+ 格式
+
+
+
+
+ 语音失败
+
+
+
+
+ 缩略媒体ID
+
+
+
+
+ 地理位置维度
+
+
+
+
+ 地理位置经度
+
+
+
+
+ 地图缩放大小
+
+
+
+
+ 地理位置信息
+
+
+
+
+ 消息标题
+
+
+
+
+ 消息描述
+
+
+
+
+ 消息链接
+
+
+
+
+ 二维码的ticket,可用来换取二维码图片
+
+
+
+
+ 地理位置纬度
+
+
+
+
+ 地理位置经度
+
+
+
+
+ 地理位置精度
+
+
+
+
diff --git a/Blog.Core.Api/Blog.Core.xml b/Blog.Core.Api/Blog.Core.xml
new file mode 100644
index 00000000..0ed61c91
--- /dev/null
+++ b/Blog.Core.Api/Blog.Core.xml
@@ -0,0 +1,1662 @@
+
+
+
+ Blog.Core.Api
+
+
+
+
+ 博客管理
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+ 获取博客列表【无权限】
+
+
+
+
+
+
+
+
+
+ 获取博客详情
+
+
+
+
+
+
+ 获取详情【无权限】
+
+
+
+
+
+
+ 获取博客测试信息 v2版本
+
+
+
+
+
+ 添加博客【无权限】
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 更新博客信息
+
+
+
+
+
+
+ 删除博客
+
+
+
+
+
+
+ apache jemeter 压力测试
+ 更新接口
+
+
+
+
+
+ 构造函数
+
+
+
+
+ 获取 整体框架 文件(主库)(一般可用第一次生成)
+
+
+
+
+
+ 获取仓储层和服务层(需指定表名和数据库)
+
+ 数据库链接名称
+ 需要生成的表名
+
+
+
+
+ 获取实体(需指定表名和数据库)
+
+ 数据库链接名称
+ 需要生成的表名
+
+
+
+
+ 获取控制器(需指定表名和数据库)
+
+ 数据库链接名称
+ 需要生成的表名
+
+
+
+
+ DbFrist 根据数据库表名 生成整体框架,包含Model层(一般可用第一次生成)
+
+ 数据库链接名称
+ 需要生成的表名
+
+
+
+
+ 获取权限部分Map数据(从库)
+ 迁移到新库(主库)
+
+
+
+
+
+ 权限数据库导出tsv
+
+
+
+
+
+ 权限数据库导出excel
+
+
+
+
+
+ 健康检查
+
+
+
+
+ 健康检查接口
+
+
+
+
+
+ 图片管理
+
+
+
+
+ 下载图片(支持中文字符)
+
+
+
+
+
+ 上传图片,多文件
+
+
+
+
+
+
+ 登录管理【无权限】
+
+
+
+
+ 构造函数注入
+
+
+
+
+
+
+
+
+
+
+ 获取JWT的方法1
+
+
+
+
+
+
+
+ 获取JWT的方法2:给Nuxt提供
+
+
+
+
+
+
+
+ 获取JWT的方法3:整个系统主要方法
+
+
+
+
+
+
+
+ 请求刷新Token(以旧换新)
+
+
+
+
+
+
+ 获取JWT的方法4:给 JSONP 测试
+
+
+
+
+
+
+
+
+
+
+ 测试 MD5 加密字符串
+
+
+
+
+
+
+ swagger登录
+
+
+
+
+
+
+ weixin登录
+
+
+
+
+
+ 接口管理
+
+
+
+
+ 获取全部接口api
+
+
+
+
+
+
+
+ 添加一条接口信息
+
+
+
+
+
+
+ 更新接口信息
+
+
+
+
+
+
+ 删除一条接口
+
+
+
+
+
+
+ 导入多条接口信息
+
+
+
+
+
+
+ 服务器配置信息
+
+
+
+
+
+ SignalR send data
+
+
+
+
+
+ 建行聚合支付类
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+ 被扫支付
+
+
+
+
+
+
+ 被扫支付
+
+
+
+
+
+
+ 支付结果查询-轮询
+
+
+
+
+
+
+ 支付结果查询-轮询
+
+
+
+
+
+
+ 退款
+
+
+
+
+
+
+ 退款
+
+
+
+
+
+
+ 菜单管理
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 获取菜单
+
+
+
+
+
+
+
+
+ 查询树形 Table
+
+ 父节点
+ 关键字
+
+
+
+
+ 添加一个菜单
+
+
+
+
+
+
+ 保存菜单权限分配
+
+
+
+
+
+
+ 获取菜单树
+
+
+
+
+
+
+
+ 获取路由树
+
+
+
+
+
+
+ 获取路由树
+
+
+
+
+
+
+ 通过角色获取菜单
+
+
+
+
+
+
+ 更新菜单
+
+
+
+
+
+
+ 删除菜单
+
+
+
+
+
+
+ 导入多条菜单信息
+
+
+
+
+
+
+ 系统接口菜单同步接口
+
+
+
+
+
+ 角色管理
+
+
+
+
+ 获取全部角色
+
+
+
+
+
+
+
+ 添加角色
+
+
+
+
+
+
+ 更新角色
+
+
+
+
+
+
+ 删除角色
+
+
+
+
+
+
+ 分页获取
+
+
+
+
+
+
+
+ 添加计划任务
+
+
+
+
+
+
+ 修改计划任务
+
+
+
+
+
+
+ 删除一个任务
+
+
+
+
+
+
+ 启动计划任务
+
+
+
+
+
+
+ 停止一个计划任务
+
+
+
+
+
+
+ 暂停一个计划任务
+
+
+
+
+
+
+ 恢复一个计划任务
+
+
+
+
+
+
+ 重启一个计划任务
+
+
+
+
+
+
+ 获取任务命名空间
+
+
+
+
+
+ 立即执行任务
+
+
+
+
+
+
+ 获取任务运行日志
+
+
+
+
+
+ 任务概况
+
+
+
+
+
+ 类别管理【无权限】
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取Tibug所有分类
+
+
+
+
+
+ Tibug 管理
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+ 获取Bug数据列表(带分页)
+ 【无权限】
+
+ 页数
+ 专题类型
+ 关键字
+
+
+
+
+
+ 获取详情【无权限】
+
+
+
+
+
+
+ 添加一个 BUG 【无权限】
+
+
+
+
+
+
+ 更新 bug
+
+
+
+
+
+
+ 删除 bug
+
+
+
+
+
+
+ 测试事务在AOP中的使用
+
+
+
+
+
+
+ 用户管理
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+
+
+
+
+
+
+ 获取全部用户
+
+
+
+
+
+
+
+ 获取用户详情根据token
+ 【无权限】
+
+ 令牌
+
+
+
+
+ 添加一个用户
+
+
+
+
+
+
+ 更新用户与角色
+
+
+
+
+
+
+ 删除用户
+
+
+
+
+
+
+ 用户角色关系
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+
+
+ 新建用户
+
+
+
+
+
+
+
+ 新建Role
+
+
+
+
+
+
+ 新建用户角色关系
+
+
+
+
+
+
+
+ Values控制器
+
+
+
+
+ 测试Rabbit消息队列发送
+
+
+
+
+ 测试Rabbit消息队列订阅
+
+
+
+
+ 测试SqlSugar二级缓存
+ 可设置过期时间
+ 或通过接口方式更新该数据,也会离开清除缓存
+
+
+
+
+
+ Get方法
+
+
+
+
+
+ 测试Redis消息队列
+
+
+
+
+
+
+ 测试RabbitMQ事件总线
+
+
+
+
+
+
+
+ Get(int id)方法
+
+
+
+
+
+
+ 测试参数是必填项
+
+
+
+
+
+
+ 通过 HttpContext 获取用户信息
+
+ 声明类型,默认 jti
+
+
+
+
+ to redirect by route template name.
+
+
+
+
+ route with template name.
+
+
+
+
+
+ 测试 post 一个对象 + 独立参数
+
+ model实体类参数
+ 独立参数
+
+
+
+ 测试 post 参数
+
+
+
+
+
+
+ 测试多库连接
+
+
+
+
+
+ 测试Fulent做参数校验
+
+
+
+
+
+
+ Put方法
+
+
+
+
+
+
+ Delete方法
+
+
+
+
+
+ 测试接入Apollo获取配置信息
+
+
+
+
+ 通过此处的key格式为 xx:xx:x
+
+
+
+
+ 获取雪花Id
+
+
+
+
+
+ 测试缓存
+
+
+
+
+
+ 雪花Id To DateTime
+
+
+
+
+
+
+ WeChatCompanyController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ WeChatConfigController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ 微信公众号管理
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+ 更新Token
+
+
+
+
+
+
+ 刷新Token
+
+
+
+
+
+
+ 获取模板
+
+
+
+
+
+
+ 获取菜单
+
+
+
+
+
+
+ 更新菜单
+
+
+
+
+
+
+ 获取订阅用户(所有)
+
+
+
+
+
+
+ 入口
+
+
+
+
+
+
+ 获取订阅用户
+
+
+
+
+
+
+
+ 获取一个绑定员工公众号二维码
+
+ 消息
+
+
+
+
+ 推送卡片消息接口
+
+ 卡片消息对象
+
+
+
+
+ 推送卡片消息接口
+
+ 卡片消息对象
+
+
+
+
+ 推送文本消息
+
+ 消息对象
+
+
+
+
+ 通过绑定用户获取微信用户信息(一般用于初次绑定检测)
+
+ 信息
+
+
+
+
+ 用户解绑
+
+ 消息
+
+
+
+
+ WeChatPushLogController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ WeChatSubController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ 查询树形 Table
+
+ 父节点
+ 关键字
+
+
+
+
+ 获取部门树
+
+
+
+
+
+
+ 服务管理
+
+
+
+
+ INacosNamingService
+
+
+
+
+
+
+
+
+
+
+ 系统实例是否启动完成
+
+
+
+
+
+ 获取Nacos 状态
+
+
+
+
+
+ 服务上线
+
+
+
+
+
+ 服务下线
+
+
+
+
+
+ SignalR测试
+
+
+
+
+ 向指定用户发送消息
+
+
+
+
+
+
+
+ 向指定角色发送消息
+
+
+
+
+
+
+
+ 分表demo
+
+
+
+
+ 分页获取数据
+
+
+
+
+
+
+
+
+
+
+ 根据ID获取信息
+
+
+
+
+
+
+ 添加一条测试数据
+
+
+
+
+
+
+ 修改一条测试数据
+
+
+
+
+
+
+ 根据id删除数据
+
+
+
+
+
+
+ SqlSugar 相关测试
+
+
+
+
+ SqlSugar 相关测试
+
+
+
+
+ 测试建表后,SqlSugar缓存
+
+
+
+
+
+ 缓存管理
+
+
+
+
+ 缓存管理
+
+
+
+
+ 获取全部缓存
+
+
+
+
+
+ 获取缓存
+
+
+
+
+
+ 新增
+
+
+
+
+
+ 删除全部缓存
+
+
+
+
+
+ 删除缓存
+
+
+
+
+
+ 数据库管理
+
+
+
+
+ 获取库配置
+
+
+
+
+
+ 获取表信息
+
+ 配置Id
+ 读取类型
+
+
+
+
+ 获取表字段
+
+ 表名
+ ConfigId
+ 读取类型
+
+
+
+
+ 编辑表备注
+
+
+
+
+
+ 编辑列备注
+
+
+
+
+
+ 动态建表 CURD
+
+
+
+
+ 动态type
+
+
+
+
+
+ 动态type 继承BaseEntity
+
+
+
+
+
+ 测试建表
+
+
+
+
+
+ 测试查询
+
+
+
+
+
+ 测试写入
+
+
+
+
+
+ 多租户-多库方案 测试
+
+
+
+
+ 获取租户下全部业务数据
+
+
+
+
+
+ 新增数据
+
+
+
+
+
+ 多租户-Id方案 测试
+
+
+
+
+ 获取租户下全部业务数据
+
+
+
+
+
+ 新增业务数据
+
+
+
+
+
+ 多租户-多表方案 测试
+
+
+
+
+ 获取租户下全部业务数据
+
+
+
+
+
+ 新增数据
+
+
+
+
+
+ 租户管理
+
+
+
+
+ 获取全部租户
+
+
+
+
+
+ 获取租户信息
+
+
+
+
+
+ 新增租户信息
+ 此处只做演示,具体要以实际业务为准
+
+
+
+
+
+ 修改租户信息
+ 此处只做演示,具体要以实际业务为准
+
+
+
+
+
+ 删除租户
+ 此处只做演示,具体要以实际业务为准
+
+
+
+
+
+ 枚举测试
+
+
+
+
+ 获取学生信息
+
+ 学生类型
+
+
+ 学生信息
+
+
+
+ 学生类型
+
+
+
+
+ 小学生
+
+
+
+
+ 中学生
+
+
+
+
+ 大学生
+
+
+
+
+ 学生姓名
+
+
+
+
+ 学生年龄
+
+
+
+
+ 学生类型
+
+
+
+
+ Summary:全局路由权限公约
+ Remarks:目的是针对不同的路由,采用不同的授权过滤器
+ 如果 controller 上不加 [Authorize] 特性,默认都是 Permission 策略
+ 否则,如果想特例其他授权机制的话,需要在 controller 上带上 [Authorize],然后再action上自定义授权即可,比如 [Authorize(Roles = "Admin")]
+
+
+
+
+ 全局权限过滤器【无效】
+
+
+
+
+ 全局异常错误日志
+
+
+
+
+ 自定义返回格式
+
+
+
+
+
+
+
+ 生产环境的消息
+
+
+
+
+ 开发环境的消息
+
+
+
+
+ 全局路由前缀公约
+
+
+
+
+ 自定义路由 /api/{version}/[controler]/[action]
+
+
+
+
+ 分组名称,是来实现接口 IApiDescriptionGroupNameProvider
+
+
+
+
+ 自定义路由构造函数,继承基类路由
+
+
+
+
+
+ 自定义版本+路由构造函数,继承基类路由
+
+
+
+
+
+
diff --git a/Blog.Core.Api/Controllers/BaseApiController.cs b/Blog.Core.Api/Controllers/BaseApiController.cs
new file mode 100644
index 00000000..97a938ea
--- /dev/null
+++ b/Blog.Core.Api/Controllers/BaseApiController.cs
@@ -0,0 +1,88 @@
+using Blog.Core.Model;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+
+namespace Blog.Core.Controllers
+{
+ public class BaseApiController : Controller
+ {
+ [NonAction]
+ public MessageModel Success(T data, string msg = "成功")
+ {
+ return new MessageModel()
+ {
+ success = true,
+ msg = msg,
+ response = data,
+ };
+ }
+
+ // [NonAction]
+ //public MessageModel Success(T data, string msg = "成功",bool success = true)
+ //{
+ // return new MessageModel()
+ // {
+ // success = success,
+ // msg = msg,
+ // response = data,
+ // };
+ //}
+ [NonAction]
+ public MessageModel Success(string msg = "成功")
+ {
+ return new MessageModel()
+ {
+ success = true,
+ msg = msg,
+ response = null,
+ };
+ }
+
+ [NonAction]
+ public MessageModel Failed(string msg = "失败", int status = 500)
+ {
+ return new MessageModel()
+ {
+ success = false,
+ status = status,
+ msg = msg,
+ response = null,
+ };
+ }
+
+ [NonAction]
+ public MessageModel Failed(string msg = "失败", int status = 500)
+ {
+ return new MessageModel()
+ {
+ success = false,
+ status = status,
+ msg = msg,
+ response = default,
+ };
+ }
+
+ [NonAction]
+ public MessageModel> SuccessPage(int page, int dataCount, int pageSize, List data,
+ int pageCount, string msg = "获取成功")
+ {
+ return new MessageModel>()
+ {
+ success = true,
+ msg = msg,
+ response = new PageModel(page, dataCount, pageSize, data)
+ };
+ }
+
+ [NonAction]
+ public MessageModel> SuccessPage(PageModel pageModel, string msg = "获取成功")
+ {
+ return new MessageModel>()
+ {
+ success = true,
+ msg = msg,
+ response = pageModel
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/BlogController.cs b/Blog.Core.Api/Controllers/BlogController.cs
new file mode 100644
index 00000000..d0e9a235
--- /dev/null
+++ b/Blog.Core.Api/Controllers/BlogController.cs
@@ -0,0 +1,278 @@
+using System.Linq.Expressions;
+using System.Text.RegularExpressions;
+using Blog.Core.Common.Helper;
+using Blog.Core.IServices;
+using Blog.Core.Model;
+using Blog.Core.Model.Models;
+using Blog.Core.Model.ViewModels;
+using Blog.Core.SwaggerHelper;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Serilog;
+using StackExchange.Profiling;
+using static Blog.Core.Extensions.CustomApiVersion;
+
+namespace Blog.Core.Controllers
+{
+ ///
+ /// 博客管理
+ ///
+ [Produces("application/json")]
+ [Route("api/Blog")]
+ public class BlogController : BaseApiController
+ {
+ public IBlogArticleServices _blogArticleServices { get; set; }
+ private readonly ILogger _logger;
+
+ ///
+ /// 构造函数
+ ///
+ ///
+ ///
+ public BlogController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+
+ ///
+ /// 获取博客列表【无权限】
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ public async Task>> Get(int id, int page = 1, string bcategory = "技术博文", string key = "")
+ {
+ int intPageSize = 6;
+ if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
+ {
+ key = "";
+ }
+
+ Expression> whereExpression = a => (a.bcategory == bcategory && a.IsDeleted == false) && ((a.btitle != null && a.btitle.Contains(key)) || (a.bcontent != null && a.bcontent.Contains(key)));
+
+ var pageModelBlog = await _blogArticleServices.QueryPage(whereExpression, page, intPageSize, " bID desc ");
+
+ using (MiniProfiler.Current.Step("获取成功后,开始处理最终数据"))
+ {
+ foreach (var item in pageModelBlog.data)
+ {
+ if (!string.IsNullOrEmpty(item.bcontent))
+ {
+ item.bRemark = (HtmlHelper.ReplaceHtmlTag(item.bcontent)).Length >= 200 ? (HtmlHelper.ReplaceHtmlTag(item.bcontent)).Substring(0, 200) : (HtmlHelper.ReplaceHtmlTag(item.bcontent));
+ int totalLength = 500;
+ if (item.bcontent.Length > totalLength)
+ {
+ item.bcontent = item.bcontent.Substring(0, totalLength);
+ }
+ }
+ }
+ }
+
+ return SuccessPage(pageModelBlog);
+ }
+
+
+ ///
+ /// 获取博客详情
+ ///
+ ///
+ ///
+ [HttpGet("{id}")]
+ //[Authorize(Policy = "Scope_BlogModule_Policy")]
+ [Authorize]
+ public async Task> Get(long id)
+ {
+ return Success(await _blogArticleServices.GetBlogDetails(id));
+ }
+
+
+ ///
+ /// 获取详情【无权限】
+ ///
+ ///
+ ///
+ [HttpGet]
+ [Route("DetailNuxtNoPer")]
+ public async Task> DetailNuxtNoPer(long id)
+ {
+ _logger.LogInformation("xxxxxxxxxxxxxxxxxxx");
+ Log.Information("yyyyyyyyyyyyyyyyy");
+ return Success(await _blogArticleServices.GetBlogDetails(id));
+ }
+
+ [HttpGet]
+ [Route("GoUrl")]
+ public async Task GoUrl(long id = 0)
+ {
+ var response = await _blogArticleServices.QueryById(id);
+ if (response != null && response.bsubmitter.IsNotEmptyOrNull())
+ {
+ string Url = @"^http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?$";
+ if (Regex.IsMatch(response.bsubmitter, Url))
+ {
+ response.btraffic += 1;
+ await _blogArticleServices.Update(response);
+ return Redirect(response.bsubmitter);
+ }
+
+ }
+
+ return Ok();
+ }
+
+ [HttpGet]
+ [Route("GetBlogsByTypesForMVP")]
+ public async Task>> GetBlogsByTypesForMVP(string types = "", int id = 0)
+ {
+ if (types.IsNotEmptyOrNull())
+ {
+ var blogs = await _blogArticleServices.Query(d => d.bcategory != null && types.Contains(d.bcategory) && d.IsDeleted == false, d => d.bID, false);
+ return Success(blogs);
+ }
+ return Success(new List() { });
+ }
+
+ [HttpGet]
+ [Route("GetBlogByIdForMVP")]
+ public async Task> GetBlogByIdForMVP(long id = 0)
+ {
+ if (id > 0)
+ {
+ return Success(await _blogArticleServices.QueryById(id));
+ }
+ return Success(new BlogArticle());
+ }
+
+ ///
+ /// 获取博客测试信息 v2版本
+ ///
+ ///
+ [HttpGet]
+ ////MVC自带特性 对 api 进行组管理
+ //[ApiExplorerSettings(GroupName = "v2")]
+ ////路径 如果以 / 开头,表示绝对路径,反之相对 controller 的想u地路径
+ //[Route("/api/v2/blog/Blogtest")]
+ //和上边的版本控制以及路由地址都是一样的
+
+ [CustomRoute(ApiVersions.V2, "Blogtest")]
+ public MessageModel V2_Blogtest()
+ {
+ return Success("我是第二版的博客信息");
+ }
+
+ ///
+ /// 添加博客【无权限】
+ ///
+ ///
+ ///
+ [HttpPost]
+ //[Authorize(Policy = "Scope_BlogModule_Policy")]
+ [Authorize]
+ public async Task> Post([FromBody] BlogArticle blogArticle)
+ {
+ if (blogArticle.btitle.Length > 5 && blogArticle.bcontent.Length > 50)
+ {
+
+ blogArticle.bCreateTime = DateTime.Now;
+ blogArticle.bUpdateTime = DateTime.Now;
+ blogArticle.IsDeleted = false;
+ blogArticle.bcategory = "技术博文";
+ var id = (await _blogArticleServices.Add(blogArticle));
+ return id > 0 ? Success(id.ObjToString()) : Failed("添加失败");
+ }
+ else
+ {
+ return Failed("文章标题不能少于5个字符,内容不能少于50个字符!");
+ }
+ }
+
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Route("AddForMVP")]
+ [Authorize(Permissions.Name)]
+ public async Task> AddForMVP([FromBody] BlogArticle blogArticle)
+ {
+ blogArticle.bCreateTime = DateTime.Now;
+ blogArticle.bUpdateTime = DateTime.Now;
+ blogArticle.IsDeleted = false;
+ var id = (await _blogArticleServices.Add(blogArticle));
+ return id > 0 ? Success(id.ObjToString()) : Failed("添加失败");
+ }
+ ///
+ /// 更新博客信息
+ ///
+ ///
+ ///
+ // PUT: api/User/5
+ [HttpPut]
+ [Route("Update")]
+ [Authorize(Permissions.Name)]
+ public async Task> Put([FromBody] BlogArticle BlogArticle)
+ {
+ if (BlogArticle != null && BlogArticle.bID > 0)
+ {
+ var model = await _blogArticleServices.QueryById(BlogArticle.bID);
+
+ if (model != null)
+ {
+ model.btitle = BlogArticle.btitle;
+ model.bcategory = BlogArticle.bcategory;
+ model.bsubmitter = BlogArticle.bsubmitter;
+ model.bcontent = BlogArticle.bcontent;
+ model.btraffic = BlogArticle.btraffic;
+
+ if (await _blogArticleServices.Update(model))
+ {
+ return Success(BlogArticle?.bID.ObjToString());
+ }
+ }
+ }
+ return Failed("更新失败");
+ }
+
+
+
+ ///
+ /// 删除博客
+ ///
+ ///
+ ///
+ [HttpDelete]
+ [Authorize(Permissions.Name)]
+ [Route("Delete")]
+ public async Task> Delete(long id)
+ {
+ if (id > 0)
+ {
+ var blogArticle = await _blogArticleServices.QueryById(id);
+ if (blogArticle == null)
+ {
+ return Failed("查询无数据");
+ }
+ blogArticle.IsDeleted = true;
+ return await _blogArticleServices.Update(blogArticle) ? Success(blogArticle?.bID.ObjToString(), "删除成功") : Failed("删除失败");
+ }
+ return Failed("入参无效");
+ }
+ ///
+ /// apache jemeter 压力测试
+ /// 更新接口
+ ///
+ ///
+ [HttpGet]
+ [Route("ApacheTestUpdate")]
+ public async Task> ApacheTestUpdate()
+ {
+ return Success(await _blogArticleServices.Update(new { bsubmitter = $"laozhang{DateTime.Now.Millisecond}", bID = 1 }), "更新成功");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs b/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
new file mode 100644
index 00000000..553dee75
--- /dev/null
+++ b/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
@@ -0,0 +1,179 @@
+using Blog.Core.Common;
+using Blog.Core.Common.DB;
+using Blog.Core.Common.Seed;
+using Blog.Core.Model;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Hosting;
+using SqlSugar;
+using System.Linq;
+
+namespace Blog.Core.Controllers
+{
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ //[Authorize(Permissions.Name)]
+ public class DbFirstController : ControllerBase
+ {
+ private readonly SqlSugarScope _sqlSugarClient;
+ private readonly IWebHostEnvironment Env;
+
+ ///
+ /// 构造函数
+ ///
+ public DbFirstController(ISqlSugarClient sqlSugarClient, IWebHostEnvironment env)
+ {
+ _sqlSugarClient = sqlSugarClient as SqlSugarScope;
+ Env = env;
+ }
+
+ ///
+ /// 获取 整体框架 文件(主库)(一般可用第一次生成)
+ ///
+ ///
+ [HttpGet]
+ public MessageModel GetFrameFiles()
+ {
+ var data = new MessageModel() { success = true, msg = "" };
+ data.response += @"file path is:C:\my-file\}";
+ var isMuti = BaseDBConfig.IsMulti;
+ if (Env.IsDevelopment())
+ {
+ data.response += $"Controller层生成:{FrameSeed.CreateControllers(_sqlSugarClient)} || ";
+
+ BaseDBConfig.ValidConfig.ForEach(m =>
+ {
+ _sqlSugarClient.ChangeDatabase(m.ConfigId.ToString().ToLower());
+ data.response += $"库{m.ConfigId}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ });
+
+ // 切回主库
+ _sqlSugarClient.ChangeDatabase(MainDb.CurrentDbConnId.ToLower());
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+
+ ///
+ /// 获取仓储层和服务层(需指定表名和数据库)
+ ///
+ /// 数据库链接名称
+ /// 需要生成的表名
+ ///
+ [HttpPost]
+ public MessageModel GetFrameFilesByTableNames([FromBody]string[] tableNames, [FromQuery]string ConnID = null)
+ {
+ ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
+
+ var isMuti = BaseDBConfig.IsMulti;
+ var data = new MessageModel() { success = true, msg = "" };
+ if (Env.IsDevelopment())
+ {
+ data.response += $"库{ConnID}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+ ///
+ /// 获取实体(需指定表名和数据库)
+ ///
+ /// 数据库链接名称
+ /// 需要生成的表名
+ ///
+ [HttpPost]
+ public MessageModel GetFrameFilesByTableNamesForEntity([FromBody] string[] tableNames, [FromQuery] string ConnID = null)
+ {
+ ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
+
+ var isMuti = BaseDBConfig.IsMulti;
+ var data = new MessageModel() { success = true, msg = "" };
+ if (Env.IsDevelopment())
+ {
+ data.response += $"库{ConnID}-Models层生成:{FrameSeed.CreateModels(_sqlSugarClient, ConnID, isMuti, tableNames)}";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+ return data;
+ }
+ ///
+ /// 获取控制器(需指定表名和数据库)
+ ///
+ /// 数据库链接名称
+ /// 需要生成的表名
+ ///
+ [HttpPost]
+ public MessageModel GetFrameFilesByTableNamesForController([FromBody] string[] tableNames, [FromQuery] string ConnID = null)
+ {
+ ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
+
+ var isMuti = BaseDBConfig.IsMulti;
+ var data = new MessageModel() { success = true, msg = "" };
+ if (Env.IsDevelopment())
+ {
+ data.response += $"库{ConnID}-Controllers层生成:{FrameSeed.CreateControllers(_sqlSugarClient, ConnID, isMuti, tableNames)}";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+ return data;
+ }
+
+ ///
+ /// DbFrist 根据数据库表名 生成整体框架,包含Model层(一般可用第一次生成)
+ ///
+ /// 数据库链接名称
+ /// 需要生成的表名
+ ///
+ [HttpPost]
+ public MessageModel GetAllFrameFilesByTableNames([FromBody]string[] tableNames, [FromQuery]string ConnID = null)
+ {
+ ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
+
+ var isMuti = BaseDBConfig.IsMulti;
+ var data = new MessageModel() { success = true, msg = "" };
+ if (Env.IsDevelopment())
+ {
+ _sqlSugarClient.ChangeDatabase(ConnID.ToLower());
+ data.response += $"Controller层生成:{FrameSeed.CreateControllers(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ // 切回主库
+ _sqlSugarClient.ChangeDatabase(MainDb.CurrentDbConnId.ToLower());
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/DbFirst/MigrateController.cs b/Blog.Core.Api/Controllers/DbFirst/MigrateController.cs
new file mode 100644
index 00000000..7865cc69
--- /dev/null
+++ b/Blog.Core.Api/Controllers/DbFirst/MigrateController.cs
@@ -0,0 +1,359 @@
+using Blog.Core.Common.Helper;
+using Blog.Core.IServices;
+using Blog.Core.Model;
+using Blog.Core.Model.Models;
+using Magicodes.ExporterAndImporter.Core;
+using Magicodes.ExporterAndImporter.Excel;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Hosting;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Blog.Core.Repository.UnitOfWorks;
+
+namespace Blog.Core.Controllers
+{
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ //[Authorize(Permissions.Name)]
+ public class MigrateController : ControllerBase
+ {
+ private readonly IUnitOfWorkManage _unitOfWorkManage;
+ private readonly IRoleModulePermissionServices _roleModulePermissionServices;
+ private readonly IUserRoleServices _userRoleServices;
+ private readonly IRoleServices _roleServices;
+ private readonly IPermissionServices _permissionServices;
+ private readonly IModuleServices _moduleServices;
+ private readonly IDepartmentServices _departmentServices;
+ private readonly ISysUserInfoServices _sysUserInfoServices;
+ private readonly IWebHostEnvironment _env;
+
+ public MigrateController(IUnitOfWorkManage unitOfWorkManage,
+ IRoleModulePermissionServices roleModulePermissionServices,
+ IUserRoleServices userRoleServices,
+ IRoleServices roleServices,
+ IPermissionServices permissionServices,
+ IModuleServices moduleServices,
+ IDepartmentServices departmentServices,
+ ISysUserInfoServices sysUserInfoServices,
+ IWebHostEnvironment env)
+ {
+ _unitOfWorkManage = unitOfWorkManage;
+ _roleModulePermissionServices = roleModulePermissionServices;
+ _userRoleServices = userRoleServices;
+ _roleServices = roleServices;
+ _permissionServices = permissionServices;
+ _moduleServices = moduleServices;
+ _departmentServices = departmentServices;
+ _sysUserInfoServices = sysUserInfoServices;
+ _env = env;
+ }
+
+
+ ///
+ /// 获取权限部分Map数据(从库)
+ /// 迁移到新库(主库)
+ ///
+ ///
+ [HttpGet]
+ public async Task> DataMigrateFromOld2New()
+ {
+ var data = new MessageModel() { success = true, msg = "" };
+ var filterPermissionId = 122;
+ if (_env.IsDevelopment())
+ {
+ try
+ {
+ var apiList = await _moduleServices.Query(d => d.IsDeleted == false);
+ var permissionsAllList = await _permissionServices.Query(d => d.IsDeleted == false);
+ var permissions = permissionsAllList.Where(d => d.Pid == 0).ToList();
+ var rmps = await _roleModulePermissionServices.GetRMPMaps();
+ List pms = new();
+
+ // 当然,你可以做个where查询
+ rmps = rmps.Where(d => d.PermissionId >= filterPermissionId).ToList();
+
+ InitPermissionTree(permissions, permissionsAllList, apiList);
+
+ var actionPermissionIds = permissionsAllList.Where(d => d.Id >= filterPermissionId).Select(d => d.Id).ToList();
+ List filterPermissionIds = new();
+ FilterPermissionTree(permissionsAllList, actionPermissionIds, filterPermissionIds);
+ permissions = permissions.Where(d => filterPermissionIds.Contains(d.Id)).ToList();
+
+ // 开启事务,保证数据一致性
+ _unitOfWorkManage.BeginTran();
+
+ // 注意信息的完整性,不要重复添加,确保主库没有要添加的数据
+
+ // 1、保持菜单和接口
+ await SavePermissionTreeAsync(permissions, pms);
+
+ long rid = 0;
+ long pid = 0;
+ long mid = 0;
+ long rpmid = 0;
+
+ // 2、保存关系表
+ foreach (var item in rmps)
+ {
+ // 角色信息,防止重复添加,做了判断
+ if (item.Role != null)
+ {
+ var isExit = (await _roleServices.Query(d => d.Name == item.Role.Name && d.IsDeleted == false)).FirstOrDefault();
+ if (isExit == null)
+ {
+ rid = await _roleServices.Add(item.Role);
+ Console.WriteLine($"Role Added:{item.Role.Name}");
+ }
+ else
+ {
+ rid = isExit.Id;
+ }
+ }
+
+ pid = (pms.FirstOrDefault(d => d.PidOld == item.PermissionId)?.PidNew).ObjToLong();
+ mid = (pms.FirstOrDefault(d => d.MidOld == item.ModuleId)?.MidNew).ObjToLong();
+ // 关系
+ if (rid > 0 && pid > 0)
+ {
+ rpmid = await _roleModulePermissionServices.Add(new RoleModulePermission()
+ {
+ IsDeleted = false,
+ CreateTime = DateTime.Now,
+ ModifyTime = DateTime.Now,
+ ModuleId = mid,
+ PermissionId = pid,
+ RoleId = rid,
+ });
+ Console.WriteLine($"RMP Added:{rpmid}");
+ }
+
+ }
+
+
+ _unitOfWorkManage.CommitTran();
+
+ data.success = true;
+ data.msg = "导入成功!";
+ }
+ catch (Exception)
+ {
+ _unitOfWorkManage.RollbackTran();
+
+ }
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+
+
+ ///
+ /// 权限数据库导出tsv
+ ///
+ ///
+ [HttpGet]
+ public async Task> SaveData2TsvAsync()
+ {
+ var data = new MessageModel() { success = true, msg = "" };
+ if (_env.IsDevelopment())
+ {
+
+ JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ };
+
+ // 取出数据,序列化,自己可以处理判空
+ var SysUserInfoJson = JsonConvert.SerializeObject(await _sysUserInfoServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "SysUserInfo.tsv"), SysUserInfoJson, Encoding.UTF8);
+
+ var DepartmentJson = JsonConvert.SerializeObject(await _departmentServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Department.tsv"), DepartmentJson, Encoding.UTF8);
+
+ var rolesJson = JsonConvert.SerializeObject(await _roleServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Role.tsv"), rolesJson, Encoding.UTF8);
+
+ var UserRoleJson = JsonConvert.SerializeObject(await _userRoleServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "UserRole.tsv"), UserRoleJson, Encoding.UTF8);
+
+
+ var permissionsJson = JsonConvert.SerializeObject(await _permissionServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Permission.tsv"), permissionsJson, Encoding.UTF8);
+
+
+ var modulesJson = JsonConvert.SerializeObject(await _moduleServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Modules.tsv"), modulesJson, Encoding.UTF8);
+
+
+ var rmpsJson = JsonConvert.SerializeObject(await _roleModulePermissionServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "RoleModulePermission.tsv"), rmpsJson, Encoding.UTF8);
+
+
+
+ data.success = true;
+ data.msg = "生成成功!";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+
+
+ ///
+ /// 权限数据库导出excel
+ ///
+ ///
+ [HttpGet]
+ public async Task> SaveData2ExcelAsync()
+ {
+ var data = new MessageModel() { success = true, msg = "" };
+ if (_env.IsDevelopment())
+ {
+
+ JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ };
+
+ // 取出数据,序列化,自己可以处理判空
+ IExporter exporter = new ExcelExporter();
+ var SysUserInfoList = await _sysUserInfoServices.Query(d => d.IsDeleted == false);
+ var result = await exporter.ExportAsByteArray(SysUserInfoList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "SysUserInfo.xlsx"), result);
+
+ var DepartmentList = await _departmentServices.Query(d => d.IsDeleted == false);
+ var DepartmentResult = await exporter.ExportAsByteArray(DepartmentList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Department.xlsx"), DepartmentResult);
+
+ var RoleList = await _roleServices.Query(d => d.IsDeleted == false);
+ var RoleResult = await exporter.ExportAsByteArray(RoleList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Role.xlsx"), RoleResult);
+
+ var UserRoleList = await _userRoleServices.Query(d => d.IsDeleted == false);
+ var UserRoleResult = await exporter.ExportAsByteArray(UserRoleList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "UserRole.xlsx"), UserRoleResult);
+
+ var PermissionList = await _permissionServices.Query(d => d.IsDeleted == false);
+ var PermissionResult = await exporter.ExportAsByteArray(PermissionList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Permission.xlsx"), PermissionResult);
+
+ var ModulesList = await _moduleServices.Query(d => d.IsDeleted == false);
+ var ModulesResult = await exporter.ExportAsByteArray(ModulesList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Modules.xlsx"), ModulesResult);
+
+ var RoleModulePermissionList = await _roleModulePermissionServices.Query(d => d.IsDeleted == false);
+ var RoleModulePermissionResult = await exporter.ExportAsByteArray(RoleModulePermissionList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "RoleModulePermission.xlsx"), RoleModulePermissionResult);
+
+
+ data.success = true;
+ data.msg = "生成成功!";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+
+ private void InitPermissionTree(List permissionsTree, List all, List apis)
+ {
+ foreach (var item in permissionsTree)
+ {
+ item.Children = all.Where(d => d.Pid == item.Id).ToList();
+ item.Module = apis.FirstOrDefault(d => d.Id == item.Mid);
+ InitPermissionTree(item.Children, all, apis);
+ }
+ }
+
+ private void FilterPermissionTree(List permissionsAll, List actionPermissionId, List filterPermissionIds)
+ {
+ actionPermissionId = actionPermissionId.Distinct().ToList();
+ var doneIds = permissionsAll.Where(d => actionPermissionId.Contains(d.Id) && d.Pid == 0).Select(d => d.Id).ToList();
+ filterPermissionIds.AddRange(doneIds);
+
+ var hasDoIds = permissionsAll.Where(d => actionPermissionId.Contains(d.Id) && d.Pid != 0).Select(d => d.Pid).ToList();
+ if (hasDoIds.Any())
+ {
+ FilterPermissionTree(permissionsAll, hasDoIds, filterPermissionIds);
+ }
+ }
+
+ private async Task SavePermissionTreeAsync(List permissionsTree, List pms, long permissionId = 0)
+ {
+ var parendId = permissionId;
+
+ foreach (var item in permissionsTree)
+ {
+ PM pm = new PM();
+ // 保留原始主键id
+ pm.PidOld = item.Id;
+ pm.MidOld = (item.Module?.Id).ObjToLong();
+
+ long mid = 0;
+ // 接口
+ if (item.Module != null)
+ {
+ var moduleModel = (await _moduleServices.Query(d => d.LinkUrl == item.Module.LinkUrl)).FirstOrDefault();
+ if (moduleModel != null)
+ {
+ mid = moduleModel.Id;
+ }
+ else
+ {
+ mid = await _moduleServices.Add(item.Module);
+ }
+ pm.MidNew = mid;
+ Console.WriteLine($"Moudle Added:{item.Module.Name}");
+ }
+ // 菜单
+ if (item != null)
+ {
+ var permissionModel = (await _permissionServices.Query(d => d.Name == item.Name && d.Pid == item.Pid && d.Mid == item.Mid)).FirstOrDefault();
+ item.Pid = parendId;
+ item.Mid = mid;
+ if (permissionModel != null)
+ {
+ permissionId = permissionModel.Id;
+ }
+ else
+ {
+ permissionId = await _permissionServices.Add(item);
+ }
+
+ pm.PidNew = permissionId;
+ Console.WriteLine($"Permission Added:{item.Name}");
+ }
+ pms.Add(pm);
+
+ await SavePermissionTreeAsync(item.Children, pms, permissionId);
+ }
+ }
+
+
+ }
+
+ public class PM
+ {
+ public long PidOld { get; set; }
+ public long MidOld { get; set; }
+ public long PidNew { get; set; }
+ public long MidNew { get; set; }
+ }
+}
diff --git a/Blog.Core.Api/Controllers/DepartmentController.cs b/Blog.Core.Api/Controllers/DepartmentController.cs
new file mode 100644
index 00000000..faf1f850
--- /dev/null
+++ b/Blog.Core.Api/Controllers/DepartmentController.cs
@@ -0,0 +1,215 @@
+using Blog.Core.Common.Helper;
+using Blog.Core.Controllers;
+using Blog.Core.IServices;
+using Blog.Core.Model;
+using Blog.Core.Model.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
+using System.Linq.Expressions;
+using System.Text;
+
+namespace Blog.Core.Api.Controllers
+{
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ [Authorize(Permissions.Name)]
+ public class DepartmentController : BaseApiController
+ {
+ private readonly IDepartmentServices _departmentServices;
+ private readonly IWebHostEnvironment _env;
+
+ public DepartmentController(IDepartmentServices departmentServices, IWebHostEnvironment env)
+ {
+ _departmentServices = departmentServices;
+ _env = env;
+ }
+
+ [HttpGet]
+ public async Task>> Get(int page = 1, string key = "", int intPageSize = 50)
+ {
+ if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
+ {
+ key = "";
+ }
+
+ Expression> whereExpression = a => true;
+
+ return new MessageModel>()
+ {
+ msg = "获取成功",
+ success = true,
+ response = await _departmentServices.QueryPage(whereExpression, page, intPageSize)
+ };
+
+ }
+
+ [HttpGet("{id}")]
+ public async Task> Get(string id)
+ {
+ return new MessageModel()
+ {
+ msg = "获取成功",
+ success = true,
+ response = await _departmentServices.QueryById(id)
+ };
+ }
+
+ ///
+ /// 查询树形 Table
+ ///
+ /// 父节点
+ /// 关键字
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task>> GetTreeTable(long f = 0, string key = "")
+ {
+ List departments = new List();
+ var departmentList = await _departmentServices.Query(d => d.IsDeleted == false);
+ if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
+ {
+ key = "";
+ }
+
+ if (key != "")
+ {
+ departments = departmentList.Where(a => a.Name.Contains(key)).OrderBy(a => a.OrderSort).ToList();
+ }
+ else
+ {
+ departments = departmentList.Where(a => a.Pid == f).OrderBy(a => a.OrderSort).ToList();
+ }
+
+ foreach (var item in departments)
+ {
+ List pidarr = new() { };
+ var parent = departmentList.FirstOrDefault(d => d.Id == item.Pid);
+
+ while (parent != null)
+ {
+ pidarr.Add(parent.Id);
+ parent = departmentList.FirstOrDefault(d => d.Id == parent.Pid);
+ }
+
+ pidarr.Reverse();
+ pidarr.Insert(0, 0);
+ item.PidArr = pidarr;
+
+ item.hasChildren = departmentList.Where(d => d.Pid == item.Id).Any();
+ }
+
+
+ return Success(departments, "获取成功");
+ }
+
+ ///
+ /// 获取部门树
+ ///
+ ///
+ ///
+ [HttpGet]
+ public async Task> GetDepartmentTree(long pid = 0)
+ {
+ var departments = await _departmentServices.Query(d => d.IsDeleted == false);
+ var departmentTrees = (from child in departments
+ where child.IsDeleted == false
+ orderby child.Id
+ select new DepartmentTree
+ {
+ value = child.Id,
+ label = child.Name,
+ Pid = child.Pid,
+ order = child.OrderSort,
+ }).ToList();
+ DepartmentTree rootRoot = new DepartmentTree
+ {
+ value = 0,
+ Pid = 0,
+ label = "根节点"
+ };
+
+ departmentTrees = departmentTrees.OrderBy(d => d.order).ToList();
+
+
+ RecursionHelper.LoopToAppendChildren(departmentTrees, rootRoot, pid);
+
+ return Success(rootRoot, "获取成功");
+ }
+
+ [HttpPost]
+ public async Task> Post([FromBody] Department request)
+ {
+ var data = new MessageModel();
+
+ var id = await _departmentServices.Add(request);
+ data.success = id > 0;
+ if (data.success)
+ {
+ data.response = id.ObjToString();
+ data.msg = "添加成功";
+ }
+
+ return data;
+ }
+
+ [HttpPut]
+ public async Task> Put([FromBody] Department request)
+ {
+ var data = new MessageModel();
+ data.success = await _departmentServices.Update(request);
+ if (data.success)
+ {
+ data.msg = "更新成功";
+ data.response = request?.Id.ObjToString();
+ }
+
+ return data;
+ }
+
+ [HttpDelete]
+ public async Task> Delete(long id)
+ {
+ var data = new MessageModel();
+ var model = await _departmentServices.QueryById(id);
+ model.IsDeleted = true;
+ data.success = await _departmentServices.Update(model);
+ if (data.success)
+ {
+ data.msg = "删除成功";
+ data.response = model?.Id.ObjToString();
+ }
+
+
+ return data;
+ }
+
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task> SaveData2Tsv()
+ {
+ var data = new MessageModel() { success = true, msg = "" };
+ if (_env.IsDevelopment())
+ {
+
+ JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ };
+
+ var rolesJson = JsonConvert.SerializeObject(await _departmentServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Department_New.tsv"), rolesJson, Encoding.UTF8);
+
+ data.success = true;
+ data.msg = "生成成功!";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/HealthCheckController.cs b/Blog.Core.Api/Controllers/HealthCheckController.cs
new file mode 100644
index 00000000..04fac9d6
--- /dev/null
+++ b/Blog.Core.Api/Controllers/HealthCheckController.cs
@@ -0,0 +1,22 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace Blog.Core.Controllers
+{
+ ///
+ /// 健康检查
+ ///
+ [Route("[controller]")]
+ [ApiController]
+ public class HealthCheckController : ControllerBase
+ {
+ ///
+ /// 健康检查接口
+ ///
+ ///
+ [HttpGet]
+ public IActionResult Get()
+ {
+ return Ok();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/ImgController.cs b/Blog.Core.Api/Controllers/ImgController.cs
new file mode 100644
index 00000000..5ba85388
--- /dev/null
+++ b/Blog.Core.Api/Controllers/ImgController.cs
@@ -0,0 +1,145 @@
+using Blog.Core.Model;
+using Blog.Core.Model.ViewModels;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Blog.Core.Controllers
+{
+ ///
+ /// 图片管理
+ ///
+ [Route("api/[controller]")]
+ [ApiController]
+ [Authorize]
+ public class ImgController : BaseApiController
+ {
+
+ private readonly IWebHostEnvironment _env;
+
+ public ImgController(IWebHostEnvironment webHostEnvironment)
+ {
+ _env = webHostEnvironment;
+ }
+
+
+ // GET: api/Download
+ ///
+ /// 下载图片(支持中文字符)
+ ///
+ ///
+ [HttpGet]
+ [Route("/images/Down/Pic")]
+ public FileStreamResult DownImg()
+ {
+ string foldername = "";
+ string filepath = Path.Combine(_env.WebRootPath, foldername, "测试下载中文名称的图片.png");
+ var stream = System.IO.File.OpenRead(filepath);
+ string fileExt = ".jpg"; // 这里可以写一个获取文件扩展名的方法,获取扩展名
+ //获取文件的ContentType
+ var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
+ var memi = provider.Mappings[fileExt];
+ var fileName = Path.GetFileName(filepath);
+
+
+ return File(stream, memi, fileName);
+ }
+
+ ///
+ /// 上传图片,多文件
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Route("/images/Upload/Pic")]
+ public async Task> InsertPicture([FromForm]UploadFileDto dto)
+ {
+
+ if (dto.file == null || !dto.file.Any()) return Failed("请选择上传的文件。");
+ //格式限制
+ var allowType = new string[] { "image/jpg", "image/png", "image/jpeg" };
+
+ var allowedFile = dto.file.Where(c => allowType.Contains(c.ContentType));
+ if (!allowedFile.Any()) return Failed("图片格式错误");
+ if (allowedFile.Sum(c => c.Length) > 1024 * 1024 * 4) return Failed("图片过大");
+
+ string foldername = "images";
+ string folderpath = Path.Combine(_env.WebRootPath, foldername);
+ if (!Directory.Exists(folderpath))
+ {
+ Directory.CreateDirectory(folderpath);
+ }
+ foreach (var file in allowedFile)
+ {
+ string strpath = Path.Combine(foldername, DateTime.Now.ToString("MMddHHmmss") + Path.GetFileName(file.FileName));
+ var path = Path.Combine(_env.WebRootPath, strpath);
+
+ using (var stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ {
+ await file.CopyToAsync(stream);
+ }
+ }
+
+ var excludeFiles = dto.file.Except(allowedFile);
+
+ if (excludeFiles.Any())
+ {
+ var infoMsg = $"{string.Join('、', excludeFiles.Select(c => c.FileName))} 图片格式错误";
+ return Success(null, infoMsg);
+ }
+
+ return Success(null, "上传成功");
+
+ }
+
+
+
+ [HttpGet]
+ [Route("/images/Down/Bmd")]
+ [AllowAnonymous]
+ public FileStreamResult DownBmd(string filename)
+ {
+ if (string.IsNullOrEmpty(filename))
+ {
+ return null;
+ }
+ // 前端 blob 接收,具体查看前端admin代码
+ string filepath = Path.Combine(_env.WebRootPath, Path.GetFileName(filename));
+ if (System.IO.File.Exists(filepath))
+ {
+ var stream = System.IO.File.OpenRead(filepath);
+ //string fileExt = ".bmd";
+ //获取文件的ContentType
+ var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
+ //var memi = provider.Mappings[fileExt];
+ var fileName = Path.GetFileName(filepath);
+
+ HttpContext.Response.Headers.Add("fileName", fileName);
+
+ return File(stream, "application/octet-stream", fileName);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // POST: api/Img
+ [HttpPost]
+ public void Post([FromBody] object formdata)
+ {
+ }
+
+ // PUT: api/Img/5
+ [HttpPut("{id}")]
+ public void Put(int id, [FromBody] string value)
+ {
+ }
+
+ // DELETE: api/ApiWithActions/5
+ [HttpDelete("{id}")]
+ public void Delete(int id)
+ {
+ }
+ }
+
+}
diff --git a/Blog.Core/Controllers/LoginController.cs b/Blog.Core.Api/Controllers/LoginController.cs
similarity index 51%
rename from Blog.Core/Controllers/LoginController.cs
rename to Blog.Core.Api/Controllers/LoginController.cs
index 704f014e..5b40773d 100644
--- a/Blog.Core/Controllers/LoginController.cs
+++ b/Blog.Core.Api/Controllers/LoginController.cs
@@ -1,18 +1,16 @@
-using System;
-using System.Collections.Generic;
-using System.IdentityModel.Tokens.Jwt;
-using System.Linq;
-using System.Security.Claims;
-using System.Threading.Tasks;
-using Blog.Core.AuthHelper;
+using Blog.Core.AuthHelper;
using Blog.Core.AuthHelper.OverWrite;
using Blog.Core.Common.Helper;
using Blog.Core.IServices;
+using Blog.Core.Model;
+using Blog.Core.Model.ViewModels;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Cors;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using Blog.Core.Common.Swagger;
+
namespace Blog.Core.Controllers
{
@@ -22,13 +20,14 @@ namespace Blog.Core.Controllers
[Produces("application/json")]
[Route("api/Login")]
[AllowAnonymous]
- public class LoginController : Controller
+ public class LoginController : BaseApiController
{
readonly ISysUserInfoServices _sysUserInfoServices;
readonly IUserRoleServices _userRoleServices;
readonly IRoleServices _roleServices;
readonly PermissionRequirement _requirement;
-
+ private readonly IRoleModulePermissionServices _roleModulePermissionServices;
+ private readonly ILogger _logger;
///
/// 构造函数注入
@@ -37,16 +36,23 @@ public class LoginController : Controller
///
///
///
- public LoginController(ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices, IRoleServices roleServices, PermissionRequirement requirement)
+ ///
+ ///
+ public LoginController(ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices,
+ IRoleServices roleServices, PermissionRequirement requirement,
+ IRoleModulePermissionServices roleModulePermissionServices, ILogger logger)
{
this._sysUserInfoServices = sysUserInfoServices;
this._userRoleServices = userRoleServices;
this._roleServices = roleServices;
_requirement = requirement;
+ _roleModulePermissionServices = roleModulePermissionServices;
+ _logger = logger;
}
#region 获取token的第1种方法
+
///
/// 获取JWT的方法1
///
@@ -55,17 +61,16 @@ public LoginController(ISysUserInfoServices sysUserInfoServices, IUserRoleServic
///
[HttpGet]
[Route("Token")]
- public async Task