docs: 全新文档

This commit is contained in:
wintel 2025-04-23 23:37:58 +08:00
parent 05922c77f3
commit 918b6a53d4
48 changed files with 4207 additions and 0 deletions

27
newdocs/README.md Normal file
View File

@ -0,0 +1,27 @@
# open-auth-net-官方文档
The Site is generated using [vuepress](https://vuepress.vuejs.org/) and [vuepress-theme-plume](https://github.com/pengzhanbo/vuepress-theme-plume)
## Install
```sh
npm i
```
## Usage
```sh
# start dev server
npm run docs:dev
# build for production
npm run docs:build
# preview production build in local
npm run docs:preview
# update vuepress and theme
npm run vp-update
```
## Documents
- [vuepress](https://vuepress.vuejs.org/)
- [vuepress-theme-plume](https://theme-plume.vuejs.press/)

27
newdocs/README.zh-CN.md Normal file
View File

@ -0,0 +1,27 @@
# open-auth-net-官方文档
网站使用 [vuepress](https://vuepress.vuejs.org/) 和 [vuepress-theme-plume](https://github.com/pengzhanbo/vuepress-theme-plume) 构建生成。
## Install
```sh
npm i
```
## Usage
```sh
# 启动开发服务
npm run docs:dev
# 构建生产包
npm run docs:build
# 本地预览生产服务
npm run docs:preview
# 更新 vuepress 和主题
npm run vp-update
```
## 文档
- [vuepress](https://vuepress.vuejs.org/)
- [vuepress-theme-plume](https://theme-plume.vuejs.press/)

View File

@ -0,0 +1,22 @@
import { defineClientConfig } from 'vuepress/client'
// import RepoCard from 'vuepress-theme-plume/features/RepoCard.vue'
// import NpmBadge from 'vuepress-theme-plume/features/NpmBadge.vue'
// import NpmBadgeGroup from 'vuepress-theme-plume/features/NpmBadgeGroup.vue'
// import Swiper from 'vuepress-theme-plume/features/Swiper.vue'
// import CustomComponent from './theme/components/Custom.vue'
// import './theme/styles/custom.css'
export default defineClientConfig({
enhance({ app }) {
// built-in components
// app.component('RepoCard', RepoCard)
// app.component('NpmBadge', NpmBadge)
// app.component('NpmBadgeGroup', NpmBadgeGroup)
// app.component('Swiper', Swiper) // you should install `swiper`
// your custom components
// app.component('CustomComponent', CustomComponent)
},
})

View File

@ -0,0 +1,173 @@
import { viteBundler } from '@vuepress/bundler-vite'
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
base: '/',
lang: 'zh-CN',
title: 'OpenAuth.Net',
description: '最好用的.net权限工作流框架,最实用的.net/vue前后端分离方案',
head: [
// 配置站点图标
['link', { rel: 'icon', type: 'image/png', href: 'https://theme-plume.vuejs.press/favicon-32x32.png' }],
],
bundler: viteBundler(),
shouldPrefetch: false, // 站点较大,页面数量较多时,不建议启用
theme: plumeTheme({
/* 添加您的部署域名, 有助于 SEO, 生成 sitemap */
hostname: 'http://doc.openauth.net.cn',
/* 文档仓库配置,用于 editLink */
// docsRepo: '',
// docsDir: 'docs',
// docsBranch: '',
/* 页内信息 */
// editLink: true,
// lastUpdated: true,
// contributors: true,
// changelog: false,
/**
*
* @see https://theme-plume.vuejs.press/config/basic/#blog
*/
// blog: false, // 禁用博客
// blog: {
// postList: true, // 是否启用文章列表页
// tags: true, // 是否启用标签页
// archives: true, // 是否启用归档页
// categories: true, // 是否启用分类页
// postCover: 'right', // 文章封面位置
// pagination: 15, // 每页显示文章数量
// },
/* 博客文章页面链接前缀 */
article: '/article/',
/**
*
* @see https://theme-plume.vuejs.press/config/basic/#cache
*/
cache: 'filesystem',
/**
* markdown frontmatter
* @see https://theme-plume.vuejs.press/config/basic/#autofrontmatter
*/
// autoFrontmatter: {
// permalink: true, // 是否生成永久链接
// createTime: true, // 是否生成创建时间
// title: true, // 是否生成标题
// },
/* 本地搜索, 默认启用 */
search: { provider: 'local' },
/**
* Algolia DocSearch
* search false
* @see https://theme-plume.vuejs.press/config/plugins/search/#algolia-docsearch
*/
// search: {
// provider: 'algolia',
// appId: '',
// apiKey: '',
// indexName: '',
// },
/**
* Shiki
* @see https://theme-plume.vuejs.press/config/plugins/code-highlight/
*/
// codeHighlighter: {
// twoslash: true, // 启用 twoslash
// whitespace: true, // 启用 空格/Tab 高亮
// lineNumbers: true, // 启用行号
// },
/* 文章字数统计、阅读时间,设置为 false 则禁用 */
// readingTime: true,
/**
* markdown
* @see https://theme-plume.vuejs.press/config/markdown/
*/
markdown: {
plantuml: true,
// abbr: true, // 启用 abbr 语法 *[label]: content
// annotation: true, // 启用 annotation 语法 [+label]: content
// pdf: true, // 启用 PDF 嵌入 @[pdf](/xxx.pdf)
// caniuse: true, // 启用 caniuse 语法 @[caniuse](feature_name)
// plot: true, // 启用隐秘文本语法 !!xxxx!!
// bilibili: true, // 启用嵌入 bilibili视频 语法 @[bilibili](bid)
// youtube: true, // 启用嵌入 youtube视频 语法 @[youtube](video_id)
// artPlayer: true, // 启用嵌入 artPlayer 本地视频 语法 @[artPlayer](url)
// audioReader: true, // 启用嵌入音频朗读功能 语法 @[audioReader](url)
// icons: true, // 启用内置图标语法 :[icon-name]:
// codepen: true, // 启用嵌入 codepen 语法 @[codepen](user/slash)
// replit: true, // 启用嵌入 replit 语法 @[replit](user/repl-name)
// codeSandbox: true, // 启用嵌入 codeSandbox 语法 @[codeSandbox](id)
// jsfiddle: true, // 启用嵌入 jsfiddle 语法 @[jsfiddle](user/id)
// npmTo: true, // 启用 npm-to 容器 ::: npm-to
// demo: true, // 启用 demo 容器 ::: demo
// repl: { // 启用 代码演示容器
// go: true, // ::: go-repl
// rust: true, // ::: rust-repl
// kotlin: true, // ::: kotlin-repl
// },
// math: { // 启用数学公式
// type: 'katex',
// },
// chartjs: true, // 启用 chart.js
// echarts: true, // 启用 ECharts
// mermaid: true, // 启用 mermaid
// flowchart: true, // 启用 flowchart
// image: {
// figure: true, // 启用 figure
// lazyload: true, // 启用图片懒加载
// mark: true, // 启用图片标记
// size: true, // 启用图片大小
// },
// include: true, // 在 Markdown 文件中导入其他 markdown 文件内容
// imageSize: 'local', // 启用 自动填充 图片宽高属性,避免页面抖动
},
/**
*
* @see https://theme-plume.vuejs.press/guide/features/watermark/
*/
// watermark: true,
/**
* comments
* @see https://theme-plume.vuejs.press/guide/features/comments/
*/
// comment: {
// provider: '', // "Artalk" | "Giscus" | "Twikoo" | "Waline"
// comment: true,
// repo: '',
// repoId: '',
// category: '',
// categoryId: '',
// mapping: 'pathname',
// reactionsEnabled: true,
// inputPosition: 'top',
// },
/**
*
* @see https://theme-plume.vuejs.press/guide/features/replace-assets/
*/
// replaceAssets: 'https://cdn.example.com',
/**
*
* @see https://theme-plume.vuejs.press/guide/features/encryption/
*/
// encrypt: {},
}),
})

View File

@ -0,0 +1,15 @@
/*
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
* @Date: 2025-04-23 20:26:48
* @LastEditTime: 2025-04-23 20:51:49
* @Description:
* Copyright (c) 2025 by yubaolee | ahfu~ , All Rights Reserved.
*/
import { defineNavbarConfig } from 'vuepress-theme-plume'
export const navbar = defineNavbarConfig([
{ text: '首页', link: '/' },
{ text: '开源后端', link: '/notes/core/README.md' },
{ text: 'vue3版本', link: '/notes/pro/README.md' },
{ text: 'vue2版本', link: '/notes/vue2/README.md' }
])

View File

@ -0,0 +1,52 @@
/*
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
* @Date: 2025-04-23 20:26:48
* @LastEditTime: 2025-04-23 23:30:36
* @Description:
* Copyright (c) 2025 by yubaolee | ahfu~ , All Rights Reserved.
*/
import { defineNoteConfig, defineNotesConfig } from 'vuepress-theme-plume'
//开源后端文档
const coreNote = defineNoteConfig({
dir: 'core',
link: '/core',
sidebar: [
'',
{
text: '基础功能',
collapsed: false,
items: [
'start', 'specialist', 'deploy', 'deployapi', 'devnew', 'multidbs', 'multitenant', 'unitwork','sqlsugar', 'entity','dynamicapi', 'datavalidation', 'log', 'identity', 'job', 'cache', 'unittest','changesdk'
]
},
{
text: '权限控制',
collapsed: true,
items: [
'moduleauth','apiauth', 'logininfo', 'dataprivilege', 'datapropertyrule'
]
},
{
text: '工作流',
collapsed: true,
items: ['form','flowinstance','flowinstanceconcept','flowinstancedev', 'thirdparty' ]
},
{
text: '前端开发',
collapsed: true,
items: ['wwwarchitect']
},
{
text: '其他',
collapsed: true,
items: ['changelog', 'routineupdate','faq']
}
],
})
export const notes = defineNotesConfig({
dir: 'notes',
link: '/',
notes: [coreNote],
})

View File

@ -0,0 +1,76 @@
/*
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
* @Date: 2025-04-23 20:26:48
* @LastEditTime: 2025-04-23 21:23:01
* @Description:
* Copyright (c) 2025 by yubaolee | ahfu~ , All Rights Reserved.
*/
import { defineThemeConfig } from 'vuepress-theme-plume'
import { navbar } from './navbar'
import { notes } from './notes'
/**
* @see https://theme-plume.vuejs.press/config/basic/
*/
export default defineThemeConfig({
logo: 'http://img.openauth.net.cn/2025-04-23-21-21-00.png',
appearance: true, // 配置 深色模式
social: [
{ icon: 'github', link: 'https://gitee.com/dotnetchina/OpenAuth.Net' },
],
// navbarSocialInclude: ['github'], // 允许显示在导航栏的 social 社交链接
// aside: true, // 页内侧边栏, 默认显示在右侧
// outline: [2, 3], // 页内大纲, 默认显示 h2, h3
/**
*
* @see https://theme-plume.vuejs.press/guide/features/copyright/
*/
// copyright: true,
// prevPage: true, // 是否启用上一页链接
// nextPage: true, // 是否启用下一页链接
// createTime: true, // 是否显示文章创建时间
/* 站点页脚 */
// footer: {
// message: 'Power by <a target="_blank" href="https://v2.vuepress.vuejs.org/">VuePress</a> & <a target="_blank" href="https://theme-plume.vuejs.press">vuepress-theme-plume</a>',
// copyright: '',
// },
/**
* @see https://theme-plume.vuejs.press/config/basic/#profile
*/
profile: {
avatar: 'http://img.openauth.net.cn/2025-04-23-21-21-00.png',
name: 'OpenAuth.Net官方文档',
description: '最好用的权限工作流框架',
// circle: true,
// location: '',
// organization: '',
},
navbar,
notes,
/**
*
* @see https://theme-plume.vuejs.press/guide/features/bulletin/
*/
// bulletin: {
// layout: 'top-right',
// contentType: 'markdown',
// title: '公告板标题',
// content: '公告板内容',
// },
/* 过渡动画 @see https://theme-plume.vuejs.press/config/basic/#transition */
// transition: {
// page: true, // 启用 页面间跳转过渡动画
// postList: true, // 启用 博客文章列表过渡动画
// appearance: 'fade', // 启用 深色模式切换过渡动画, 或配置过渡动画类型
// },
})

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 72 72">
<path fill="#5086a1" d="M42.334 49.147a29.945 29.945 0 0 1-19.338-8.151c-8.014-7.365-8.378-18.076-8.533-22.649l-.022-.627a2.904 2.904 0 0 1 3.457-2.951c17.005 3.355 21.695 16.324 22.056 17.4a49.543 49.543 0 0 1 3.574 15.922a1 1 0 0 1-.967 1.052c-.029.001-.106.004-.227.004" />
<path fill="#8cccd5" d="M44.436 55.316c-11.646 0-17.376-6.974-17.653-7.354a1 1 0 0 1 .262-1.424a11.103 11.103 0 0 1 12.774-1.574c-1.465-9.078 1.877-13.568 2.031-13.77a.998.998 0 0 1 .75-.39a.97.97 0 0 1 .78.325c8.944 9.771 8.793 16.532 7.908 19.691c-.034.14-1.062 4.092-4.772 4.406c-.711.062-1.405.09-2.08.09" />
<g fill="none" stroke="#333" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<path d="M55.184 57.69S34.96 45.877 23.097 24.206m22.131 30.096c-11.93.46-17.628-6.88-17.628-6.88" />
<path d="M40.528 42.483c-.56-7.195 2.116-10.679 2.116-10.679c8.834 9.654 8.406 16.162 7.681 18.747m-13.311-3.129a30.15 30.15 0 0 1-13.341-7.162c-8.072-7.419-8.067-18.241-8.232-22.577a1.903 1.903 0 0 1 2.264-1.932C34.694 19.103 39.02 32.528 39.02 32.528" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { ref } from 'vue'
const message = ref('Hello World!')
</script>
<template>
<div class="my-custom-content">
{{ message }}
</div>
</template>

View File

@ -0,0 +1,6 @@
declare module '*.vue' {
import type { ComponentOptions } from 'vue'
const comp: ComponentOptions
export default comp
}

View File

@ -0,0 +1,50 @@
:root {
/** 主题颜色 */
/*
--vp-c-brand-1: #5086a1;
--vp-c-brand-2: #6aa1b7;
--vp-c-brand-3: #8cccd5;
--vp-c-brand-soft: rgba(131, 208, 218, 0.314);
*/
/** 背景颜色 */
/*
--vp-c-bg: #fff;
--vp-c-bg-alt: #f6f6f7;
--vp-c-bg-elv: #fff;
--vp-c-bg-soft: #f6f6f7;
*/
/** 文本颜色 */
/*
--vp-c-text-1: rgba(60, 60, 67);
--vp-c-text-2: rgba(60, 60, 67, 0.78);
--vp-c-text-3: rgba(60, 60, 67, 0.56);
*/
}
/** 深色模式 */
[data-theme="dark"] {
/*
--vp-c-brand-1: #8cccd5;
--vp-c-brand-2: #6aa1b7;
--vp-c-brand-3: #5086a1;
--vp-c-brand-soft: rgba(131, 208, 218, 0.314);
*/
/*
--vp-c-bg: #1b1b1f;
--vp-c-bg-alt: #161618;
--vp-c-bg-elv: #202127;
--vp-c-bg-soft: #202127;
*/
/*
--vp-c-text-1: rgba(255, 255, 245, 0.86);
--vp-c-text-2: rgba(235, 235, 245, 0.6);
--vp-c-text-3: rgba(235, 235, 245, 0.38);
*/
}

22
newdocs/docs/README.md Normal file
View File

@ -0,0 +1,22 @@
---
pageLayout: home
externalLinkIcon: false
config:
-
type: hero
full: true
background: tint-plate
hero:
name: OpenAuth.Net
tagline:
text: 最好用的.net权限工作流框架,最实用的.net/vue前后端分离方案
actions:
-
theme: brand
text: 博客
link: /blog/
-
theme: alt
text: Github →
link: https://gitee.com/dotnetchina/OpenAuth.Net
---

View File

@ -0,0 +1,67 @@
---
title: 开源后端
createTime: 2025/04/20 21:49:49
permalink: /core/
---
![LOGO](/logocore.png "1.png")
OpenAuth.Net是基于最新版.Net的开源权限工作流快速开发框架。源于Martin Fowler企业级应用开发思想及最新技术组合SqlSugar、EF、Quartz、AutoFac、WebAPI、Swagger、Mock、NUnit、Vue2/3、Element-ui/plus、IdentityServer等。核心模块包括角色授权、代码生成、API鉴权、智能打印、表单设计、工作流、定时任务等。
开源版本演示:[http://demo.openauth.net.cn:1802/](http://demo.openauth.net.cn:1802/)
如果你想了解企业版的内容,请访问:[http://doc.openauth.net.cn/pro](http://doc.openauth.net.cn/pro/)
::: tip 提示
gitee上面两个版本。其中
* [OpenAuth.Net](https://gitee.com/dotnetchina/OpenAuth.Net) 默认SDK版本为.Net 9.0.100,如果需要切换到.Net其他版本请参考[切换sdk版本](http://doc.openauth.net.cn/core/changesdk.html)
* [OpenAuth.Core](https://gitee.com/yubaolee/OpenAuth.Core) 的SDK版本为.Net Core 3.1.100,已停止维护,不推荐使用。
.Net目前SDK升级特别方便。请参考[3分钟的时间把.net core 3.1的升级到.NET 5](https://www.cnblogs.com/yubaolee/p/Net3ToNet5.html)所以不要纠结SDK版本问题。
:::
## 技术栈
![](https://img.shields.io/badge/release-6.0-blue) ![](https://img.shields.io/badge/SqlSugar-5.1.4-blue) ![](https://img.shields.io/badge/IdentityServer4-3.0.1-blue) ![](https://img.shields.io/badge/quartz-3.0.7-blue) ![](https://img.shields.io/badge/Autofac-5.2-blue) ![](https://img.shields.io/badge/NUnit-3.13.1-blue) ![](https://img.shields.io/badge/SwaggerUI-OAS%203.0-blue) ![](https://img.shields.io/badge/Moq-4.13-blue) ![](https://img.shields.io/badge/log4net-2.0.12-blue)
![](https://img.shields.io/badge/vue-2.6.10-brightgreen) ![](https://img.shields.io/badge/vue-3.3.4-brightgreen) ![](https://img.shields.io/badge/vite-4.4.9-brightgreen) ![](https://img.shields.io/badge/element--ui-2.10.1-brightgreen) ![](https://img.shields.io/badge/element--plus-2.3.9-brightgreen) ![](https://img.shields.io/badge/node-%3E%3D4.0-brightgreen) ![](https://img.shields.io/badge/npm-9.7.1-brightgreen) ![](https://img.shields.io/badge/layui-2.8.6-brightgreen)
## 核心看点
* 支持最新版.Net 9.0.100
* 同时支持EntityFramework、SqlSugar两款最流行的ORM框架
* 超强的自定义权限控制功能,请参考:[通用权限设计与实现](https://www.cnblogs.com/yubaolee/p/DataPrivilege.html)
* 完整API鉴权可以控制角色可访问的API资源及模块功能字段可见及是否返回请参考[按角色授权API资源](http://doc.openauth.net.cn/core/apiauth.html#%E6%8C%89%E8%A7%92%E8%89%B2%E6%8E%88%E6%9D%83api%E8%B5%84%E6%BA%90) 及 [字段权限](http://doc.openauth.net.cn/core/datapropertyrule.html)
* 可拖拽的表单设计。详情:[可拖拽表单](http://doc.openauth.net.cn/pro/dragform.html)
* 可视化流程设计。[可视化流程设计](http://doc.openauth.net.cn/pro/startflow.html)
* 全网最好用的打印解决方案。详情:[智能打印](http://doc.openauth.net.cn/pro/printerplan.html)
* 基于Quartz.Net的定时任务控制,可随时启/停可视化配置Cron表达式功能请参考[定时任务](http://doc.openauth.net.cn/core/job.html)
* 基于CodeSmith的代码生成功能可快速生成带有头/明细结构的页面
* 支持sqlserver、mysql、Oracle、PostgreSql数据库理论上支持所有数据库
* 支持同时访问多数据源
* 支持多租户
* 支持搭建自己的IdentityServer服务器实现基于OAuth2的登录体系请参考[登录认证及OAuth集成](http://doc.openauth.net.cn/core/identity.html)
* 建立三方对接规范,已有系统可以无缝对接流程引擎
* 前端采用 vue + layui + element-ui + ztree + gooflow + leipiformdesign
* 后端采用 .net +EF + sqlsugar + autofac + quartz +IdentityServer4 + nunit + swagger
* 设计工具 PowerDesigner +PDManer + Enterprise Architect

View File

@ -0,0 +1,59 @@
---
title: API权限控制
createTime: 2025/04/23 21:03:10
permalink: /core/apiauth/
---
在使用OpenAuth.WebApi过程中系统会对所有的Api进行权限控制。如果没有登录就访问Api接口会提示下面信息
```javascript
{
"message": "认证失败,请提供认证信息",
"code": 401
}
```
如果想正常调用,必需先调用登录接口`/api/Check/Login`拿到登录`token`,如下:
```javascript
{
"returnUrl": "http://localhost:56813",
"token": "e4a5aa00",
"result": null,
"message": "操作成功",
"code": 200
}
```
把token值放置在http header X-Token中即可正常调用其他接口。如下
```javascript
GET /api/Applications/Load?page=1&limit=10 HTTP/1.1
Host: localhost:52789
X-Token: e4a5aa00
```
## 按角色授权API资源
目前主流的接口平台都提供按角色或账号授权访问API的功能OpenAuth.Net也不例外。在OpenAuth.Net中接口API被当作资源处理。如图
![2025-03-11-11-18-31](http://img.openauth.net.cn/2025-03-11-11-18-31.png)
如果后端新增或删除API点击【同步系统API资源】按钮即可同步到资源列表中。在角色管理功能中可以对登录的角色进行API资源授权。
![](http://img.openauth.net.cn/2025-03-11-11-13-54.png)
## 不登录直接访问
有些场景我们需要不进行登录直接访问接口,可以直接在接口上面加[AllowAnonymous]注解即可。如下:
```csharp
[HttpGet]
[AllowAnonymous]
public async Task<TableData> Load([FromQuery]QueryWmsInboundOrderDtblListReq request)
{
return await _app.Load(request);
}
```

View File

@ -0,0 +1,66 @@
---
title: 缓存机制
createTime: 2025/04/23 21:03:10
permalink: /core/cache/
---
# 缓存机制
## 服务器缓存
在OpenAuth中缓存通过`ICacheContext`接口实现的。系统有三个实现方式:
* 基于.net自带的`MemoryCache`实现的`CacheContext`
* 基于`StackExchange.Redis`实现的`RedisCacheContext`【新增💪】
* 基于`Enyim Memcache`实现的`EnyimMemcachedContext`
可以根据自己需要扩展其他缓存。OpenAuth.Mvc和OpenAuth.Api默认使用的是CacheContext。可以在`AutofacExt.cs`跟换自己喜欢的缓存:
```csharp
public static void InitAutofac(ContainerBuilder builder)
{
...
//更换缓存
builder.RegisterType(typeof(CacheContext)).As(typeof(ICacheContext));
}
```
## 服务器缓存有效时间
服务器默认缓存时间为10天在`LoginParse.cs`中设置
```csharp
_cacheContext.Set(currentSession.Token, currentSession, DateTime.Now.AddDays(10));
```
::: warning 注意事项1
默认使用的是.net的内存Cache在用IIS发布后由于IIS本身存在自动回收的机制会导致系统缓存20分钟就会失效。
:::
::: warning 注意事项2
如果使用Redis缓存注意调整配置文件中关于redis的配置
```csharp
"AppSetting": {
//其他配置..
"RedisConf": "your_redis_server:6379,password=your_redis_password" //redis配置信息
}
```
:::
## 企业版前端缓存
企业版前端使用js-cookie存储登录token信息。默认为`session cookie`也就是这个session在关闭浏览器后会被删除。如果想延长登录有效期限可以调整`src\utils\auth.js`中写入cookie的时间
```javascript
//设置登录有效期为7天
export function setToken(token) {
return Cookies.set(TokenKey, token, { expires: 7 })
}
```

View File

@ -0,0 +1,222 @@
---
title: 版本发布
createTime: 2025/04/23 21:03:10
permalink: /core/changelog/
---
# 版本发布
### v7.0
* 全面支持.Net 9
* 新增Dockerfile支持
* 修复vue3代码生成部分bug
### v6.5
* fix #IAGT6Z:归档/知会功能 增加知会功能
* fix #I9J6WS:审核流程审批人转交审核问题 增加加签逻辑
* fix #IARU2B:模块管理添加菜单报错postgre数据库
* fix #IADLX5:角色管理,为角色分配按钮权限不起作用。
* fix #IAE0NF:非System用户提示配置Category表字段
* fix #IABKQN:输入框输入收清除其他下拉框或选择框的内容
### v6.3
* fix #I9HQWU:审核问题 已审核过的用户,后面不需要再次审核
* fix #I9T1F8:添加流程实例的时候异常 添加流程实例的时候异常
* 优化代码结构,调整查询条件类名
* 修复流程审批字符串比较
* 删除CodeSmith生成WebApi
### v6.2
* [新增] 模块可以配置界面是否缓存
* [新增] vue版本调整根据需要加载自定义表单而不是初始化时全部加载
* [修复] fix #I949OU:Oracle启动的时候提示视图不存在 Oracle启动的时候提示视图不存在
* [修复] fix #I8WCQ8:定时任务添加本地任务时不应该显示HTTPPOST 定时任务添加本地任务时不应该显示HTTPPOST
### v6.1
* 全网最好用的打印解决方案。详情:[智能打印](http://doc.openauth.net.cn/pro/printerplan.html)
* 增加PDManer数据结构说明;
### v6.0
* 全面支持SqlSugar Orm。详情[sqlsugar访问数据库](http://doc.openauth.net.cn/core/sqlsugar.html)
* 全面更新mvc版本升级layui版本至最新v2.8.11
* 升级.Net版本6.0,所有三方组件全面更新;
### v5.0
* 新增Oracle数据库驱动;
* 支持同时配置多个类型数据库的连接字符串;
* 调整APP层文件结构按功能划分
* 流程表单项增加读写权限控制;
* 代码生成器设置可以控制界面展示;
* 流程处理增加消息通知;
* 优化swagger分组
### v4.0
* 【新增】集成Variant Form - 可视化低代码表单;
* 【新增】完成vue3 setup模式单表代码生成
### v3.3
* 【新增】流程表单项增加读写权限控制;
* 【新增】代码生成器增加主从表生成;
* 【新增】代码生成器设置可以控制界面展示;
* 【新增】流程处理增加消息通知;
* 【新增】优化swagger分组
### v3.2
* 【新增】在swagger界面查看接口调用时间及SQL执行时间; [查看使用说明](http://doc.openauth.net.cn/core/log.html#%E5%9C%A8swagger%E4%B8%AD%E8%BE%93%E5%87%BA%E6%97%A5%E5%BF%97 )
* 【新增】swagger接口分组;
* 【新增】流程编辑功能(草稿或驳回状态时);
* 【新增】流程召回功能;
* 【新增】运行时选定执行人、执行角色功能;
* 【新增】自定义模态验证异常返回信息;
* 【新增】配置启动端口;
### v3.1
* 【新增】Oracle数据库驱动
* 【新增】流程召回功能
* 【新增】调整APP层文件结构按功能划分
* 【新增】支持同时配置多个类型数据库的连接字符串,详见:[这里](http://doc.openauth.net.cn/core/multidbs.html)
### v3.0
* 【新增】多数据源支持
* 【新增】提供全新的事务接口方式
* 【新增】新增异步接口
* 【新增】新增灵活的API提交数据验证
* 【新增】新增附件管理,上传图片支持生成缩略图
* 【新增】调整代码生成器把CodeSmith改为站内代码生成
### v2.1
* 【新增】为角色分配用户
* 【新增】为部门分配用户
### v2.0
* 【新增】框架升级至.net core sdk 3.1.100
* 【新增】增加`个人中心`页面,可修改个人信息及切换当前默认部门
* 【优化】升级layui至2.5.6
* 【优化】可以灵活配置用户可访问的机构数据权限
* 【优化】优化会签功能呢
* 【优化】优化角色添加自动关联当前登录用户
### v1.6
* 【优化】优化导航排序、支持多级导航
* 【优化】企业版启用全新登录界面;
* 【新增】启用数据字典功能;
* 【新增】日志及用户消息板块;
* 【新增】企业版代码生成器,可以快速生成带有头/明细结构的页面;
* 【新增】数据权限控制,超强的自定义权限控制功能。详见:[这里](https://www.cnblogs.com/yubaolee/p/DataPrivilege.html)
* 【新增】完整的字段权限控制可以控制字段可见及API是否返回字段值
### v1.5
* 【优化】升级layui至2.5.4
* 【优化】流程处理页面展示流转记录;
* 【优化】流程支持角色审批;
* 【新增】集成IdentityServer4实现基于OAuth2的登录体系
* 【新增】建立三方对接规范,已有系统可以无缝对接流程引擎;
### v1.4
* 【优化】升级layui至2.4.5
* 【优化】升级vue至2.6.10
* 【优化】全面重写界面初始化交互优化layui与vue数据初始读取
* 【新增】全面实现数据字段权限控制。针对自定义模块,可以为角色分配可见字段;
* 【新增】模块可隐藏功能,只授权,但不在导航栏显示;
### v1.3
* 基于.Net Core 2.1开发;
* 全面支持sqlserver、mysql数据库
* 全面实现模块控制、菜单控制;
* 完整的代码生成器pro版本提供;
* 前端采用 vue + gooflow + leipiformdesign
* 后端采用 asp.net mvc core 2.1 + EF core+ autofac + json.net
* 代码生成工具 CodeSmith
* 设计工具 PowerDesigner + Enterprise Architect

View File

@ -0,0 +1,32 @@
---
title: 切换sdk版本
createTime: 2025/04/23 21:03:10
permalink: /core/changesdk/
---
# 切换sdk版本
OpenAuth.Net最新版默认使用.Net SDK 9.0.100。如果你使用的是其他版本的sdk如.net 6.0/7.0等打开项目需要调整csproj项目文件的TargetFramework。用记事本等工具打开 `Infrastructure.csproj` `OpenAuth.Repository.csproj` `OpenAuth.App.csproj` `OpenAuth.Mvc.csproj` `OpenAuth.WebApi.csproj` `OpenAuth.IdentityServer.csproj`,将
```csharp
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
```
修改为
```csharp
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
```
保存,然后依次编译,如果报错,按照提示修改,直到成功。
## VS2019打开6.0及以后版本
VS2019不支持.net 6.0及以后的版本。如果打开项目需要调整csproj项目文件。调整为
```csharp
<PropertyGroup>
<TargetFrameworks>net5.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(MSBuildVersion)' &gt;= '17.0' ">$(TargetFrameworks);net6.0</TargetFrameworks>
</PropertyGroup>
```
当然建议使用最新版visual studio

View File

@ -0,0 +1,8 @@
---
title: 数据权限
createTime: 2025/04/23 21:03:10
permalink: /core/dataprivilege/
---
# 数据权限
关于数据权限控制,可以详细查看博文:[通用权限设计与实现](https://www.cnblogs.com/yubaolee/p/DataPrivilege.html)

View File

@ -0,0 +1,92 @@
---
title: 字段权限
createTime: 2025/04/23 21:03:10
permalink: /core/datapropertyrule/
---
# 字段权限
::: warning 注意
字段权限只针对【非系统模块】有效即在添加新模块的时候需要设置模块属性“是否系统”为false。
:::
## 使用场景
字段权限控制分为两种:
1. 直接不返回字段的值。用于敏感数据不向客户端反馈。
1. 返回字段的值但界面不显示。常常用于数据需要和后端交互但不想在界面显示比如各种Id。这种直接在返回实体增加`[Browsable(false)]`注解即可。
## 如何做?
### 后端代码处理
针对场景1在做返回处理的时候需要过滤数据库查询字段如下本文以Resource表为例
```csharp
var columnFields = loginContext.GetTableColumnsFromDb("Resource");
if (columnFields == null || columnFields.Count == 0)
{
throw new Exception("未找到Resource表的字段属性");
}
var propertyStr = string.Join(',', columnFields.Select(u => u.ColumnName));
result.columnFields = columnFields;
result.data = resources.OrderBy(u => u.TypeId)
.Skip((request.page - 1) * request.limit)
.Take(request.limit).Select($"new ({propertyStr})");
result.count = await resources.CountAsync();
return result;
```
::: warning 注意
因为开源版没有代码生成器所以需要直接从数据读取表的字段结构使用的是loginContext.GetTableColumnsFromDb获取可访问的字段
:::
### 前端代码处理
在做表格的时候需要使用动态列。以`Views/Resources/index.cshtml`为例,如下:
```HTML
<table class="layui-table" id="mainList"
lay-data="{height: 'full-80', page:true, id:'mainList'}"
lay-filter="list" lay-size="sm">
</table>
```
在用户自定义的脚本`wwwroot/userJs/resources.js`中,动态加载列:
```javascript
//加载表头
$.getJSON('/Resources/Load',
{ page: 1, limit: 1 },
function (data) {
var columns = data.columnFields.filter(u => u.IsList ===true).map(function (e) {
return {
field: e.ColumnName,
title: e.Remark
};
});
columns.unshift({
type: 'checkbox',
fixed: 'left'
});
table.render({
elem: '#mainList',
page: true,
url: '/Resources/Load',
cols: [columns]
, response: {
statusCode: 200 //规定成功的状态码默认0
}
});
});
```
### 运行界面配置
完成代码编写后,在【基础配置】--【角色管理】--【为角色分配模块】最后为角色分配【可见字段】中分配权限
![](/roleassignproperty.png)

View File

@ -0,0 +1,63 @@
---
title: WebApi请求验证
createTime: 2025/04/23 21:03:10
permalink: /core/datavalidation/
---
# WebApi请求验证
框架提供灵活的实体模型验证功能。可以方便地对实体进行验证。只需两步即可:
## 增加注解
在请求参数中添加验证注解
```csharp
namespace OpenAuth.App.Request
{
public class UpdateUserReq
{
/// <summary>
/// </summary>
/// <returns></returns>
[Required(ErrorMessage = "账号肯定不能为空啊~~")]
public string Account { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
/// <returns></returns>
[Required(ErrorMessage="姓名不能为空")]
public string Name { get; set; }
/// <summary>
/// 所属组织Id多个可用分隔
/// </summary>
/// <value>The organizations.</value>
[Required(ErrorMessage = "请为用户分配机构")]
public string OrganizationIds { get; set; }
...
}
}
```
## 业务代码中验证
在OpenAuth.App中调用验证
```csharp
namespace OpenAuth.App
{
public class UserManagerApp : BaseApp<User,OpenAuthDBContext>
{
public void AddOrUpdate(UpdateUserReq request)
{
//验证Account/Name/OrganizationIds
request.ValidationEntity(u => new {u.Account,u.Name, u.OrganizationIds});
...//其他代码略
}
}
}
```

View File

@ -0,0 +1,84 @@
---
title: 部署
createTime: 2025/04/23 21:03:10
permalink: /core/deploy/
---
# 部署MVC
::: tip 提示
因.net core内部有自托管的Web服务器推荐使用控制台方式部署。本内容基于控制台命令的方式。如果部署到IIS请自行百度:cold_sweat:
:::
## 生成发布文件
* 修改部署环境的连接字符串信息,特别注意是`appsettings.Production.json`文件:
![说明](/configmvc.png "说明")
::: warning 注意
决定系统部署后读取`appsettings.json`还是`appsettings.Production.json`是通过操作系统的环境变量`ASPNETCORE_ENVIRONMENT`来控制的。
在centos切换成正式可以用
```shell
export ASPNETCORE_ENVIRONMENT=Production
```
或者修改/etc/profile配置在结尾添加
```shell
ASPNETCORE_ENVIRONMENT=Production
export ASPNETCORE_ENVIRONMENT
```
然后刷新:
```shell
source /etc/profile
```
在Widows系统中增加对应环境变量即可
:::
* 直接在解决方案资源管理器中选中OpenAuth.Mvc右键【发布】出现下面的配置框使用文件系统即可
![说明](http://pj.openauth.net.cn/zentao/file-read-8.png "说明")
* 发布完成后可以在输出目录看到发布详情(红色框内即为发布的文件夹):
![说明](http://pj.openauth.net.cn/zentao/file-read-69.png "说明")
## 部署OpenAuth.Mvc
将发布后的文件拷贝到服务器文件夹。直接使用`dotnet openauth.mvc.dll` 命令启动。启动成功后使用浏览器打开http://localhost:1802 即可访问,如下图所示:
![说明](/mvcmain.png "说明")
## jenkins部署OpenAuth.Mvc
OpenAuth.Net采用的是gitee托管源码只需使用Gitee WebHook构建触发器。配置如下
![说明](/giteesource.png "说明")
做好上面的配置后代码提交时就会触发jenkins工作。剩下的就是编写自己的构建脚本。增加构建步骤选择执行Shell。并输入以下脚本
```shell
#!/bin/bash
kill -9 $(ps -ef|grep OpenAuth.Mvc.dll|grep -v grep|awk '{print $2}')
#项目启动之后才不会被Jenkins杀掉
export BUILD_ID=dontKillMe
pwd
echo $PATH
dotnet restore # 还原nuget包
cd ./OpenAuth.Mvc
dotnet build # 编译
rm -rf /data/openauthmvc #最终站点路径
mkdir /data/openauthmvc
dotnet publish -c:Release -o /data/openauthmvc # 生成发布文件到/data/openauthmvc。如果服务器上有多个.NET版本加上目标版本号-f net6.0
nohup dotnet /data/openauthmvc/OpenAuth.Mvc.dll &
echo '============================end build======================================='
```

View File

@ -0,0 +1,92 @@
---
title: 部署API
createTime: 2025/04/23 21:03:10
permalink: /core/deployapi/
---
# 部署API
## 生成发布文件
* 修改部署环境的连接字符串信息,特别注意是`appsettings.Production.json`文件:
![20220101232738](http://img.openauth.net.cn/20220101232738.png)
::: warning 注意
决定系统部署后读取`appsettings.json`还是`appsettings.Production.json`是通过操作系统的环境变量`ASPNETCORE_ENVIRONMENT`来控制的。
在centos切换成正式可以用
```shell
export ASPNETCORE_ENVIRONMENT=Production
```
或者修改/etc/profile配置在结尾添加
```shell
ASPNETCORE_ENVIRONMENT=Production
export ASPNETCORE_ENVIRONMENT
```
然后刷新:
```shell
source /etc/profile
```
在Widows系统中增加对应环境变量即可
:::
* 直接在解决方案资源管理器中选中OpenAuth.WebApi右键【发布】出现下面的配置框使用文件系统即可
![20220101232912](http://img.openauth.net.cn/20220101232912.png)
* 发布完成后可以在输出目录看到发布详情(红色框内即为发布的文件夹):
![20220101233049](http://img.openauth.net.cn/20220101233049.png)
* 将Debug目录中的OpenAuth.WebApi.xml拷贝到发布文件夹publish:
![20220101235436](http://img.openauth.net.cn/20220101235436.png)
## 部署OpenAuth.WebApi
将发布后的文件拷贝到服务器文件夹。直接使用`dotnet OpenAuth.WebApi.dll` 命令启动。启动成功后使用浏览器打开[http://localhost:52789/swagger/index.html](http://localhost:52789/swagger/index.html) 即可访问,如下图所示:
![20220101233542](http://img.openauth.net.cn/20220101233542.png)
## jenkins部署OpenAuth.WebApi
OpenAuth.Net采用的是gitee托管源码只需使用Gitee WebHook构建触发器。配置如下
![说明](/giteesource.png "说明")
做好上面的配置后代码提交时就会触发jenkins工作。剩下的就是编写自己的构建脚本。增加构建步骤选择执行Shell。并输入以下脚本
```shell
#!/bin/bash
kill -9 $(ps -ef|grep OpenAuth.WebApi.dll|grep -v grep|awk '{print $2}')
#export BUILD_ID=dontKillMe这一句很重要这样指定了项目启动之后才不会被Jenkins杀掉。
export BUILD_ID=dontKillMe
pwd
echo $PATH
dotnet restore
cd ./OpenAuth.WebApi
pwd
echo '============================begin build======================================='
dotnet build # 为了生成XML注释文件 用于swagger注释
rm -rf /data/openauthapi
mkdir /data/openauthapi
cp ./bin/Debug/netcoreapp3.1/OpenAuth.Repository.xml /data/openauthapi/
cp ./bin/Debug/netcoreapp3.1/OpenAuth.App.xml /data/openauthapi/
cp ./bin/Debug/netcoreapp3.1/Infrastructure.xml /data/openauthapi/
dotnet publish -c:Release -o /data/openauthapi # 如果服务器上有多个.NET版本加上目标版本号-f net6.0
nohup dotnet /data/openauthapi/OpenAuth.WebApi.dll &
#cp ./bin/Debug/netcoreapp2.0/您的项目路径.xml $WORKSPACE/jenkins_publish/ # 拷贝swagger注释
echo '============================end build======================================='
```

View File

@ -0,0 +1,99 @@
---
title: 添加新模块
createTime: 2025/04/23 21:03:10
permalink: /core/devnew/
---
# 添加新模块
## 前言
OpenAuth.Mvc添加新模块的方式非常简单完全可以参考系统已有的`资源管理`模块编写相应的代码。参考的`资源管理`功能对应的代码如下:
![](http://pj.openauth.net.cn/zentao/file-read-55.png)
如果我们想新加一个仓储管理的模块,模块标识为`Stock`。那么需要添加的文件如下:
├─OpenAuth.Mvc
│ ├─ Controllers
│ │ └─ StocksController.cs
│ ├─ Views
│ │ └─ Stocks
│ │ └─ index.cshtml
│ ├─ wwwroot
│ │ └─ userJs
│ │ └─ stock.js
├─OpenAuth.App
│ ├─ StockApp.cs
│ ├─ Request
│ │ └─ QueryStockReq.cs
├─ OpenAuth.Repository
│ ├─ OpenAuthDBContext.cs
│ ├─ Domain
│ └─ Stock.cs
当然全部手撸这些代码还是会疯的。用户可以直接使用项目`CodeSmith`文件夹里面的模板一键生成上述代码。而且CodeSmith模板本身也是全部源码可以根据自己需求调整生成的内容。
## 工具准备
CodeSmith Generator Studio 8.0或以上
数据库OpenAuthDB中添加仓储表【Stock】本文以该数据表为例
## 添加实体
如下图使用CodeSmith文件夹中的模板右击【ApiGenerate.cst】--【Execute】选择需要生成的表本文以Stock为例及相关的上下文命名空间点击【Generate】
![20240613220037](http://img.openauth.net.cn/20240613220037.png)
注意,有两个配置项:
* WholeDb: 如果选中,则按数据库中所有表生成实体及逻辑;否则,按选择的表生成
* HeaderModel会生成主、从表结构类似 WmsInboundOrderTbl / WmsInboundOrderDtbl
生成成功后在CodeSmith/Csharp文件夹下面会有Stock实体相关文档如下图
![20240613220224](http://img.openauth.net.cn/20240613220224.png)
把CSharp\OpenAuth.App覆盖到自己项目对应目录
把CSharp\OpenAuth.Repository\Domain覆盖到自己项目对应目录
**把CSharp\OpenAuth.Repository\OpenAuthDBContext.cs中的内容添加到自己项目的文件中千万不要直接覆盖文件**
## 添加界面
如下图使用CodeSmith文件夹中的模板右击【WebGenerate.cst】--【Execute】选择需要生成的表本文以Stock为例及相关的上下文命名空间点击【Generate】
![](http://img.openauth.net.cn/2025-02-25-10-56-08.png)
生成成功后在CodeSmith/Csharp文件夹下面会有相关的界面代码如下图
![](http://img.openauth.net.cn/2025-02-25-10-57-44.png)
Controllers、Views直接覆盖到OpenAuth.Mvc项目中对应的文件夹即可
userJs直接覆盖到OpenAuth.Mvc/wwwroot中
## 添加模块
编写完上面代码后运行系统使用System账号登录系统在【模块管理】中添加`仓储管理`模块,
![20240613220434](http://img.openauth.net.cn/20240613220434.png)
::: warning 注意
因为生成的Controller名称类似XXXsController所以模块的Url地址应该是XXXs/Index
:::
添加模块时系统会自动添加三个默认菜单【添加】【编辑】【删除】。可根据需要调整。这里我再添加一个菜单【btnCancel】如下图
![](http://img.openauth.net.cn/2025-02-25-11-05-08.png)
重新登录系统,即可看到新加的仓储管理模块。
![](http://img.openauth.net.cn/2025-02-25-11-08-26.png)

View File

@ -0,0 +1,102 @@
---
title: 动态API
createTime: 2025/04/23 21:03:10
permalink: /core/dynamicapi/
---
# 动态API
加快系统开发速度框架提供动态API功能可以实现无代码调整操作数据库。
## 数据库操作
在开发过程中对于有些简单表的处理如果每次都编写对应的增删改查会增加工作量且代码臃肿。这时我们可以使用动态API来处理。只需要前端按规范调用即可后端无需做任何工作。OpenAuth.Net的动态API支持以下功能
- 新增记录 `/api/dynamicapi/add`
- 修改记录 `/api/dynamicapi/update`
- 删除记录 `/api/dynamicapi/delete`
- 查询单条 `/api/dynamicapi/get`
- 查询列表 `/api/dynamicapi/getlist`
具体的参数可以查询对应的接口文档。我们以一个简单的表`noentity`为例来说明如何使用动态API。
```sql
CREATE TABLE `noentity` (
`id` varchar(50) NOT NULL,
`name` varchar(255) NULL,
`age` int(11) NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
无需在后端添加任何代码,只需前端按规范调用即可。
#### 新增记录
前端请求方式为`POST`,请求地址为`/api/dynamicapi/add`,请求参数为:
```json
{
"tableName": "noentity",
"obj": "{\"name\":\"测试\"}"
}
```
#### 修改记录
前端请求方式为`POST`,请求地址为`/api/dynamicapi/update`,请求参数为:
```json
{
"tableName": "noentity",
"obj": "{\"id\":\"1\",\"name\":\"测试新\"}"
}
```
注意修改的时候必须包含主键Id字段。
#### 删除记录
前端请求方式为`POST`,请求地址为`/api/dynamicapi/delete`,请求参数为:
```json
{
"tableName": "noentity",
"ids": ["1"]
}
```
#### 查询单条记录
前端请求方式为`POST`,请求地址为`/api/dynamicapi/get`,请求参数为:
```json
{
"tableName": "noentity",
"id": "1"
}
```
#### 查询列表
前端请求方式为`POST`,请求地址为`/api/dynamicapi/getlist`,请求参数为:
```json
{
"tableName": "noentity",
"pageIndex": 1,
"pageSize": 10
}
```
## 调用已有模块
除了数据库操作,系统内置一个接口`/api/dynamic/Invoke`前端可以直接通过这个接口调用OpenAuth.App层的方法。
```json
{
"serviceName": "UserManagerApp",
"methodName": "Load",
"parameters": "{\"request\":{\"page\":1,\"limit\":10,\"key\":\"\"}}"
}
```

View File

@ -0,0 +1,132 @@
---
title: 数据库实体
createTime: 2025/04/23 21:03:10
permalink: /core/entity/
---
# 数据库实体
## 更换主键名称
系统默认的主键是以`Id`命名,如果数据库主键是其他名称,可以直接用注解进行更改:
```csharp
[Column("CustomerId")]
public string Id { get; set; }
```
## 如何添加主键类型为numberic的业务代码
如果数据库表中存在其他类型的主键,可以通过继承`BaseEntity`实现。目前系统默认有三个实体基类:
- `StringEntity`针对数据库主键为varchar类型的数据表,主键按guid方式生成;
- `LongEntity`针对数据库主键为numberic(15)的数据表,主键按雪花算法生成;【新功能,官方推荐使用方式👍】
- `IntAutoGenEntity`针对数据库主键为numberic且为数据库自动生成的类型表通常为SqlServer的自动增长类型和Oracle的Sequence生成【新功能】
这三个基类可以覆盖90%以上的业务场景。如果这两个不能满足需求,可以自己按需求扩展。参考代码如下:
```csharp
/// <summary>
/// 数据库Id为int类型的数据实体使用该基类用法同Entity
/// </summary>
public class IntEntity :BaseEntity
{
[Browsable(false)]
public int Id { get; set; }
public override bool KeyIsNull()
{
return Id == 0;
}
/// <summary>
/// 需要自己有个生成随机ID的算法可参考LongEntity中的雪花算法
/// </summary>
public override void GenerateDefaultKeyVal()
{
Id = RandomInt();
}
}
```
## 具体如何做
我们以一个主键为numeric(16)的表表名为LongTable为例
```SQL
create table LongTable
(
Id numeric(16) not null
constraint LongTable_pk
primary key nonclustered,
Name varchar(50)
)
go
```
1. 首先创建对应的业务实体。在`OpenAuth.Repository.Domain`中添加:
```csharp
namespace OpenAuth.Repository.Domain
{
[Table("LongTable")]
public class LongTable :LongEntity
{
public string Name { get; set; }
}
}
```
2. 修改`OpenAuth.Repository.OpenAuthDBContext`,增加成员变量:
```csharp
public virtual DbSet<LongTable> IntTables { get; set; }
```
3. 最后创建对应的业务层代码。在`OpenAuth.App`中添加:
```csharp
namespace OpenAuth.App
{
/// <summary>
/// 主键为numberic类型的业务使用BaseLongApp基类
/// </summary>
public class LongTableApp :BaseLongApp<LongTable, OpenAuthDBContext>
{
public void Add(LongTable application)
{
Repository.Add(application);
}
public void Update(LongTable application)
{
Repository.Update(application);
}
public async Task<List<LongTable>> GetList(QueryAppListReq request)
{
var applications = UnitWork.Find<LongTable>(null) ;
return applications.ToList();
}
public LongTableApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<LongTable,OpenAuthDBContext> repository,IAuth auth)
: base(unitWork, repository, auth)
{
}
}
}
```
然后就可以像其他应用服务一样使用这个服务
::: warning 注意
最新版才支持以前的版本2.0或以前的版本可以参考BaseEntity进行改造
:::

View File

@ -0,0 +1,113 @@
---
title: 常见问题处理
createTime: 2025/04/23 21:03:10
permalink: /core/faq/
---
# 常见问题处理
## 注释的使用
在Controller返回给前端的字段上通常会有两个“注释”如下
```csharp
/// <summary>
/// 用户登录帐号
/// </summary>
[Description("用户登录帐号")]
public string Account { get; set; }
```
开发者在使用的时候会觉得多余。但他们的用途不同:
* /// 注释是真正的代码注释用于方便读取代码并为swagger提供字段解释
* Description注解是当前端表格需要动态表头时返回的表头中文说明
## 项目显示不可用
![](/notavailable.png)
这种情况一般是开发工具或SDK的版本号不对。严格按照下面的提示打开项目
* v2.0及以后版本因使用.net core 3.1必须使用visual Studio 2019及以上版本打开
* v2.0以前的版本可以使用visual Studio 2017 及.net core 2.1.4
## 系统使用Sql Server 2008数据库的问题
在使用Sql Server 2008时会提示下面错误
> System.Data.SqlClient.SqlException:“'OFFSET' 附近有语法错误。在 FETCH 语句中选项 NEXT 的用法无效。
因为SQL SERVER 2008 不支持FETCH分页方式所以需要在startup.cs中修改配置
```csharp
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=OpenAuthDB;User=sa;Password=123456;Integrated Security=True;",
b => b.UseRowNumberForPaging());
```
即使用rownumber的分页方式。 当然最好的解决方式是升级SQL SERVER到2012或以上版本。
::: warning 注意
目前.Net的SDK已经放弃了这种方式因此只能通过升级Sql Server的方式解决该问题
:::
## 使用mysql时提示无法找到openauthdb.Org
在linux下面mysql是区分数据库大小写的但OpenAuth.Net使用EF映射数据库表是按照首字母大写来处理的。在mysql配置中里面加上
```shell
lower_case_table_names=1
```
从而不区分大小写,即可解决该问题
## WebApi里增加一个控制器,Swagger不显示
需要在控制器上面添加注释,如:
```csharp
/// <summary> 文件上传</summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class FilesController :ControllerBase
```
## 实体没有主键
定义一个实体有时会出现没有主键的问题即提示“Unable to track an instance of type xxxx because it does not have a primary key.”,这时可以强制在`OpenAuthDbContext.cs`中指定一个主键,如下:
```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DataPrivilegeRule>()
.HasKey(c => new { c.Id });
}
```
## 新添加数据,马上执行【删除】,不能删除数据库记录
原因新增记录时没有返回新增数据的ID信息导致删除不成功。
#### 解决方法一
重新加载列表,直接把 this.list.unshift(this.temp)换成this.getList()。如下:
```javascript
createData() {
// 保存提交
this.$refs['dataForm'].validate((valid) => {
if (valid) {
categorys.add(this.temp).then(() => {
this.getList();
...
})
}
})
},
```
#### 解决方法二
执行添加后把Id返回给前端界面。详情请参考网友博客[OpenAuth.net入门【5】——解决添加完数据在未刷新列表时执行删除数据未被真正删除的问题](https://www.cnblogs.com/wjx-blog/p/15892811.html)

View File

@ -0,0 +1,105 @@
---
title: 工作流实例
createTime: 2025/04/23 21:03:10
permalink: /core/flowinstance/
---
# 工作流介绍
OpenAuth.Net工作流基于国际标准的BPMN2.0规范,并在此基础上做了一些扩展,以满足国内各种需求。系统工作流分为两个大类:
1. 无业务关联流程,如请假、报销等。
![无业务关联流程](http://img.openauth.net.cn/2025-04-06-22-35-35.png)
2. 有业务关联流程,如采购、销售等。
![订单送审](http://img.openauth.net.cn/2025-04-06-22-34-34.png)
这两种流程的差异有以下几点:
| 对比维度 | 无业务关联流程 | 有业务关联流程 |
|---------|--------------|--------------|
| 适用场景 | 请假、报销等日常办公 | 采购、销售、入库等业务操作 |
| 发起方式 | 流程中心 -> 我的流程 -> 新的申请 | 直接在业务模块中发起(如:仓储中心 -> 入库订单 -> 送审) |
| 表单类型 | 简单表单,适用拖拽表单设计器 | 复杂表单需要自定义表单或URL表单 |
| 审批结束处理 | 仅更新流程状态 | 需要修改业务数据状态 |
表中提到的表单类型差异可以查看:[表单设计](./form.md)
# 基本操作
一个完整的工作流从设计到发起,到审批,需要经过:
1. 表单设计:【基础配置/表单设计】中添加一个用于流程的表单;
2. 流程设计:【基础配置/流程设计】中添加一个流程模版,流程模版选择刚刚建的表单;
3. 流程发起:【流程中心/我的流程】中【新的申请】创建一个流程实例,或在业务系统中直接【送审】发起;
4. 流程审批:【流程中心/待处理流程】中进行审批;
这里只介绍开源版本的操作流程vue版本操作流程请参考👉[操作手册](/pro/startflow.md)
## 流程设计
在【基础配置/流程设计】界面,点击“添加模板”。填写好流程模板的名称及需要的信息。点击“选择表单”选择流程关联的表单。
![2025-04-19-10-16-58](http://img.openauth.net.cn/2025-04-19-10-16-58.png)
流程模版使用的表单,需要在【基础配置/表单设计】中添加,具体查看[表单设计-基本介绍](/core/form.html)
选择好表单后,点击“流程设计”进入流程设计。
![2025-04-19-10-19-59](http://img.openauth.net.cn/2025-04-19-10-19-59.png)
#### 节点属性
* 节点名称:**必填** 节点名称
* 三方回调URL当节点审批完成时如果需要通知其他系统或模块,则填写对应系统的接口地址。
* 执行权限 **必填** 节点的执行权限,如:指定用户、指定角色等。
* 所有用户: 任何人都可以审批
* 指定用户:指定用户审批,当选中这项时需要选择指定的用户
* 指定角色:指定角色审批,当选中这项时需要选择指定的角色
👉使用[vue版本](/pro/startflow.html)解锁更多类型指定SQL、上一节点执行人的直属上级、连续多级直属上级、部门负责人、运行时指定角色、运行时指定用户等等当然你也可以为[开源版本](https://gitee.com/dotnetchina/OpenAuth.Net)贡献代码,添加更多类型。
👉使用[vue版本](/pro/startflow.html),设置连线条件属性。你也可以为[开源版本](https://gitee.com/dotnetchina/OpenAuth.Net)贡献代码,让它支持该属性。
## 流程发起
开源版本只能发起无业务关联的流程,使用[vue版本](/pro/startflow.html),解锁有业务类型关联的流程。当然你也可以为[开源版本](https://gitee.com/dotnetchina/OpenAuth.Net)贡献代码,支持更多类型。
### 无业务关联流程
完成流程模版设计后,在【流程中心/我的流程】中【新的申请】开始创建一个流程实例。
![2025-04-19-10-37-09](http://img.openauth.net.cn/2025-04-19-10-37-09.png)
1. 在左边选择流程模版;
2. 填写待审批的表单内容;
3. 保存完成后,在【流程中心/我的流程】中点击“搜索”按钮刷新查询,就可以看到刚刚发起的流程实例。
## 流程审批
用户可以在【流程中心/待处理流程】中看到自己需要审批的流程,点击【处理】按钮并进行相应的处理;
![2025-04-19-22-46-06](http://img.openauth.net.cn/2025-04-19-22-46-06.png)
其中:
* 同意:流程审批通过,流程结束;
* 不同意:流程审批不通过,流程结束;
* 驳回:可以驳回到指定的步骤,该步骤的人可以重新审批提交;
👉使用[vue版本](/pro/startflow.html),解锁更多加签、撤销审批操作。你也可以为[开源版本](https://gitee.com/dotnetchina/OpenAuth.Net)贡献代码,让它支持这些功能。

View File

@ -0,0 +1,78 @@
---
title: 工作流中的概念
createTime: 2025/04/23 21:03:10
permalink: /core/flowinstanceconcept/
---
# 工作流中的概念
## 并行网关
并行网关处理的是流程分支和汇聚,每个分支可以是不同的业务逻辑和不同的处理人。它有以下特点:
- 分支时:所有出口流向都会被激活(创建多条并行路径)
- 汇聚时:等待所有进入的分支完成才继续往下执行
- 每条路径通常由不同的活动和不同的处理人完成
- 路径之间互相独立
在网关开始时(即分支时),可以设置并行网关的类型,目前支持两种模式:全部通过和至少一个通过。如下:
![2025-04-20-20-26-28](http://img.openauth.net.cn/2025-04-20-20-26-28.png)
全部通过:网关所有分支审批通过,节点审批通过。
至少一个通过:网关中任意一个分支审批通过,节点审批通过。
具体的审批人员或角色,需要在【网关开始】和【网关结束】之间的节点配置,如上图中的直接上级、公司副总、公司总裁等。
## 会签
会签又称为联名签署,处理的是同一个任务需要多人审批的情况。它的特点:
- 是同一个任务的多个副本
- 分配给多个执行人执行相同的工作
- 可以设置完成条件(如全部通过、部分通过即可)
- 处理的是同一个业务节点,只是执行人不同
![2025-04-20-20-58-50](http://img.openauth.net.cn/2025-04-20-20-58-50.png)
## 加签
有时需要在原有审批流程中**临时**增加一个或多个审批节点,这时就需要用到加签的功能。它通常有以下特性:
* 临时性:加签是在流程执行过程中临时增加的,并非流程设计时就已经固定的审批节点。
* 发起主体:加签通常由当前审批人发起,他们认为需要额外的人员进行审核或批准。
* 新增审批节点:加签会在当前审批节点之后,插入一个或多个新的审批节点,这些节点需要审批通过后,原流程才能继续执行。
* 不改变流程结构:加签不会改变原有流程的整体逻辑或终点,只是插入临时节点,完成后流程继续按原定路径执行。
#### 与会签的区别:
* 加签:在已有审批流程上临时添加审批人,原审批人仍有审批权。
* 会签:多个审批人同时审批,所有会签人均需审批,才能通过节点。
加签功能常用在遇到不明确的情况时,需要其他人协助处理。
![2024-10-22-15-24-08](http://img.openauth.net.cn/2024-10-22-15-24-08.png)
## 条件分支
有时需要根据提交数据不同(如报销金额、请假天数等)流程转向不同的审批者。这时需要在连线上面配置分支条件,如下图:
![20240417114340](http://img.openauth.net.cn/20240417114340.png)
## 知会
知会指的是在流程执行过程中,将审批结果通知给指定人员,但这些人员不参与实际审批或决策过程。知会的目的是确保相关人员知晓流程的进展或结果,但他们不会影响流程的走向。如下图:
![2024-10-22-15-42-49](http://img.openauth.net.cn/2024-10-22-15-42-49.png)

View File

@ -0,0 +1,192 @@
---
title: 流程相关的代码
createTime: 2025/04/23 21:03:10
permalink: /core/flowinstancedev/
---
# 流程相关的代码
## 流程审批逻辑
当最终用户在【待处理流程】中审批一个流程实例时,流程实例会经过下面步骤进行处理:
@startuml
skinparam handwritten true
skinparam backgroundColor #EEEBDC
start
if (当前活动节点类型为会签) then (yes)
:标识当前节点状态;
:从所有的分支中找到一个用户可以审批的节点canCheckId;
if (没找到?) then (yes)
stop
endif
:标识canCheckId节点状态;
#HotPink:进行会签,结果为res;
if(res == TagState.No) then (yes)
:修改流程最终状态为不同意;
else if(res != string.Empty) then (yes)
stop
else (no)
:修改流程最终状态,修改活动节点,修改可执行人;
:添加扭转记录;
endif
else (no)
:标识当前节点状态;
if (同意) then (yes)
:修改流程最终状态,修改活动节点,修改可执行人;
:添加扭转记录;
else
:修改流程最终状态为不同意;
endif
:操作记录;
endif
stop
@enduml
## 流程模板
流程模板指流程的定义。数据存放在FlowScheme表中该表核心字段如下
#### FrmId流程模版关联的表单id
#### FrmType表单类型
#### SchemeContent流程实例的具体内容
该字段存储的是一个JSON对象具体内容如下所示
```javascript
{
"nodes": [
{
"type": "node", //节点类型,开始,普通,网关,会签等
"name": "任务节点", //节点名称
"icon": "iconfont icon-jiaoseguanli", //节点图标
"belongto": "commonNodes", //节点样式类型:普通四边形节点,菱形网关
"id": "node-011c37dd1db34596b9cbd6812971b8a6", //节点id
"setInfo": {
"NodeRejectType": 0, //节点驳回类型:
"NodeConfluenceType": "", //节点会签/网关类型
"NodeDesignate": "SPECIAL_ROLE",//执行权限类型:指定角色、指定用户等
"ThirdPartyUrl": "",//执行完成后回调地址
"NodeDesignateData": { //根据NodeDesignate不同表示不同的权限数据角色、用户等
"datas": [
"77e6d0c3-f9e1-4933-92c3-c1c6eef75593"
],
"Texts": "神"
},
"CanWriteFormItemIds": //可写表单项id
[
"radio113860",
"radio74071"
]
}
}
],
"lines": [
{
"type": "sl", //原有gooflow里面的值"sl":直线, "lr":中段可左右移动型折线, "tb":中段可上下移动型折线
"id": "link-6351c01fd31d4e6d85d476be6e0b0ae2",
"from": "start-3fcaf7e8577644ff8b52fabaf975437e",
"to": "node-011c37dd1db34596b9cbd6812971b8a6",
"label": "值>3", //连线上面显示的文字
"cls": {
"linkType": "Flowchart",
"linkColor": "#2a2929",
"linkThickness": 1
},
"Compares": [{ //连线条件
"FieldName": "Age", //表单项id
"Operation": ">", //条件类型
"Value": "3" //条件值
}]
},
{
"type": "sl",
"id": "link-785f8823a60e4472884f482b16c16f26",
"from": "node-011c37dd1db34596b9cbd6812971b8a6",
"to": "end-a749ef5b89bb49d588009b71f53316f5",
"label": "",
"cls": {
"linkType": "Flowchart",
"linkColor": "#2a2929",
"linkThickness": 1
}
}
]
}
```
其中nodes为流程实例的所有节点。lines为流程实例的所有连线。节点属性如下
###### 基础属性
| 属性名 | 类型 | 说明 | 可选值 |
|--------|------|------|---------|
| type | 字符串 | 节点类型 | start开始节点<br>node普通节点<br>fork分支节点<br>join合并节点<br>end结束节点 |
| name | 字符串 | 节点名称 | - |
| icon | 字符串 | 节点图标 | - |
| belongto | 字符串 | 节点样式类型 | - |
| id | 字符串 | 节点id | - |
###### 配置信息(setInfo)
####### 节点驳回配置
| 属性名 | 类型 | 说明 | 可选值 |
|--------|------|------|---------|
| NodeRejectType | 数字 | 节点驳回类型 | 0前一步<br>1第一步<br>2指定节点 |
| NodeRejectStep | 字符串 | 驳回节点id | 当NodeRejectType=2时使用 |
###### 节点会签/网关配置
| 属性名 | 类型 | 说明 | 可选值 |
|--------|------|------|---------|
| NodeConfluenceType | 字符串 | 节点会签/网关类型 | sequential顺序<br>all全部通过<br>one至少一个通过 |
###### 执行权限配置
| 属性名 | 类型 | 说明 | 可选值 |
|--------|------|------|---------|
| NodeDesignate | 字符串 | 执行权限类型 | SPECIAL_ROLE指定角色<br>SPECIAL_USER指定用户<br>SPECIAL_SQL指定SQL<br>RUNTIME_SPECIAL_ROLE运行时指定角色<br>RUNTIME_SPECIAL_USER运行时指定用户 |
| NodeDesignateData | 对象 | 执行权限数据 | - |
| NodeDesignateData.datas | 数组 | 执行权限数据 | - |
| NodeDesignateData.Texts | 字符串 | 执行权限数据 | - |
###### 其他配置
| 属性名 | 类型 | 说明 |
|--------|------|------|
| ThirdPartyUrl | 字符串 | 执行完成后回调地址 |
| CanWriteFormItemIds | 数组 | 可写表单项id |
## 流程实例
流程实例指正在运行的一个流程。数据存放在FlowInstance表中该表核心字段如下
#### IsFinish流程的当前状态
- -1 草稿/召回:流程发起人主动召回流程;
- 0 正在运行;
- 1 完成:流程结束,同时所有的审批都通过;
- 3 不同意:即流程结束,同时审批人员没有通过;
- 4 驳回:流程结束,可能发起的流程内容有问题,要求被驳回重新提交;
#### ActivityId: 当前活动节点,即待审批的节点
与流程实例密切相关的还有两个表流程实例的操作记录FlowInstanceOperationHistory及流转记录FlowInstanceTransitionHistory。它们有不同的作用
### 操作记录FlowInstanceOperationHistory
该表记录了流程实例的所有操作记录,包括流程的创建、撤回、驳回、同意、不同意等操作。
### 流转记录FlowInstanceTransitionHistory
记录某个流程实例所有已审批的从一个活动节点到下一个活动节点的操作人、操作时间。

View File

@ -0,0 +1,36 @@
---
title: 表单设计
createTime: 2025/04/23 21:03:10
permalink: /core/form/
---
# 表单设计
OpenAuth.Net集成了表单设计的功能目前表单仅用于流程审批。后期会集成到代码生成功能中。系统内置的表单类型有以下几种
## 动态表单
动态表单基于Ueditor富文本编辑器适用于灵活设计界面逻辑简单的表单。这种表单无需编码即可直接集成到流程功能。
::: warning 注意事项
因Vform功能已经全面覆盖Ueditor且用户体验更好所以动态表单在vue3版本已废弃目前开源版、vue2版本历史原因还保留。
:::
## URL表单
URL表单本质上不是实际存在的表单指的是审批的过程中审批内容是发起流程时传入的一个URL网址审批人员根据这个URL展示的内容进行审批。详细操作请参考[URL表单](/pro/urlform.html)
![URL表单流程](http://img.openauth.net.cn/2025-04-06-22-46-13.png)
## 自定义开发表单【企业版】
该类型表单需要开发者在源码中先编写好表单界面基于vue component,再提供给用户选择使用。适用于交互复杂的界面。详细请参考:[企业版工作流添加自定义表单](/pro/form.html)
![自定义开发表单](http://img.openauth.net.cn/2025-04-06-22-53-02.png)
## 可拖拽表单【企业版】
适用场景和普通的动态表单一样。但该表单操作方便,与系统界面风格匹配度高,缺点是排版没有普通的动态表单灵活,只能做简单的行排列。详细请参考:[可拖拽表单](/pro/dragform.html)

View File

@ -0,0 +1,82 @@
---
title: identity
createTime: 2025/04/23 21:03:10
permalink: /core/identity/
---
# 登录认证
OpenAuth.Net支持两种登录认证方式token认证和自己搭建的OpenAuth.IdentityServer认证。
这两种方式通过配置webapi或mvc的appsettings.json可以自由切换:
```json
"IdentityServerUrl": "http://localhost:12796", //IdentityServer服务器地址。如果为空则不启用OAuth认证
```
1. 当IdentityServerUrl为空时采用普通的token认证这时不需要OpenAuth.Identity启动支持。无论是OpenAuth.Mvc还是OpenAuth.WebApi都会在请求头中添加X-Token字段携带token值。以OpenAuth.WebApi为例客户端在访问的接口时先调用登录接口,得到授权token
![20220119182845](http://img.openauth.net.cn/20220119182845.png)
然后把获取到的token值添加到http header的X-Token中,即可调用对应的API接口。
![20220119182853](http://img.openauth.net.cn/20220119182853.png)
2. 当IdentityServerUrl配置了地址时则采用自己搭建的OpenAuth.IdentityServer认证方式。
不同于其他项目的统一登录(如微信登录、支付宝登录等),OpenAuth.Net的统一登录指的是自己搭建一套OAuth登录服务提供给其他项目使用。即OpenAuth.IdentityServer。这种模式下无论是OpenAuth.Mvc还是OpenAuth.WebApi都只是它的客户端。
![2025-03-18-23-12-18](http://img.openauth.net.cn/2025-03-18-23-12-18.png)
## OpenAuth.Mvc OAuth认证
当启用了Identity时系统启动后界面如下
![MVC启用identity](/mvcidentity.png "mvcidentity")
这时点击登录超链接会跳转到OpenAuth.Identity登录界面。效果如下
![](/identity.png)
## OpenAuth.WebApi OAuth
当启用了Identity时客户端调用API需要先通过OpenAuth.IdentityServer服务器的OAuth验证才能调用接口。OpenAuth.Net调用API的客户端有两种
#### OpenAuth.Pro vue3
在使用企业版vue界面访问OpenAuth.WebApi时已经在文件`.env.dev`中配置好相关选项,可以直接使用,无需其他处理。
```python
VITE_OIDC_AUTHORITY = http://localhost:12796 #Identity服务器地址
VITE_OIDC_CLIENTID = OpenAuth.Pro #客户端名称
VITE_OIDC_REDIRECTURI = http://localhost:1803 #登录回调
VITE_OIDC_RESPONSETYPE = code #认证方式
VITE_OIDC_SCOPE = openid profile openauthapi #认证范围
VITE_OIDC_AUTOMATICSILENTRENEW = true #自动续期
```
如果服务端启用了Identity认证则打开登录界面如下
![2025-03-10-14-46-47](http://img.openauth.net.cn/2025-03-10-14-46-47.png)
这时点击登录超链接操作同OpenAuth.Mvc一样。
#### SwaggerUI
当我们启动了OpenAuth.WebApi在浏览器打开[http://localhost:52789/swagger/index.html](http://localhost:52789/swagger/index.html)时其实是Swagger框架给我们生成的一个调动客户端对于启用了Identity的服务Swagger会有一个Authorise的操作按钮
![20220119180445](http://img.openauth.net.cn/20220119180445.png)
![20220119180503](http://img.openauth.net.cn/20220119180503.png)
点击登录超链接会跳转到OpenAuth.Identity登录界面。登录成功后会自动跳转回来。提示授权成功
![20220119180546](http://img.openauth.net.cn/20220119180546.png)
这时所有的接口都可以直接访问访问时会在http头上自动加认证信息
![20220119180608](http://img.openauth.net.cn/20220119180608.png)

View File

@ -0,0 +1,53 @@
---
title: 定时任务
createTime: 2025/04/23 21:03:10
permalink: /core/job/
---
# 定时任务
::: tip 提示
定时任务基于Quartz.Net开发
:::
## 编写任务代码
在OpenAuth.App中编写定时任务的执行代码。比如`TestJob`
```csharp
namespace OpenAuth.App.Jobs
{
public class TestJob : IJob
{
private OpenJobApp _openJobApp;
public TestJob(OpenJobApp openJobApp)
{
_openJobApp = openJobApp;
}
public Task Execute(IJobExecutionContext context)
{
var jobId = context.MergedJobDataMap.GetString(Define.JOBMAPKEY);
//todo:获取到定时任务的id可以可以加入自己的自动任务逻辑
_openJobApp.RecordRun(jobId);
return Task.Delay(1);
}
}
}
```
## 添加任务执行规则
编写完任务的执行代码后即可运行系统,在界面【基础配置】-【定时任务】中添加任务的执行规则,如图:
![](/addjob.png)
添加任务规则后,在界面直接点击`启用`即可
::: tip 提示
企业版提供可视化的CRON编辑界面,如图:
![](/addjobpro.png)
:::

View File

@ -0,0 +1,125 @@
---
title: 日志操作
createTime: 2025/04/23 21:03:10
permalink: /core/log/
---
# 日志操作
## 普通日志
框架默认使用Log4Net作为记录日志的方式可以在Program.cs中配置日志参数或调整为其他日志。日志默认按日期生成日志文件并存放在`log\`目录下。简单用法如下:
```csharp
//具体代码参考OpenAuth.App/OpenJobApp.cs此处简化真实逻辑方便理解
public void RecordRun(string jobId)
{
//其他代码略
_logger.LogInformation($"运行了自动任务:{job.JobName}");
}
public OpenJobApp(IUnitWork unitWork, IRepository<OpenJob> repository,
IAuth auth, ILogger<OpenJobApp> logger) : base(unitWork, repository, auth)
{
_logger = logger;
}
```
## 数据库日志
如果想使用数据库记录业务日志(如系统默认的用户操作日志等),可以使用`SysLogApp`模块功能。日志可以在站点【消息日志】->【系统日志】中查看到记录的日志信息。简单用法如下:
```csharp
//具体代码参考OpenAuth.App/OpenJobApp.cs此处简化真实逻辑方便理解
public void RecordRun(string jobId)
{
//其他代码略
_sysLogApp.Add(new SysLog
{
CreateName = "Quartz",
CreateId = "Quartz",
TypeName = "定时任务",
TypeId = "AUTOJOB",
Content = $"运行了自动任务:{job.JobName}"
});
}
public OpenJobApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<OpenJob,OpenAuthDBContext> repository,
IAuth auth, SysLogApp sysLogApp) : base(unitWork, repository, auth)
{
_sysLogApp = sysLogApp;
}
```
## EF打印Sql日志
在调试数据库时需要打印真正执行的SQL信息。最简单的方式是使用下面方法输出到控制台
```csharp
public partial class OpenAuthDBContext : DbContext
{
public static readonly ILoggerFactory MyLoggerFactory
= LoggerFactory.Create(builder => { builder.AddConsole(); });
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableSensitiveDataLogging (true); //允许打印参数
optionsBuilder.UseLoggerFactory (MyLoggerFactory);
base.OnConfiguring (optionsBuilder);
}
}
```
## EF输出Sql到log4net
框架目前直接配置`appsettings.Development.json`即可完成输出sql语句到log4net对应的日志文件中。如下
```
"Logging": {
"LogLevel": {
"Microsoft.EntityFrameworkCore.Database.Command": "Information" //EF输出SQL语句
}
}
```
正式发布环境下,如无特殊需求,建议在`appsettings.Production.json`配置中关闭该输出
## 在Swagger中输出日志
框架集成mini profiler工具在swagger中或其他客户端调用WebApi接口时可以直接在swagger中显示日志信息需要刷新。如下图
![](/miniprofiler1.png)
点击`sql`列的时间查看详细的sql执行情况
![](/miniprofiler2.png)
如果需要订制日志信息,查看更详细的日志情况,可以自己调整代码实现。以登录接口为例,添加以下代码:
```csharp
[HttpPost]
[AllowAnonymous]
public LoginResult Login(PassportLoginRequest request)
{
var result = new LoginResult();
using (MiniProfiler.Current.Step("步骤一"))
{
result = _authUtil.Login(request.AppKey, request.Account, request.Password);
}
using (MiniProfiler.Current.Step("步骤二"))
{
//代码略
}
using (MiniProfiler.Current.Step("步骤三"))
{
//代码略
}
return result;
}
```
这时调用该API后即可看到具体步骤一、步骤二、步骤三的执行时间情况了

View File

@ -0,0 +1,34 @@
---
title: 登录信息
createTime: 2025/04/23 21:03:10
permalink: /core/logininfo/
---
# 登录信息
框架在应用层任意业务逻辑中,均可以通过`IAuth`接口判断是否登录和获取登录信息。所有继承BaseApp的业务逻辑可以直接使用`_auth`成员变量直接获取登录用户信息。
```csharp
public class RoleApp : BaseApp<Role,OpenAuthDBContext>
{
/// <summary>
/// 加载当前登录用户可访问的全部角色
/// </summary>
public List<Role> Load(QueryRoleListReq request)
{
var loginUser = _auth.GetCurrentUser();
if (loginUser == null)
{
throw new CommonException("登录已过期", Define.INVALID_TOKEN);
}
//其他代码略
}
public RoleApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Role,OpenAuthDBContext> repository,IAuth auth) : base(unitWork, repository, auth)
{
}
}
```

View File

@ -0,0 +1,44 @@
---
title: 模块/菜单权限
createTime: 2025/04/23 21:03:10
permalink: /core/moduleauth/
---
# 模块/菜单权限
网络上流行的经典的权限设计是【主体】- 【领域】 - 【权限】( who、what、how问题原型 ) 的设计思想,其中:
【主体】可以是用户,可以是角色,也可以是一个部门
【领域】可以是一个模块,可以是一个页面,也可以是页面上的按钮
【权限】可以是“可见”,可以是“只读”,也可以是“可用”(如按钮可以点击)
为了简化程序开发在OpenAuth.Net中去掉了权限的控制简化为【主体】- 【领域】的模式,且【主体】限定为角色。即只能给角色分配模块和按钮,不能直接分配给用户账号或部门。且一旦分配即表示该角色拥有操作该模块(按钮)的权限。结构如下
@startuml
skinparam handwritten true
skinparam backgroundColor #EEEBDC
用户User o-- 角色Role
用户User o-- 部门Org
角色Role o-- 模块Module
'角色Role o-left- 部门Org
模块Module o-- 菜单ModuleElement
模块Module o-- 数据字段
@enduml
## 具体操作
添加好模块/菜单后,在【角色管理】功能中,选中一个角色,点击【为角色分配模块】,点击下一步会依次弹出:
1. 为角色分配模块对话框,用于分配该角色可以访问哪些功能;
2. 为角色分配菜单对话框,用于分配该角色可以操作哪些菜单;
3. 为角色分配可见字段对话框,用于分配该可以查看哪些字段;
![20230910193521](http://img.openauth.net.cn/20230910193521.png)

View File

@ -0,0 +1,103 @@
---
title: 配置多数据库
createTime: 2025/04/23 21:03:10
permalink: /core/multidbs/
---
# 配置多数据库
框架支持同时访问多个数据库。具体操作如下:
## 添加新数据库连接字符串
在配置文件appsettings.json中添加新的连接字符串`OpenAuthDBContext2`
```csharp
"ConnectionStrings": {
"OpenAuthDBContext": "Data Source=.;Initial Catalog=OpenAuthPro;User=sa;Password=000000",
"OpenAuthDBContext2": "Data Source=.;Initial Catalog=OpenAuthDB;User=sa;Password=000000"
}
"AppSetting": {
"DbTypes": {
"OpenAuthDBContext":"SqlServer" //数据库类型SqlServer、MySql、Oracle
,"OpenAuthDBContext2":"SqlServer" //链接字符串OpenAuthDBContext2对应的数据库类型
}
}
```
## 添加新的数据上下文
在OpenAuth.Repository中添加新的数据库上下文比如`OpenAuthDBContext2`
```csharp
public class OpenAuthDBContext2 : DbContext
{
private IConfiguration _configuration;
private ILoggerFactory _LoggerFactory;
private const string _connectstr = "OpenAuthDBContext2";
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLoggerFactory (_LoggerFactory);
string connect = _configuration.GetConnectionString(_connectstr);
if (string.IsNullOrEmpty(connect))
{
throw new Exception($"未能找到{_connectstr}对应的连接字符串信息");
}
//这个地方如果用IOption在单元测试的时候会获取不到AppSetting的值😅
var dbtypes = _configuration.GetSection("AppSetting:DbTypes").GetChildren()
.ToDictionary(x => x.Key, x => x.Value);
var dbType = dbtypes[_connectstr];
if (dbType == Define.DBTYPE_SQLSERVER)
{
optionsBuilder.UseSqlServer(connect);
}
else if(dbType == Define.DBTYPE_MYSQL) //mysql
{
optionsBuilder.UseMySql(connect);
}
else
{
optionsBuilder.UseOracle(connect);
}
base.OnConfiguring (optionsBuilder);
}
public OpenAuthDBContext2(DbContextOptions<OpenAuthDBContext2> options,
ILoggerFactory loggerFactory,IConfiguration configuration)
: base(options)
{
_LoggerFactory = loggerFactory;
_configuration = configuration;
}
... //其他代码请参考OpenAuthDbContext
}
```
## 注入新数据库
在项目OpenAuth.WebApi等的启动代码`Startup.cs`中,注入刚刚添加的数据库
```csharp
services.AddDbContext<OpenAuthDBContext2>();
```
## 编写业务代码
我们以系统日志模块为例,只需要调整以下代码,然后运行就可以发现,日志已经全部记录到新的数据库中。
```csharp
public class SysLogApp : BaseApp<SysLog,OpenAuthDBContext2>
{
public SysLogApp(IUnitWork<OpenAuthDBContext2> unitWork, IRepository<SysLog,OpenAuthDBContext2> repository) : base(unitWork, repository, null)
{
}
...//剩余的代码和系统自带的模块完全一致
}
```

View File

@ -0,0 +1,85 @@
---
title: 多租户
createTime: 2025/04/23 21:03:10
permalink: /core/multitenant/
---
# 多租户
目前市面上主流的多租户方案有三种:
1. **独立数据库** 即为不同的租户提供独立的数据库。
1. **共享数据库独立Schema** 即多个或所有租户共享一个数据库实例但是每个租户一个Schema也可叫做一个user。底层库比如是DB2、ORACLE等一个数据库下可以有多个SCHEMA。
1. **共享数据库共享Schema共享数据表** 即租户共享同一个数据库实例、同一个Schema但在表中增加TenantID多租户的数据字段在程序逻辑上进行区分。
为了兼容以前的版本OpenAuth采用的是第一种方式即为每个租户建一个新的数据库然后通过客户端请求的租户IdtenantId来分离数据。
## 如何增加一个新租户?
#### 后端添加
后端添加新租户连接字符串即可:
```javascript
"ConnectionStrings": {
"new_tenantid": "server=127.0.0.1;user id=root;database=openauthpro;password=000000" //新租户id对应的连接字符串
},
```
::: warning 注意
这里为了方便理解租户id用的是`new_tenantid`,真实环境里最好用类似UUID风格的无意义id
:::
#### 前端添加
比如在vue element-ui中,在登录时增加选择租户列表:
```html
<el-select v-model="tenant" placeholder="请选择" @change="tenantChange">
<el-option
v-for="item in tenants"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
export default {
name: 'login',
data() {
return {
tenant: this.tenantid || 'OpenAuthDBContext', //当前选择的租户
tenants:[{
value: 'OpenAuthDBContext',
label: '默认租户'
},{ //添加的新租户
value: 'new_tenantid',
label: '新租户'
}]
}
}
}
```
前端在所有http请求的时候在请求头中增加`tenantId`信息,保证每次请求带上租户信息。比如用axios请求时
```javascript
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // api的base_url
timeout: 50000 // 请求超时时间
})
// request拦截器
service.interceptors.request.use(config => {
config.headers['tenantId'] = store.getters.tenantid
//其他代码略...
})
```

View File

@ -0,0 +1,298 @@
---
title: 日常提交
createTime: 2025/04/23 21:03:10
permalink: /core/routineupdate/
---
# 日常提交(针对dev分支)
* 2025.03.17 代码生成加上外部数据源支持
* 2025.03.16 新增测试数据源
* 2025.03.14 优化vue3代码生成
* 2025.03.11 完成在api中对接口权限进行鉴权
* 2025.03.08 流程增加任意节点撤回审批功能
* 2025.03.07 layui table点击行选中优化
* 2025.03.04 修复pg存储的时候时间少8个小时
* 2025.02.26 修复因调整数据结构导致的获取流程通知用户异常
* 2025.02.24 调整代码生成器生成变量命名方式
* 2025.02.18 调整mysql oracle sqlserver pg脚本使更符合数据库人员习惯
* 2025.02.13 目前Oracle工作流列表不能加载
* 2025.01.20 修复流程列表展示当前审批人
* 2025.01.14 优化撤销、驳回
* 2025.01.13 优化历史操作记录
* 2024.12.23 重构流程实例代码
* 2024.11.28 升级到.Net 9
* 2024.11.16 添加dockerfile,为.net 9做准备
* 2024.10.10 增加知会功能。详情:[知会](http://doc.openauth.net.cn/core/flowinstance.html#%E7%9F%A5%E4%BC%9A)
* 2024.09.29 新增增加签逻辑。详情:[加签](http://doc.openauth.net.cn/core/flowinstance.html#%E5%8A%A0%E7%AD%BE)
* 2024.07.20 mvc项目去掉vue采用原生layui
* 2024.07.11 fix #IABKQN
* 2024.06.27 删除CodeSmith生成WebApi
* 2024.06.20 fix IABKQN 输入框输入收清除其他下拉框或选择框的内容;
* 2024.06.10 update layui to 2.9.13
* 2024.05.31 fix #I9STI2 项目菜单新增和保存报错
* 2024.04.24 fix #I9HQWU 已审核过的用户,后面不需要再次审核;
* 2024.04.18 fix #I9G05U 流程设计时,选择角色时,没有显示角色名称
* 2024.04.05 fix #I9E72C 不能获取pgSql数据库结构
* 2024.03.08 修复Oracle脚本使用驼峰命名异常的问题
* 2024.02.26 全面调整流程添加逻辑;
* 2024.02.24 角色分配模块时,可以级联
* 2024.02.22 fix #I9302C Vue3表单设计无法展示自定义页面
* 2024.02.17 vue3模块增加配置是否缓存
* 2024.02.03 fix #I90F8B 生成的主从表页面, 在从表那里增加全屏, 或者是隐藏列表的按钮
* 2024.01.15 fix #I8WCQ8 定时任务添加本地任务时不应该显示HTTPPOST
* 2024.01.09 修复前端缓存时间
* 2024.01.06 update layui to 2.9.3
* 2023.12.30 模块增加配置是否缓存。请参考[界面缓存](http://doc.openauth.net.cn/pro/keepalive.html)
* 2023.12.27 登录账号旁边实时显示未读消息条数
* 2023.12.23 完善人员显示直接上级及部门显示负责人
* 2023.12.19 流程设计可以选择部门负责人
* 2023.11.25 hiprint自动连接打印客户端失败的报错
* 2023.11.20 打印导出PDF时数据为空
* 2023.10.04 全面完成智能打印板块功能开发。请参考[智能打印](http://doc.openauth.net.cn/pro/printerplan.html)
* 2023.10.02 fix #I82FO6 完成业务功能配置打印方案
* 2023.09.29 完成功能模块添加打印按钮
* 2023.09.28 #I82FO6 完成模块配置打印方案的设置
* 2023.09.27 增加PDManer数据结构
* 2023.09.17 fix #I81YQA SqlSugar使用MySql时异常
* 2023.09.16 #I7A7YE 加入hiprint打印功能
* 2023.09.01 fix #I7XLQK checkbox控件值表单条件判断
* 2023.08.27 fix issue #I7A7XF 全面支持SqlSugar Orm。详情[sqlsugar访问数据库](http://doc.openauth.net.cn/core/sqlsugar.html)
* 2023.08.18 fix #I7U1BM 左侧展开图标丢失
* 2023.08.16 fix #I7U14K layui-icon图标大小不一致
* 2023.08.13 update layui to 2.8.11
* 2023.08.01 默认.Net SDK版本升级为6.0
* 2023.06.01 fix #I7EKFG 关于使用oracle数据库时代码生成界面的问题
* 2023.05.01 fix #I5ZL3B 代码生成器,动态列排序,保存无效
* 2022.12.22 退出登录时清空tag标签;
* 2022.12.20 修复多个模块名称相同时只能打开一个的BUG;
* 2022.12.17 fix 流程发起页面切换vform不能正常执行onCreated脚本;
* 2022.12.15 升级vform到2.3.6;
* 2022.11.26 修复[事务中使用异步方式后报错](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I63AOC);
* 2022.11.18 修复[拖拽表单不能关联数据库](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I61V1D);
* 2022.10.05 完成vue3多表代码生成器模版;
* 2022.10.01 增加vue3多表代码生成器模版;
* 2022.09.21 完成vue3 setup模式单表代码生成;
* 2022.09.15 增加vue3代码生成器模版完成单表动态头部生成;
* 2022.09.12 代码生成器增加vue3参数;
* 2022.08.15 修复选择租户;
* 2022.08.14 修复左侧导航栏异常;
* 2022.08.13 完成vue3版本流程设计、流程处理及展示;
* 2022.08.03 完成vue3版本流程图工具、画布处理;
* 2022.07.26 完成vue3 jsplumb引入;
* 2022.06.14 完成vue3版本表单设计器;
* 2022.06.12 完成vue2版本表单设计器;
* 2022.05.12 初始化vue3+vite版本;
* 2022.01.19 增加对sql只返回string的支持;
* 2022.01.17 修复添加表单时如果关联的数据库已存在的bug
* 2022.01.15 增加拖动表单生成数据库表
* 2022.01.03 增加plantuml支持
* 2022.01.01 增加API部署说明
* 2021.12.28 增加工作流添加自定义表单
* 2021.12.10 修复非动态头部生成vue界面时异常
* 2021.12.08 主从表以ParentId为准而不是DetailTable
* 2021.12.07 sqlserver float类型对应C# double类型
* 2021.11.30 修复子表加载失败的问题
* 2021.11.14 修复代码生成器
* 2021.11.04 简化代码
* 2021.10.18 采用代码生成器的表结构控制前端显示
* 2021.10.03 升级EF及所有三方的版本
* 2021.09.22 fix issue [OpenAuth.Pro前端可编辑数量为单数时只显示单数减一的字段数](https://gitee.com/yubaolee/OpenAuth.Core/issues/I4BBIG)
* 2021.09.11 发布3.3版;
* 2021.09.08 fix issue [删除角色后用户还有角色模块访问权限](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I494N1)
* 2021.09.05 完成主从表生成;
* 2021.09.02 完成单个表格vue的生成
* 2021.08.31 使用全新的头部渲染;
* 2021.08.23 可以动态控制复杂界面显示编辑权限,采用代码生成的表定义来控制;
* 2021.07.09 流程审批时增加可编辑表单处理;
* 2021.07.02 fix issue 兼容oracle 11g
* 2021.06.22 系统消息按时间倒序排列;
* 2021.06.18 使用雪花算法做Id时出现异常
* 2021.06.15 修复加载消息列表异常;
* 2021.06.13 增加系统消息;
* 2021.06.02 删除已过期文件,优化注释;
* 2021.05.26 流程处理增加消息通知;
* 2021.05.24 集成miniprofiler可以监控API运行情况。[查看使用说明](http://doc.openauth.net.cn/core/log.html#%E5%9C%A8swagger%E4%B8%AD%E8%BE%93%E5%87%BA%E6%97%A5%E5%BF%97 )
* 2021.05.23 [模块管理页面加载时默认显示第一条](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3RUOR)
* 2021.05.21 新增编辑流程功能(草稿和驳回状态);
* 2021.05.17 [增加配置启动端口](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3QUV1)
* 2021.05.14 调整样式添加刷新页面tag标签保留功能
* 2021.05.12 [修复拖动表单上传异常](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3QN22)
* 2021.05.09 增加自定义模态验证异常返回信息;
* 2021.05.08 合并PR[增加API访问审计;禁用.net自动模态验证,采用系统全局异常捕获机制](https://gitee.com/dotnetchina/OpenAuth.Net/pulls/12)
* 2021.05.07 swagger增加分组的功能
* 2021.05.06 fix issue [会签节点异常,提示'-1' was not present in the dictionary](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3PE3R)
* 2021.05.01 fix issue [CodeSmith生成的后端代码报错](https://gitee.com/yubaolee/OpenAuth.Core/issues/I3OXJZ)
* 2021.04.28 增加站点启动时自动运行状态为【正在运行】的定时任务;
* 2021.04.27 增加存储过程调用的支持;
* 2021.04.26 fix issue [生成的更新字段不包含默认的CreateUser等](https://gitee.com/yubaolee/OpenAuth.Core/issues/I3O5S3)
* 2021.04.25 增加流程执行时可以选择用户或角色(而不是设计时选择);
* 2021.04.21 不同的租户,可以连不同类型数据库;
* 2021.04.16 增加Oracle驱动支持
* 2021.04.15 调整项目文件结构,代码生成器按新的结构生成;
* 2021.04.14 增加流程启动、撤销功能;
* 2021.04.13 增加新的流程状态-草稿;
* 2021.04.01 优化代码生成器,可以根据主键类型自动匹配父类;
* 2021.03.29 优化雪花算法;
* 2021.03.22 全面删除svg图标使用iconfont并增加图标选择
* 2021.03.18 fix https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3BUF5
* 2021.03.17 驳回状态可以在待处理列表中展示并处理;
* 2021.03.13 增加雪花算法支持、增加自动增长型Id的支持
* 2021.03.09 增加redis缓存支持
* 2021.03.03 代码生成器加上删除时添加弹出提醒的代码;
* 2021.03.02 修复流程分支判定;
* 2021.03.01 修复流程分支不能判断字符串的问题;
* 2021.02.20 新增三级菜单名称前Icon小图标
* 2021.02.18 增加三级菜单支持
* 2021.01.17 调整非法租户逻辑;
* 2021.01.14 fix issue [#I2D0CX](https://gitee.com/yubaolee/OpenAuth.Core/issues/I2D0CX)
* 2021.01.10 完成对多租户的支持;
* 2021.01.06 fix issue [#I2C4K0](https://gitee.com/yubaolee/OpenAuth.Core/issues/I2C4K0)
* 2021.01.03 启动时显示连接字符串;
* 很久很久以前的需求,麻烦看提交记录了😊😊😊

View File

@ -0,0 +1,31 @@
---
title: 后端开发规范
createTime: 2025/04/23 21:03:10
permalink: /core/specialist/
---
# 后端开发规范
## 数据库表及字段命名
SqlServer采用PascalCase命名Oracle采用全大写命名其他数据库采用camelCase命名。
::: tip 提示
开源版代码生成时通过表结尾Dtbl来判断是否是生成明细表代码。因此建议数据库表命名时按子系统名称+业务名称+表尾,其中表尾名称规则:
- 基础主数据以Mst结尾
- 普通业务表以Tbl结尾
- 业务明细表以Dtbl结尾
WMS系统入库订单明细表WmsInboundOrderDtbl
:::
## 数据库字段类型
主键id统一使用Domain:PrimaryKey针对SqlServer数据库非Sql Server根据需要定义
状态类,标识类的字段统一使用bit not null
表示分类的字段统一使用PrimaryKey。数值从Category中获取。

View File

@ -0,0 +1,68 @@
---
title: sqlsugar
createTime: 2025/04/23 21:03:10
permalink: /core/sqlsugar/
---
# SqlSugar访问数据库
SqlSugar 是一款老牌.NET开源ORM框架相对于EntityFramework复杂的Linq表达式它拥有灵活的动态查询如果你喜欢直接码Sql那么它是你的不二之选。OpenAuth.Net 6.0及以后版本默认支持使用SqlSugar方式访问数据库。目前大多数模块都已使用SqlSugar的方式这里以资源管理为例
```csharp
public class ResourceApp:SqlSugarBaseApp<Resource>
{
public void Add(AddOrUpdateResReq resource)
{
...
Repository.Insert(obj);
}
public void Update(AddOrUpdateResReq obj)
{
Repository.Update(u => new Resource
{
Name = obj.Name,
//todo:要修改的字段赋值
},u => u.Id == obj.Id);
}
public void Delete(string[] ids)
{
Repository.DeleteByIds(ids);
}
public ResourceApp(ISqlSugarClient client, IAuth auth) : base(client, auth)
{
}
}
```
## 使用方法
如上所示代码,只需要继承`SqlSugarBaseApp`即可使用SqlSugar强大功能。其中
Repository实现的是SqlSugar的仓储模式详细Api请查看[SqlSugar使用仓储](https://www.donet5.com/Home/Doc?typeId=1228)。在OpenAuth.Net中
```csharp
public class ResourceApp:SqlSugarBaseApp<Resource>
{
public void Add(AddOrUpdateResReq resource)
{
...
Repository.Insert(obj);
}
}
```
SugarClient即SqlSugar最基础的数据库读写用法。详细Api请查看[SqlSugar入门必看](https://www.donet5.com/Home/Doc?typeId=1181)。在OpenAuth.Net中
```csharp
public class ResourceApp:SqlSugarBaseApp<Resource>
{
public List<Resource> Load()
{
...
return SugarClient.Queryable<Resource>().ToList();
}
}
```

View File

@ -0,0 +1,177 @@
---
title: 快速开始
createTime: 2025/04/23 21:03:10
permalink: /core/start/
---
# 快速开始
## 下载代码
gitee上面两个版本。其中
* [OpenAuth.Net](https://gitee.com/dotnetchina/OpenAuth.Net) 默认SDK版本为.Net 9.0.100,如果需要切换到.Net其他版本请参考[切换sdk版本](http://doc.openauth.net.cn/core/changesdk.html)
* [OpenAuth.Core](https://gitee.com/yubaolee/OpenAuth.Core) 的SDK版本为.Net Core 3.1.100,已停止维护,不推荐使用。
.Net目前SDK升级特别方便。请参考[3分钟的时间把.net core 3.1的升级到.NET 5](https://www.cnblogs.com/yubaolee/p/Net3ToNet5.html)所以不要纠结SDK版本问题。
## 安装sdk
下载安装微软官方SDK代码地址https://dotnet.microsoft.com/download
## 项目结构
OpenAuth.Net文件夹结构及功能说明如下
```
📦OpenAuth.Net
┣ 📂CodeSmith
┃ ┗ 📂CSharp
┃ ┃ ┗ 📜WebGenerate.cst //生成Web页面
┣ 📂Infrastructure //基础工具类
┣ 📂mysql初始化脚本
┣ 📂OpenAuth.App //应用逻辑代码
┣ 📂OpenAuth.Identity //IdentityServer4服务器提供OAuth服务
┣ 📂OpenAuth.Mvc //开源版Web站点
┣ 📂OpenAuth.Repository //数据库访问相关代码
┣ 📂OpenAuth.WebApi //WebApi接口站点
┣ 📂sql server 初始化脚本
┣ 📜.gitattributes
┣ 📜.gitignore
┣ 📜LICENSE
┣ 📜OpenAuth.Net.sln //解决方案
┗ 📜README.md
```
其中调用关系为:
@startuml
hide footbox
skinparam handwritten true
actor 用户
boundary index.cshtml
control XXController
entity OpenAuth.App
entity OpenAuth.Repository
database OpenAuthDB
box "OpenAuth.Mvc" #LightBlue
participant index.cshtml
participant XXController
end box
participant OpenAuth.App
participant OpenAuth.Repository
participant OpenAuthDB
用户 -> index.cshtml : 用户浏览页面
index.cshtml -> XXController : 前端通过ajax调用数据
XXController -> OpenAuth.App : 调用逻辑层
OpenAuth.App -> OpenAuth.Repository : 逻辑层调用仓储进行数据读写
OpenAuth.Repository -> OpenAuthDB : 仓储层进行数据库操作
@enduml
我们以【资源管理】功能为例,该功能涉及的文件如下:
![20220407153729](http://img.openauth.net.cn/20220407153729.png)
## 初始化数据库
使用数据库脚本`sql server 初始化脚本`或`mysql初始化脚本` 文件夹里面的结构脚本和数据脚本初始化数据库
::: warning 注意
如果使用企业版的OpenAuth.WebApi,则新建一个空数据库OpenAuthPro。使用OpenAuth.Pro前端源码文件夹【sql脚本】中运行`Sql Server脚本.sql`或mysql脚本
:::
## 打开项目
使用Visual Studio 2022或Rider打开 `OpenAuth.Net.sln`
::: tip 提示
如果开发使用的电脑安装有多个版本的SDK可以在根目录新建一个`global.json`文件来指定.net版本文件内容如下
```
{
"sdk": {
"version": "9.0.100"
}
}
```
:::
## 修改配置
`ASP.NET Core` 应用程序启动时默认加载`appsettings.json`作为应用配置。同时还支持不同的运行环境加载对应的配置文件,如:
- 开发环境Development对应 `appsettings.Development.json`
- 部署环境Production对应 `appsettings.Production.json`
::: tip 提示
- 很多用户部署后提示连接数据库失败,很大原因就是没有修改`appsettings.Production.json`里面连接字符串
- 有些用户找不到`appsettings.Production.json`在哪visual studio中点击`appsettings.json`左边的三角标识即可看到
:::
#### 修改单数据库连接字符串
* 修改OpenAuth.Mvc/appsettings.json连接字符串如下
```json
"ConnectionStrings": {
"OpenAuthDBContext": "Data Source=.;Initial Catalog=OpenAuthPro;User=sa;Password=000000"
},
"AppSetting": {
"DbTypes": {
"OpenAuthDBContext":"SqlServer" //数据库类型SqlServer、MySql、Oracle
}
```
#### 修改多数据库连接字符串
```json
"ConnectionStrings": {
"OpenAuthDBContext": "Data Source=.;Initial Catalog=OpenAuthPro;User=sa;Password=000000"
"OpenAuthDBContext2": "DATA SOURCE=192.168.0.118:1521/YUBAO;PASSWORD=000000;Validate Connection=true;PERSIST SECURITY INFO=True;USER ID=yubaolee;" //racle
"OpenAuthDBContext3": "server=127.0.0.1;user id=root;database=openauthpro;password=000000" //my sql
},
"AppSetting": {
"DbTypes": {
"OpenAuthDBContext":"SqlServer" //数据库类型SqlServer、MySql、Oracle
,"OpenAuthDBContext2":"Oracle"
,"OpenAuthDBContext3":"MySql"
},
```
## 编译运行MVC
使用visualstudio生成解决方案。
`注首次启动时visual studio会启动nuget还原第三方依赖包请保持网络通畅并等待一段时间`
启动openauth.mvc项目。
![启动](/startmvc.png "启动")
启动成功后使用浏览器打开[http://localhost:1802](http://localhost:1802) 即可访问,如下图所示:
![说明](/mvcmain.png "说明")
## 编译运行WebApi
使用visualstudio生成解决方案。
`注首次启动时visual studio会启动nuget还原第三方依赖包请保持网络通畅并等待一段时间`
启动openauth.webapi项目。
![20220102000528](http://img.openauth.net.cn/20220102000528.png)
启动成功后使用浏览器打开[http://localhost:52789/swagger/index.html](http://localhost:52789/swagger/index.html) 即可访问,如下图所示:
![20220101233542](http://img.openauth.net.cn/20220101233542.png)

View File

@ -0,0 +1,42 @@
---
title: 三方对接
createTime: 2025/04/23 21:03:10
permalink: /core/thirdparty/
---
# 三方对接
* 在OpenAuth中设计表单注意表单中的控件名称在步骤3调用OpenAuth创建流程实例接口时frmData参数中的属性必须严格按该命名提交。
![](/formthirdparty.png "表单设计说明")
* 在OpenAuth中设计流程制定相关的工作流程并在每个流程节点配置回调URL路径如下
![](/flowthirdparty.png "三方URL设置")
* 三方已有系统界面提交表单时调用创建流程实例接口http://localhost:52789/api/FlowInstances/Add在OpenAuth中创建一条新的流程实例 接口参数如下:
```javascript
{
schemeId:'cdd8191e-6a99-4d66-aac0-fae52c0f2232', //流程模板中已存在的模板ID
schemeCode:'', //与流程模板ID二者选一个即可
frmData:'{\"TOOLS\":\"电脑\",\"NUMBERS\":\"1\"}', //严格按照第一步中表单规则
code:'1563811467051',
customName:'三方创建的新物品领用',
}
```
* 用户正常在OpenAuth中执行流程如果当前节点设置了回调URL的节点OpenAuth会采用WebAPI POST方式回调回调时具体参数如下
```javascript
{
flowInstanceId:"0ceff0f8-f848-440c-bc26-d8605ac858cd", //流程实例ID
nodeName: "admin审批", //节点名称
nodeId: "15333321", //节点ID
userId: "0ceff0f8-f848-440c-bc26-d8605ac858cd",
userName: "admin", //审核人账号
result: 1, //审核结果 1通过;2不通过3驳回
description: "做的不错", //审核描述
execTime: "2019-07-07 12:00:00", //审核时间
isFinish: true //是否结束
}
```

View File

@ -0,0 +1,77 @@
---
title: 单元测试
createTime: 2025/04/23 21:03:10
permalink: /core/unittest/
---
# 单元测试
为了方便项目调试框架的所有层均支持单元测试。代码基于NUnit框架编写。测试内如大概如下
* OpenAuth.Reposiroty: 直接测试数据库是否可以正常读写测试级别DbContext。在该项目的`TestBase.cs`中配置连接字符串;
* OpenAuth.App: 测试所有业务逻辑测试级别为各种xxxApp/xxxService等。可以模拟用户登录和前端Cookie提交的信息。在该项目的`TestBase.cs`中配置连接字符串;
* OpenAuth.Mvc: 测试MVC的访问可以模拟用户登录和前端Cookie提交的信息。使用OpenAuth.App中的测试连接字符串
* OpenAuth.WebApi: 测试接口WebApi访问可以模拟用户登录和前端Cookie提交的信息。使用OpenAuth.App中的测试连接字符串
所有的测试代码均在每个项目的`Test`文件夹中编写。比如`OpenAuth.App\Test\TestAccessObjs.cs`
```csharp
/// <summary>
/// 测试为部门分配用户
/// </summary>
[Test]
public void AssignOrgUsers()
{
var app = _autofacServiceProvider.GetService<RevelanceManagerApp>();
var userApp = _autofacServiceProvider.GetService<UserManagerApp>();
app.AssignOrgUsers(new AssignOrgUsers
{
OrgId = "8e31553c-cab8-4eb3-90b5-5f8ff1d21801",
UserIds = new []{"96f63f9d-e8c8-4258-963e-3327ed7d6f56"}
});
//获取机构的所有用户
var result = userApp.Load(new QueryUserListReq
{
orgId = "8e31553c-cab8-4eb3-90b5-5f8ff1d21801",
page = 1,
limit = 10
});
Console.WriteLine(JsonHelper.Instance.Serialize(result));
}
```
::: warning 注意
每个单元测试类都会继承`TestBase`,该类有一个虚函数`GetService`默认只注入了缓存Cache配置Option。如果在测试的过程中需要模拟登录用户cookie等信息需要在测试类中重写该方法。比如一个典型的重写如下
```csharp
public override ServiceCollection GetService()
{
var services = new ServiceCollection();
//模拟帐号test3记录在缓存中并与tokentest关联
var cachemock = new Mock<ICacheContext>();
cachemock.Setup(x => x.Get<UserAuthSession>("tokentest")).Returns(new UserAuthSession { Account = "test3" });
services.AddScoped(x => cachemock.Object);
//模拟客户端请求的token值为`tokentest`
var httpContextAccessorMock = new Mock<IHttpContextAccessor>();
httpContextAccessorMock.Setup(x => x.HttpContext.Request.Query[Define.TOKEN_NAME]).Returns("tokentest");
services.AddScoped(x => httpContextAccessorMock.Object);
//模拟httpclientfactory
var mockHttpFac = new Mock<IHttpClientFactory>();
services.AddScoped(x => mockHttpFac.Object);
return services;
}
```
:::

View File

@ -0,0 +1,281 @@
---
title: 数据库读写及事务处理
createTime: 2025/04/23 21:03:10
permalink: /core/unitwork/
---
# 数据库读写及事务处理
OpenAuth.Net使用Repository和Unitwork两种方式访问数据库。
## 使用场景
Repository适用于单表操作没有事务需求的场景
Unitwork适用于多表操作尤其是更新操作有事务需求的场景
::: tip 什么是UnitWork
在web应用中由于每个用户的请求都是属于不同线程的需要保持每次请求的所有数据操作都成功的情况下提交数据只要有一个失败的操作则会对用户的此次请求的所有操作进行回滚以确保用户操作的数据始终处于有效的状态。其实就两个字**事务**
:::
## 单表操作Repository
假设数据库有一个表名称为Stock。则在OpenAuth.App中编写业务代码。比如`StockApp`
```csharp
namespace OpenAuth.App
{
public class StockApp : BaseApp<Stock,OpenAuthDBContext>
{
/// <summary>
/// 加载列表
/// </summary>
public TableData Load(QueryStockListReq request)
{
var result = new TableData();
var objs = Repository.Find(null);
if (!string.IsNullOrEmpty(request.key))
{
objs = objs.Where(u => u.Id.Contains(request.key));
}
result.data = objs.OrderBy(u => u.Id)
.Skip((request.page - 1) * request.limit)
.Take(request.limit);
result.count = objs.Count();
return result;
}
public void Add(AddOrUpdateStockReq req)
{
var obj = req.MapTo<Stock>();
//todo:补充或调整自己需要的字段
obj.CreateTime = DateTime.Now;
Repository.Add(obj);
}
public void Update(AddOrUpdateStockReq obj)
{
Repository.Update(u => u.Id == obj.Id, u => new Stock
{
//todo:补充或调整自己需要的字段
});
}
public StockApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Stock,OpenAuthDBContext> repository,IAuth auth) : base(unitWork, repository,auth)
{
}
}
}
```
## 事务操作UnitWork
默认情况下EF每执行一次SaveChanges()方法时就会新建一个事务然后将context中的CUD操作都在这个事务中进行。使用方式如下
```csharp
public void Update(AddOrUpdateStockReq obj)
{
UnitWork.Add<SysLog>(new SysLog
{
//todo:模拟新增操作
});
var stock = UnitWork.FirstOrDefault<Stock>(u => u.Id == obj.Id);
stock.Name = "xxxx";
UnitWork.Update(stock); //更新操作
var other = UnitWork.FirstOrDefault<OtherTable>(u => u.Id == obj.Id);
other.Name = "xxxx";
UnitWork.Update(other); //其他更新操作
UnitWork.Save(); //只有一次Save()操作
}
```
如果在一个事务里面有多次`SaveChanges()`的情况需要使用OpenAuth.Net提供的`ExecuteWithTransaction`处理。如下:
```csharp
//代码详见TestTransaction.cs/NormalSubmit()
UnitWork.ExecuteWithTransaction(() =>
{
var account = "user_" + DateTime.Now.ToString("yyyy_MM_dd HH:mm:ss");
var user = new User
{
Id = account,
Account = account,
Name = account,
};
unitWork.Add(user);
unitWork.Save(); //第一次savechanges()
user.Account = "Trans_" + user.Account;
unitWork.Update(user);
unitWork.Save(); //第二次savechanges()
//Z.EntityFramework.Plus的Update内部自动调用了SaveChanges(),算第三次
unitWork.Update<User>(u => u.Id == account, u => new User
{
Account = "Trans2_" + user.Account
});
});
```
或者异步方式:
```csharp
public async Task AddUserAndLogAsync()
{
await UnitWork.ExecuteWithTransactionAsync(async () =>
{
var account = await AddUserAsync();
UnitWork.Add(new SysLog()
{
Content = $"新增了用户{account}",
Id = account
});
UnitWork.Save();
});
}
private async Task<string> AddUserAsync()
{
var account = "user_" + DateTime.Now.ToString("yyyy_MM_dd HH:mm:ss");
var user = new User
{
Account = account,
Name = account
};
await Repository.AddAsync(user);
return account;
}
```
发生这种情况,通常是因为在各个应用层逻辑内部已经调用了`UnitWrok.Save()`,比如:
```csharp
//详细代码请查看UserManagerApp.cs,本例简化真实逻辑,方便理解
private RevelanceManagerApp _revelanceApp;
public void AddOrUpdate(UpdateUserReq request)
{
UnitWork.ExecuteWithTransaction(() =>
{
User requser = request;
requser.CreateTime = DateTime.Now;
UnitWork.Add(requser);
UnitWork.Save();
string[] orgIds = request.OrganizationIds.Split(',').ToArray();
//下面两个方法各自内部都会调用UnitWork.Save()
_revelanceApp.DeleteBy(Define.USERORG, requser.Id);
_revelanceApp.Assign(Define.USERORG, orgIds.ToLookup(u => requser.Id));
});
}
```
## 多表查询
简单的多表查询可以使用UnitWork完成。例如
```csharp
/// <summary>
/// 加载用户的部门
/// </summary>
public List<Org> LoadForUser(string userId)
{
var result = from userorg in UnitWork.Find<Relevance>(null)
join org in UnitWork.Find<Org>(null) on userorg.SecondId equals org.Id
where userorg.FirstId == userId && userorg.Key == Define.USERORG
select org;
return result.ToList();
}
```
如果是复杂的SQL查询建议使用下面的SQL语句查询以获得更高的性能。
## SQL 语句查询
框架提供两个SQL语句查询的接口:
* FromSql: 返回数据库表对应的实体必需在在DbContext中增加对应的DbSset
### 返回数据库表
```csharp
//UserManagerApp.cs
var users = UnitWork.FromSql<User>("select * from user");
```
### 返回非数据库表
```csharp
//OpenAuthDBContext中添加访问
public virtual DbSet<UserResp> UserResps { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
modelBuilder.Entity<UserResp>().HasNoKey();
}
//使用
var users = UnitWork.FromSql<UserResp>("select * from user");
```
## 执行存储过程
#### Sql Server
UnitWork提供执行存储过程接口`ExecProcedure`,使用如下:
``` csharp
var unitWork = _autofacServiceProvider.GetService<IUnitWork<OpenAuthDBContext>>();
var param = new SqlParameter("keyword", SqlDbType.NVarChar);
param.Value = "test%";
var users = unitWork.ExecProcedure<User>("sp_alluser", new []{param});
Console.WriteLine(JsonHelper.Instance.Serialize(users));
```
存储过程`sp_alluser`定义如下:
```sql
create procedure sp_alluser @keyword nvarchar(20) as
begin
select * from [user] where Account like @keyword;
end;
```
#### MySql
UnitWork提供执行存储过程接口`ExecProcedure`,使用如下:
``` csharp
var unitWork = _autofacServiceProvider.GetService<IUnitWork<OpenAuthDBContext>>();
var param = new MySqlParameter("keyword", SqlDbType.NVarChar);
param.Value = "test%";
var users = unitWork.ExecProcedure<User>("sp_alluser", new []{param});
Console.WriteLine(JsonHelper.Instance.Serialize(users));
```
::: warning 特别注意
这里的MySqlParameter命名空间使用的是
``` csharp
using MySqlConnector;
```
:::
存储过程`sp_alluser`定义如下:
```sql
create procedure sp_alluser(in keyword nvarchar(20))
begin
select * from user where Account like keyword;
end;
```

View File

@ -0,0 +1,129 @@
---
title: 前端结构
createTime: 2025/04/23 21:03:10
permalink: /core/wwwarchitect/
---
# 前端结构
OpenAuth.Mvc前端采用典型的mvc结构部署其中
* Views: 为静态资源页面最终会渲染成html实在不懂百度Asp.Net Mvc中的View
* wwwroot/js: 通用的js组件
* wwwroot/userJs: 业务相关的js代码。通常一个csthml页面对应一个userJs中的js文件。如`Categories\Index.cshtml`对应`userJs\categories.js`
```shell
|-- OpenAuth.Mvc
|-- Views
| |-- _ViewStart.cshtml
| |-- Categories
| | |-- Index.cshtml
| |-- DataPrivilegeRules
| | |-- index.cshtml
| |-- Error
| | |-- Auth.cshtml
| |-- FlowInstances
| | |-- Detail.cshtml
| | |-- Disposed.cshtml
| | |-- Edit.cshtml
| | |-- Index.cshtml
| | |-- Verification.cshtml
| | |-- Wait.cshtml
| |-- FlowSchemes
| | |-- Design.cshtml
| | |-- Index.cshtml
| | |-- NodeInfo.cshtml
| | |-- Preview.cshtml
| |-- Forms
| | |-- Edit.cshtml
| | |-- index.cshtml
| | |-- Preview.cshtml
| |-- Home
| | |-- git.cshtml
| | |-- Index.cshtml
| | |-- Main.cshtml
| |-- Login
| | |-- Index.cshtml
| |-- ModuleManager
| | |-- Assign.cshtml
| | |-- Index.cshtml
| |-- OpenJobs
| | |-- index.cshtml
| |-- OrgManager
| | |-- Index.cshtml
| |-- Redirects
| | |-- IdentityAuth.cshtml
| |-- Resources
| | |-- Assign.cshtml
| | |-- Index.cshtml
| |-- RoleManager
| | |-- Assign.cshtml
| | |-- Index.cshtml
| |-- Shared
| | |-- _Layout.cshtml
| |-- SysLogs
| | |-- index.cshtml
| |-- SysMessages
| | |-- index.cshtml
| |-- UserManager
| | |-- ChangePassword.cshtml
| | |-- Index.cshtml
| | |-- Profile.cshtml
| |-- WmsInboundOrderTbls
| |-- index.cshtml
|-- wwwroot
|-- css
| |-- formpreview.css
| |-- images.css
| |-- login.css
| |-- main.css
| |-- treetable.css
|-- js
|-- bodyTab.js
|-- bootstrap.js
|-- cookie.js
|-- droptree.js
|-- dtree.js
|-- flowlayout.js
|-- iconPicker.js
|-- index.js
|-- leftNav.js
|-- openauth.js
|-- slimscroll.js
|-- utils.js
|-- vue.js
|-- ztree.js
|-- userJs
|-- assignModule.js
|-- assignResource.js
|-- assignRole.js
|-- categories.js
|-- changePwd.js
|-- dataprivilegerules.js
|-- flowinstanceDetail.js
|-- flowInstanceDisposed.js
|-- flowInstanceEdit.js
|-- flowInstances.js
|-- flowInstanceWait.js
|-- flowSchemeDesign.js
|-- flowSchemePreview.js
|-- flowSchemes.js
|-- formEdit.js
|-- forms.js
|-- login.js
|-- main.js
|-- modules.js
|-- nodeInfo.js
|-- openjobs.js
|-- orgs.js
|-- preview.js
|-- profile.js
|-- resources.js
|-- roles.js
|-- syslogs.js
|-- sysmessages.js
|-- users.js
|-- verification.js
|-- wmsinboundordertbls.js
```

View File

@ -0,0 +1,10 @@
---
title: 自定义组件
tags:
- 预览
- 组件
createTime: 2025/04/20 21:49:49
permalink: /article/7zjuzrb4/
---
<CustomComponent />

View File

@ -0,0 +1,410 @@
---
title: Markdown
tags:
- markdown
createTime: 2025/04/20 21:49:49
permalink: /article/dsw2e41q/
---
## 标题H2
### 标题H3
#### 标题H4
##### 标题H5
###### 标题H6
## 标题2 Badge <Badge type="tip" text="Badge" />
### 标题3 Badge <Badge type="warning" text="Badge" />
#### 标题4 Badge <Badge type="danger" text="Badge" />
正文内容。
`@property` CSS at-rule是 [CSS Houdini API](https://developer.mozilla.org/zh-CN/docs/Web/Guide/Houdini)
的一部分,它允许开发者显式地定义他们的 [CSS 自定义属性](https://developer.mozilla.org/zh-CN/docs/Web/CSS/--*),
允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承。
`@property` 的出现,极大的增强了 CSS 的能力。
加粗:**加粗文字**
斜体: _斜体文字_
~~删除文字~~
内容 ==标记==
数学表达式: $-(2^{n-1})$ ~ $2^{n-1} -1$
$\frac {\partial^r} {\partial \omega^r} \left(\frac {y^{\omega}} {\omega}\right)
= \left(\frac {y^{\omega}} {\omega}\right) \left\{(\log y)^r + \sum_{i=1}^r \frac {(-1)^ Ir \cdots (r-i+1) (\log y)^{ri}} {\omega^i} \right\}$
19^th^
H~2~O
::: center
内容居中
:::
::: right
内容右对齐
:::
- 无序列表1
- 无序列表2
- 无序列表3
1. 有序列表1
2. 有序列表2
3. 有序列表3
- [ ] 任务列表1
- [ ] 任务列表2
- [x] 任务列表3
- [x] 任务列表4
| Tables | Are | Cool |
| ------------- |:-------------:| -----:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
> 引用内容
>
> 引用内容
[链接](/)
[外部链接](https://github.com/pengzhanbo)
![plume](/plume.svg)
**Badge**
- <Badge type="info" text="info badge" />
- <Badge type="tip" text="tip badge" />
- <Badge type="warning" text="warning badge" />
- <Badge type="danger" text="danger badge" />
**图标:**
- home - <Icon name="material-symbols:home" color="currentColor" size="1em" />
- vscode - <Icon name="skill-icons:vscode-dark" size="2em" />
- twitter - <Icon name="skill-icons:twitter" size="2em" />
**demo wrapper**
::: demo-wrapper title="示例" no-padding height="200px"
<style scoped>
.open-door {
display: flex;
gap: 20px;
padding: 20px;
}
.open-door .main {
background: #ccc;
}
</style>
<div class="open-door">
<div class="main">main</div>
<div class="aside">aside</div>
</div>
:::
**代码:**
```js whitespace
const a = 1
const b = 2
const c = a + b
// [!code word:obj]
const obj = {
toLong: {
deep: {
deep: {
deep: {
value: 'this is to long text. this is to long text. this is to long text. this is to long text.', // [!code highlight]
}
}
}
}
}
```
**Code Blocks TwoSlash**
```ts twoslash
// @errors: 2339
const welcome = 'Tudo bem gente?'
const words = welcome.contains(' ')
```
```ts twoslash
import express from 'express'
const app = express()
app.get('/', (req, res) => {
res.send
})
app.listen(3000)
```
```ts twoslash
import { createHighlighter } from 'shiki'
const highlighter = await createHighlighter({ themes: ['nord'], langs: ['javascript'] })
// @log: Custom log message
const a = 1
// @error: Custom error message
const b = 1
// @warn: Custom warning message
const c = 1
// @annotate: Custom annotation message
```
```ts twoslash
// @errors: 2540
interface Todo {
title: string
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users'.toUpperCase(),
// ^?
}
todo.title = 'Hello'
Number.parseInt('123', 10)
// ^|
//
//
```
```vue twoslash
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<p>{{ count }}</p>
</template>
```
**代码分组:**
::: code-tabs
@tab tab1
```js
const a = 1
const b = 2
const c = a + b
```
@tab tab2
```ts
const a: number = 1
const b: number = 2
const c: number = a + b
```
:::
**代码块高亮:**
```ts
function foo() {
const a = 1 // [!code highlight]
console.log(a)
const b = 2 // [!code ++]
const c = 3 // [!code --]
console.log(a + b + c) // [!code error]
console.log(a + b) // [!code warning]
}
```
**代码块聚焦:**
```ts
function foo() {
const a = 1 // [!code focus]
}
```
::: tip 仅标题
:::
::: note 注释
注释内容 [link](https://github.com/pengzhanbo) `inline code`
```js
const a = 1
const b = 2
const c = a + b
```
:::
::: info 信息
信息内容 [link](https://github.com/pengzhanbo) `inline code`
```js
const a = 1
const b = 2
const c = a + b
```
:::
::: tip 提示
提示内容 [link](https://github.com/pengzhanbo) `inline code`
```js
const a = 1
const b = 2
const c = a + b
```
:::
::: warning 警告
警告内容 [link](https://github.com/pengzhanbo) `inline code`
```js
const a = 1
const b = 2
const c = a + b
```
:::
::: caution 错误
错误内容 [link](https://github.com/pengzhanbo) `inline code`
```js
const a = 1
const b = 2
const c = a + b
```
:::
::: important 重要
重要内容 [link](https://github.com/pengzhanbo) `inline code`
```js
const a = 1
const b = 2
const c = a + b
```
:::
::: details 详细标题
这里是内容。
:::
**GFM alert**
> [!note]
> note
> [!info]
> info
> [!tip]
> tip
> [!warning]
> warning
> [!caution]
> caution
> [!important]
> important
**代码演示:**
:::: demo title="常规示例" desc="一个常规示例"
::: code-tabs
@tab HTML
```html
<div id="app">
<h3>vuepress-theme-plume</h3>
</div>
```
@tab Javascript
```js
const a = 'So Awesome!'
const app = document.querySelector('#app')
app.appendChild(window.document.createElement('small')).textContent = a
```
@tab CSS
```css
#app {
font-size: 2em;
text-align: center;
}
```
:::
::::
**选项卡:**
::: tabs
@tab 标题1
内容区块
@tab 标题2
内容区块
:::
:::: warning
::: tabs
@tab 标题1
内容区块
@tab 标题2
内容区块
:::
::::
**脚注:**
脚注 1 链接[^first]。
脚注 2 链接[^second]。
行内的脚注^[行内脚注文本] 定义。
重复的页脚定义[^second]。
[^first]: 脚注 **可以包含特殊标记**
也可以由多个段落组成
[^second]: 脚注文字。

27
newdocs/package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "openauth-net-docs",
"type": "module",
"version": "1.0.0",
"description": "最好用的.net权限工作流框架,最实用的.net/vue前后端分离方案",
"author": "yubaolee <yubaolee@163.com>",
"license": "MIT",
"engines": {
"node": "^18.19.0 || ^20.6.0 || >=22.0.0"
},
"scripts": {
"docs:dev": "vuepress dev docs",
"docs:dev-clean": "vuepress dev docs --clean-cache --clean-temp",
"docs:build": "vuepress build docs --clean-cache --clean-temp",
"docs:preview": "http-server docs/.vuepress/dist",
"vp-update": "npx vp-update"
},
"devDependencies": {
"@vuepress/bundler-vite": "2.0.0-rc.21",
"vuepress": "2.0.0-rc.21",
"vuepress-theme-plume": "1.0.0-rc.143",
"http-server": "^14.1.1",
"vue": "^3.5.13",
"sass-embedded": "^1.86.3",
"typescript": "^5.8.3"
}
}