mirror of
https://gitee.com/dotnetchina/OpenAuth.Net.git
synced 2026-07-28 06:07:59 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04142acaaa | ||
|
|
c084e2409f | ||
|
|
4ed8c0819b | ||
|
|
217b407cd9 | ||
|
|
2fb964f9d0 | ||
|
|
6a8eb675e9 | ||
|
|
d7f48e0537 | ||
|
|
e6410c9da6 | ||
|
|
4730ac7a36 | ||
|
|
33cc0b1e3b | ||
|
|
87866d08fb | ||
|
|
6b2c50252b | ||
|
|
c85793bb55 | ||
|
|
f980fc5afc | ||
|
|
d83a40e07e | ||
|
|
695f5af89f | ||
|
|
82bb5b8f3e | ||
|
|
1c6ab0348f | ||
|
|
add77fb23c | ||
|
|
f392992605 | ||
|
|
b61b315d27 | ||
|
|
b38391fddd | ||
|
|
77ce71d603 | ||
|
|
437d657131 | ||
|
|
1f3eb20676 | ||
|
|
1b162e22cc | ||
|
|
a44ca9ae16 | ||
|
|
220f49743f | ||
|
|
d7f4b667a1 | ||
|
|
7c36c79f37 | ||
|
|
a8681f962c | ||
|
|
ebfbc7eceb | ||
|
|
ae92db7e1a |
237
.cursor/rules/openauth.mdc
Normal file
237
.cursor/rules/openauth.mdc
Normal file
@@ -0,0 +1,237 @@
|
||||
---
|
||||
alwaysApply: false
|
||||
---
|
||||
# OpenAuth.Net Cursor Rules
|
||||
|
||||
## 项目概述
|
||||
OpenAuth.Net是一个基于.NET 9的企业级权限管理和快速开发框架,采用Martin Fowler企业级应用开发思想,集成了最新的技术栈。
|
||||
|
||||
## 技术栈
|
||||
- **后端**: .NET 9, ASP.NET Core WebAPI
|
||||
- **ORM**: SqlSugar (主要) + Entity Framework Core (兼容)
|
||||
- **依赖注入**: Autofac
|
||||
- **数据库**: 支持SqlServer、MySQL、Oracle、PostgreSQL
|
||||
- **定时任务**: Quartz.NET
|
||||
- **缓存**: Redis, MemoryCache
|
||||
- **前端**: Vue2 + Element-UI
|
||||
- **测试**: NUnit
|
||||
- **文档**: Swagger
|
||||
|
||||
## 项目架构
|
||||
```
|
||||
📦OpenAuth.Net
|
||||
┣ 📂Infrastructure # 基础设施层 - 工具类、扩展方法、帮助类
|
||||
┣ 📂OpenAuth.Repository # 数据访问层 - 实体定义、数据访问
|
||||
┣ 📂OpenAuth.App # 应用服务层 - 业务逻辑
|
||||
┣ 📂OpenAuth.WebApi # 表示层 - WebAPI控制器
|
||||
┣ 📂OpenAuth.Identity # 身份认证服务 - IdentityServer4
|
||||
┣ 📂Vue2 # 前端项目
|
||||
┗ 📂数据库脚本 # 数据库初始化脚本
|
||||
```
|
||||
|
||||
## 编码规范
|
||||
|
||||
### 通用规范
|
||||
- 使用C# 9+语法特性
|
||||
- 遵循Microsoft C#编码规范
|
||||
- 类名使用PascalCase,方法名使用PascalCase
|
||||
- 私有字段使用_camelCase,公共属性使用PascalCase
|
||||
- 常量使用UPPER_CASE
|
||||
- 异步方法必须添加Async后缀
|
||||
|
||||
### 命名规范
|
||||
- **Controller**: 以Controller结尾,如`UsersController`
|
||||
- **Service/App**: 以App结尾,如`UserManagerApp`
|
||||
- **Repository**: 以Repository结尾,如`UserRepository`
|
||||
- **Entity**: 实体类直接使用名词,如`SysUser`
|
||||
- **Request**: 请求类以Req结尾,如`QueryUserListReq`
|
||||
- **Response**: 响应类以Resp结尾,如`PagedListDataResp`
|
||||
- **DTO**: 视图模型以View结尾,如`UserView`
|
||||
|
||||
### 注释规范
|
||||
- 所有公共方法必须添加XML注释
|
||||
- 复杂业务逻辑必须添加行内注释
|
||||
- 使用/// <summary>标记方法说明
|
||||
- 参数使用/// <param name="参数名">说明</param>
|
||||
- 返回值使用/// <returns>说明</returns>
|
||||
|
||||
## 分层架构规则
|
||||
|
||||
### Infrastructure层 (基础设施层)
|
||||
- **职责**: 提供通用工具类、扩展方法、帮助类、常量定义
|
||||
- **规则**:
|
||||
- 不依赖其他业务层
|
||||
- 提供可复用的基础功能
|
||||
- 包含缓存、配置、工具类等
|
||||
- **文件组织**:
|
||||
- `/Cache` - 缓存相关
|
||||
- `/Extensions` - 扩展方法
|
||||
- `/Helpers` - 帮助类
|
||||
- `/Const` - 常量定义
|
||||
|
||||
### Repository层 (数据访问层)
|
||||
- **职责**: 数据访问、实体定义、数据库操作
|
||||
- **规则**:
|
||||
- 继承自`BaseRepository<T,TContext>`
|
||||
- 实体类继承自`StringEntity`、`LongEntity`或`IntAutoGenEntity`
|
||||
- 使用SqlSugar或EF Core进行数据访问
|
||||
- 包含DbContext配置
|
||||
- **基类使用**:
|
||||
- `StringEntity`: 字符串主键实体
|
||||
- `LongEntity`: 长整型主键实体
|
||||
- `IntAutoGenEntity`: 自增整型主键实体
|
||||
|
||||
### App层 (应用服务层)
|
||||
- **职责**: 业务逻辑处理、数据传输对象、业务规则
|
||||
- **规则**:
|
||||
- 继承自`SqlSugarBaseApp<T>`、`BaseStringApp<T>`、`BaseLongApp<T>`等基类
|
||||
- 通过构造函数注入依赖
|
||||
- 实现业务逻辑,不直接操作数据库
|
||||
- 使用Request/Response模式
|
||||
- **依赖注入**:
|
||||
```csharp
|
||||
public UserManagerApp(ISqlSugarClient client, RevelanceManagerApp app, IAuth auth)
|
||||
: base(client, auth)
|
||||
```
|
||||
|
||||
### WebApi层 (表示层)
|
||||
- **职责**: HTTP请求处理、参数验证、响应格式化
|
||||
- **规则**:
|
||||
- 继承自`ControllerBase`
|
||||
- 使用`[ApiController]`特性
|
||||
- 统一返回`Response<T>`格式
|
||||
- 进行参数验证
|
||||
- 添加Swagger文档注释
|
||||
|
||||
## 数据库操作规范
|
||||
|
||||
### SqlSugar使用规范
|
||||
```csharp
|
||||
// 查询
|
||||
var users = SugarClient.Queryable<SysUser>()
|
||||
.Where(u => u.Status == 1)
|
||||
.ToList();
|
||||
|
||||
// 分页查询
|
||||
var result = new PagedListDataResp<Role>();
|
||||
var objs = SugarClient.Queryable<Role>();
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
objs = objs.Where(u => u.Name.Contains(request.key));
|
||||
}
|
||||
|
||||
result.Data = await objs.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit).ToListAsync();
|
||||
result.Count = await objs.CountAsync();
|
||||
return result;
|
||||
|
||||
// 联表查询
|
||||
var result = SugarClient.Queryable<Relevance>()
|
||||
.LeftJoin<SysOrg>((u, o) => u.SecondId == o.Id)
|
||||
.Where((u, o) => u.FirstId == userId && u.RelKey == Define.USERORG)
|
||||
.Select((u, o) => o);
|
||||
return result.ToList();
|
||||
```
|
||||
|
||||
### 事务处理
|
||||
```csharp
|
||||
SugarClient.Ado.BeginTran();
|
||||
try
|
||||
{
|
||||
// 数据库操作
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
catch
|
||||
{
|
||||
SugarClient.Ado.RollbackTran();
|
||||
throw;
|
||||
}
|
||||
```
|
||||
|
||||
## 权限和安全规范
|
||||
|
||||
### 权限验证
|
||||
- 使用`IAuth`接口获取当前用户信息
|
||||
- 通过`_auth.GetCurrentUser()`获取登录用户
|
||||
- 数据权限通过机构级联控制
|
||||
|
||||
## API设计规范
|
||||
|
||||
### 控制器设计
|
||||
```csharp
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly UserManagerApp _app;
|
||||
|
||||
public UsersController(UserManagerApp app)
|
||||
{
|
||||
_app = app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户列表
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<Response<PagedListDataResp<UserView>>> Get([FromQuery] QueryUserListReq request)
|
||||
{
|
||||
var result = await _app.Load(request);
|
||||
return Response.Ok(result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖注入规范
|
||||
|
||||
### Autofac配置
|
||||
- 在`AutofacExt.cs`中配置依赖注入
|
||||
- 实现`IDependency`接口的类自动注册
|
||||
- 使用构造函数注入
|
||||
|
||||
## 测试规范
|
||||
|
||||
### 单元测试
|
||||
- 使用NUnit框架
|
||||
- 继承自`TestBase`基类
|
||||
- 测试类以Test结尾
|
||||
- 测试方法使用描述性名称
|
||||
|
||||
### 集成测试
|
||||
- 使用`AutofacWebApplicationFactory`
|
||||
- 模拟HTTP请求
|
||||
- 验证完整的业务流程
|
||||
|
||||
## 工作流规范
|
||||
|
||||
### 流程定义
|
||||
- 使用`FlowScheme`定义流程模板
|
||||
- 通过`FlowInstance`管理流程实例
|
||||
- `FlowNode`表示流程节点
|
||||
|
||||
### 流程引擎
|
||||
- 使用`FlowRuntime`执行流程
|
||||
- 支持顺序、并行、条件等流程类型
|
||||
- 流程状态通过`FlowInstanceStatus`管理
|
||||
|
||||
## 定时任务规范
|
||||
|
||||
### Quartz使用
|
||||
- 继承自`IJob`接口
|
||||
- 在`QuartzService`中注册任务
|
||||
- 支持Cron表达式配置
|
||||
|
||||
## 文档规范
|
||||
|
||||
### 代码文档
|
||||
- 重要业务逻辑添加注释
|
||||
- 复杂算法添加说明
|
||||
- 配置文件添加说明注释
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 配置文件
|
||||
- `appsettings.json`: 基础配置
|
||||
- `appsettings.Development.json`: 开发环境配置
|
||||
- `appsettings.Production.json`: 生产环境配置
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -268,3 +268,4 @@ __pycache__/
|
||||
/OpenAuth.Mvc/Properties/PublishProfiles
|
||||
*.pubxml
|
||||
/OpenAuth.WebApi/temp-keys
|
||||
/newdocs/docs/.vuepress/.cache
|
||||
|
||||
59
CHANGELOG.md
59
CHANGELOG.md
@@ -1,3 +1,62 @@
|
||||
|
||||
|
||||
## v8.1
|
||||
|
||||
* [重磅] 统一后端返回格式response.result调整为response.data
|
||||
* [重磅] 表格组件增加排序功能
|
||||
* [优化] 持续优化代码
|
||||
|
||||
## v8.0
|
||||
|
||||
* [重磅] 开源十周年特别版!
|
||||
* [重磅] 全面开源原付费vue2版本源码及文档,免费使用。
|
||||
* [重磅] 删除原有mvc项目,从此以后只有前后端分离。
|
||||
|
||||
|
||||
## v7.6
|
||||
|
||||
* [重磅] 分离会签和网关功能,详情请查看工作流中的概念
|
||||
* [优化] 前后端统一流程节点类型。详情请查看文档流程相关代码-流程模板
|
||||
* [优化] 修复顺序加签
|
||||
|
||||
## v7.5
|
||||
|
||||
* [新增] 流程执行节点支持通过Sql配置用户
|
||||
* [优化] 流程节点设置json对象统一为datas字段
|
||||
* [优化] 优化layui样式
|
||||
|
||||
## v7.4
|
||||
|
||||
* [新增] 代码生成加上外部数据源支持;
|
||||
* [新增] 新增动态API功能;
|
||||
* [优化] 流程模板调整为sqlsugar;
|
||||
|
||||
## v7.3
|
||||
|
||||
* [新增] 新增API鉴权功能
|
||||
* [优化] 优化vue3代码生成;
|
||||
|
||||
## v7.2
|
||||
|
||||
* [重磅]流程增加任意节点撤回审批功能
|
||||
* [重磅]全面优化数据库初始脚本,SqlServer采用帕斯卡命名,MySql/pg采用小写命名,Oracle采用大写
|
||||
* [重磅]优化layui点击行可选中
|
||||
|
||||
## v7.1
|
||||
|
||||
* [重磅]全面优化对Oracle数据库的支持
|
||||
* [优化]FIX issue #IBLX2E:目前Oracle工作流列表不能加载 目前Oracle工作流列表不能加载
|
||||
* [优化]流程实例历史操作记录
|
||||
|
||||
## v7.0
|
||||
|
||||
- **新特性**
|
||||
|
||||
- [新增] 全面支持.Net 9
|
||||
- [新增] 新增Dockerfile支持
|
||||
- [新增] 修复vue3代码生成部分bug
|
||||
|
||||
|
||||
## v6.5
|
||||
|
||||
- **新特性**
|
||||
|
||||
@@ -28,7 +28,13 @@ namespace Infrastructure
|
||||
{
|
||||
if (obj == null) return default(T);
|
||||
|
||||
var config = new MapperConfiguration(cfg=>cfg.CreateMap(obj.GetType(),typeof(T)));
|
||||
// 当Id为空时,不进行映射
|
||||
var config = new MapperConfiguration(cfg => {
|
||||
cfg.CreateMap(obj.GetType(), typeof(T))
|
||||
.ForMember("Id", opt => opt.Condition((src, dest, srcValue) =>
|
||||
srcValue != null && !string.IsNullOrEmpty(srcValue.ToString())
|
||||
));
|
||||
});
|
||||
var mapper = config.CreateMapper();
|
||||
return mapper.Map<T>(obj);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
/// </summary>
|
||||
public static class Define
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认租户ID
|
||||
/// </summary>
|
||||
public const string DEFAULT_TENANT_ID = "OpenAuthDBContext";
|
||||
|
||||
//Relevance关联KEY
|
||||
/// <summary>
|
||||
/// 用户角色关联KEY
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Infrastructure.Extensions.AutofacManager
|
||||
public static TService GetService<TService>() where TService:class
|
||||
{
|
||||
Type typeParameterType = typeof(TService);
|
||||
return (TService)_provider.GetService(typeParameterType);
|
||||
return (TService)_provider?.GetService(typeParameterType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ namespace Infrastructure.Utilities
|
||||
{
|
||||
public static class HttpContextUtil
|
||||
{
|
||||
private static IHttpContextAccessor _accessor=AutofacContainerModule.GetService<IHttpContextAccessor>();
|
||||
// 不要在静态初始化时获取IHttpContextAccessor,而是在需要时获取
|
||||
private static IHttpContextAccessor _accessor => AutofacContainerModule.GetService<IHttpContextAccessor>();
|
||||
|
||||
public static Microsoft.AspNetCore.Http.HttpContext Current => _accessor.HttpContext;
|
||||
public static Microsoft.AspNetCore.Http.HttpContext Current => _accessor?.HttpContext;
|
||||
|
||||
/// <summary>
|
||||
/// 获取租户ID
|
||||
@@ -15,7 +16,7 @@ namespace Infrastructure.Utilities
|
||||
/// <returns></returns>
|
||||
public static string GetTenantId(this IHttpContextAccessor accessor)
|
||||
{
|
||||
string tenantId = "OpenAuthDBContext";
|
||||
string tenantId = Define.DEFAULT_TENANT_ID;
|
||||
|
||||
if (accessor != null && accessor.HttpContext != null)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Infrastructure;
|
||||
using Infrastructure.Utilities;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.Repository;
|
||||
using OpenAuth.Repository.Core;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using SqlSugar;
|
||||
using Autofac;
|
||||
using Infrastructure.Extensions.AutofacManager;
|
||||
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
@@ -13,7 +18,7 @@ namespace OpenAuth.App
|
||||
/// SqlSugar基础类
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class SqlSugarBaseApp<T> where T : class, new()
|
||||
public abstract class SqlSugarBaseApp<T> where T : BaseEntity, new()
|
||||
{
|
||||
protected ISqlSugarClient SugarClient;
|
||||
|
||||
@@ -21,8 +26,23 @@ namespace OpenAuth.App
|
||||
|
||||
protected IAuth _auth;
|
||||
|
||||
/// <summary>
|
||||
/// 保持向后兼容的构造函数,避免修改子类
|
||||
/// </summary>
|
||||
public SqlSugarBaseApp(ISqlSugarClient client, IAuth auth)
|
||||
{
|
||||
string tenantId = Define.DEFAULT_TENANT_ID;
|
||||
var httpContextAccessor = AutofacContainerModule.GetService<IHttpContextAccessor>();
|
||||
if (httpContextAccessor != null)
|
||||
{
|
||||
tenantId = httpContextAccessor.GetTenantId();
|
||||
}
|
||||
|
||||
if(tenantId != Define.DEFAULT_TENANT_ID) //如果不是默认租户,则使用租户id获取连接
|
||||
{
|
||||
client = client.AsTenant().GetConnection(tenantId);
|
||||
}
|
||||
|
||||
Repository = new SqlSugarRepository<T>(client); //这里用new而不用注入,可以保证client和repository用的是同一个client
|
||||
SugarClient = client;
|
||||
_auth = auth;
|
||||
|
||||
58
OpenAuth.App/Base/SqlSugarBaseTreeApp.cs
Normal file
58
OpenAuth.App/Base/SqlSugarBaseTreeApp.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.Repository.Core;
|
||||
using SqlSugar;
|
||||
using OpenAuth.Repository.Interface;
|
||||
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
/// <summary>
|
||||
/// 树状结构处理
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// /// <typeparam name="TDbContext"></typeparam>
|
||||
public class SqlSugarBaseTreeApp<T> :SqlSugarBaseApp<T> where T : TreeEntity, new()
|
||||
{
|
||||
|
||||
|
||||
public SqlSugarBaseTreeApp(ISqlSugarClient client, IAuth auth)
|
||||
: base(client, auth)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新树状结构实体
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="U"></typeparam>
|
||||
public void UpdateTreeObj<U>(U obj) where U : TreeEntity, new()
|
||||
{
|
||||
CaculateCascade(obj);
|
||||
|
||||
//获取旧的的CascadeId
|
||||
var cascadeId = SugarClient.Queryable<U>().First(o => o.Id == obj.Id).CascadeId;
|
||||
//根据CascadeId查询子部门
|
||||
var objs = SugarClient.Queryable<U>().Where(u => u.CascadeId.Contains(cascadeId) && u.Id != obj.Id)
|
||||
.OrderBy(u => u.CascadeId).ToList();
|
||||
|
||||
//更新操作
|
||||
SugarClient.Updateable(obj).ExecuteCommand();
|
||||
|
||||
//更新子模块的CascadeId
|
||||
foreach (var a in objs)
|
||||
{
|
||||
a.CascadeId = a.CascadeId.Replace(cascadeId, obj.CascadeId);
|
||||
if (a.ParentId == obj.Id)
|
||||
{
|
||||
a.ParentName = obj.Name;
|
||||
}
|
||||
|
||||
SugarClient.Updateable(a).ExecuteCommand();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -337,6 +337,7 @@ namespace OpenAuth.App
|
||||
.Replace("{ModuleCode}", sysTableInfo.ModuleCode)
|
||||
.Replace("{ModuleName}", sysTableInfo.ModuleName)
|
||||
.Replace("{ClassName}", sysTableInfo.ClassName)
|
||||
.Replace("{Namespace}", sysTableInfo.Namespace)
|
||||
.Replace("{UpdateColumns}", updateColumns)
|
||||
.Replace("{InsertColumns}", insertColumns)
|
||||
.Replace("{StartName}", StratName);
|
||||
@@ -370,6 +371,7 @@ namespace OpenAuth.App
|
||||
.Replace("{ModuleCode}", sysTableInfo.ModuleCode)
|
||||
.Replace("{ModuleName}", sysTableInfo.ModuleName)
|
||||
.Replace("{ClassName}", sysTableInfo.ClassName)
|
||||
.Replace("{Namespace}", sysTableInfo.Namespace)
|
||||
.Replace("{SubForeignKey}", subTable.ForeignKey)
|
||||
.Replace("{SubClassName}", subTable.ClassName)
|
||||
.Replace("{SubModuleCode}", subTable.ModuleCode)
|
||||
@@ -508,6 +510,7 @@ namespace OpenAuth.App
|
||||
domainContent = FileHelper.ReadFile(@"Template\\BuildControllerApi.html")
|
||||
.Replace("{TableName}", sysTableInfo.TableName)
|
||||
.Replace("{ModuleCode}", sysTableInfo.ModuleCode)
|
||||
.Replace("{Namespace}", sysTableInfo.Namespace)
|
||||
.Replace("{ModuleName}", sysTableInfo.ModuleName)
|
||||
.Replace("{ClassName}", sysTableInfo.ClassName)
|
||||
.Replace("{StartName}", StratName);
|
||||
@@ -607,6 +610,7 @@ namespace OpenAuth.App
|
||||
|
||||
domainContent = domainContent.Replace("{ClassName}", tableInfo.ClassName)
|
||||
.Replace("{AttributeList}", attributeBuilder.ToString())
|
||||
.Replace("{Namespace}", tableInfo.Namespace)
|
||||
.Replace("{Construction}", constructionBuilder.ToString());
|
||||
|
||||
|
||||
@@ -621,10 +625,29 @@ namespace OpenAuth.App
|
||||
tableAttr.Append(" [Table(\"" + tableInfo.TableName + "\")]");
|
||||
domainContent = domainContent.Replace("{AttributeManager}", tableAttr.ToString());
|
||||
|
||||
FileHelper.WriteFile(
|
||||
mapPath +
|
||||
$"\\OpenAuth.Repository\\Domain\\", tableInfo.ClassName + ".cs",
|
||||
domainContent);
|
||||
// 检查命名空间是否以OpenAuth.Repository开头
|
||||
if (!tableInfo.Namespace.StartsWith("OpenAuth.Repository"))
|
||||
{
|
||||
throw new Exception("命名空间必须以OpenAuth.Repository开头!");
|
||||
}
|
||||
// 获取OpenAuth.Repository后面的部分
|
||||
var subNamespace = tableInfo.Namespace.Substring("OpenAuth.Repository".Length).TrimStart('.');
|
||||
// 构建目录层级
|
||||
var domainPath = Path.Combine(mapPath, "OpenAuth.Repository");
|
||||
if (!string.IsNullOrEmpty(subNamespace))
|
||||
{
|
||||
foreach (var part in subNamespace.Split('.'))
|
||||
{
|
||||
domainPath = Path.Combine(domainPath, part);
|
||||
}
|
||||
}
|
||||
// 确保目录存在
|
||||
if (!Directory.Exists(domainPath))
|
||||
{
|
||||
Directory.CreateDirectory(domainPath);
|
||||
}
|
||||
|
||||
FileHelper.WriteFile(domainPath, tableInfo.ClassName + ".cs", domainContent);
|
||||
}
|
||||
|
||||
Dictionary<string, Type> PrimitiveTypes = new Dictionary<string, Type>()
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace OpenAuth.App
|
||||
var user = _auth.GetCurrentUser().User;
|
||||
obj.CreateUserId = user.Id;
|
||||
obj.CreateUserName = user.Name;
|
||||
await SugarClient.Insertable(obj).ExecuteCommandAsync();
|
||||
Repository.Insert(obj);
|
||||
}
|
||||
|
||||
public void Update(AddOrUpdateCategoryReq obj)
|
||||
|
||||
@@ -590,6 +590,16 @@ namespace OpenAuth.App.Flow
|
||||
throw new Exception("无法寻找到下一个节点");
|
||||
}
|
||||
|
||||
//如果request为空,则应该是草稿状态变为启动,或为网关节点,使用nextNode的setInfo
|
||||
if (request == null)
|
||||
{
|
||||
request = new NodeDesignateReq
|
||||
{
|
||||
NodeDesignateType = nextNode.setInfo.NodeDesignate,
|
||||
NodeDesignates = nextNode.setInfo.NodeDesignateData.datas
|
||||
};
|
||||
}
|
||||
|
||||
if (GetNextNodeType() == Define.NODE_TYPE_FORK) //如果是网关节点
|
||||
{
|
||||
makerList = GetForkNodeMakers(nextNodeId);
|
||||
|
||||
@@ -4,13 +4,15 @@ using System.Linq;
|
||||
using Infrastructure;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using OpenAuth.Repository.Interface;
|
||||
using SqlSugar;
|
||||
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public class OrgManagerApp : BaseTreeApp<SysOrg,OpenAuthDBContext>
|
||||
public class OrgManagerApp : SqlSugarBaseTreeApp<SysOrg>
|
||||
{
|
||||
private RevelanceManagerApp _revelanceApp;
|
||||
/// <summary>
|
||||
@@ -28,22 +30,20 @@ namespace OpenAuth.App
|
||||
}
|
||||
CaculateCascade(sysOrg);
|
||||
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
UnitWork.Add(sysOrg);
|
||||
UnitWork.Save();
|
||||
SugarClient.Ado.BeginTran();
|
||||
Repository.Insert(sysOrg);
|
||||
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
if (loginContext.User.Account != Define.SYSTEM_USERNAME)
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
if (loginContext.User.Account != Define.SYSTEM_USERNAME)
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
type = Define.USERORG,
|
||||
firstId = loginContext.User.Id,
|
||||
secIds = new[] { sysOrg.Id }
|
||||
});
|
||||
}
|
||||
});
|
||||
type = Define.USERORG,
|
||||
firstId = loginContext.User.Id,
|
||||
secIds = new[] { sysOrg.Id }
|
||||
});
|
||||
}
|
||||
SugarClient.Ado.CommitTran();
|
||||
|
||||
return sysOrg.Id;
|
||||
}
|
||||
@@ -58,47 +58,48 @@ namespace OpenAuth.App
|
||||
|
||||
return sysOrg.Id;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定ID的部门及其所有子部门
|
||||
/// </summary>
|
||||
public void DelOrgCascade(string[] ids)
|
||||
{
|
||||
var delOrgCascadeIds = UnitWork.Find<SysOrg>(u => ids.Contains(u.Id)).Select(u => u.CascadeId).ToArray();
|
||||
var delOrgCascadeIds = SugarClient.Queryable<SysOrg>().Where(u => ids.Contains(u.Id)).Select(u => u.CascadeId).ToArray();
|
||||
var delOrgIds = new List<string>();
|
||||
foreach (var cascadeId in delOrgCascadeIds)
|
||||
{
|
||||
delOrgIds.AddRange(UnitWork.Find<SysOrg>(u=>u.CascadeId.Contains(cascadeId)).Select(u =>u.Id).ToArray());
|
||||
delOrgIds.AddRange(SugarClient.Queryable<SysOrg>().Where(u => u.CascadeId.Contains(cascadeId)).Select(u => u.Id).ToArray());
|
||||
}
|
||||
|
||||
UnitWork.Delete<Relevance>(u =>u.RelKey == Define.USERORG && delOrgIds.Contains(u.SecondId));
|
||||
UnitWork.Delete<SysOrg>(u => delOrgIds.Contains(u.Id));
|
||||
UnitWork.Save();
|
||||
|
||||
|
||||
SugarClient.Deleteable<Relevance>().Where(u => u.RelKey == Define.USERORG && delOrgIds.Contains(u.SecondId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<SysOrg>().Where(u => delOrgIds.Contains(u.Id)).ExecuteCommand();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载特定用户的部门
|
||||
/// 获取所有机构
|
||||
/// </summary>
|
||||
/// <param name="userId">The user unique identifier.</param>
|
||||
public List<SysOrg> LoadForUser(string userId)
|
||||
/// <returns></returns>
|
||||
public List<OrgView> LoadAll()
|
||||
{
|
||||
var result = from userorg in UnitWork.Find<Relevance>(null)
|
||||
join org in UnitWork.Find<SysOrg>(null) on userorg.SecondId equals org.Id
|
||||
where userorg.FirstId == userId && userorg.RelKey == Define.USERORG
|
||||
select org;
|
||||
return result.ToList();
|
||||
return SugarClient.Queryable<SysOrg>()
|
||||
.LeftJoin<SysUser>((org, user) => org.ChairmanId ==user.Id)
|
||||
.Select((org,user)=>new OrgView
|
||||
{
|
||||
Id = org.Id.SelectAll(),
|
||||
ChairmanName = user.Name
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public OrgManagerApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<SysOrg,OpenAuthDBContext> repository,IAuth auth,
|
||||
RevelanceManagerApp revelanceApp) : base(unitWork, repository, auth)
|
||||
public OrgManagerApp(ISqlSugarClient client, IAuth auth,
|
||||
RevelanceManagerApp revelanceApp) : base(client, auth)
|
||||
{
|
||||
_revelanceApp = revelanceApp;
|
||||
}
|
||||
|
||||
public string[] GetChairmanId(string[] orgIds)
|
||||
{
|
||||
return Repository.Find(u => orgIds.Contains(u.Id)&&u.ChairmanId!= null).Select(u => u.ChairmanId).ToArray();
|
||||
return SugarClient.Queryable<SysOrg>().Where(u => orgIds.Contains(u.Id) && u.ChairmanId != null).Select(u => u.ChairmanId).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,11 @@ namespace OpenAuth.App
|
||||
var elementIds = _revelanceApp.Get(Define.ROLERESOURCE, true, roleId);
|
||||
return SugarClient.Queryable<SysResource>().Where(u => elementIds.Contains(u.Id) && (appId == null || appId =="" || u.AppId == appId)).ToArray();
|
||||
}
|
||||
|
||||
public List<SysResource> LoadByIds(string[] ids)
|
||||
{
|
||||
return SugarClient.Queryable<SysResource>().Where(u => ids.Contains(u.Id)).ToList();
|
||||
}
|
||||
|
||||
public async Task<PagedDynamicDataResp> Load(QueryResourcesReq request)
|
||||
{
|
||||
|
||||
@@ -11,9 +11,11 @@ using Microsoft.EntityFrameworkCore;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.Repository;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public class RoleApp : BaseStringApp<Role,OpenAuthDBContext>
|
||||
public class RoleApp : SqlSugarBaseApp<Role>
|
||||
{
|
||||
private RevelanceManagerApp _revelanceApp;
|
||||
|
||||
@@ -39,7 +41,7 @@ namespace OpenAuth.App
|
||||
public async Task<PagedListDataResp<Role>> LoadAll(QueryRoleListReq request)
|
||||
{
|
||||
var result = new PagedListDataResp<Role>();
|
||||
var objs = UnitWork.Find<Role>(null);
|
||||
var objs = SugarClient.Queryable<Role>();
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
objs = objs.Where(u => u.Name.Contains(request.key));
|
||||
@@ -52,47 +54,54 @@ namespace OpenAuth.App
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID加载角色
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns></returns>
|
||||
public List<Role> LoadByIds(string[] ids)
|
||||
{
|
||||
return Repository.GetList(u => ids.Contains(u.Id));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加角色,如果当前登录用户不是System,则直接把新角色分配给当前登录用户
|
||||
/// </summary>
|
||||
public void Add(RoleView obj)
|
||||
{
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
Role role = obj;
|
||||
role.CreateTime = DateTime.Now;
|
||||
UnitWork.Add(role);
|
||||
UnitWork.Save();
|
||||
obj.Id = role.Id; //要把保存后的ID存入view
|
||||
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
if (loginUser.User.Account != Define.SYSTEM_USERNAME)
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
type = Define.USERROLE,
|
||||
firstId = loginUser.User.Id,
|
||||
secIds = new[] {role.Id}
|
||||
});
|
||||
}
|
||||
});
|
||||
SugarClient.Ado.BeginTran();
|
||||
Role role = obj;
|
||||
role.CreateTime = DateTime.Now;
|
||||
Repository.Insert(role);
|
||||
obj.Id = role.Id; //要把保存后的ID存入view
|
||||
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
if (loginUser.User.Account != Define.SYSTEM_USERNAME)
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
type = Define.USERROLE,
|
||||
firstId = loginUser.User.Id,
|
||||
secIds = new[] {role.Id}
|
||||
});
|
||||
}
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除角色时,需要删除角色对应的权限
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
public override void Delete(string[] ids)
|
||||
public new void Delete(string[] ids)
|
||||
{
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
UnitWork.Delete<Relevance>(u=>(u.RelKey == Define.ROLEMODULE || u.RelKey == Define.ROLEELEMENT) && ids.Contains(u.FirstId));
|
||||
UnitWork.Delete<Relevance>(u=>u.RelKey == Define.USERROLE && ids.Contains(u.SecondId));
|
||||
UnitWork.Delete<Role>(u =>ids.Contains(u.Id));
|
||||
UnitWork.Save();
|
||||
});
|
||||
SugarClient.Ado.BeginTran();
|
||||
SugarClient.Deleteable<Relevance>().Where(u=>(u.RelKey == Define.ROLEMODULE || u.RelKey == Define.ROLEELEMENT) && ids.Contains(u.FirstId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<Relevance>().Where(u=>u.RelKey == Define.USERROLE && ids.Contains(u.SecondId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<Role>().Where(u =>ids.Contains(u.Id)).ExecuteCommand();
|
||||
SugarClient.Ado.CommitTran();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,19 +110,16 @@ namespace OpenAuth.App
|
||||
/// <param name="obj"></param>
|
||||
public void Update(RoleView obj)
|
||||
{
|
||||
Role role = obj;
|
||||
|
||||
UnitWork.Update<Role>(u => u.Id == obj.Id, u => new Role
|
||||
Repository.Update(u => new Role
|
||||
{
|
||||
Name = role.Name,
|
||||
Status = role.Status
|
||||
});
|
||||
|
||||
Name = obj.Name,
|
||||
Status = obj.Status
|
||||
}, u => u.Id == obj.Id);
|
||||
}
|
||||
|
||||
|
||||
public RoleApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Role,OpenAuthDBContext> repository,
|
||||
RevelanceManagerApp app,IAuth auth) : base(unitWork, repository, auth)
|
||||
public RoleApp(ISqlSugarClient client,
|
||||
RevelanceManagerApp app,IAuth auth) : base(client, auth)
|
||||
{
|
||||
_revelanceApp = app;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
@@ -60,44 +61,80 @@ namespace OpenAuth.App.Test
|
||||
|
||||
serviceCollection.AddDbContext<OpenAuthDBContext>();
|
||||
|
||||
var dbtypes = config.GetSection("AppSetting:DbTypes").GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
var connectionString = config.GetSection("ConnectionStrings")["OpenAuthDBContext"];
|
||||
|
||||
Console.WriteLine($"单元测试数据库信息:{dbtypes[httpContextAccessorMock.Object.GetTenantId()]}/{connectionString}");
|
||||
|
||||
var dbtypes = config.GetSection("AppSetting:DbTypes").GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);;
|
||||
var sqlsugarTypes = UtilMethods.EnumToDictionary<SqlSugar.DbType>();
|
||||
var dbType = sqlsugarTypes.FirstOrDefault(it =>
|
||||
dbtypes.ToDictionary(u => u.Key, v => v.Value.ToLower()).ContainsValue(it.Key));
|
||||
|
||||
serviceCollection.AddScoped<ISqlSugarClient>(s =>
|
||||
{
|
||||
var sqlSugar = new SqlSugarClient(new ConnectionConfig()
|
||||
// 获取所有连接字符串配置
|
||||
var connectionStrings = config.GetSection("ConnectionStrings").GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
// 准备ConnectionConfig列表
|
||||
var connectionConfigs = new List<ConnectionConfig>();
|
||||
|
||||
// 遍历所有连接字符串
|
||||
foreach (var conn in connectionStrings)
|
||||
{
|
||||
DbType = dbType.Value,
|
||||
ConnectionString = connectionString,
|
||||
IsAutoCloseConnection = true
|
||||
});
|
||||
|
||||
if(dbType.Value != SqlSugar.DbType.PostgreSQL){
|
||||
return sqlSugar;
|
||||
}
|
||||
// 配置bool类型转换为smallint
|
||||
sqlSugar.Aop.OnExecutingChangeSql = (sql, parameters) =>
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
// 获取对应的数据库类型
|
||||
var connDbType = dbtypes.ContainsKey(conn.Key) ?
|
||||
sqlsugarTypes.FirstOrDefault(it => dbtypes[conn.Key].ToLower().Contains(it.Key)).Value :
|
||||
DbType.SqlServer; // 如果没有定义DbType,使用默认类型
|
||||
|
||||
// 创建连接配置
|
||||
var config = new ConnectionConfig
|
||||
{
|
||||
if (param.Value is bool boolValue)
|
||||
{
|
||||
param.DbType = System.Data.DbType.Int16;
|
||||
// 将 bool 转换为 smallint
|
||||
param.Value = boolValue ? (short)1 : (short)0;
|
||||
}
|
||||
DbType = connDbType,
|
||||
ConnectionString = conn.Value,
|
||||
IsAutoCloseConnection = true,
|
||||
};
|
||||
|
||||
// 如果不是默认连接,设置ConfigId
|
||||
if (conn.Key != Define.DEFAULT_TENANT_ID)
|
||||
{
|
||||
config.ConfigId = conn.Key;
|
||||
}
|
||||
// 返回修改后的 SQL 和参数
|
||||
return new System.Collections.Generic.KeyValuePair<string, SugarParameter[]>(sql, parameters);
|
||||
};
|
||||
|
||||
connectionConfigs.Add(config);
|
||||
Console.WriteLine($"添加数据库连接: {conn.Key} / {(dbtypes.ContainsKey(conn.Key) ? dbtypes[conn.Key] : "未指定类型")},连接字符串:{conn.Value}");
|
||||
}
|
||||
|
||||
//通过ConfigId为空判断是否有默认的连接字符串
|
||||
if(!connectionConfigs.Any(x => x.ConfigId == null))
|
||||
{
|
||||
throw new Exception($"没有找到默认的连接字符串:{Define.DEFAULT_TENANT_ID}");
|
||||
}
|
||||
|
||||
//把connectionConfigs排序,ConfigId为空的放在最前面,即默认的连接字符串必须排最前面
|
||||
connectionConfigs = connectionConfigs.OrderBy(x => x.ConfigId == null ? 0 : 1).ToList();
|
||||
|
||||
var sqlSugar = new SqlSugarClient(connectionConfigs);
|
||||
|
||||
// 配置PostgreSQL数据库处理
|
||||
foreach (var connConfig in connectionConfigs)
|
||||
{
|
||||
if(connConfig.DbType == SqlSugar.DbType.PostgreSQL)
|
||||
{
|
||||
// 配置bool类型转换为smallint
|
||||
sqlSugar.Aop.OnExecutingChangeSql = (sql, parameters) =>
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.Value is bool boolValue)
|
||||
{
|
||||
param.DbType = System.Data.DbType.Int16;
|
||||
// 将 bool 转换为 smallint
|
||||
param.Value = boolValue ? (short)1 : (short)0;
|
||||
}
|
||||
}
|
||||
// 返回修改后的 SQL 和参数
|
||||
return new System.Collections.Generic.KeyValuePair<string, SugarParameter[]>(sql, parameters);
|
||||
};
|
||||
break; // 找到一个PostgreSQL连接后就设置一次即可
|
||||
}
|
||||
}
|
||||
|
||||
return sqlSugar;
|
||||
});
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace OpenAuth.App.Test
|
||||
|
||||
//模拟路径
|
||||
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
|
||||
.Replace("\\OpenAuth.App\\bin\\Debug\\netcoreapp3.1","");
|
||||
.Replace("\\OpenAuth.App\\bin\\Debug\\net9.0","");
|
||||
var mockPathProvider = new Mock<IPathProvider>();
|
||||
mockPathProvider.Setup(x => x.MapPath("",false)).Returns(path);
|
||||
services.AddScoped(x => mockHttpFac.Object);
|
||||
|
||||
@@ -12,100 +12,120 @@ using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using OpenAuth.Repository.Interface;
|
||||
using SqlSugar;
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public class UserManagerApp : BaseStringApp<SysUser,OpenAuthDBContext>
|
||||
public class UserManagerApp : SqlSugarBaseApp<SysUser>
|
||||
{
|
||||
private RevelanceManagerApp _revelanceApp;
|
||||
private OrgManagerApp _orgManagerApp;
|
||||
public UserManagerApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<SysUser,OpenAuthDBContext> repository,
|
||||
RevelanceManagerApp app,IAuth auth, OrgManagerApp orgManagerApp) : base(unitWork, repository, auth)
|
||||
public UserManagerApp(ISqlSugarClient client,
|
||||
RevelanceManagerApp app, IAuth auth, OrgManagerApp orgManagerApp) : base(client, auth)
|
||||
{
|
||||
_revelanceApp = app;
|
||||
_orgManagerApp = orgManagerApp;
|
||||
}
|
||||
public SysUser GetByAccount(string account)
|
||||
{
|
||||
return Repository.FirstOrDefault(u => u.Account == account);
|
||||
return SugarClient.Queryable<SysUser>().First(u => u.Account == account);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载用户列表
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="ignoreAuth">是否忽略权限,如果忽略权限,可以获取到所有用户</param>
|
||||
/// <returns></returns>
|
||||
private async Task<PagedListDataResp<UserView>> LoadUsers(QueryUserListReq request, bool ignoreAuth = false)
|
||||
{
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
var query = SugarClient.Queryable<SysUser>();
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
query = query.Where(u => u.Name.Contains(request.key) || u.Account.Contains(request.key));
|
||||
}
|
||||
|
||||
var orgs = SugarClient.Queryable<SysOrg>();
|
||||
if(!ignoreAuth) //如果没有忽略权限,则只能访问自己所在的机构
|
||||
{
|
||||
var orgIds = loginUser.Orgs.Select(u => u.Id).ToArray();
|
||||
orgs = orgs.Where(u => orgIds.Contains(u.Id));
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(request.orgId)) //如果请求的orgId不为空,加载这个机构及该机构下级的所有用户
|
||||
{
|
||||
var reqorg = SugarClient.Queryable<SysOrg>().First(u => u.Id == request.orgId);
|
||||
var cascadeId = reqorg.CascadeId;
|
||||
var orgIds = orgs.Where(u => u.CascadeId.Contains(cascadeId)).Select(u => u.Id).ToArray();
|
||||
var userIds = SugarClient.Queryable<Relevance>().Where(r => r.RelKey == Define.USERORG
|
||||
&& orgIds.Contains(r.SecondId)).Select(r => r.FirstId).Distinct().ToList();
|
||||
query = query.Where(u => userIds.Contains(u.Id));
|
||||
|
||||
}else{
|
||||
if(!ignoreAuth) //如果没有忽略权限,则根据用户所在的机构获取用户
|
||||
{
|
||||
var orgIds = orgs.Select(o => o.Id).ToArray();
|
||||
var userIds = SugarClient.Queryable<Relevance>().Where(r => r.RelKey == Define.USERORG
|
||||
&& orgIds.Contains(r.SecondId)).Select(r => r.FirstId).Distinct().ToList();
|
||||
query = query.Where(u => userIds.Contains(u.Id));
|
||||
}
|
||||
|
||||
//没有限制权限、没有传入orgId,则query就是获取最原始的所有用户
|
||||
}
|
||||
|
||||
var userOrgs = query
|
||||
.LeftJoin<SysUser>((user, u) => user.ParentId == u.Id)
|
||||
.LeftJoin<Relevance>((user, u, r) => user.Id == r.FirstId && r.RelKey == Define.USERORG)
|
||||
.LeftJoin<SysOrg>((user, u, r, o) => r.SecondId == o.Id);
|
||||
|
||||
var userOrgsResult = userOrgs.Select((user, u, r, o) => new
|
||||
{
|
||||
Account = user.Account,
|
||||
Name = user.Name,
|
||||
Id = user.Id,
|
||||
Sex = user.Sex,
|
||||
Status = user.Status,
|
||||
BizCode = user.BizCode,
|
||||
CreateId = user.CreateId,
|
||||
CreateTime = user.CreateTime,
|
||||
TypeId = user.TypeId,
|
||||
TypeName = user.TypeName,
|
||||
ParentId = user.ParentId,
|
||||
ParentName = u.Name,
|
||||
Key = r.RelKey,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
});
|
||||
var userViews = (await userOrgsResult.ToListAsync()).GroupBy(b => b.Account)
|
||||
.Select(u => new UserView
|
||||
{
|
||||
Id = u.First().Id,
|
||||
Account = u.Key,
|
||||
Name = u.First().Name,
|
||||
ParentName = u.First().ParentName,
|
||||
Sex = u.First().Sex,
|
||||
Status = u.First().Status,
|
||||
ParentId = u.First().ParentId,
|
||||
CreateTime = u.First().CreateTime,
|
||||
CreateUser = u.First().CreateId,
|
||||
OrganizationIds = string.Join(",", u.Select(x => x.OrgId)),
|
||||
Organizations = string.Join(",", u.Select(x => x.OrgName))
|
||||
});
|
||||
return new PagedListDataResp<UserView>
|
||||
{
|
||||
Count = userViews.Count(),
|
||||
Data = userViews.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit).ToList(),
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载当前登录用户可访问的一个部门及子部门全部用户
|
||||
/// 如果请求的request.OrgId为空,则可以获取到已被删除机构的用户(即:没有分配任何机构的用户)
|
||||
/// </summary>
|
||||
public async Task<PagedDynamicDataResp> Load(QueryUserListReq request)
|
||||
public async Task<PagedListDataResp<UserView>> Load(QueryUserListReq request)
|
||||
{
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
IQueryable<SysUser> query = UnitWork.Find<SysUser>(null);
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
query = UnitWork.Find<SysUser>(u => u.Name.Contains(request.key) || u.Account.Contains(request.key));
|
||||
}
|
||||
var userOrgs = from user in query
|
||||
join user2 in UnitWork.Find<SysUser>(null)
|
||||
on user.ParentId equals user2.Id into tempuser
|
||||
from u in tempuser.DefaultIfEmpty()
|
||||
join relevance in UnitWork.Find<Relevance>(u => u.RelKey == "UserOrg")
|
||||
on user.Id equals relevance.FirstId into temp
|
||||
from r in temp.DefaultIfEmpty()
|
||||
join org in UnitWork.Find<SysOrg>(null)
|
||||
on r.SecondId equals org.Id into orgtmp
|
||||
from o in orgtmp.DefaultIfEmpty()
|
||||
select new
|
||||
{
|
||||
user.Account,
|
||||
user.Name,
|
||||
user.Id,
|
||||
user.Sex,
|
||||
user.Status,
|
||||
user.BizCode,
|
||||
user.CreateId,
|
||||
user.CreateTime,
|
||||
user.TypeId,
|
||||
user.TypeName,
|
||||
user.ParentId,
|
||||
ParentName = u.Name, //直属上级
|
||||
Key = r.RelKey,
|
||||
r.SecondId,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
};
|
||||
//如果请求的orgId不为空
|
||||
if (!string.IsNullOrEmpty(request.orgId))
|
||||
{
|
||||
var org = loginUser.Orgs.SingleOrDefault(u => u.Id == request.orgId);
|
||||
var cascadeId = org.CascadeId;
|
||||
var orgIds = loginUser.Orgs.Where(u => u.CascadeId.Contains(cascadeId)).Select(u => u.Id).ToArray();
|
||||
//只获取机构里面的用户
|
||||
userOrgs = userOrgs.Where(u => u.Key == Define.USERORG && orgIds.Contains(u.OrgId));
|
||||
}
|
||||
else //todo:如果请求的orgId为空,即为跟节点,这时可以额外获取到机构已经被删除的用户,从而进行机构分配。可以根据自己需求进行调整
|
||||
{
|
||||
var orgIds = loginUser.Orgs.Select(u => u.Id).ToArray();
|
||||
//获取用户可以访问的机构的用户和没有任何机构关联的用户(机构被删除后,没有删除这里面的关联关系)
|
||||
userOrgs = userOrgs.Where(u => (u.Key == Define.USERORG && orgIds.Contains(u.OrgId)) || (u.OrgId == null));
|
||||
}
|
||||
var userViews = (await userOrgs.ToListAsync()).GroupBy(b => b.Account)
|
||||
.Select(u =>new UserView
|
||||
{
|
||||
Id = u.First().Id,
|
||||
Account = u.Key,
|
||||
Name = u.First().Name,
|
||||
ParentName = u.First().ParentName,
|
||||
Sex = u.First().Sex,
|
||||
Status = u.First().Status,
|
||||
ParentId = u.First().ParentId,
|
||||
CreateTime = u.First().CreateTime,
|
||||
CreateUser = u.First().CreateId,
|
||||
OrganizationIds = string.Join(",", u.Select(x=>x.OrgId))
|
||||
,Organizations = string.Join(",", u.Select(x=>x.OrgName))
|
||||
});
|
||||
return new PagedDynamicDataResp
|
||||
{
|
||||
Count =userViews.Count(),
|
||||
Data =userViews.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit),
|
||||
};
|
||||
return await LoadUsers(request, false);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取所有的用户
|
||||
@@ -113,128 +133,66 @@ namespace OpenAuth.App
|
||||
/// </summary>
|
||||
public async Task<PagedListDataResp<UserView>> LoadAll(QueryUserListReq request)
|
||||
{
|
||||
IQueryable<SysUser> query = UnitWork.Find<SysUser>(null);
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
query = UnitWork.Find<SysUser>(u => u.Name.Contains(request.key) || u.Account.Contains(request.key));
|
||||
}
|
||||
var userOrgs = from user in query
|
||||
join user2 in UnitWork.Find<SysUser>(null)
|
||||
on user.ParentId equals user2.Id into tempuser
|
||||
from u in tempuser.DefaultIfEmpty()
|
||||
join relevance in UnitWork.Find<Relevance>(u => u.RelKey == "UserOrg")
|
||||
on user.Id equals relevance.FirstId into temp
|
||||
from r in temp.DefaultIfEmpty()
|
||||
join org in UnitWork.Find<SysOrg>(null)
|
||||
on r.SecondId equals org.Id into orgtmp
|
||||
from o in orgtmp.DefaultIfEmpty()
|
||||
select new
|
||||
{
|
||||
user.Account,
|
||||
user.Name,
|
||||
user.Id,
|
||||
user.Sex,
|
||||
user.Status,
|
||||
user.BizCode,
|
||||
user.CreateId,
|
||||
user.CreateTime,
|
||||
user.TypeId,
|
||||
user.TypeName,
|
||||
user.ParentId,
|
||||
ParentName = u.Name, //直属上级
|
||||
Key = r.RelKey,
|
||||
r.SecondId,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
};
|
||||
//如果请求的orgId不为空
|
||||
if (!string.IsNullOrEmpty(request.orgId))
|
||||
{
|
||||
userOrgs = userOrgs.Where(u => u.Key == Define.USERORG && u.OrgId == request.orgId);
|
||||
}
|
||||
var userViews = (await userOrgs.ToListAsync()).GroupBy(b => b.Account).Select(u =>new UserView
|
||||
{
|
||||
Id = u.First().Id,
|
||||
Account = u.Key,
|
||||
Name = u.First().Name,
|
||||
Sex = u.First().Sex,
|
||||
Status = u.First().Status,
|
||||
CreateTime = u.First().CreateTime,
|
||||
CreateUser = u.First().CreateId,
|
||||
ParentName = u.First().ParentName,
|
||||
ParentId = u.First().ParentId,
|
||||
OrganizationIds = string.Join(",", u.Select(x=>x.OrgId))
|
||||
,Organizations = string.Join(",", u.Select(x=>x.OrgName))
|
||||
});
|
||||
return new PagedListDataResp<UserView>()
|
||||
{
|
||||
Count = userViews.Count(),
|
||||
Data = userViews.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit).ToList()
|
||||
};
|
||||
return await LoadUsers(request, true);
|
||||
}
|
||||
public void AddOrUpdate(UpdateUserReq request)
|
||||
{
|
||||
request.ValidationEntity(u => new {u.Account,u.Name, u.OrganizationIds});
|
||||
request.ValidationEntity(u => new { u.Account, u.Name, u.OrganizationIds });
|
||||
if (string.IsNullOrEmpty(request.OrganizationIds))
|
||||
throw new Exception("请为用户分配机构");
|
||||
SysUser requser = request;
|
||||
requser.CreateId = _auth.GetCurrentUser().User.Id;
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
SugarClient.Ado.BeginTran();
|
||||
if (string.IsNullOrEmpty(request.Id))
|
||||
{
|
||||
if (string.IsNullOrEmpty(request.Id))
|
||||
if (SugarClient.Queryable<SysUser>().Any(u => u.Account == request.Account))
|
||||
{
|
||||
if (UnitWork.Any<SysUser>(u => u.Account == request.Account))
|
||||
{
|
||||
throw new Exception("用户账号已存在");
|
||||
}
|
||||
if (string.IsNullOrEmpty(requser.Password))
|
||||
{
|
||||
requser.Password = requser.Account; //如果客户端没提供密码,默认密码同账号
|
||||
}
|
||||
requser.CreateTime = DateTime.Now;
|
||||
UnitWork.Add(requser);
|
||||
request.Id = requser.Id; //要把保存后的ID存入view
|
||||
throw new Exception("用户账号已存在");
|
||||
}
|
||||
else
|
||||
if (string.IsNullOrEmpty(requser.Password))
|
||||
{
|
||||
UnitWork.Update<SysUser>(u => u.Id == request.Id, u => new SysUser
|
||||
{
|
||||
Account = requser.Account,
|
||||
BizCode = requser.BizCode,
|
||||
Name = requser.Name,
|
||||
Sex = requser.Sex,
|
||||
Status = requser.Status,
|
||||
ParentId = request.ParentId
|
||||
});
|
||||
if (!string.IsNullOrEmpty(requser.Password)) //密码为空的时候,不做修改
|
||||
{
|
||||
UnitWork.Update<SysUser>(u => u.Id == request.Id, u => new SysUser
|
||||
{
|
||||
Password = requser.Password
|
||||
});
|
||||
}
|
||||
requser.Password = requser.Account; //如果客户端没提供密码,默认密码同账号
|
||||
}
|
||||
UnitWork.Save();
|
||||
string[] orgIds = request.OrganizationIds.Split(',').ToArray();
|
||||
_revelanceApp.DeleteBy(Define.USERORG, requser.Id);
|
||||
_revelanceApp.Assign(Define.USERORG, orgIds.ToLookup(u => requser.Id));
|
||||
});
|
||||
requser.CreateTime = DateTime.Now;
|
||||
Repository.Insert(requser);
|
||||
request.Id = requser.Id; //要把保存后的ID存入view
|
||||
}
|
||||
else
|
||||
{
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Account = requser.Account,
|
||||
BizCode = requser.BizCode,
|
||||
Name = requser.Name,
|
||||
Sex = requser.Sex,
|
||||
Status = requser.Status,
|
||||
ParentId = request.ParentId
|
||||
}, u => u.Id == request.Id);
|
||||
if (!string.IsNullOrEmpty(requser.Password)) //密码为空的时候,不做修改
|
||||
{
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Password = requser.Password
|
||||
}, u => u.Id == request.Id);
|
||||
}
|
||||
}
|
||||
string[] orgIds = request.OrganizationIds.Split(',').ToArray();
|
||||
_revelanceApp.DeleteBy(Define.USERORG, requser.Id);
|
||||
_revelanceApp.Assign(Define.USERORG, orgIds.ToLookup(u => requser.Id));
|
||||
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除用户,包含用户与组织关系、用户与角色关系
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
public override void Delete(string[] ids)
|
||||
public new void Delete(string[] ids)
|
||||
{
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
UnitWork.Delete<Relevance>(u =>(u.RelKey == Define.USERROLE || u.RelKey == Define.USERORG)
|
||||
&& ids.Contains(u.FirstId));
|
||||
UnitWork.Delete<SysUser>(u => ids.Contains(u.Id));
|
||||
UnitWork.Save();
|
||||
});
|
||||
SugarClient.Ado.BeginTran();
|
||||
SugarClient.Deleteable<Relevance>().Where(u => (u.RelKey == Define.USERROLE || u.RelKey == Define.USERORG)
|
||||
&& ids.Contains(u.FirstId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<SysUser>().Where(u => ids.Contains(u.Id)).ExecuteCommand();
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改密码
|
||||
@@ -242,10 +200,10 @@ namespace OpenAuth.App
|
||||
/// <param name="request"></param>
|
||||
public void ChangePassword(ChangePasswordReq request)
|
||||
{
|
||||
Repository.Update(u => u.Account == request.Account, user => new SysUser
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Password = request.Password
|
||||
});
|
||||
}, u => u.Account == request.Account);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定角色包含的用户列表
|
||||
@@ -254,15 +212,15 @@ namespace OpenAuth.App
|
||||
/// <returns></returns>
|
||||
public async Task<PagedDynamicDataResp> LoadByRole(QueryUserListByRoleReq request)
|
||||
{
|
||||
var users = from userRole in UnitWork.Find<Relevance>(u =>
|
||||
u.SecondId == request.roleId && u.RelKey == Define.USERROLE)
|
||||
join user in UnitWork.Find<SysUser>(null) on userRole.FirstId equals user.Id into temp
|
||||
from c in temp.Where(u =>u.Id != null)
|
||||
select c;
|
||||
var users = SugarClient.Queryable<Relevance>()
|
||||
.Where(u => u.SecondId == request.roleId && u.RelKey == Define.USERROLE)
|
||||
.LeftJoin<SysUser>((userRole, user) => userRole.FirstId == user.Id)
|
||||
.Where((userRole, user) => user.Id != null)
|
||||
.Select((userRole, user) => user);
|
||||
return new PagedDynamicDataResp
|
||||
{
|
||||
Count =await users.CountAsync(),
|
||||
Data =await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
Count = await users.CountAsync(),
|
||||
Data = await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
@@ -272,15 +230,15 @@ namespace OpenAuth.App
|
||||
/// <returns></returns>
|
||||
public async Task<PagedDynamicDataResp> LoadByOrg(QueryUserListByOrgReq request)
|
||||
{
|
||||
var users = from userOrg in UnitWork.Find<Relevance>(u =>
|
||||
u.SecondId == request.orgId && u.RelKey == Define.USERORG)
|
||||
join user in UnitWork.Find<SysUser>(null) on userOrg.FirstId equals user.Id into temp
|
||||
from c in temp.Where(u =>u.Id != null)
|
||||
select c;
|
||||
var users = SugarClient.Queryable<Relevance>()
|
||||
.Where(u => u.SecondId == request.orgId && u.RelKey == Define.USERORG)
|
||||
.LeftJoin<SysUser>((userOrg, user) => userOrg.FirstId == user.Id)
|
||||
.Where((userOrg, user) => user.Id != null)
|
||||
.Select((userOrg, user) => user);
|
||||
return new PagedDynamicDataResp
|
||||
{
|
||||
Count =await users.CountAsync(),
|
||||
Data =await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
Count = await users.CountAsync(),
|
||||
Data = await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
@@ -293,13 +251,13 @@ namespace OpenAuth.App
|
||||
{
|
||||
throw new Exception("不能修改超级管理员信息");
|
||||
}
|
||||
Repository.Update(u => u.Account == request.Account, user => new SysUser
|
||||
{
|
||||
Name = request.Name,
|
||||
Sex = request.Sex
|
||||
});
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Name = request.Name,
|
||||
Sex = request.Sex
|
||||
}, u => u.Account == request.Account);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户的直属上级ID
|
||||
/// </summary>
|
||||
@@ -311,7 +269,7 @@ namespace OpenAuth.App
|
||||
{
|
||||
throw new Exception("超级管理员没有直属上级,请检查配置");
|
||||
}
|
||||
return Repository.FirstOrDefault(u => u.Id == userid).ParentId;
|
||||
return SugarClient.Queryable<SysUser>().First(u => u.Id == userid).ParentId;
|
||||
}
|
||||
|
||||
|
||||
@@ -325,20 +283,61 @@ namespace OpenAuth.App
|
||||
var sql = $@"
|
||||
select u.*
|
||||
from sysuser u
|
||||
join (select distinct SecondId as UserId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_USER}'
|
||||
and FirstId = '{instanceId}'
|
||||
union
|
||||
select distinct FirstId as UserId
|
||||
from Relevance a
|
||||
inner join (select SecondId as RoleId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_ROLE}'
|
||||
and FirstId = '{instanceId}') b on a.SecondId = b.RoleId
|
||||
where RelKey = 'UserRole') userids on u.Id = userids.UserId";
|
||||
var users = UnitWork.FromSql<SysUser>(sql);
|
||||
return users.Select(u=>u.Id).ToList();
|
||||
join (select distinct SecondId as UserId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_USER}'
|
||||
and FirstId = '{instanceId}'
|
||||
union
|
||||
select distinct FirstId as UserId
|
||||
from Relevance a
|
||||
inner join (select SecondId as RoleId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_ROLE}'
|
||||
and FirstId = '{instanceId}') b on a.SecondId = b.RoleId
|
||||
where RelKey = '{Define.USERROLE}') userids on u.Id = userids.UserId";
|
||||
var users = SugarClient.Ado.SqlQuery<SysUser>(sql);
|
||||
return users.Select(u => u.Id).ToList();
|
||||
}
|
||||
|
||||
public List<UserView> LoadByIds(string[] ids)
|
||||
{
|
||||
var users = SugarClient.Queryable<SysUser>().Where(u => ids.Contains(u.Id));
|
||||
|
||||
//获取用户及用户关联的机构
|
||||
var userOrgs = users
|
||||
.LeftJoin<Relevance>((user, r) => user.Id == r.FirstId && r.RelKey == Define.USERORG)
|
||||
.LeftJoin<SysOrg>((user, r, o) => r.SecondId == o.Id)
|
||||
.Select((user, r, o) => new
|
||||
{
|
||||
user.Id,
|
||||
user.Account,
|
||||
user.Name,
|
||||
user.Sex,
|
||||
user.Status,
|
||||
user.CreateTime,
|
||||
user.CreateId,
|
||||
user.ParentId,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
});
|
||||
|
||||
var userOrgsList = userOrgs.ToList(); // 先执行ToList()
|
||||
var userViews = userOrgsList.GroupBy(b => b.Account).Select(g => new UserView
|
||||
{
|
||||
Id = g.First().Id,
|
||||
Account = g.Key,
|
||||
Name = g.First().Name,
|
||||
Sex = g.First().Sex,
|
||||
Status = g.First().Status,
|
||||
CreateTime = g.First().CreateTime,
|
||||
CreateUser = g.First().CreateId,
|
||||
ParentName = g.First().ParentId,
|
||||
ParentId = g.First().ParentId,
|
||||
OrganizationIds = string.Join(",", g.Select(x => x.OrgId)),
|
||||
Organizations = string.Join(",", g.Select(x => x.OrgName))
|
||||
});
|
||||
|
||||
return userViews.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,8 +76,8 @@ namespace OpenAuth.IdentityServer
|
||||
//在startup里面只能通过这种方式获取到appsettings里面的值,不能用IOptions😰
|
||||
var dbtypes = ((ConfigurationSection)Configuration.GetSection("AppSetting:DbTypes")).GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
var dbType = dbtypes["OpenAuthDBContext"];
|
||||
var connectionString = Configuration.GetConnectionString("OpenAuthDBContext");
|
||||
var dbType = dbtypes[Define.DEFAULT_TENANT_ID];
|
||||
var connectionString = Configuration.GetConnectionString(Define.DEFAULT_TENANT_ID);
|
||||
if (dbType == Define.DBTYPE_SQLSERVER)
|
||||
{
|
||||
services.AddDbContext<OpenAuthDBContext>(options =>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SqlSugar;
|
||||
using OpenAuth.Repository.Core;
|
||||
using SqlSugar;
|
||||
|
||||
namespace OpenAuth.Repository
|
||||
{
|
||||
@@ -6,12 +7,22 @@ namespace OpenAuth.Repository
|
||||
/// SqlSugar仓储
|
||||
/// <para>具体用法参考:https://www.donet5.com/Home/Doc?typeId=1228</para>
|
||||
/// </summary>
|
||||
public class SqlSugarRepository<T> : SimpleClient<T> where T : class, new()
|
||||
public class SqlSugarRepository<T> : SimpleClient<T> where T : BaseEntity, new()
|
||||
{
|
||||
public SqlSugarRepository(ISqlSugarClient client)
|
||||
{
|
||||
base.Context = client;
|
||||
}
|
||||
|
||||
public new bool Insert(T entity)
|
||||
{
|
||||
if (entity.KeyIsNull())
|
||||
{
|
||||
entity.GenerateDefaultKeyVal();
|
||||
}
|
||||
|
||||
return base.Insert(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -67,44 +68,70 @@ namespace OpenAuth.Repository.Test
|
||||
|
||||
serviceCollection.AddDbContext<OpenAuthDBContext>();
|
||||
|
||||
var dbtypes = config.GetSection("AppSetting:DbTypes").GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
var connectionString = config.GetSection("ConnectionStrings")["OpenAuthDBContext"];
|
||||
Console.WriteLine($"单元测试数据库信息:{dbtypes[httpContextAccessorMock.Object.GetTenantId()]}/{connectionString}");
|
||||
|
||||
var dbtypes = config.GetSection("AppSetting:DbTypes").GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);;
|
||||
var sqlsugarTypes = UtilMethods.EnumToDictionary<SqlSugar.DbType>();
|
||||
var dbType = sqlsugarTypes.FirstOrDefault(it =>
|
||||
dbtypes.ToDictionary(u => u.Key, v => v.Value.ToLower()).ContainsValue(it.Key));
|
||||
|
||||
serviceCollection.AddScoped<ISqlSugarClient>(s =>
|
||||
{
|
||||
var sqlSugar = new SqlSugarClient(new ConnectionConfig()
|
||||
// 获取所有连接字符串配置
|
||||
var connectionStrings = config.GetSection("ConnectionStrings").GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
// 准备ConnectionConfig列表
|
||||
var connectionConfigs = new List<ConnectionConfig>();
|
||||
|
||||
// 遍历所有连接字符串
|
||||
foreach (var conn in connectionStrings)
|
||||
{
|
||||
DbType = dbType.Value,
|
||||
ConnectionString = connectionString,
|
||||
IsAutoCloseConnection = true
|
||||
});
|
||||
|
||||
if(dbType.Value != SqlSugar.DbType.PostgreSQL){
|
||||
return sqlSugar;
|
||||
// 获取对应的数据库类型
|
||||
var connDbType = dbtypes.ContainsKey(conn.Key) ?
|
||||
sqlsugarTypes.FirstOrDefault(it => dbtypes[conn.Key].ToLower().Contains(it.Key)).Value :
|
||||
DbType.SqlServer; // 如果没有定义DbType,使用默认类型
|
||||
|
||||
// 创建连接配置
|
||||
var config = new ConnectionConfig
|
||||
{
|
||||
DbType = connDbType,
|
||||
ConnectionString = conn.Value,
|
||||
IsAutoCloseConnection = true,
|
||||
};
|
||||
|
||||
// 如果不是默认连接,设置ConfigId
|
||||
if (conn.Key != Define.DEFAULT_TENANT_ID)
|
||||
{
|
||||
config.ConfigId = conn.Key;
|
||||
}
|
||||
|
||||
connectionConfigs.Add(config);
|
||||
Console.WriteLine($"添加数据库连接: {conn.Key} / {(dbtypes.ContainsKey(conn.Key) ? dbtypes[conn.Key] : "未指定类型")},连接字符串:{conn.Value}");
|
||||
}
|
||||
|
||||
// 配置bool类型转换为smallint
|
||||
sqlSugar.Aop.OnExecutingChangeSql = (sql, parameters) =>
|
||||
var sqlSugar = new SqlSugarClient(connectionConfigs);
|
||||
|
||||
// 配置PostgreSQL数据库处理
|
||||
foreach (var connConfig in connectionConfigs)
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
if(connConfig.DbType == SqlSugar.DbType.PostgreSQL)
|
||||
{
|
||||
if (param.Value is bool boolValue)
|
||||
// 配置bool类型转换为smallint
|
||||
sqlSugar.Aop.OnExecutingChangeSql = (sql, parameters) =>
|
||||
{
|
||||
param.DbType = System.Data.DbType.Int16;
|
||||
// 将 bool 转换为 smallint
|
||||
param.Value = boolValue ? (short)1 : (short)0;
|
||||
}
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.Value is bool boolValue)
|
||||
{
|
||||
param.DbType = System.Data.DbType.Int16;
|
||||
// 将 bool 转换为 smallint
|
||||
param.Value = boolValue ? (short)1 : (short)0;
|
||||
}
|
||||
}
|
||||
// 返回修改后的 SQL 和参数
|
||||
return new System.Collections.Generic.KeyValuePair<string, SugarParameter[]>(sql, parameters);
|
||||
};
|
||||
break; // 找到一个PostgreSQL连接后就设置一次即可
|
||||
}
|
||||
// 返回修改后的 SQL 和参数
|
||||
return new System.Collections.Generic.KeyValuePair<string, SugarParameter[]>(sql, parameters);
|
||||
};
|
||||
}
|
||||
|
||||
return sqlSugar;
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
using Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenAuth.App;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenAuth.WebApi.Controllers
|
||||
{
|
||||
@@ -79,6 +81,37 @@ namespace OpenAuth.WebApi.Controllers
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有机构
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public Response<List<OrgView>> LoadAll()
|
||||
{
|
||||
var result = new Response<List<OrgView>>();
|
||||
try
|
||||
{
|
||||
result.Data = _app.LoadAll();
|
||||
}
|
||||
catch (CommonException ex)
|
||||
{
|
||||
if (ex.Code == Define.INVALID_TOKEN)
|
||||
{
|
||||
result.Code = ex.Code;
|
||||
result.Message = ex.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException != null
|
||||
? "OpenAuth.WebAPI数据库访问失败:" + ex.InnerException.Message
|
||||
: "OpenAuth.WebAPI数据库访问失败:" + ex.Message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除选中的部门及所有的子部门
|
||||
|
||||
@@ -70,6 +70,14 @@ namespace OpenAuth.WebApi.Controllers
|
||||
return resp;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public Response<List<SysResource>> LoadByIds([FromBody]string[] ids)
|
||||
{
|
||||
var result = new Response<List<SysResource>>();
|
||||
result.Data = _app.LoadByIds(ids);
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public Response<string> Add([FromBody] AddOrUpdateResReq obj)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,24 @@ namespace OpenAuth.WebApi.Controllers
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public Response LoadByIds([FromBody]string[] ids)
|
||||
{
|
||||
var result = new Response<List<Role>>();
|
||||
try
|
||||
{
|
||||
result.Data = _app.LoadByIds(ids);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -106,7 +107,7 @@ namespace OpenAuth.WebApi.Controllers
|
||||
/// 获取当前登录用户可访问的一个部门及子部门全部用户
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<PagedDynamicDataResp> Load([FromQuery]QueryUserListReq request)
|
||||
public async Task<PagedListDataResp<UserView>> Load([FromQuery]QueryUserListReq request)
|
||||
{
|
||||
return await _app.Load(request);
|
||||
}
|
||||
@@ -139,6 +140,24 @@ namespace OpenAuth.WebApi.Controllers
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public Response LoadByIds([FromBody]string[] ids)
|
||||
{
|
||||
var result = new Response<List<UserView>>();
|
||||
try
|
||||
{
|
||||
result.Data = _app.LoadByIds(ids);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载指定角色的用户
|
||||
/// </summary>
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace OpenAuth.WebApi
|
||||
|
||||
logger.LogInformation($"api doc basepath:{AppContext.BaseDirectory}");
|
||||
foreach (var name in Directory.GetFiles(AppContext.BaseDirectory, "*.*",
|
||||
SearchOption.AllDirectories).Where(f => Path.GetExtension(f).ToLower() == ".xml"))
|
||||
SearchOption.AllDirectories).Where(f => Path.GetExtension(f).ToLower() == ".xml"))
|
||||
{
|
||||
option.IncludeXmlComments(name, includeControllerXmlComments: true);
|
||||
// logger.LogInformation($"find api file{name}");
|
||||
@@ -126,9 +126,6 @@ namespace OpenAuth.WebApi
|
||||
services.AddControllers(option => { option.Filters.Add<OpenAuthFilter>(); })
|
||||
.ConfigureApiBehaviorOptions(options =>
|
||||
{
|
||||
// 禁用自动模态验证
|
||||
// options.SuppressModelStateInvalidFilter = true;
|
||||
|
||||
//启动WebAPI自动模态验证,处理返回值
|
||||
options.InvalidModelStateResponseFactory = (ActionContext context) =>
|
||||
{
|
||||
@@ -146,66 +143,86 @@ namespace OpenAuth.WebApi
|
||||
});
|
||||
services.AddMemoryCache();
|
||||
services.AddCors();
|
||||
// todo:如果正式 环境请用下面的方式限制随意访问跨域
|
||||
// var origins = new []
|
||||
// {
|
||||
// "http://localhost:1803",
|
||||
// "http://localhost:52789"
|
||||
// };
|
||||
// if (Environment.IsProduction())
|
||||
// {
|
||||
// origins = new []
|
||||
// {
|
||||
// "http://demo.openauth.net.cn:1803",
|
||||
// "http://demo.openauth.net.cn:52789"
|
||||
// };
|
||||
// }
|
||||
// services.AddCors(option=>option.AddPolicy("cors", policy =>
|
||||
// policy.AllowAnyHeader().AllowAnyMethod().AllowCredentials().WithOrigins(origins)));
|
||||
|
||||
//在startup里面只能通过这种方式获取到appsettings里面的值,不能用IOptions😰
|
||||
var dbtypes = ((ConfigurationSection) Configuration.GetSection("AppSetting:DbTypes")).GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
var connectionString = Configuration.GetConnectionString("OpenAuthDBContext");
|
||||
logger.LogInformation($"系统配置的数据库类型:{JsonHelper.Instance.Serialize(dbtypes)},连接字符串:{connectionString}");
|
||||
services.AddDbContext<OpenAuthDBContext>();
|
||||
|
||||
services.AddHttpClient();
|
||||
|
||||
services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(Configuration["DataProtection"]));
|
||||
|
||||
//在startup里面只能通过这种方式获取到appsettings里面的值,不能用IOptions😰
|
||||
var dbtypes = ((ConfigurationSection) Configuration.GetSection("AppSetting:DbTypes")).GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
var sqlsugarTypes = UtilMethods.EnumToDictionary<SqlSugar.DbType>();
|
||||
var dbType = sqlsugarTypes.FirstOrDefault(it =>
|
||||
dbtypes.ToDictionary(u => u.Key, v => v.Value.ToLower()).ContainsValue(it.Key));
|
||||
|
||||
services.AddScoped<ISqlSugarClient>(s =>
|
||||
{
|
||||
var sqlSugar = new SqlSugarClient(new ConnectionConfig()
|
||||
// 获取所有连接字符串配置
|
||||
var connectionStrings = Configuration.GetSection("ConnectionStrings").GetChildren()
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
// 准备ConnectionConfig列表
|
||||
var connectionConfigs = new List<ConnectionConfig>();
|
||||
|
||||
// 遍历所有连接字符串
|
||||
foreach (var conn in connectionStrings)
|
||||
{
|
||||
DbType = dbType.Value,
|
||||
ConnectionString = connectionString,
|
||||
IsAutoCloseConnection = true
|
||||
}, db => { db.Aop.OnLogExecuting = (sql, pars) => { logger.LogInformation(sql); }; });
|
||||
|
||||
if(dbType.Value != SqlSugar.DbType.PostgreSQL){
|
||||
return sqlSugar;
|
||||
// 获取对应的数据库类型
|
||||
var connDbType = dbtypes.ContainsKey(conn.Key) ?
|
||||
sqlsugarTypes.FirstOrDefault(it => dbtypes[conn.Key].ToLower().Contains(it.Key)).Value :
|
||||
DbType.SqlServer; // 如果没有定义DbType,使用默认类型
|
||||
|
||||
// 创建连接配置
|
||||
var config = new ConnectionConfig
|
||||
{
|
||||
DbType = connDbType,
|
||||
ConnectionString = conn.Value,
|
||||
IsAutoCloseConnection = true,
|
||||
};
|
||||
|
||||
// 如果不是默认连接,设置ConfigId
|
||||
if (conn.Key != Define.DEFAULT_TENANT_ID)
|
||||
{
|
||||
config.ConfigId = conn.Key;
|
||||
}
|
||||
|
||||
connectionConfigs.Add(config);
|
||||
logger.LogInformation($"添加数据库连接: {conn.Key} / {(dbtypes.ContainsKey(conn.Key) ? dbtypes[conn.Key] : "未指定类型")},连接字符串:{conn.Value}");
|
||||
}
|
||||
|
||||
// 配置bool类型转换为smallint
|
||||
sqlSugar.Aop.OnExecutingChangeSql = (sql, parameters) =>
|
||||
//通过ConfigId为空判断是否有默认的连接字符串
|
||||
if(!connectionConfigs.Any(x => x.ConfigId == null))
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
throw new Exception($"没有找到默认的连接字符串:{Define.DEFAULT_TENANT_ID}");
|
||||
}
|
||||
|
||||
//把connectionConfigs排序,ConfigId为空的放在最前面,即默认的连接字符串必须排最前面
|
||||
connectionConfigs = connectionConfigs.OrderBy(x => x.ConfigId == null ? 0 : 1).ToList();
|
||||
|
||||
var sqlSugar = new SqlSugarClient(connectionConfigs);
|
||||
|
||||
// 配置PostgreSQL数据库处理
|
||||
foreach (var connConfig in connectionConfigs)
|
||||
{
|
||||
if(connConfig.DbType == SqlSugar.DbType.PostgreSQL)
|
||||
{
|
||||
if (param.Value is bool boolValue)
|
||||
// 配置bool类型转换为smallint
|
||||
sqlSugar.Aop.OnExecutingChangeSql = (sql, parameters) =>
|
||||
{
|
||||
param.DbType = System.Data.DbType.Int16;
|
||||
// 将 bool 转换为 smallint
|
||||
param.Value = boolValue ? (short)1 : (short)0;
|
||||
}
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.Value is bool boolValue)
|
||||
{
|
||||
param.DbType = System.Data.DbType.Int16;
|
||||
// 将 bool 转换为 smallint
|
||||
param.Value = boolValue ? (short)1 : (short)0;
|
||||
}
|
||||
}
|
||||
// 返回修改后的 SQL 和参数
|
||||
return new System.Collections.Generic.KeyValuePair<string, SugarParameter[]>(sql, parameters);
|
||||
};
|
||||
break; // 找到一个PostgreSQL连接后就设置一次即可
|
||||
}
|
||||
// 返回修改后的 SQL 和参数
|
||||
return new System.Collections.Generic.KeyValuePair<string, SugarParameter[]>(sql, parameters);
|
||||
};
|
||||
}
|
||||
|
||||
return sqlSugar;
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using OpenAuth.App;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using {Namespace};
|
||||
|
||||
namespace OpenAuth.WebApi.Controllers
|
||||
{
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// This code was generated by a CodeSmith Template.
|
||||
//
|
||||
// DO NOT MODIFY contents of this file. Changes to this
|
||||
// file will be lost if the code is regenerated.
|
||||
// Author:Yubao Li
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
|
||||
* @Description: 实体类
|
||||
* Copyright (c) 2025 by yubaolee | ahfu~ , All Rights Reserved.
|
||||
*/
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using OpenAuth.Repository.Core;
|
||||
|
||||
namespace OpenAuth.Repository.Domain
|
||||
namespace {Namespace}
|
||||
{
|
||||
{AttributeManager}
|
||||
public class {ClassName} : {BaseEntityName}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Infrastructure;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using {Namespace};
|
||||
using SqlSugar;
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ using Infrastructure;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using {Namespace};
|
||||
using SqlSugar;
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ using Infrastructure;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using {Namespace};
|
||||
using SqlSugar;
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ using Infrastructure;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using {Namespace};
|
||||
using SqlSugar;
|
||||
|
||||
|
||||
|
||||
56
README.md
56
README.md
@@ -1,4 +1,4 @@
|
||||
🔥.Net权限管理及快速开发框架、最好用的权限工作流系统。源于Martin Fowler企业级应用开发思想及最新技术组合(SqlSugar、EF、Quartz、AutoFac、WebAPI、Swagger、Mock、NUnit、Vue2/3、Element-ui/plus、IdentityServer等)。核心模块包括:角色授权、代码生成、API鉴权、智能打印、表单设计、工作流、定时任务等。架构易扩展,是中小企业的首选。
|
||||
🔥.Net权限管理及快速开发框架、最好用的权限工作流系统。源于Martin Fowler企业级应用开发思想及最新技术组合(SqlSugar、EF、Quartz、AutoFac、WebAPI、Swagger、Mock、NUnit、UniApp、Vue2/3、Element-ui/plus、IdentityServer等)。核心模块包括:角色授权、代码生成、API鉴权、智能打印、表单设计、工作流、定时任务等。架构易扩展,是中小企业的首选。
|
||||
|
||||
<p align="center">
|
||||
<img src="https://gitee.com/uploads/images/2018/0425/163228_7077c3fd_362401.png" alt="LOGO" width="300" />
|
||||
@@ -65,41 +65,25 @@
|
||||
## 💡核心功能
|
||||
项目深入参考《企业应用架构模式》《重构与模式》《ASP.NET设计模式》等巨著完成每一行代码编写。主要特性:
|
||||
|
||||
* 支持最新版.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/)
|
||||
|
||||
* 可拖拽的表单设计。详情:[可拖拽表单](http://doc.openauth.net.cn/pro/dragform/)
|
||||
|
||||
* 可视化流程设计。[可视化流程设计](http://doc.openauth.net.cn/pro/startflow/)
|
||||
|
||||
* 全网最好用的打印解决方案。详情:[智能打印](http://doc.openauth.net.cn/pro/printerplan/)
|
||||
|
||||
* 基于Quartz.Net的定时任务控制,可随时启/停,可视化配置Cron表达式功能,请参考:[定时任务](http://doc.openauth.net.cn/core/job/)
|
||||
|
||||
* 零代码动态API接口,详情:[动态API](http://doc.openauth.net.cn/core/dynamicapi/)
|
||||
|
||||
* 自带代码生成器,可快速生成带有头/明细结构的页面
|
||||
|
||||
* 支持sqlserver、mysql、Oracle、PostgreSql数据库,理论上支持所有数据库
|
||||
|
||||
* 支持同时访问多数据源
|
||||
|
||||
* 支持多租户
|
||||
|
||||
* 支持搭建自己的IdentityServer服务器,实现基于OAuth2的登录体系,请参考:[登录认证及OAuth集成](http://doc.openauth.net.cn/core/identity/)
|
||||
|
||||
* 建立三方对接规范,已有系统可以无缝对接流程引擎
|
||||
|
||||
* vue前端采用 vue + element-ui + vform + hiprinter
|
||||
|
||||
* 后端采用 .net +EF + sqlsugar + autofac + quartz +IdentityServer4 + nunit + swagger
|
||||
|
||||
* 设计工具 PowerDesigner +PDManer + Enterprise Architect
|
||||
* ✅支持最新版.Net 9
|
||||
* ✅同时支持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/)
|
||||
* ✅可拖拽表单设计。详情:[可拖拽表单](http://doc.openauth.net.cn/pro/dragform/)
|
||||
* ✅可视化流程设计。详情:[可视化流程设计](http://doc.openauth.net.cn/pro/startflow/)
|
||||
* ✅全网最好用的打印解决方案,详情:[智能打印](http://doc.openauth.net.cn/pro/printerplan/)
|
||||
* ✅基于Quartz的定时任务控制,可随时启/停,可视化配置Cron表达式,详情:[定时任务](http://doc.openauth.net.cn/core/job/)
|
||||
* ✅零代码动态API接口,详情:[动态API](http://doc.openauth.net.cn/core/dynamicapi/)
|
||||
* ✅超好用代码生成器,可快速生成单表、主从表结构的界面
|
||||
* ✅支持sqlserver、mysql、Oracle、PostgreSql数据库,理论上支持所有数据库
|
||||
* ✅支持多数据源
|
||||
* ✅支持多租户
|
||||
* ✅支持多语言
|
||||
* ✅支持自建OAuth2登录体系,详情:[登录认证及OAuth集成](http://doc.openauth.net.cn/core/identity/)
|
||||
* ✅支持已有系统无缝对接本项目流程引擎
|
||||
* ✅vue前端采用 vue2/3 + element-ui/plus + vform + hiprint + pinia + axios + uniapp
|
||||
* ✅后端采用 .net +EF + sqlsugar + autofac + quartz +IdentityServer4 + nunit + swagger
|
||||
* ✅设计工具 PowerDesigner +PDManer + Enterprise Architect
|
||||
|
||||
## 🔜后续
|
||||
生命不息,更新不止
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
|
||||
* @Date: 2025-04-23 20:26:48
|
||||
* @LastEditTime: 2025-06-07 23:11:29
|
||||
* @LastEditTime: 2025-06-25 15:12:53
|
||||
* @Description: 笔记配置
|
||||
* Copyright (c) 2025 by yubaolee | ahfu~ , All Rights Reserved.
|
||||
*/
|
||||
@@ -49,7 +49,7 @@ const proNote = defineNoteConfig({
|
||||
{
|
||||
text: '基础开发',
|
||||
collapsed: false,
|
||||
items: ['start','deploy','structure','devnew','devnewmulti', 'router','openurl','keepalive','datapropertyrule']
|
||||
items: ['start','deploy','structure','multilangs','devnew','devnewmulti', 'router','openurl','keepalive','datapropertyrule']
|
||||
},
|
||||
{
|
||||
text: '内置组件',
|
||||
|
||||
@@ -4,6 +4,54 @@ createTime: 2025/04/23 21:03:10
|
||||
permalink: /core/changelog/
|
||||
---
|
||||
|
||||
### v8.1
|
||||
|
||||
* 🔄refactor: 统一后端返回格式response.result调整为response.data
|
||||
* ⚠️feat: 表格组件增加排序功能
|
||||
* 🔄refactor: 持续优化代码
|
||||
|
||||
|
||||
### v8.0
|
||||
|
||||
* 开源十周年特别版!
|
||||
* ✅全面开源原付费vue2版本源码及文档,免费使用。
|
||||
* ✅删除原有mvc项目,从此以后只有前后端分离。
|
||||
|
||||
### v7.6
|
||||
|
||||
* [重磅] 分离会签和网关功能,详情请查看工作流中的概念
|
||||
* [优化] 前后端统一流程节点类型。详情请查看文档流程相关代码-流程模板
|
||||
* [优化] 修复顺序加签
|
||||
|
||||
### v7.5
|
||||
|
||||
* [新增] 流程执行节点支持通过Sql配置用户
|
||||
* [优化] 流程节点设置json对象统一为datas字段
|
||||
* [优化] 优化layui样式
|
||||
|
||||
### v7.4
|
||||
|
||||
* [新增] 代码生成加上外部数据源支持;
|
||||
* [新增] 新增动态API功能;
|
||||
* [优化] 流程模板调整为sqlsugar;
|
||||
|
||||
### v7.3
|
||||
|
||||
* [新增] 新增API鉴权功能
|
||||
* [优化] 优化vue3代码生成;
|
||||
|
||||
### v7.2
|
||||
|
||||
* [重磅]流程增加任意节点撤回审批功能
|
||||
* [重磅]全面优化数据库初始脚本,SqlServer采用帕斯卡命名,MySql/pg采用小写命名,Oracle采用大写
|
||||
* [重磅]优化layui点击行可选中
|
||||
|
||||
### v7.1
|
||||
|
||||
* [重磅]全面优化对Oracle数据库的支持
|
||||
* [优化]FIX issue #IBLX2E:目前Oracle工作流列表不能加载 目前Oracle工作流列表不能加载
|
||||
* [优化]流程实例历史操作记录
|
||||
|
||||
### v7.0
|
||||
|
||||
* 全面支持.Net 9
|
||||
|
||||
@@ -4,7 +4,7 @@ createTime: 2025/04/23 21:03:10
|
||||
permalink: /core/changesdk/
|
||||
---
|
||||
|
||||
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`,将
|
||||
OpenAuth.Net最新版默认使用.Net SDK 9.0.100。如果你使用的是其他版本的sdk(如.net 6.0/7.0等)打开项目,需要调整csproj项目文件的TargetFramework。用记事本等工具,打开 `Infrastructure.csproj` `OpenAuth.Repository.csproj` `OpenAuth.App.csproj` `OpenAuth.WebApi.csproj` `OpenAuth.IdentityServer.csproj`,将
|
||||
```csharp
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
|
||||
@@ -32,19 +32,11 @@ OpenAuth.Net支持两种登录认证方式:Token认证和==自己搭建=={.tip
|
||||
不同于其他项目的统一登录(如微信登录、支付宝登录等),OpenAuth.Net的统一登录指的是自己搭建一套OAuth登录服务,提供给其他项目使用。即OpenAuth.IdentityServer。启动后,直接访问[http://localhost:12796](http://localhost:12796),效果如下:
|
||||

|
||||
|
||||
这时我们修改OpenAuth.WebApi/Mvc的IdentityServerUrl配置:
|
||||
这时我们修改OpenAuth.WebApi的IdentityServerUrl配置:
|
||||
```json
|
||||
"IdentityServerUrl": "http://localhost:12796", //IdentityServer服务器地址。
|
||||
```
|
||||
|
||||
### OpenAuth.Mvc效果
|
||||
|
||||
当启用了Identity时,mvc启动后界面如下:
|
||||

|
||||
|
||||
这时点击登录超链接,会跳转到OpenAuth.Identity登录界面。效果如下:
|
||||

|
||||
|
||||
|
||||
### OpenAuth.WebApi效果
|
||||
|
||||
@@ -66,7 +58,8 @@ VITE_OIDC_AUTOMATICSILENTRENEW = true #自动续期
|
||||
如果服务端启用了Identity认证,则打开登录界面如下:
|
||||

|
||||
|
||||
这时点击登录超链接,操作同OpenAuth.Mvc一样。
|
||||
这时点击登录超链接,会跳转到OpenAuth.Identity登录界面。效果如下:
|
||||

|
||||
|
||||
|
||||
#### SwaggerUI
|
||||
|
||||
@@ -3,12 +3,17 @@ title: 多数据库
|
||||
createTime: 2025/04/23 21:03:10
|
||||
permalink: /core/multidbs/
|
||||
---
|
||||
::: tip 提示
|
||||
* 多数据库指一个应用程序同时连接和操作多个不同的数据库。
|
||||
* 多租户是架构设计模式,用户登录时选择租户信息,后面就只能访问该租户对应的数据库,即只访问一个数据库。
|
||||
|
||||
:::
|
||||
|
||||
框架支持同时访问多个数据库。具体操作如下:
|
||||
|
||||
## 添加新连接字符串
|
||||
|
||||
在配置文件appsettings.json中,添加新的连接字符串`OpenAuthDBContext2`
|
||||
在配置文件appsettings.json中,添加新的连接字符串 `OpenAuthDBContext2`
|
||||
|
||||
```csharp
|
||||
"ConnectionStrings": {
|
||||
@@ -23,70 +28,110 @@ permalink: /core/multidbs/
|
||||
}
|
||||
```
|
||||
|
||||
## 添加数据上下文
|
||||
## SqlSugar操作多数据库
|
||||
|
||||
在OpenAuth.Repository中添加新的数据库上下文,比如`OpenAuthDBContext2`
|
||||
当需要使用SqlSugar操作多数据库时,因为框架初始化时会自动识别所有的连接字符串,所以只需要按以下步骤编写业务代码即可。
|
||||
|
||||
### 新建数据库访问基类
|
||||
|
||||
在项目OpenAuth.App中,新建数据库访问基类,比如 `SqlSugarApp2`
|
||||
|
||||
```csharp
|
||||
public class OpenAuthDBContext2 : DbContext
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public abstract class SqlSugarApp2<T> : SqlSugarBaseApp<T> where T : BaseEntity, new()
|
||||
{
|
||||
private IConfiguration _configuration;
|
||||
private ILoggerFactory _LoggerFactory;
|
||||
private const string _connectstr = "OpenAuthDBContext2";
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
public SqlSugarApp2(ISqlSugarClient client, IAuth auth) : base(client, auth)
|
||||
{
|
||||
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);
|
||||
client = client.AsTenant().GetConnection("OpenAuthDBContext2");
|
||||
Repository = new SqlSugarRepository<T>(client); //这里用new而不用注入,可以保证client和repository用的是同一个client
|
||||
SugarClient = client;
|
||||
_auth = auth;
|
||||
}
|
||||
|
||||
public OpenAuthDBContext2(DbContextOptions<OpenAuthDBContext2> options,
|
||||
ILoggerFactory loggerFactory,IConfiguration configuration)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 编写业务代码
|
||||
|
||||
我们以系统日志模块为例,只需要调整以下代码,然后运行就可以发现,日志已经全部记录到新的数据库中。
|
||||
|
||||
```csharp
|
||||
public class SysLogApp2 : SqlSugarApp2<SysLog>
|
||||
{
|
||||
public void Add(SysLog obj)
|
||||
{
|
||||
//程序类型取入口应用的名称,可以根据自己需要调整
|
||||
obj.Application = Assembly.GetEntryAssembly().FullName.Split(',')[0];
|
||||
Repository.Insert(obj);
|
||||
}
|
||||
|
||||
public void Update(SysLog obj)
|
||||
{
|
||||
Repository.Update(u => new SysLog
|
||||
{
|
||||
Content = obj.Content,
|
||||
CreateTime = obj.CreateTime,
|
||||
Id = obj.Id,
|
||||
Ip = obj.Ip,
|
||||
},u => u.Id == obj.Id);
|
||||
}
|
||||
|
||||
public SysLogApp2(ISqlSugarClient client, IAuth auth) : base(client, auth)
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## EF操作多数据库
|
||||
|
||||
### 添加数据上下文
|
||||
|
||||
在OpenAuth.Repository中添加新的数据库上下文,比如 `OpenAuthDBContext2`
|
||||
|
||||
```csharp
|
||||
public partial class OpenAuthDBContext2 : DbContext
|
||||
{
|
||||
private ILoggerFactory _LoggerFactory;
|
||||
private IConfiguration _configuration;
|
||||
|
||||
private const string _connectstr = "OpenAuthDBContext2"; //这里是第二数据库的连接字符串
|
||||
|
||||
public OpenAuthDBContext2(DbContextOptions<OpenAuthDBContext2> options, ILoggerFactory loggerFactory,
|
||||
IConfiguration configuration,
|
||||
IOptions<AppSetting> appConfiguration)
|
||||
: base(options)
|
||||
{
|
||||
_LoggerFactory = loggerFactory;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
... //其他代码请参考OpenAuthDbContext
|
||||
//初始化多租户信息,根据租户id调整数据库
|
||||
private void InitTenant(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
string connect = _configuration.GetConnectionString(_connectstr);
|
||||
if (string.IsNullOrEmpty(connect))
|
||||
{
|
||||
throw new Exception($"未能找到租户{_connectstr}对应的连接字符串信息");
|
||||
}
|
||||
|
||||
// 其他代码参考OpenAuthDBContext.cs
|
||||
}
|
||||
// 其他代码参考OpenAuthDBContext.cs
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 注入新数据库
|
||||
### 注入新数据库
|
||||
|
||||
在项目(OpenAuth.WebApi等)的启动代码`Startup.cs`中,注入刚刚添加的数据库
|
||||
在项目OpenAuth.WebApi的启动代码 `Startup.cs`中,把 `ConfigureServices`方法中注入刚刚添加的数据库上下文
|
||||
|
||||
```csharp
|
||||
services.AddDbContext<OpenAuthDBContext2>();
|
||||
```
|
||||
|
||||
## 编写业务代码
|
||||
### 编写业务代码
|
||||
|
||||
我们以系统日志模块为例,只需要调整以下代码,然后运行就可以发现,日志已经全部记录到新的数据库中。
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@ createTime: 2025/04/23 21:03:10
|
||||
permalink: /core/multitenant/
|
||||
---
|
||||
|
||||
::: tip 提示
|
||||
* 多数据库指一个应用程序同时连接和操作多个不同的数据库。
|
||||
* 多租户是架构设计模式,用户登录时选择租户信息,后面就只能访问该租户对应的数据库,即只访问一个数据库。
|
||||
|
||||
:::
|
||||
|
||||
目前市面上主流的多租户方案有三种:
|
||||
|
||||
1. **独立数据库** 即为不同的租户提供独立的数据库。
|
||||
@@ -19,12 +25,23 @@ permalink: /core/multitenant/
|
||||
|
||||
#### 后端添加
|
||||
|
||||
后端添加新租户连接字符串即可:
|
||||
目前OpenAuth.Net的租户管理直接通过连接字符串配置,如有需要可以改为功能配置,期待你的pull request。
|
||||
|
||||
在后端OpenAuth.WebApi的`appsettings.json`中添加新租户连接字符串,并配置数据库类型:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"OpenAuthDBContext": "Data Source=.;Encrypt=false;Initial Catalog=OpenAuthPro;User=sa;Password=000000", //默认租户id,必须要有,启动项目使用
|
||||
"new_tenantid": "server=127.0.0.1;user id=root;database=openauthpro;password=000000" //新租户id对应的连接字符串
|
||||
},
|
||||
"AppSetting": {
|
||||
"DbTypes": {
|
||||
"OpenAuthDBContext": "SqlServer",
|
||||
"new_tenantid": "MySql" //新租户id对应的数据库类型
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
::: warning 注意
|
||||
|
||||
@@ -3,6 +3,115 @@ title: 日常提交
|
||||
createTime: 2025/04/23 21:03:10
|
||||
permalink: /core/routineupdate/
|
||||
---
|
||||
* 2025.06.25 📃docs: 增加多语言说明
|
||||
|
||||
* 2025.06.24 📃docs: 增加sqlsugar访问多数据库
|
||||
|
||||
* 2025.06.14 ⚠️feat: 代码生成器增加排序功能
|
||||
|
||||
* 2025.06.14 ⚠️feat: 增加排序字段
|
||||
|
||||
* 2025.06.11 🔄refactor: 完善代码生成器
|
||||
|
||||
* 2025.06.07 ⚠️feat: 正式删除mvc项目
|
||||
|
||||
* 2025.06.06 ⚠️feat: 正式开源vue2客户端
|
||||
|
||||
* 2025.05.28 🐛fix: 修复生成单表代码异常
|
||||
|
||||
* 2025.05.18 🐛fix: 强化代码生成器
|
||||
|
||||
* 2025.05.15 🔄refactor: 删除FlowinstanceTransitionHistory
|
||||
|
||||
* 2025.05.14 🔄refactor: 分类调整为sqlsugar
|
||||
|
||||
* 2025.05.14 ⚠️feat: 字典分类增加高级查询
|
||||
|
||||
* 2025.05.13 ⚠️feat: 打印增加高级查询
|
||||
|
||||
* 2025.05.13 ⚠️feat: 数据权限调整为sqlsugar
|
||||
|
||||
* 2025.05.13 ⚠️feat: 代码生成器单表支持高级查询和列设置
|
||||
|
||||
* 2025.05.11 ⚠️feat: 增加根据表和数据源获取表结构
|
||||
|
||||
* 2025.05.11 🔄refactor: 优化提交字段校验
|
||||
|
||||
* 2025.05.11 ⚠️feat: 优化代码生成
|
||||
|
||||
* 2025.05.10 ⚠️feat: 强化代码生成器
|
||||
|
||||
* 2025.05.10 ⚠️feat: 强化多表代码生成
|
||||
|
||||
* 2025.05.08 🔧chore: 增加入库订单单元测试
|
||||
|
||||
* 2025.05.08 🐛fix: 修复入库订单更新异常
|
||||
|
||||
* 2025.05.08 🔧chore: 增加cursor codebase indexing忽略配置
|
||||
|
||||
* 2025.05.07 ⚠️feat: 入库订单调整为sqlsugar,并支持自定义查询
|
||||
|
||||
* 2025.05.06 ⚠️feat: 增加高级查询
|
||||
|
||||
* 2025.04.29 ⚠️feat: 增加低代码平台脚本
|
||||
|
||||
* 2025.04.29 🔧chore: 增加cursor mcp Servers支持
|
||||
|
||||
* 2025.04.21 🐛fix: 紧急修复待办列表数据异常
|
||||
|
||||
* 2025.04.19 🐛fix: #IC2GBH 流程审批页面显示不出数据
|
||||
|
||||
* 2025.04.19 🐛fix: 修复顺序审批时,节点审批人为全部加签的异常
|
||||
|
||||
* 2025.04.18 🐛fix: 修复会签节点审批
|
||||
|
||||
* 2025.04.17 ⚠️feat: 分离会签和网关功能
|
||||
|
||||
* 2025.04.17 🔄refactor: 修改approvetype类型
|
||||
|
||||
* 2025.04.17 🔄refactor: 调整历史记录的fromnodetype/tonodetype
|
||||
|
||||
* 2025.04.17 🔄refactor: 流程模板end round 切换为end,统一判断流程结束
|
||||
|
||||
* 2025.04.17 🔄refactor: 去掉流程实例的ActivityType,重构节点类型相关代码
|
||||
|
||||
* 2025.04.17 🔄refactor: 优化代码结构
|
||||
|
||||
* 2025.04.14 🐛fix: 修复点击选中行
|
||||
|
||||
* 2025.04.13 🔄refactor: 删除treetable css
|
||||
|
||||
* 2025.04.12 ⚠️feat: 优化layui样式
|
||||
|
||||
* 2025.04.11 ⚠️feat: 审批节点可以配置SQL指定审批人
|
||||
|
||||
* 2025.04.11 🔄refactor: 优化流程审批节点权限
|
||||
|
||||
* 2025.04.11 🐛fix: 优化审批节点逻辑
|
||||
|
||||
* 2025.04.11 🔄refactor: Relevance替换key为relkey
|
||||
|
||||
* 2025.04.11 🐛fix: #I62Y74 执行权限扩展成支持Sql
|
||||
|
||||
* 2025.04.10 ⚠️feat: 节点执行权限增加指定sql
|
||||
|
||||
* 2025.04.09 📃docs: 删除.net 4.0的文档
|
||||
|
||||
* 2025.04.09 📃docs: 增加url表单操作说明
|
||||
|
||||
* 2025.04.08 📃docs: 分离vue2和vue3版本
|
||||
|
||||
* 2025.04.07 ⚠️feat: 流程审批通知时,可以使用相对路径
|
||||
|
||||
* 2025.04.06 📃docs: 更新表单说明
|
||||
|
||||
* 2025.04.06 📃docs: 业务发起送审
|
||||
|
||||
* 2025.04.06 🔄refactor: 流程模板调整为sqlsugar
|
||||
|
||||
* 2025.04.06 ⚠️feat: #IBYEGX 业务系统增加送审功能
|
||||
|
||||
* 2025.04.04 ⚠️feat: #IBYEGX 增加URL表单
|
||||
|
||||
* 2025.03.17 代码生成加上外部数据源支持
|
||||
|
||||
|
||||
@@ -4,10 +4,25 @@ createTime: 2025/04/23 23:43:26
|
||||
permalink: /pro/
|
||||
---
|
||||
::: warning 注意
|
||||
如果你使用的是vue2版本,请参考:[OpenAuth.Net Vue2版本](/vue2/)
|
||||
如果你使用的是开源的vue2版本,请参考:[OpenAuth.Net Vue2版本](/vue2/)
|
||||
:::
|
||||
|
||||
OpenAuth.Net Vue3版本基于vue3 + element-plus。使用OpenAuth.Net的API接口(即:OpenAuth.WebApi)提供数据服务。系统架构如下:
|
||||
目前OpenAuth.Net开源版源码、文档全部免费向大家提供,为了使项目走的更远,我们特推出付费订阅的vue3版本,以便更好服务于企业用户。相对于vue2版本,主要有以下优势:
|
||||
|
||||
| 对比项 | Vue3版本 | Vue2版本 |
|
||||
|---------------------|--------------------------------------------|--------------------------------------------|
|
||||
| 技术栈 | Vue3 + Element Plus | Vue2 + Element UI |
|
||||
| 移动端支持 | 提供UniApp版本 | 不支持移动端 |
|
||||
| 组件写法 | 组合式API(setup语法糖) | 选项式API |
|
||||
| 性能优化 | 更优的响应式系统,支持Tree-shaking | 响应式系统较旧,Tree-shaking支持较弱 |
|
||||
| 代码可维护性 | 更高,逻辑复用性强,易于模块化 | 逻辑复用性一般,模块化难度较高 |
|
||||
| 最新功能 | 新特性新功能第一时间上(如:表格列设置、流程加签等) | 社区更新较慢 |
|
||||
| 问题响应 | 官方团队第一时间响应 | 社区响应较慢 |
|
||||
| 技术支持 | 官方团队007待岗响应 | 社区大群沟通 |
|
||||
| 商业授权 | 需商业授权获取源码 | 开源免费 |
|
||||
| 适用场景 | 企业生产环境使用 | 个人、团队研究学习使用 |
|
||||
|
||||
系统架构如下:
|
||||
|
||||

|
||||
|
||||
|
||||
89
newdocs/docs/notes/pro/multilangs.md
Normal file
89
newdocs/docs/notes/pro/multilangs.md
Normal file
@@ -0,0 +1,89 @@
|
||||
---
|
||||
title: 多语言
|
||||
createTime: 2025/06/25 23:43:26
|
||||
permalink: /pro/multilangs/
|
||||
---
|
||||
|
||||
## 多语言配置
|
||||
|
||||

|
||||
|
||||
vue3版本集成 vue-i18n 实现多语言支持
|
||||
|
||||
### 使用方法
|
||||
|
||||
|
||||
1. **模板中使用**
|
||||
|
||||
框架已经全局注册$t方法,所以可以在模板中直接使用,如下:
|
||||
```html
|
||||
<div>{{ $t('login.title') }}</div>
|
||||
```
|
||||
|
||||
2. **vue script中使用**
|
||||
```javascript
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const i18n = useI18n()
|
||||
|
||||
let title = i18n.t('route.dashboard');
|
||||
```
|
||||
|
||||
3. **普通js代码中使用**
|
||||
|
||||
如果在普通的js(非vue component)代码中使用,需要使用 `i18n.global.t` 方法。
|
||||
|
||||
```javascript
|
||||
import i18n from '@/i18n'
|
||||
|
||||
let title = i18n.global.t('route.dashboard');
|
||||
```
|
||||
|
||||
### 配置说明
|
||||
|
||||
界面显示的文本,在 `src\i18n\langs\` 文件夹中配置,目前支持中文、英文。以 `zh-cn.js` 为例:
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
login: {
|
||||
title: 'OpenAuth.Net Vue3版',
|
||||
logIn: '登 录',
|
||||
username: '账号',
|
||||
password: '密码',
|
||||
usernamePlaceholder: '请输入登录账号',
|
||||
oauthLoginTip: '接口服务器启用了Oauth认证,请点击这里登录',
|
||||
tips: {
|
||||
system: '默认System登录后,你可以无法无天',
|
||||
admin: 'admin/admin登录后,会少一点权限,资源管理/分类管理的字段会少一点',
|
||||
test: 'test/test登录后,权限会更少,资源管理/分类管理的字段会更少'
|
||||
}
|
||||
},
|
||||
tagsView: {
|
||||
refresh: '刷新',
|
||||
close: '关闭',
|
||||
closeOthers: '关闭其它',
|
||||
closeAll: '关闭所有'
|
||||
},
|
||||
common: {
|
||||
language: '语言',
|
||||
welcome: '欢迎您,',
|
||||
ok: '确定',
|
||||
cancel: '取消',
|
||||
},
|
||||
language: {
|
||||
zh: '简体中文',
|
||||
en: '英文'
|
||||
},
|
||||
dashboard: {
|
||||
siteInfo: '为了大家体验的一致性,数据库每1小时还原一次。不同于其他基于Element框架界面的花里胡哨,各种大按钮大缝隙,我们的原则:美观大方、简洁易用',
|
||||
footer: {
|
||||
copyright: '最好用的.Net权限工作流框架',
|
||||
officialWebsite: '官方网站'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
|
||||
- 使用嵌套对象结构组织翻译项
|
||||
- 参数化文本使用 `{param}` 语法
|
||||
@@ -4,165 +4,181 @@ createTime: 2025/05/24 23:43:26
|
||||
permalink: /pro/selectusercom/
|
||||
---
|
||||
|
||||
SelectUsersCom是一个用于选择用户或角色的基础组件。如下图:
|
||||
SelectUsersCom是一个用于选择用户或角色的组件,提供了两种使用方式:
|
||||
1. 对话框模式 (index.vue)
|
||||
2. 输入框触发模式 (indexwithinput.vue)
|
||||
|
||||

|
||||

|
||||
|
||||
一般通过按钮触发弹框进行选择,如下:
|
||||
## 基础对话框组件 (index.vue)
|
||||
|
||||
```vue
|
||||
<el-button @click="selectDialog = true">选择用户</el-button>
|
||||
<el-dialog :destroy-on-close="true" width="850px" title="选择用户" v-model="selectDialog">
|
||||
<selectUsersCom v-if="selectDialog" :ignore-auth="ignoreAuth" v-model:show="selectDialog" :loginKey="'loginUser'"
|
||||
v-model:users="selectUsers" v-model:userNames="names"></selectUsersCom>
|
||||
</el-dialog>
|
||||
### 组件功能
|
||||
- 支持选择用户或角色
|
||||
- 支持组织树结构浏览
|
||||
- 支持搜索功能
|
||||
- 支持分页显示
|
||||
- 支持已选项目可视化管理
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import SelectUsersCom from '@/components/SelectUsersCom/index.vue'
|
||||
|
||||
const selectDialog = ref(false)
|
||||
const selectUsers = ref([])
|
||||
const names = ref('')
|
||||
const ignoreAuth = ref(false)
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
还有一种通过输入框触发弹框进行选择,这时需要回填数据到文本框中。如下:
|
||||
|
||||

|
||||
|
||||
```vue
|
||||
<el-input @click="selectDialog = true" readonly v-model="names" :placeholder="placeholder"></el-input>
|
||||
<el-dialog :destroy-on-close="true" width="850px" title="选择用户" v-model="selectDialog">
|
||||
<selectUsersCom v-if="selectDialog" :ignore-auth="ignoreAuth" v-model:show="selectDialog" :loginKey="'loginUser'"
|
||||
v-model:users="selectUsers" v-model:userNames="names"></selectUsersCom>
|
||||
</el-dialog>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import SelectUsersCom from '@/components/SelectUsersCom/index.vue'
|
||||
|
||||
const selectDialog = ref(false)
|
||||
const selectUsers = ref([])
|
||||
const names = ref('')
|
||||
const ignoreAuth = ref(false)
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
为了方便使用,我们在`SelectUsersCom`组件的基础上封装了`/components/SelectUsersCom/dialog.vue`组件用于带文本框的场景。使用如下:
|
||||
|
||||
```vue
|
||||
<select-users v-model:userNames="names" :users="users" :ignore-auth="true"></select-users>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import SelectUsersDialog from '@/components/SelectUsersCom/dialog.vue'
|
||||
|
||||
const names = ref('')
|
||||
const roles = ref([])
|
||||
</script>
|
||||
```
|
||||
|
||||
## 属性
|
||||
### 属性说明
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| show | Boolean | false | 控制组件显示/隐藏 |
|
||||
| loginKey | String | - | 选择类型,'loginUser'表示选择用户,其他值表示选择角色 |
|
||||
| orgId | String | - | 组织ID,如果为空则显示左侧树状结构 |
|
||||
| ignoreAuth | Boolean | false | 是否忽略登录用户权限,直接获取全部数据,用于可以跨部门选择用户、角色的场景 |
|
||||
| hiddenFooter | Boolean | false | 是否隐藏底部的确定/取消按钮 |
|
||||
| userNames | String | - | 已选用户/角色名称,逗号分隔 |
|
||||
| users | Array | [] | 已选用户/角色ID列表 |
|
||||
| ignoreAuth | Boolean | false | 是否忽略登录用户权限,直接获取全部数据 |
|
||||
| selectType | String | 'User' | 选择类型,'User'表示选择用户,'Role'表示选择角色 |
|
||||
| orgId | String | - | 组织ID,如果为空则显示左边树状结构 |
|
||||
| userNames | String | - | 用户名称(逗号分隔) |
|
||||
| users | Object | - | 初始选中项ID列表或对象列表 |
|
||||
| inType | String | 'id' | 父级传入的是id列表还是对象列表,取值为'id'或'obj' |
|
||||
| modelValue | Boolean | false | 控制对话框显示 |
|
||||
|
||||
## 事件
|
||||
### 事件说明
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| update:show | 组件显示状态变化时触发 | (show: Boolean) |
|
||||
| update:userNames | 选择的用户/角色名称变化时触发 | (userNames: String) |
|
||||
| update:users | 选择的用户/角色ID变化时触发 | (users: Array) |
|
||||
| 事件名 | 说明 |
|
||||
| --- | --- |
|
||||
| update:userNames | 更新用户名称 |
|
||||
| update:users | 更新用户列表 |
|
||||
| save | 保存选择结果 |
|
||||
| update:modelValue | 更新对话框显示状态 |
|
||||
|
||||
## 方法
|
||||
|
||||
| 方法名 | 说明 | 参数 |
|
||||
| --- | --- | --- |
|
||||
| handleSaveUsers | 保存已选中的用户/角色,可通过ref调用 | - |
|
||||
|
||||
## 更多示例
|
||||
|
||||
### 选择角色
|
||||
### 使用示例
|
||||
|
||||
```vue
|
||||
<el-input @click="selectDialog = true" readonly v-model="names" :placeholder="placeholder"></el-input>
|
||||
<el-dialog :destroy-on-close="true" width="850px" title="选择角色" v-model="selectDialog">
|
||||
<selectUsersCom v-if="selectDialog" :ignore-auth="ignoreAuth" v-model:show="selectDialog" :loginKey="'loginRole'"
|
||||
v-model:users="selectRoles" v-model:userNames="names"></selectUsersCom>
|
||||
</el-dialog>
|
||||
<template>
|
||||
<el-button @click="showDialog = true">选择用户</el-button>
|
||||
|
||||
<SelectUsersCom
|
||||
v-model="showDialog"
|
||||
:ignore-auth="true"
|
||||
select-type="User"
|
||||
v-model:users="selectedUsers"
|
||||
v-model:userNames="selectedNames"
|
||||
@save="handleSave"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import SelectUsersCom from '@/components/SelectUsersCom/index.vue'
|
||||
|
||||
const selectDialog = ref(false)
|
||||
const selectRoles = ref([])
|
||||
const names = ref('')
|
||||
const ignoreAuth = ref(false)
|
||||
const showDialog = ref(false)
|
||||
const selectedUsers = ref([])
|
||||
const selectedNames = ref('')
|
||||
|
||||
const handleSave = () => {
|
||||
console.log('已选用户ID:', selectedUsers.value)
|
||||
console.log('已选用户名称:', selectedNames.value)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
为了方便使用,我们在`SelectUsersCom`组件的基础上封装了`SelectRoles`组件用于选择角色。使用如下:
|
||||
## 输入框触发模式 (indexwithinput.vue)
|
||||
|
||||
### 组件功能
|
||||
- 默认显示为输入框
|
||||
- 点击输入框弹出选择对话框
|
||||
- 支持根据用户ID自动获取用户姓名
|
||||
- 支持选择用户并回显名称
|
||||
|
||||
### 属性说明
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| users | Array/String | - | 用户ID列表或单个用户ID |
|
||||
| userNames | String | '' | 用户名称(逗号分隔) |
|
||||
| placeholder | String | '' | 输入框占位符 |
|
||||
| ignoreAuth | Boolean | false | 是否忽略权限限制 |
|
||||
|
||||
### 事件说明
|
||||
|
||||
| 事件名 | 说明 |
|
||||
| --- | --- |
|
||||
| users-change | 用户选择变更时触发,参数为('users', 选中的用户ID列表)或('Texts', 选中的用户名称) |
|
||||
|
||||
### 使用示例
|
||||
|
||||
```vue
|
||||
<select-roles v-model:userNames="names" :roles="roles" :ignore-auth="true"></select-roles>
|
||||
<template>
|
||||
<SelectUsersComInput
|
||||
:users="selectedUserIds"
|
||||
:user-names="selectedUserNames"
|
||||
placeholder="请选择用户"
|
||||
:ignore-auth="true"
|
||||
@users-change="handleUsersChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import SelectRoles from '@/components/SelectRoles/index.vue'
|
||||
import SelectUsersComInput from '@/components/SelectUsersCom/indexwithinput.vue'
|
||||
|
||||
const names = ref('')
|
||||
const roles = ref([])
|
||||
const selectedUserIds = ref(['user1', 'user2'])
|
||||
const selectedUserNames = ref('张三,李四')
|
||||
|
||||
const handleUsersChange = (type, value) => {
|
||||
if (type === 'users') {
|
||||
selectedUserIds.value = value
|
||||
} else if (type === 'Texts') {
|
||||
selectedUserNames.value = value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 不显示底部按钮,通过ref调用方法
|
||||
## 角色选择输入框 (SelectRoles/indexwithinput.vue)
|
||||
|
||||
### 组件功能
|
||||
- 基于SelectUsersCom实现的角色选择器
|
||||
- 默认显示为输入框
|
||||
- 点击输入框弹出选择角色对话框
|
||||
|
||||
### 属性说明
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| roles | Array | - | 角色ID列表 |
|
||||
| userNames | String | - | 角色名称(逗号分隔) |
|
||||
| placeholder | String | - | 输入框占位符 |
|
||||
| ignoreAuth | Boolean | false | 是否忽略权限限制 |
|
||||
|
||||
### 事件说明
|
||||
|
||||
| 事件名 | 说明 |
|
||||
| --- | --- |
|
||||
| roles-change | 角色选择变更时触发,参数为('roles', 选中的角色ID列表)或('Texts', 选中的角色名称) |
|
||||
|
||||
### 使用示例
|
||||
|
||||
```vue
|
||||
<el-dialog width="80%" draggable :title="'选择用户'" v-model="dialogSelectUser">
|
||||
<selectUsersCom ref="selectUserRef" v-if="dialogSelectUser" :hiddenFooter="true" :loginKey="'loginUser'"
|
||||
v-model:users="selectUsers"></selectUsersCom>
|
||||
<template v-slot:footer>
|
||||
<div style="text-align: right">
|
||||
<el-button size="small" type="info" @click="dialogSelectUser = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" @click="handleSaveUsers">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template>
|
||||
<SelectRolesInput
|
||||
:roles="selectedRoleIds"
|
||||
:user-names="selectedRoleNames"
|
||||
placeholder="请选择角色"
|
||||
:ignore-auth="true"
|
||||
@roles-change="handleRolesChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import SelectUsersCom from '@/components/SelectUsersCom/index.vue'
|
||||
import SelectRolesInput from '@/components/SelectRoles/indexwithinput.vue'
|
||||
|
||||
const selectUserRef = ref(null)
|
||||
const dialogSelectUser = ref(false)
|
||||
const selectUsers = ref([])
|
||||
const selectedRoleIds = ref(['role1', 'role2'])
|
||||
const selectedRoleNames = ref('管理员,操作员')
|
||||
|
||||
//确定添加的用户
|
||||
const handleSaveUsers = () => {
|
||||
selectUserRef.value.handleSaveUsers()
|
||||
dialogSelectUser.value = false
|
||||
const handleRolesChange = (type, value) => {
|
||||
if (type === 'roles') {
|
||||
selectedRoleIds.value = value
|
||||
} else if (type === 'Texts') {
|
||||
selectedRoleNames.value = value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 当`ignoreAuth`为`true`时,将调用`loadAll`接口获取所有数据,否则调用`getList`接口获取有权限的数据
|
||||
1. 使用indexwithinput.vue时,如果在弹出框中使用,建议设置`:destroy-on-close="true"`,避免names记录上一次选中行的值
|
||||
2. 选择用户时可以通过组织树进行筛选,也可以直接搜索
|
||||
3. ignoreAuth属性可以控制是否忽略用户权限限制,直接获取全部数据
|
||||
4. 组件内部会自动处理用户ID和用户名称的映射关系
|
||||
@@ -578,8 +578,8 @@ COMMENT ON TABLE "EXTERNALDATASOURCE" IS '外部数据源管理';
|
||||
-- ----------------------------
|
||||
-- Records of EXTERNALDATASOURCE
|
||||
-- ----------------------------
|
||||
INSERT INTO "EXTERNALDATASOURCE" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764fe', '本地SqlServer', '1', 'Data Source=localhost;Encrypt=false;Initial Catalog=openauthpro;User=sa;Password=000000;', 'localhost', NULL, 'openauthpro', 'sa', '000000', '1', TO_DATE('2025-03-15 20:09:35', 'SYYYY-MM-DD HH24:MI:SS'), TO_DATE('2025-03-18 11:42:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL, '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
INSERT INTO "EXTERNALDATASOURCE" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764ff', '本地mysql', '0', 'Server=127.0.0.1;Database=openauthpro;User=root;Password=000000;', '127.0.0.1', '3306', 'openauthpro', 'root', '000000', '1', TO_DATE('2025-03-15 00:02:11', 'SYYYY-MM-DD HH24:MI:SS'), TO_DATE('2025-03-15 20:12:30', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL, '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
INSERT INTO "EXTERNALDATASOURCE" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764fe', '非默认的SqlServer', '1', 'Data Source=localhost;Encrypt=false;Initial Catalog=openauthpro;User=sa;Password=000000;', 'localhost', NULL, 'openauthpro', 'sa', '000000', '1', TO_DATE('2025-03-15 20:09:35', 'SYYYY-MM-DD HH24:MI:SS'), TO_DATE('2025-03-18 11:42:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL, '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
INSERT INTO "EXTERNALDATASOURCE" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764ff', '非默认的mysql', '0', 'Server=127.0.0.1;Database=openauthpro;User=root;Password=000000;', '127.0.0.1', '3306', 'openauthpro', 'root', '000000', '1', TO_DATE('2025-03-15 00:02:11', 'SYYYY-MM-DD HH24:MI:SS'), TO_DATE('2025-03-15 20:12:30', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL, '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for FLOWAPPROVER
|
||||
@@ -1189,7 +1189,7 @@ INSERT INTO "MODULE" VALUES ('bc80478d-0547-4437-9cff-be4b40144bdf', '.0.1.26.',
|
||||
INSERT INTO "MODULE" VALUES ('bedb41a2-f310-4775-af99-01be08adda93', '.0.1.30.', '角色管理', '/RoleManager/Index', NULL, '0', '0', 'bumenguanli', '0', '基础配置', NULL, '1', '7580672f-a390-4bb6-982d-9a4570cb5199', 'Role', '1', '1');
|
||||
INSERT INTO "MODULE" VALUES ('e11b4ece-b4c6-44f5-b1c1-8f1dadbf037c', '.0.1.40.', '数据源管理', '/externaldatasources/index', NULL, '0', '0', 'jifen', '0', '基础配置', NULL, '10', '7580672f-a390-4bb6-982d-9a4570cb5199', 'ExternalDatasource', '0', '1');
|
||||
INSERT INTO "MODULE" VALUES ('e8dc5db6-4fc4-4795-a1cc-681cbcceec91', '.0.1.38.', '资源管理', '/Resources/Index', NULL, '0', '0', 'ziyuanguanli', '0', '基础配置', NULL, '7', '7580672f-a390-4bb6-982d-9a4570cb5199', 'SysResource', '0', '1');
|
||||
INSERT INTO "MODULE" VALUES ('ef386d5d-cd58-43c0-a4ab-80afd0dbcd6c', '.0.1.31.', '用户管理', '/UserManager/Index', NULL, '0', '0', 'yonghuguanli', '0', '基础配置', NULL, '2', '7580672f-a390-4bb6-982d-9a4570cb5199', 'User', '1', '1');
|
||||
INSERT INTO "MODULE" VALUES ('ef386d5d-cd58-43c0-a4ab-80afd0dbcd6c', '.0.1.31.', '用户管理', '/UserManager/Index', NULL, '0', '0', 'yonghuguanli', '0', '基础配置', NULL, '2', '7580672f-a390-4bb6-982d-9a4570cb5199', 'SysUser', '1', '1');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for MODULEELEMENT
|
||||
@@ -2292,8 +2292,8 @@ COMMENT ON TABLE "SYSPRINTERPLAN" IS '打印方案模板';
|
||||
-- ----------------------------
|
||||
-- Records of SYSPRINTERPLAN
|
||||
-- ----------------------------
|
||||
INSERT INTO "SYSPRINTERPLAN" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb354', '用户名片(卡片式)', 'select * from sysuser', 'user', NULL, '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', '0', TO_DATE('2023-09-27 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 'System', NULL);
|
||||
INSERT INTO "SYSPRINTERPLAN" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb355', '用户名片(卡片式)【带参数】', 'select * from sysuser where Account=@Account', 'user', NULL, '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', '0', TO_DATE('2023-09-26 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 'System', 'Account');
|
||||
INSERT INTO "SYSPRINTERPLAN" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb354', '用户名片(卡片式)', 'select * from sysuser', 'sysuser', NULL, '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', '0', TO_DATE('2023-09-27 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 'System', NULL);
|
||||
INSERT INTO "SYSPRINTERPLAN" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb355', '用户名片(卡片式)【带参数】', 'select * from sysuser where Account=@Account', 'sysuser', NULL, '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', '0', TO_DATE('2023-09-26 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 'System', 'Account');
|
||||
INSERT INTO "SYSPRINTERPLAN" VALUES ('b06bc72d-6b56-449d-aa7d-63dc9c153f71', '入库随货同行单(列表式)', 'select dtl.*, e.name OrderType, d.name GoodsType, c.name TransName
|
||||
from wmsinboundorderdtbl dtl
|
||||
left join wmsinboundordertbl main on dtl.orderid = main.id
|
||||
|
||||
@@ -480,8 +480,8 @@ COMMENT ON TABLE "public"."externaldatasource" IS '外部数据源管理';
|
||||
-- ----------------------------
|
||||
-- Records of externaldatasource
|
||||
-- ----------------------------
|
||||
INSERT INTO "public"."externaldatasource" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764fe', '本地SqlServer', 1, 'Data Source=localhost;Encrypt=false;Initial Catalog=openauthpro;User=sa;Password=000000;', 'localhost', NULL, 'openauthpro', 'sa', '000000', 1, '2025-03-15 20:09:35', '2025-03-18 11:42:08', 0, '', '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
INSERT INTO "public"."externaldatasource" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764ff', '本地mysql', 0, 'Server=127.0.0.1;Database=openauthpro;User=root;Password=000000;', '127.0.0.1', 3306, 'openauthpro', 'root', '000000', 1, '2025-03-15 00:02:11', '2025-03-15 20:12:30', 0, '', '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
INSERT INTO "public"."externaldatasource" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764fe', '非默认的SqlServer', 1, 'Data Source=localhost;Encrypt=false;Initial Catalog=openauthpro;User=sa;Password=000000;', 'localhost', NULL, 'openauthpro', 'sa', '000000', 1, '2025-03-15 20:09:35', '2025-03-18 11:42:08', 0, '', '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
INSERT INTO "public"."externaldatasource" VALUES ('94279d93-cef3-46e0-83af-3b7dc48764ff', '非默认的mysql', 0, 'Server=127.0.0.1;Database=openauthpro;User=root;Password=000000;', '127.0.0.1', 3306, 'openauthpro', 'root', '000000', 1, '2025-03-15 00:02:11', '2025-03-15 20:12:30', 0, '', '00000000-0000-0000-0000-000000000000', '超级管理员', '00000000-0000-0000-0000-000000000000', '超级管理员');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for flowapprover
|
||||
@@ -983,7 +983,7 @@ INSERT INTO "public"."module" VALUES ('bc80478d-0547-4437-9cff-be4b40144bdf', '.
|
||||
INSERT INTO "public"."module" VALUES ('bedb41a2-f310-4775-af99-01be08adda93', '.0.1.30.', '角色管理', '/RoleManager/Index', '', 0, 0, 'bumenguanli', 0, '基础配置', '', 1, '7580672f-a390-4bb6-982d-9a4570cb5199', 'Role', 1, 1);
|
||||
INSERT INTO "public"."module" VALUES ('e11b4ece-b4c6-44f5-b1c1-8f1dadbf037c', '.0.1.40.', '数据源管理', '/externaldatasources/index', '', 0, 0, 'jifen', 0, '基础配置', '', 10, '7580672f-a390-4bb6-982d-9a4570cb5199', 'ExternalDatasource', 0, 1);
|
||||
INSERT INTO "public"."module" VALUES ('e8dc5db6-4fc4-4795-a1cc-681cbcceec91', '.0.1.38.', '资源管理', '/Resources/Index', '', 0, 0, 'ziyuanguanli', 0, '基础配置', '', 7, '7580672f-a390-4bb6-982d-9a4570cb5199', 'SysResource', 0, 1);
|
||||
INSERT INTO "public"."module" VALUES ('ef386d5d-cd58-43c0-a4ab-80afd0dbcd6c', '.0.1.31.', '用户管理', '/UserManager/Index', '', 0, 0, 'yonghuguanli', 0, '基础配置', '', 2, '7580672f-a390-4bb6-982d-9a4570cb5199', 'User', 1, 1);
|
||||
INSERT INTO "public"."module" VALUES ('ef386d5d-cd58-43c0-a4ab-80afd0dbcd6c', '.0.1.31.', '用户管理', '/UserManager/Index', '', 0, 0, 'yonghuguanli', 0, '基础配置', '', 2, '7580672f-a390-4bb6-982d-9a4570cb5199', 'SysUser', 1, 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for moduleelement
|
||||
@@ -1964,8 +1964,8 @@ COMMENT ON TABLE "public"."sysprinterplan" IS '打印方案模板';
|
||||
-- ----------------------------
|
||||
-- Records of sysprinterplan
|
||||
-- ----------------------------
|
||||
INSERT INTO "public"."sysprinterplan" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb354', '用户名片(卡片式)', 'select * from sysuser', 'user', '', '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', 0, '2023-09-27', 'System', '');
|
||||
INSERT INTO "public"."sysprinterplan" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb355', '用户名片(卡片式)【带参数】', 'select * from sysuser where Account=@Account', 'user', '', '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', 0, '2023-09-26', 'System', 'Account');
|
||||
INSERT INTO "public"."sysprinterplan" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb354', '用户名片(卡片式)', 'select * from sysuser', 'sysuser', '', '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', 0, '2023-09-27', 'System', '');
|
||||
INSERT INTO "public"."sysprinterplan" VALUES ('01f49e66-b7c0-4c83-a24d-0667e99cb355', '用户名片(卡片式)【带参数】', 'select * from sysuser where Account=@Account', 'sysuser', '', '{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', 0, '2023-09-26', 'System', 'Account');
|
||||
INSERT INTO "public"."sysprinterplan" VALUES ('b06bc72d-6b56-449d-aa7d-63dc9c153f71', '入库随货同行单(列表式)', 'select dtl.*, e.name OrderType, d.name GoodsType, c.name TransName
|
||||
from wmsinboundorderdtbl dtl
|
||||
left join wmsinboundordertbl main on dtl.orderid = main.id
|
||||
|
||||
@@ -1522,10 +1522,10 @@ GO
|
||||
-- ----------------------------
|
||||
-- Records of ExternalDataSource
|
||||
-- ----------------------------
|
||||
INSERT INTO [dbo].[ExternalDataSource] ([Id], [Name], [DbType], [ConnectionString], [Server], [Port], [DatabaseName], [UserName], [Password], [Enabled], [CreateTime], [UpdateTime], [TestSuccess], [Description], [CreateUserId], [CreateUserName], [UpdateUserId], [UpdateUserName]) VALUES (N'94279d93-cef3-46e0-83af-3b7dc48764fe', N'本地SqlServer', N'1', N'Data Source=localhost;Encrypt=false;Initial Catalog=openauthpro;User=sa;Password=000000;', N'localhost', NULL, N'openauthpro', N'sa', N'000000', N'1', N'2025-03-15', N'2025-03-18', N'0', N'', N'00000000-0000-0000-0000-000000000000', N'超级管理员', N'00000000-0000-0000-0000-000000000000', N'超级管理员')
|
||||
INSERT INTO [dbo].[ExternalDataSource] ([Id], [Name], [DbType], [ConnectionString], [Server], [Port], [DatabaseName], [UserName], [Password], [Enabled], [CreateTime], [UpdateTime], [TestSuccess], [Description], [CreateUserId], [CreateUserName], [UpdateUserId], [UpdateUserName]) VALUES (N'94279d93-cef3-46e0-83af-3b7dc48764fe', N'非默认的SqlServer', N'1', N'Data Source=localhost;Encrypt=false;Initial Catalog=openauthpro;User=sa;Password=000000;', N'localhost', NULL, N'openauthpro', N'sa', N'000000', N'1', N'2025-03-15', N'2025-03-18', N'0', N'', N'00000000-0000-0000-0000-000000000000', N'超级管理员', N'00000000-0000-0000-0000-000000000000', N'超级管理员')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[ExternalDataSource] ([Id], [Name], [DbType], [ConnectionString], [Server], [Port], [DatabaseName], [UserName], [Password], [Enabled], [CreateTime], [UpdateTime], [TestSuccess], [Description], [CreateUserId], [CreateUserName], [UpdateUserId], [UpdateUserName]) VALUES (N'94279d93-cef3-46e0-83af-3b7dc48764ff', N'本地mysql', N'0', N'Server=127.0.0.1;Database=openauthpro;User=root;Password=000000;', N'127.0.0.1', N'3306', N'openauthpro', N'root', N'000000', N'1', N'2025-03-15', N'2025-03-15', N'0', N'', N'00000000-0000-0000-0000-000000000000', N'超级管理员', N'00000000-0000-0000-0000-000000000000', N'超级管理员')
|
||||
INSERT INTO [dbo].[ExternalDataSource] ([Id], [Name], [DbType], [ConnectionString], [Server], [Port], [DatabaseName], [UserName], [Password], [Enabled], [CreateTime], [UpdateTime], [TestSuccess], [Description], [CreateUserId], [CreateUserName], [UpdateUserId], [UpdateUserName]) VALUES (N'94279d93-cef3-46e0-83af-3b7dc48764ff', N'非默认的mysql', N'0', N'Server=127.0.0.1;Database=openauthpro;User=root;Password=000000;', N'127.0.0.1', N'3306', N'openauthpro', N'root', N'000000', N'1', N'2025-03-15', N'2025-03-15', N'0', N'', N'00000000-0000-0000-0000-000000000000', N'超级管理员', N'00000000-0000-0000-0000-000000000000', N'超级管理员')
|
||||
GO
|
||||
|
||||
|
||||
@@ -3187,7 +3187,7 @@ GO
|
||||
INSERT INTO [dbo].[Module] ([Id], [CascadeId], [Name], [Url], [HotKey], [IsLeaf], [IsAutoExpand], [IconName], [Status], [ParentName], [Vector], [SortNo], [ParentId], [Code], [IsSys], [KeepAlive]) VALUES (N'e8dc5db6-4fc4-4795-a1cc-681cbcceec91', N'.0.1.38.', N'资源管理', N'/Resources/Index', N'', N'0', N'0', N'ziyuanguanli', N'0', N'基础配置', N'', N'7', N'7580672f-a390-4bb6-982d-9a4570cb5199', N'SysResource', N'0', N'1')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[Module] ([Id], [CascadeId], [Name], [Url], [HotKey], [IsLeaf], [IsAutoExpand], [IconName], [Status], [ParentName], [Vector], [SortNo], [ParentId], [Code], [IsSys], [KeepAlive]) VALUES (N'ef386d5d-cd58-43c0-a4ab-80afd0dbcd6c', N'.0.1.31.', N'用户管理', N'/UserManager/Index', N'', N'0', N'0', N'yonghuguanli', N'0', N'基础配置', N'', N'2', N'7580672f-a390-4bb6-982d-9a4570cb5199', N'User', N'1', N'1')
|
||||
INSERT INTO [dbo].[Module] ([Id], [CascadeId], [Name], [Url], [HotKey], [IsLeaf], [IsAutoExpand], [IconName], [Status], [ParentName], [Vector], [SortNo], [ParentId], [Code], [IsSys], [KeepAlive]) VALUES (N'ef386d5d-cd58-43c0-a4ab-80afd0dbcd6c', N'.0.1.31.', N'用户管理', N'/UserManager/Index', N'', N'0', N'0', N'yonghuguanli', N'0', N'基础配置', N'', N'2', N'7580672f-a390-4bb6-982d-9a4570cb5199', N'SysUser', N'1', N'1')
|
||||
GO
|
||||
|
||||
|
||||
@@ -6226,10 +6226,10 @@ GO
|
||||
-- ----------------------------
|
||||
-- Records of SysPrinterPlan
|
||||
-- ----------------------------
|
||||
INSERT INTO [dbo].[SysPrinterPlan] ([Id], [Name], [SourceSql], [ColumnView], [GroupBy], [PlanContent], [Disable], [CreateTime], [CreateUser], [InParamColumn]) VALUES (N'01f49e66-b7c0-4c83-a24d-0667e99cb354', N'用户名片(卡片式)', N'select * from sysuser', N'user', N'', N'{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', N'0', N'2023-09-27', N'System', N'')
|
||||
INSERT INTO [dbo].[SysPrinterPlan] ([Id], [Name], [SourceSql], [ColumnView], [GroupBy], [PlanContent], [Disable], [CreateTime], [CreateUser], [InParamColumn]) VALUES (N'01f49e66-b7c0-4c83-a24d-0667e99cb354', N'用户名片(卡片式)', N'select * from sysuser', N'sysuser', N'', N'{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', N'0', N'2023-09-27', N'System', N'')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[SysPrinterPlan] ([Id], [Name], [SourceSql], [ColumnView], [GroupBy], [PlanContent], [Disable], [CreateTime], [CreateUser], [InParamColumn]) VALUES (N'01f49e66-b7c0-4c83-a24d-0667e99cb355', N'用户名片(卡片式)【带参数】', N'select * from sysuser where Account=@Account', N'user', N'', N'{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', N'0', N'2023-09-26', N'System', N'Account')
|
||||
INSERT INTO [dbo].[SysPrinterPlan] ([Id], [Name], [SourceSql], [ColumnView], [GroupBy], [PlanContent], [Disable], [CreateTime], [CreateUser], [InParamColumn]) VALUES (N'01f49e66-b7c0-4c83-a24d-0667e99cb355', N'用户名片(卡片式)【带参数】', N'select * from sysuser where Account=@Account', N'sysuser', N'', N'{"panels":[{"index":0,"name":1,"height":30,"width":100,"paperHeader":0,"paperFooter":85.03937007874016,"printElements":[{"options":{"left":16.5,"top":12,"height":9.75,"width":63,"title":"文本","field":"name","testData":"李玉宝","coordinateSync":false,"widthHeightSync":false,"hideTitle":true,"fontSize":15,"qrCodeLevel":0,"right":88.5,"bottom":30.75,"vCenter":57,"hCenter":25.875},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":103.5,"top":12,"height":32,"width":40,"testData":"XS888888888","fontSize":12,"lineHeight":18,"fontWeight":"700","textContentVerticalAlign":"middle","textType":"qrcode","title":"二维码","right":231.75,"bottom":51.5,"vCenter":171.75,"hCenter":35.5,"coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"二维码","type":"text"}},{"options":{"left":16.5,"top":33,"height":9.75,"width":75,"title":"账号","right":99,"bottom":51,"vCenter":61.5,"hCenter":46.125,"field":"account","testData":"System","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}},{"options":{"left":16.5,"top":55.5,"height":9.75,"width":120,"title":"研发部、办公室","right":146.25,"bottom":73.5,"vCenter":86.25,"hCenter":68.625,"testData":"研发部、办公室","coordinateSync":false,"widthHeightSync":false,"qrCodeLevel":0},"printElementType":{"title":"文本","type":"text"}}],"paperNumberLeft":253,"paperNumberTop":63,"paperNumberDisabled":true,"paperNumberContinue":true,"fontFamily":"Microsoft YaHei","orient":2,"watermarkOptions":{"content":"","fillStyle":"rgba(184, 184, 184, 0.3)","fontSize":"14px","rotate":25,"width":200,"height":200,"timestamp":false,"format":"YYYY-MM-DD HH:mm"}}]}', N'0', N'2023-09-26', N'System', N'Account')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[SysPrinterPlan] ([Id], [Name], [SourceSql], [ColumnView], [GroupBy], [PlanContent], [Disable], [CreateTime], [CreateUser], [InParamColumn]) VALUES (N'b06bc72d-6b56-449d-aa7d-63dc9c153f71', N'入库随货同行单(列表式)', N'select dtl.*, e.name OrderType, d.name GoodsType, c.name TransName
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user