添加项目文件。

This commit is contained in:
2023-03-13 15:00:34 +08:00
parent 42bf06ca3e
commit 1d73df3235
1205 changed files with 185078 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
using JNPF.Common.Core.Manager;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.Extend.Entitys;
using JNPF.Extend.Entitys.Dto.Email;
using JNPF.Message.Entitys;
using JNPF.Message.Interfaces.Message;
using JNPF.VisualDev.Entitys.Dto.Dashboard;
using JNPF.WorkFlow.Entitys.Entity;
using JNPF.WorkFlow.Interfaces.Repository;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
namespace JNPF.VisualDev;
/// <summary>
/// 业务实现:主页显示.
/// </summary>
[ApiDescriptionSettings(Tag = "VisualDev", Name = "Dashboard", Order = 174)]
[Route("api/visualdev/[controller]")]
public class DashboardService : IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository<EmailReceiveEntity> _emailReceiveRepository;
/// <summary>
/// 流程任务.
/// </summary>
private readonly IFlowTaskRepository _flowTaskRepository;
/// <summary>
/// 系统消息服务.
/// </summary>
private readonly IMessageService _messageService;
/// <summary>
/// 用户管理.
/// </summary>
private readonly IUserManager _userManager;
/// <summary>
/// 初始化一个<see cref="DashboardService"/>类型的新实例.
/// </summary>
public DashboardService(
ISqlSugarRepository<EmailReceiveEntity> emailReceiveRepository,
IFlowTaskRepository flowTaskRepository,
IMessageService messageService,
IUserManager userManager)
{
_emailReceiveRepository = emailReceiveRepository;
_flowTaskRepository = flowTaskRepository;
_messageService = messageService;
_userManager = userManager;
}
#region Get
/// <summary>
/// 获取我的待办.
/// </summary>
[HttpGet("FlowTodoCount")]
public async Task<dynamic> GetFlowTodoCount()
{
int flowCount = await _emailReceiveRepository.AsSugarClient().Queryable<FlowDelegateEntity>().Where(x => x.CreatorUserId == _userManager.UserId && x.DeleteMark == null).CountAsync();
List<FlowTaskEntity>? waitList = await _flowTaskRepository.GetWaitList();
List<FlowTaskEntity>? trialList = await _flowTaskRepository.GetTrialList();
return new FlowTodoCountOutput()
{
toBeReviewed = waitList.Count(),
entrust = flowCount,
flowDone = trialList.Count()
};
}
/// <summary>
/// 获取通知公告.
/// </summary>
[HttpGet("Notice")]
public async Task<dynamic> GetNotice()
{
List<NoticeOutput> list = await _emailReceiveRepository.AsSugarClient().Queryable<MessageEntity, MessageReceiveEntity>((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.MessageId))
.Where((a, b) => a.Type == 1 && a.DeleteMark == null && b.UserId == _userManager.UserId)
.Select((a) => new NoticeOutput()
{
id = a.Id,
fullName = a.Title,
creatorTime = a.CreatorTime
}).ToListAsync();
return new { list = list };
}
/// <summary>
/// 获取待办事项.
/// </summary>
[HttpGet("FlowTodo")]
public async Task<dynamic> GetFlowTodo()
{
dynamic list = await _flowTaskRepository.GetPortalWaitList();
return new { list = list };
}
/// <summary>
/// 获取我的待办事项.
/// </summary>
[HttpGet("MyFlowTodo")]
public async Task<dynamic> GetMyFlowTodo()
{
List<FlowTodoOutput> list = new List<FlowTodoOutput>();
(await _flowTaskRepository.GetWaitList()).ForEach(l =>
{
list.Add(new FlowTodoOutput()
{
id = l.Id,
fullName = l.FlowName,
creatorTime = l.CreatorTime
});
});
return new { list = list };
}
/// <summary>
/// 获取未读邮件.
/// </summary>
[HttpGet("Email")]
public async Task<dynamic> GetEmail()
{
List<EmailHomeOutput>? res = (await _emailReceiveRepository.AsQueryable().Where(x => x.Read == 0 && x.CreatorUserId == _userManager.UserId && x.DeleteMark == null)
.OrderBy(x => x.CreatorTime, OrderByType.Desc).ToListAsync()).Adapt<List<EmailHomeOutput>>();
return new { list = res };
}
#endregion
}

View File

@@ -0,0 +1,376 @@
using JNPF.Common.Core.Manager;
using JNPF.Common.Core.Manager.Files;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Filter;
using JNPF.Common.Models.User;
using JNPF.Common.Security;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.Systems.Entitys.Permission;
using JNPF.Systems.Entitys.System;
using JNPF.Systems.Interfaces.Common;
using JNPF.VisualDev.Entitys;
using JNPF.VisualDev.Entitys.Dto.Portal;
using JNPF.VisualDev.Entitys.Dto.VisualDev;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
namespace JNPF.VisualDev;
/// <summary>
/// 业务实现:门户设计.
/// </summary>
[ApiDescriptionSettings(Tag = "VisualDev", Name = "Portal", Order = 173)]
[Route("api/visualdev/[controller]")]
public class PortalService : IDynamicApiController, ITransient
{
/// <summary>
/// 服务基础仓储.
/// </summary>
private readonly ISqlSugarRepository<PortalEntity> _portalRepository;
/// <summary>
/// 用户管理.
/// </summary>
private readonly IUserManager _userManager;
/// <summary>
/// 文件服务.
/// </summary>
private readonly IFileManager _fileManager;
/// <summary>
/// 初始化一个<see cref="PortalService"/>类型的新实例.
/// </summary>
public PortalService(
ISqlSugarRepository<PortalEntity> portalRepository,
IUserManager userManager,
IFileManager fileManager)
{
_portalRepository = portalRepository;
_userManager = userManager;
_fileManager = fileManager;
}
#region Get
/// <summary>
/// 列表.
/// </summary>
/// <param name="input">请求参数.</param>
/// <returns>返回列表.</returns>
[HttpGet("")]
public async Task<dynamic> GetList([FromQuery] VisualDevListQueryInput input)
{
SqlSugarPagedList<PortalListOutput>? portalList = await _portalRepository.AsSugarClient().Queryable<PortalEntity, UserEntity, UserEntity, DictionaryDataEntity>((a, b, c, d) => new JoinQueryInfos(JoinType.Left, b.Id == a.CreatorUserId, JoinType.Left, c.Id == a.LastModifyUserId, JoinType.Left, d.Id == a.Category))
.WhereIF(!string.IsNullOrEmpty(input.keyword), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword))
.WhereIF(!string.IsNullOrEmpty(input.category), a => a.Category == input.category).Where(a => a.DeleteMark == null)
.OrderBy(a => a.SortCode, OrderByType.Asc)
.OrderBy(a => a.CreatorTime, OrderByType.Desc)
.OrderBy(a => a.LastModifyTime, OrderByType.Desc)
.Select((a, b, c, d) => new PortalListOutput
{
id = a.Id,
fullName = a.FullName,
enCode = a.EnCode,
deleteMark = SqlFunc.ToString(a.DeleteMark),
description = a.Description,
category = d.FullName,
creatorTime = a.CreatorTime,
creatorUser = SqlFunc.MergeString(b.RealName, "/", b.Account),
parentId = a.Category,
lastModifyUser = SqlFunc.MergeString(c.RealName, SqlFunc.IIF(c.RealName == null, string.Empty, "/"), c.Account),
lastModifyTime = SqlFunc.ToDate(a.LastModifyTime),
enabledMark = a.EnabledMark,
type = a.Type,
sortCode = SqlFunc.ToString(a.SortCode)
})
.ToPagedListAsync(input.currentPage, input.pageSize);
return PageResult<PortalListOutput>.SqlSugarPageResult(portalList);
}
/// <summary>
/// 获取门户侧边框列表.
/// </summary>
/// <returns></returns>
[HttpGet("Selector")]
public async Task<dynamic> GetSelector([FromQuery] string type)
{
List<PortalSelectOutput>? data = new List<PortalSelectOutput>();
if ("1".Equals(type) && !_userManager.IsAdministrator)
{
List<string>? roleId = await _portalRepository.AsSugarClient().Queryable<RoleEntity>().In(r => r.Id, _userManager.Roles).Where(r => r.EnabledMark == 1 && r.DeleteMark == null).Select(r => r.Id).ToListAsync();
var items = await _portalRepository.AsSugarClient().Queryable<AuthorizeEntity>().Where(a => roleId.Contains(a.ObjectId) && a.ItemType == "portal").GroupBy(it => new { it.ItemId }).Select(it => new { it.ItemId }).ToListAsync();
if (items.Any())
{
data = await _portalRepository.AsQueryable().In(p => p.Id, items.Select(it => it.ItemId).ToArray())
.Where(p => p.EnabledMark == 1 && p.DeleteMark == null).OrderBy(p => p.SortCode)
.Select(s => new PortalSelectOutput
{
id = s.Id,
fullName = s.FullName,
parentId = s.Category
}).ToListAsync();
}
}
else
{
data = await _portalRepository.AsQueryable()
.Where(p => p.EnabledMark == 1 && p.DeleteMark == null).OrderBy(o => o.SortCode)
.Select(s => new PortalSelectOutput
{
id = s.Id,
fullName = s.FullName,
parentId = s.Category,
}).ToListAsync();
}
List<string>? parentIds = data.Select(it => it.parentId).Distinct().ToList();
List<PortalSelectOutput>? treeList = new List<PortalSelectOutput>();
if (parentIds.Any())
{
treeList = await _portalRepository.AsSugarClient().Queryable<DictionaryDataEntity>().In(it => it.Id, parentIds.ToArray())
.Where(d => d.DeleteMark == null && d.EnabledMark == 1).OrderBy(o => o.SortCode)
.Select(d => new PortalSelectOutput
{
id = d.Id,
parentId = "0",
fullName = d.FullName
}).ToListAsync();
}
return new { list = treeList.Union(data).ToList().ToTree("0") };
}
/// <summary>
/// 获取门户信息.
/// </summary>
/// <param name="id">主键id.</param>
/// <returns></returns>
[HttpGet("{id}")]
public async Task<dynamic> GetInfo(string id)
{
PortalEntity? data = await _portalRepository.AsQueryable().FirstAsync(p => p.Id == id);
return data.Adapt<PortalInfoOutput>();
}
/// <summary>
/// 信息.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}/auth")]
public async Task<dynamic> GetInfoAuth(string id)
{
if (_userManager.Roles != null && !_userManager.IsAdministrator)
{
List<string>? roleId = await _portalRepository.AsSugarClient().Queryable<RoleEntity>().Where(r =>_userManager.Roles.Contains(r.Id)).Where(r => r.EnabledMark == 1 && r.DeleteMark == null).Select(r => r.Id).ToListAsync();
var items = await _portalRepository.AsSugarClient().Queryable<AuthorizeEntity>().Where(a => roleId.Contains(a.ObjectId)).Where(a => a.ItemType == "portal").GroupBy(it => new { it.ItemId }).Select(it => new { it.ItemId }).ToListAsync();
if (items.Count == 0) return null;
PortalEntity? entity = await _portalRepository.AsQueryable().Where(p => items.Select(it => it.ItemId).Contains(p.Id)).SingleAsync(p => p.Id == id && p.EnabledMark == 1 && p.DeleteMark == null);
//_ = entity ?? throw Oops.Oh(ErrorCode.COM1005);
if (entity == null) return new PortalInfoAuthOutput();
return entity.Adapt<PortalInfoAuthOutput>();
}
if (_userManager.IsAdministrator)
{
PortalEntity? entity = await _portalRepository.AsQueryable().FirstAsync(p => p.Id == id && p.EnabledMark == 1 && p.DeleteMark == null);
//_ = entity ?? throw Oops.Oh(ErrorCode.COM1005);
if (entity == null) return new PortalInfoAuthOutput();
return entity.Adapt<PortalInfoAuthOutput>();
}
throw Oops.Oh(ErrorCode.D1900);
}
#endregion
#region Post
/// <summary>
/// 门户导出.
/// </summary>
/// <param name="modelId"></param>
/// <returns></returns>
[HttpPost("{modelId}/Actions/ExportData")]
public async Task<dynamic> ActionsExportData(string modelId)
{
// 模板实体
PortalEntity? templateEntity = await _portalRepository.AsQueryable().FirstAsync(p => p.Id == modelId);
string? jsonStr = templateEntity.ToJsonString();
return await _fileManager.Export(jsonStr, templateEntity.FullName, ExportFileType.vp);
}
/// <summary>
/// 门户导入.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("Model/Actions/ImportData")]
public async Task ActionsImportData(IFormFile file)
{
string? fileType = Path.GetExtension(file.FileName).Replace(".", string.Empty);
if (!fileType.ToLower().Equals(ExportFileType.vp.ToString())) throw Oops.Oh(ErrorCode.D3006);
string? josn = _fileManager.Import(file);
PortalEntity? templateEntity = null;
try
{
templateEntity = josn.ToObject<PortalEntity>();
}
catch
{
throw Oops.Oh(ErrorCode.D3006);
}
if (templateEntity == null) throw Oops.Oh(ErrorCode.D3006);
if (templateEntity != null && templateEntity.FormData.IsNotEmptyOrNull() && templateEntity.FormData.IndexOf("layouyId") <= 0)
throw Oops.Oh(ErrorCode.D3006);
if (templateEntity.Id.IsNotEmptyOrNull() && await _portalRepository.IsAnyAsync(it => it.Id == templateEntity.Id && it.DeleteMark == null))
throw Oops.Oh(ErrorCode.D1400);
if (await _portalRepository.IsAnyAsync(it => it.EnCode == templateEntity.EnCode && it.FullName == templateEntity.FullName && it.DeleteMark == null))
throw Oops.Oh(ErrorCode.D1400);
StorageableResult<PortalEntity>? stor = _portalRepository.AsSugarClient().Storageable(templateEntity).Saveable().ToStorage(); // 存在更新不存在插入 根据主键
await stor.AsInsertable.ExecuteCommandAsync(); // 执行插入
await stor.AsUpdateable.ExecuteCommandAsync(); // 执行更新
}
/// <summary>
/// 新建门户信息.
/// </summary>
/// <param name="input">实体对象.</param>
/// <returns></returns>
[HttpPost("")]
public async Task Create([FromBody] PortalCrInput input)
{
PortalEntity? entity = input.Adapt<PortalEntity>();
if (string.IsNullOrEmpty(entity.Category)) throw Oops.Oh(ErrorCode.D1901);
else if (string.IsNullOrEmpty(entity.FullName)) throw Oops.Oh(ErrorCode.D1902);
else if (string.IsNullOrEmpty(entity.EnCode)) throw Oops.Oh(ErrorCode.D1903);
else await _portalRepository.AsSugarClient().Insertable(entity).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
}
/// <summary>
/// 修改接口.
/// </summary>
/// <param name="id">主键id.</param>
/// <param name="input">参数.</param>
/// <returns></returns>
[HttpPut("{id}")]
public async Task Update(string id, [FromBody] PortalUpInput input)
{
PortalEntity? entity = input.Adapt<PortalEntity>();
int isOk = await _portalRepository.AsSugarClient().Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1001);
}
/// <summary>
/// 删除接口.
/// </summary>
/// <param name="id">主键id.</param>
/// <returns></returns>
[HttpDelete("{id}")]
public async Task Delete(string id)
{
PortalEntity? entity = await _portalRepository.AsQueryable().FirstAsync(p => p.Id == id && p.DeleteMark == null);
_ = entity ?? throw Oops.Oh(ErrorCode.COM1005);
int isOk = await _portalRepository.AsSugarClient().Updateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1002);
}
/// <summary>
/// 复制.
/// </summary>
/// <param name="id">主键值.</param>
/// <returns></returns>
[HttpPost("{id}/Actions/Copy")]
public async Task ActionsCopy(string id)
{
PortalEntity? newEntity = new PortalEntity();
string? random = new Random().NextLetterAndNumberString(5);
PortalEntity? entity = await _portalRepository.AsQueryable().FirstAsync(p => p.Id == id && p.DeleteMark == null);
newEntity.FullName = entity.FullName + "副本" + random;
newEntity.EnCode = entity.EnCode + random;
newEntity.Category = entity.Category;
newEntity.FormData = entity.FormData;
newEntity.Description = entity.Description;
newEntity.EnabledMark = 0;
newEntity.SortCode = entity.SortCode;
newEntity.Type = entity.Type;
newEntity.LinkType = entity.LinkType;
newEntity.CustomUrl = entity.CustomUrl;
try
{
int isOk = await _portalRepository.AsSugarClient().Insertable(newEntity).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
}
catch
{
if (entity.FullName.Length >= 100 || entity.EnCode.Length >= 50) throw Oops.Oh(ErrorCode.D1403); // 数据长度超过 字段设定长度
else throw;
}
}
/// <summary>
/// 设置默认门户.
/// </summary>
/// <returns></returns>
[HttpPut("{id}/Actions/SetDefault")]
public async Task SetDefault(string id)
{
UserEntity? userEntity = _userManager.User;
_ = userEntity ?? throw Oops.Oh(ErrorCode.D5002);
if (userEntity != null)
{
userEntity.PortalId = id;
int isOk = await _portalRepository.AsSugarClient().Updateable<UserEntity>().SetColumns(it => new UserEntity()
{
PortalId = id,
LastModifyTime = SqlFunc.GetDate(),
LastModifyUserId = _userManager.UserId
}).Where(it => it.Id == userEntity.Id).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.D5014);
}
}
#endregion
#region PublicMethod
/// <summary>
/// 获取默认.
/// </summary>
/// <returns></returns>
[NonAction]
public async Task<string> GetDefault()
{
UserEntity? user = _userManager.User;
if (!user.IsAdministrator.ParseToBool())
{
if (!string.IsNullOrEmpty(user.RoleId))
{
string[]? roleIds = user.RoleId.Split(',');
List<string>? roleId = await _portalRepository.AsSugarClient().Queryable<RoleEntity>().Where(r => roleIds.Contains(r.Id)).Where(r => r.EnabledMark == 1 && r.DeleteMark == null).Select(r => r.Id).ToListAsync();
var items = await _portalRepository.AsSugarClient().Queryable<AuthorizeEntity>().Where(a => roleId.Contains(a.ObjectId)).Where(a => a.ItemType == "portal").GroupBy(it => new { it.ItemId }).Select(it => new { it.ItemId }).ToListAsync();
if (items.Count == 0) return string.Empty;
List<string>? portalList = await _portalRepository.AsQueryable().In(p => p.Id, items.Select(it => it.ItemId).ToArray()).Where(p => p.EnabledMark == 1 && p.DeleteMark == null).OrderBy(o => o.SortCode).Select(s => s.Id).ToListAsync();
return portalList.FirstOrDefault();
}
return string.Empty;
}
else
{
List<string>? portalList = await _portalRepository.AsQueryable().Where(p => p.EnabledMark == 1 && p.DeleteMark == null).OrderBy(o => o.SortCode).Select(s => s.Id).ToListAsync();
return portalList.FirstOrDefault();
}
}
#endregion
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
using JNPF.Common.Enums;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.VisualData.Entity;
using JNPF.VisualData.Entitys.Dto.ScreenCategory;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Yitter.IdGenerator;
namespace JNPF.VisualData;
/// <summary>
/// 业务实现:大屏.
/// </summary>
[ApiDescriptionSettings(Tag = "BladeVisual", Name = "category", Order = 160)]
[Route("api/blade-visual/[controller]")]
public class ScreenCategoryService : IDynamicApiController, ITransient
{
/// <summary>
/// 服务基础仓储.
/// </summary>
private readonly ISqlSugarRepository<VisualCategoryEntity> _visualCategoryRepository;
/// <summary>
/// 初始化一个<see cref="ScreenCategoryService"/>类型的新实例.
/// </summary>
public ScreenCategoryService(ISqlSugarRepository<VisualCategoryEntity> visualCategoryRepository)
{
_visualCategoryRepository = visualCategoryRepository;
}
#region Get
/// <summary>
/// 获取大屏分类分页列表.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("page")]
public async Task<dynamic> GetPagetList([FromQuery] ScreenCategoryListQueryInput input)
{
SqlSugarPagedList<ScreenCategoryListOutput>? data = await _visualCategoryRepository.AsQueryable().Where(v => v.IsDeleted == 0).Select(v => new ScreenCategoryListOutput { id = v.Id, categoryKey = v.CategoryKey, categoryValue = v.CategoryValue, isDeleted = v.IsDeleted }).ToPagedListAsync(input.current, input.size);
return new { current = data.pagination.CurrentPage, pages = data.pagination.Total / data.pagination.PageSize, records = data.list, size = data.pagination.PageSize, total = data.pagination.Total };
}
/// <summary>
/// 获取大屏分类列表.
/// </summary>
/// <returns></returns>
[HttpGet("list")]
public async Task<dynamic> GetList([FromQuery] ScreenCategoryListQueryInput input)
{
SqlSugarPagedList<ScreenCategoryListOutput>? list = await _visualCategoryRepository.AsQueryable().Where(v => v.IsDeleted == 0)
.Select(v => new ScreenCategoryListOutput
{
id = v.Id,
categoryKey = v.CategoryKey,
categoryValue = v.CategoryValue,
isDeleted = v.IsDeleted
}).ToPagedListAsync(input.current, input.size);
return list.list;
}
/// <summary>
/// 详情.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("detail")]
public async Task<dynamic> GetInfo(string id)
{
VisualCategoryEntity? entity = await _visualCategoryRepository.AsQueryable().FirstAsync(v => v.Id == id);
return entity.Adapt<ScreenCategoryInfoOutput>();
}
#endregion
#region Post
/// <summary>
/// 新增.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("save")]
public async Task Create([FromBody] ScreenCategoryCrInput input)
{
bool isExist = await _visualCategoryRepository.IsAnyAsync(v => v.CategoryValue == input.categoryValue && v.IsDeleted == 0);
if (isExist) throw Oops.Oh(ErrorCode.D2200);
VisualCategoryEntity? entity = input.Adapt<VisualCategoryEntity>();
entity.IsDeleted = 0;
entity.Id = YitIdHelper.NextId().ToString();
int isOk = await _visualCategoryRepository.AsInsertable(entity).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1000);
}
/// <summary>
/// 修改.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("update")]
public async Task Update([FromBody] ScreenCategoryUpInput input)
{
bool isExist = await _visualCategoryRepository.IsAnyAsync(v => v.CategoryValue == input.categoryValue && v.Id != input.Id && v.IsDeleted == 0);
if (isExist) throw Oops.Oh(ErrorCode.D2200);
VisualCategoryEntity? entity = input.Adapt<VisualCategoryEntity>();
int isOk = await _visualCategoryRepository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1001);
}
/// <summary>
/// 删除.
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpPost("remove")]
public async Task Delete(string ids)
{
List<VisualCategoryEntity>? entity = await _visualCategoryRepository.AsQueryable().In(v => v.Id, ids.Split(',').ToArray()).Where(v => v.IsDeleted == 0).ToListAsync();
_ = entity ?? throw Oops.Oh(ErrorCode.COM1005);
int isOk = await _visualCategoryRepository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Delete()).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1002);
}
#endregion
}

View File

@@ -0,0 +1,245 @@
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.VisualData.Entity;
using JNPF.VisualData.Entitys.Dto.ScreenDataSource;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Yitter.IdGenerator;
namespace JNPF.VisualData;
/// <summary>
/// 业务实现:大屏.
/// </summary>
[ApiDescriptionSettings(Tag = "BladeVisual", Name = "db", Order = 160)]
[Route("api/blade-visual/[controller]")]
public class ScreenDataSourceService : IDynamicApiController, ITransient
{
/// <summary>
/// 客户端初始化.
/// </summary>
public ISqlSugarClient _sqlSugarClient;
/// <summary>
/// 服务基础仓储.
/// </summary>
private readonly ISqlSugarRepository<VisualDBEntity> _visualDBRepository;
/// <summary>
/// 初始化一个<see cref="ScreenDataSourceService"/>类型的新实例.
/// </summary>
public ScreenDataSourceService(
ISqlSugarRepository<VisualDBEntity> visualDBRepository,
ISqlSugarClient context)
{
_visualDBRepository = visualDBRepository;
_sqlSugarClient = context;
}
#region Get
/// <summary>
/// 分页.
/// </summary>
/// <returns></returns>
[HttpGet("list")]
public async Task<dynamic> GetList([FromQuery] ScreenDataSourceListQueryInput input)
{
SqlSugarPagedList<ScreenDataSourceListOutput>? data = await _visualDBRepository.AsQueryable().Where(v => v.IsDeleted == 0)
.Select(v => new ScreenDataSourceListOutput { id = v.Id, name = v.Name, driverClass = v.DriverClass, password = v.Password, remark = v.Remark, url = v.Url, username = v.UserName, isDeleted = v.IsDeleted })
.ToPagedListAsync(input.current, input.size);
return new { current = data.pagination.CurrentPage, pages = data.pagination.Total / data.pagination.PageSize, records = data.list, size = data.pagination.PageSize, total = data.pagination.Total };
}
/// <summary>
/// 详情.
/// </summary>
/// <returns></returns>
[HttpGet("detail")]
public async Task<dynamic> GetInfo(string id)
{
VisualDBEntity? entity = await _visualDBRepository.AsQueryable().FirstAsync(v => v.Id == id && v.IsDeleted == 0);
return entity.Adapt<ScreenDataSourceInfoOutput>();
}
/// <summary>
/// 下拉数据源.
/// </summary>
/// <returns></returns>
[HttpGet("db-list")]
public async Task<dynamic> GetDBList()
{
return await _visualDBRepository.AsQueryable().Select(v => new ScreenDataSourceSeleectOutput { id = v.Id, name = v.Name, driverClass = v.DriverClass }).ToListAsync();
}
#endregion
#region Post
/// <summary>
/// 新增与修改.
/// </summary>
/// <returns></returns>
[HttpPost("submit")]
public async Task Submit([FromBody] ScreenDataSourceUpInput input)
{
VisualDBEntity? entity = input.Adapt<VisualDBEntity>();
int isOk = 0;
if (input.id == null)
isOk = await _visualDBRepository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteCommandAsync();
else
isOk = await _visualDBRepository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1000);
}
/// <summary>
/// 新增.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("save")]
public async Task Create([FromBody] ScreenDataSourceCrInput input)
{
VisualDBEntity? entity = input.Adapt<VisualDBEntity>();
int isOk = await _visualDBRepository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1000);
}
/// <summary>
/// 修改.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("update")]
public async Task Update([FromBody] ScreenDataSourceUpInput input)
{
VisualDBEntity? entity = input.Adapt<VisualDBEntity>();
int isOk = await _visualDBRepository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1001);
}
/// <summary>
/// 删除.
/// </summary>
/// <returns></returns>
[HttpPost("remove")]
public async Task Delete(string ids)
{
VisualDBEntity? entity = await _visualDBRepository.AsQueryable().FirstAsync(v => v.Id == ids && v.IsDeleted == 0);
_ = entity ?? throw Oops.Oh(ErrorCode.COM1005);
int isOk = await _visualDBRepository.AsUpdateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.IsDeleted }).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1002);
}
/// <summary>
/// 数据源测试连接.
/// </summary>
/// <returns></returns>
[HttpPost("db-test")]
public dynamic Test([FromBody] ScreenDataSourceUpInput input)
{
if (input.id == null)
input.id = YitIdHelper.NextId().ToString();
_sqlSugarClient.AsTenant().AddConnection(new ConnectionConfig()
{
ConfigId = input.id,
DbType = ToDbTytpe(input.driverClass),
ConnectionString = ToConnectionString(input.driverClass, input.url, input.username, input.password),
InitKeyType = InitKeyType.Attribute,
IsAutoCloseConnection = true
});
_sqlSugarClient = _sqlSugarClient.AsTenant().GetConnectionScope(input.id);
if (_sqlSugarClient.Ado.IsValidConnection())
return Task.FromResult(true);
else
throw Oops.Oh(ErrorCode.D1507);
}
/// <summary>
/// 动态执行SQL.
/// </summary>
/// <returns></returns>
[HttpPost("dynamic-query")]
public async Task<dynamic> Query([FromBody] ScreenDataSourceDynamicQueryInput input)
{
if (input.sql.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.D1513);
if (!string.IsNullOrWhiteSpace(input.id))
{
VisualDBEntity? entity = await _visualDBRepository.AsQueryable().FirstAsync(v => v.Id == input.id && v.IsDeleted == 0);
_sqlSugarClient.AsTenant().AddConnection(new ConnectionConfig()
{
ConfigId = input.id,
DbType = ToDbTytpe(entity.DriverClass),
ConnectionString = ToConnectionString(entity.DriverClass, entity.Url, entity.UserName, entity.Password),
InitKeyType = InitKeyType.Attribute,
IsAutoCloseConnection = true
});
_sqlSugarClient = _sqlSugarClient.AsTenant().GetConnectionScope(input.id);
try
{
return await _sqlSugarClient.Ado.GetDataTableAsync(input.sql);
}
catch (Exception ex)
{
throw Oops.Oh(ErrorCode.D1512, ex.Message);
}
}
return Task.FromResult(true);
}
#endregion
#region PrivateMethod
/// <summary>
/// 转换数据库类型.
/// </summary>
/// <param name="dbType"></param>
/// <returns></returns>
private SqlSugar.DbType ToDbTytpe(string dbType)
{
switch (dbType)
{
case "org.postgresql.Driver":
return SqlSugar.DbType.PostgreSQL;
case "com.mysql.cj.jdbc.Driver":
return SqlSugar.DbType.MySql;
case "oracle.jdbc.OracleDriver":
return SqlSugar.DbType.Oracle;
case "com.microsoft.sqlserver.jdbc.SQLServerDriver":
return SqlSugar.DbType.SqlServer;
default:
throw Oops.Oh(ErrorCode.D1505);
}
}
/// <summary>
/// 转换连接字符串.
/// </summary>
/// <returns></returns>
private string ToConnectionString(string driverClass, string url, string name, string password)
{
switch (driverClass)
{
case "org.postgresql.Driver":
return string.Format(url, name, password);
case "com.mysql.cj.jdbc.Driver":
return string.Format(url, name, password);
case "oracle.jdbc.OracleDriver":
return string.Format(url, name, password);
case "com.microsoft.sqlserver.jdbc.SQLServerDriver":
return string.Format(url, name, password);
default:
throw Oops.Oh(ErrorCode.D1505);
}
}
#endregion
}

View File

@@ -0,0 +1,116 @@
using JNPF.Common.Enums;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.VisualData.Entity;
using JNPF.VisualData.Entitys.Dto.ScreenMap;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Yitter.IdGenerator;
namespace JNPF.VisualData;
/// <summary>
/// 业务实现:大屏地图.
/// </summary>
[ApiDescriptionSettings(Tag = "BladeVisual", Name = "Map", Order = 160)]
[Route("api/blade-visual/[controller]")]
public class ScreenMapConfigService : IDynamicApiController, ITransient
{
/// <summary>
/// 服务基础仓储.
/// </summary>
private readonly ISqlSugarRepository<VisualMapEntity> _visualMapRepository;
/// <summary>
/// 初始化一个<see cref="ScreenMapConfigService"/>类型的新实例.
/// </summary>
public ScreenMapConfigService(ISqlSugarRepository<VisualMapEntity> visualMapRepository)
{
_visualMapRepository = visualMapRepository;
}
#region Get
/// <summary>
/// 分页.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("list")]
public async Task<dynamic> GetList([FromQuery] ScreenMapListQueryInput input)
{
SqlSugarPagedList<ScreenMapListOutput>? data = await _visualMapRepository.AsQueryable().Select(v => new ScreenMapListOutput { id = v.Id, name = v.Name }).ToPagedListAsync(input.current, input.size);
return new { current = data.pagination.CurrentPage, pages = data.pagination.Total / data.pagination.PageSize, records = data.list, size = data.pagination.PageSize, total = data.pagination.Total };
}
/// <summary>
/// 详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("detail")]
public async Task<dynamic> GetInfo([FromQuery] string id)
{
VisualMapEntity? entity = await _visualMapRepository.AsQueryable().FirstAsync(v => v.Id == id);
return entity.Adapt<ScreenMapInfoOutput>();
}
/// <summary>
/// 数据详情.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[NonUnify]
[HttpGet("data")]
public dynamic GetDataInfo(string id)
{
VisualMapEntity? entity = _visualMapRepository.AsQueryable().First(v => v.Id == id);
return entity.data;
}
#endregion
#region Post
/// <summary>
/// 新增.
/// </summary>
/// <returns></returns>
[HttpPost("save")]
public async Task Create([FromBody] ScreenMapCrInput input)
{
VisualMapEntity? entity = input.Adapt<VisualMapEntity>();
entity.Id = YitIdHelper.NextId().ToString();
int isOk = await _visualMapRepository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1000);
}
/// <summary>
/// 修改.
/// </summary>
/// <returns></returns>
[HttpPost("update")]
public async Task Update([FromBody] ScreenMapUpInput input)
{
VisualMapEntity? entity = input.Adapt<VisualMapEntity>();
int isOk = await _visualMapRepository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1001);
}
/// <summary>
/// 删除.
/// </summary>
/// <returns></returns>
[HttpPost("remove")]
public async Task Delete(string ids)
{
Task<VisualMapEntity>? entity = _visualMapRepository.AsQueryable().FirstAsync(v => v.Id == ids);
_ = entity ?? throw Oops.Oh(ErrorCode.COM1005);
int isOk = await _visualMapRepository.AsDeleteable().Where(it => ids.Contains(it.Id)).ExecuteCommandAsync();
if (!(isOk > 0)) throw Oops.Oh(ErrorCode.COM1002);
}
#endregion
}

View File

@@ -0,0 +1,322 @@
using JNPF.Common.Configuration;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Security;
using JNPF.DatabaseAccessor;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.Logging.Attributes;
using JNPF.VisualData.Entity;
using JNPF.VisualData.Entitys.Dto.Screen;
using JNPF.VisualData.Entitys.Dto.ScreenCategory;
using JNPF.VisualData.Entitys.Dto.ScreenConfig;
using JNPF.VisualData.Entitys.Enum;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Yitter.IdGenerator;
namespace JNPF.VisualData;
/// <summary>
/// 业务实现:大屏.
/// </summary>
[ApiDescriptionSettings(Tag = "BladeVisual", Name = "Visual", Order = 160)]
[Route("api/blade-visual/[controller]")]
public class ScreenService : IDynamicApiController, ITransient
{
/// <summary>
/// 服务基础仓储.
/// </summary>
private readonly ISqlSugarRepository<VisualEntity> _visualRepository;
/// <summary>
/// 多租户事务.
/// </summary>
private readonly ITenant _db;
/// <summary>
/// 初始化一个<see cref="ScreenService"/>类型的新实例.
/// </summary>
public ScreenService(
ISqlSugarRepository<VisualEntity> visualRepository,
ISqlSugarClient context)
{
_visualRepository = visualRepository;
_db = context.AsTenant();
}
#region Get
/// <summary>
/// 分页.
/// </summary>
/// <returns></returns>
[HttpGet("list")]
public async Task<dynamic> GetList([FromQuery] ScreenListQueryInput input)
{
input.category = input.category == null ? 1 : input.category;
SqlSugarPagedList<ScreenListOutput>? data = await _visualRepository.AsQueryable().Where(v => v.IsDeleted == 0).Where(v => v.Category == input.category)
.Select(v => new ScreenListOutput
{
id = v.Id,
backgroundUrl = v.BackgroundUrl,
category = v.Category,
createDept = v.CreateDept,
createTime = SqlFunc.ToString(v.CreateTime),
createUser = v.CreateUser,
isDeleted = v.IsDeleted,
password = v.Password,
status = v.Status,
title = v.Title,
updateTime = SqlFunc.ToString(v.UpdateTime),
updateUser = v.UpdateUser
}).MergeTable().OrderByDescending(v => v.createTime).OrderByDescending(v => v.updateTime).ToPagedListAsync(input.current, input.size);
return new { current = data.pagination.CurrentPage, pages = data.pagination.Total / data.pagination.PageSize, records = data.list, size = data.pagination.PageSize, total = data.pagination.Total };
}
/// <summary>
/// 详情.
/// </summary>
/// <returns></returns>
[HttpGet("detail")]
public async Task<dynamic> GetInfo([FromQuery] string id)
{
VisualEntity? entity = await _visualRepository.AsQueryable().FirstAsync(v => v.Id == id);
VisualConfigEntity? configEntity = await _visualRepository.AsSugarClient().Queryable<VisualConfigEntity>().FirstAsync(v => v.VisualId == id);
return new { config = configEntity.Adapt<ScreenConfigInfoOutput>(), visual = entity.Adapt<ScreenInfoOutput>() };
}
/// <summary>
/// 获取类型.
/// </summary>
/// <returns></returns>
[HttpGet("category")]
public async Task<dynamic> GetCategoryList()
{
VisualCategoryEntity? entity = await _visualRepository.AsSugarClient().Queryable<VisualCategoryEntity>().FirstAsync(v => v.IsDeleted == 0);
return entity.Adapt<ScreenCategoryListOutput>();
}
/// <summary>
/// 获取图片列表.
/// </summary>
/// <returns></returns>
[HttpGet("{type}")]
public dynamic GetImgFileList(string type)
{
List<ScreenImgFileOutput>? list = new List<ScreenImgFileOutput>();
var typeEnum = EnumExtensions.GetEnumDescDictionary(typeof(ScreenImgEnum));
var imgEnum = typeEnum.Where(t => t.Value.Equals(type)).FirstOrDefault();
if (imgEnum.Value != null)
{
string? path = Path.Combine(FileVariable.BiVisualPath, imgEnum.Value);
foreach (FileInfo? item in FileHelper.GetAllFiles(path))
{
list.Add(new ScreenImgFileOutput()
{
link = string.Format("/api/file/VisusalImg/{0}/{1}", type, item.Name),
originalName = item.Name
});
}
}
return list;
}
/// <summary>
/// 查看图片.
/// </summary>
/// <returns></returns>
[HttpGet("{type}/{fileName}"), AllowAnonymous, IgnoreLog]
public dynamic GetImgFile(string type, string fileName)
{
var typeEnum = EnumExtensions.GetEnumDescDictionary(typeof(ScreenImgEnum));
var imgEnum = typeEnum.Where(t => t.Value.Equals(type)).FirstOrDefault();
if (imgEnum.Value != null)
{
string? path = Path.Combine(FileVariable.BiVisualPath, imgEnum.Value, fileName);
return new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName };
}
return Task.FromResult(false);
}
/// <summary>
/// 大屏下拉框.
/// </summary>
/// <returns></returns>
[HttpGet("selector")]
public async Task<dynamic> GetSelector()
{
List<ScreenSelectorOuput>? screenList = await _visualRepository.AsQueryable().Where(v => v.IsDeleted == 0)
.Select(v => new ScreenSelectorOuput
{
id = v.Id,
parentId = SqlFunc.ToString(v.Category),
fullName = v.Title,
isDeleted = v.IsDeleted
}).ToListAsync();
List<ScreenSelectorOuput>? categortList = await _visualRepository.AsSugarClient().Queryable<VisualCategoryEntity>().Where(v => v.IsDeleted == 0)
.Select(v => new ScreenSelectorOuput
{
id = v.CategoryValue,
parentId = "0",
fullName = v.CategoryKey,
isDeleted = v.IsDeleted
}).ToListAsync();
return new { list = categortList.Union(screenList).ToList().ToTree("0") };
}
#endregion
#region Post
/// <summary>
/// 新增.
/// </summary>
/// <returns></returns>
[HttpPost("save")]
public async Task<dynamic> Save([FromBody] ScreenCrInput input)
{
VisualEntity? entity = input.visual.Adapt<VisualEntity>();
VisualConfigEntity? configEntity = input.config.Adapt<VisualConfigEntity>();
try
{
_db.BeginTran(); // 开启事务
VisualEntity? newEntity = await _visualRepository.AsInsertable(entity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
configEntity.VisualId = newEntity.Id;
await _visualRepository.AsSugarClient().Insertable(configEntity).CallEntityMethod(m => m.Create()).ExecuteCommandAsync();
_db.CommitTran();
return new { id = newEntity.Id };
}
catch (Exception)
{
_db.RollbackTran();
throw Oops.Oh(ErrorCode.COM1000);
}
}
/// <summary>
/// 修改.
/// </summary>
/// <returns></returns>
[HttpPost("update")]
public async Task Update([FromBody] ScreenUpInput input)
{
VisualEntity? entity = new VisualEntity();
if (input.visual.backgroundUrl != null)
{
entity = await _visualRepository.AsQueryable().FirstAsync(v => v.Id == input.visual.id);
entity.BackgroundUrl = input.visual.backgroundUrl;
}
else
{
entity = input.visual.Adapt<VisualEntity>();
}
VisualConfigEntity? configEntity = input.config.Adapt<VisualConfigEntity>();
try
{
_db.BeginTran(); // 开启事务
await _visualRepository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
if (configEntity != null)
await _visualRepository.AsSugarClient().Updateable(configEntity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
_db.CommitTran();
}
catch (Exception)
{
_db.RollbackTran();
throw Oops.Oh(ErrorCode.COM1000);
}
}
/// <summary>
/// 逻辑删除.
/// </summary>
/// <returns></returns>
[HttpPost("remove")]
public async Task Remove(string ids)
{
VisualEntity? entity = await _visualRepository.AsQueryable().FirstAsync(v => v.Id == ids);
await _visualRepository.AsUpdateable(entity).CallEntityMethod(m => m.Delete()).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
}
/// <summary>
/// 复制.
/// </summary>
/// <returns></returns>
[HttpPost("copy")]
[NonUnify]
[UnitOfWork]
public async Task<dynamic> Copy(string id)
{
VisualEntity? entity = await _visualRepository.AsQueryable().FirstAsync(v => v.Id == id);
VisualConfigEntity? configEntity = await _visualRepository.AsSugarClient().Queryable<VisualConfigEntity>().FirstAsync(v => v.VisualId == id);
VisualEntity? newEntity = await _visualRepository.AsInsertable(entity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
configEntity.VisualId = newEntity.Id;
await _visualRepository.AsSugarClient().Insertable(configEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
return new { code = 200, msg = newEntity.Id };
}
/// <summary>
/// 上传文件.
/// </summary>
/// <returns></returns>
[HttpPost("put-file/{type}"), AllowAnonymous, IgnoreLog]
public async Task<dynamic> SaveFile(string type, IFormFile file)
{
var typeEnum = EnumExtensions.GetEnumDescDictionary(typeof(ScreenImgEnum));
var imgEnum = typeEnum.Where(t => t.Value.Equals(type)).FirstOrDefault();
if (imgEnum.Value != null)
{
string? ImgType = Path.GetExtension(file.FileName).Replace(".", string.Empty);
if (!this.AllowImageType(ImgType))
throw Oops.Oh(ErrorCode.D5013);
var path = imgEnum.Value;
string? filePath = Path.Combine(FileVariable.BiVisualPath, path);
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
string? fileName = YitIdHelper.NextId().ToString() + "." + ImgType;
using (FileStream? stream = File.Create(Path.Combine(filePath, fileName)))
{
await file.CopyToAsync(stream);
}
return new { name = "/" + Path.Combine("api", "file", "VisusalImg", path, fileName), link = "/" + Path.Combine("api", "file", "VisusalImg", path, fileName), originalName = file.FileName };
}
return Task.FromResult(false);
}
#endregion
#region PrivateMethod
/// <summary>
/// 允许文件类型.
/// </summary>
/// <param name="fileExtension">文件后缀名.</param>
/// <returns></returns>
private bool AllowImageType(string fileExtension)
{
List<string>? allowExtension = KeyVariable.AllowImageType;
string? isExist = allowExtension.Find(a => a == fileExtension.ToLower());
if (!string.IsNullOrEmpty(isExist))
return true;
else
return false;
}
#endregion
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\Tnb.Common.Core\Tnb.Common.Core.csproj" />
<ProjectReference Include="..\..\extend\Tnb.Extend.Interfaces\Tnb.Extend.Interfaces.csproj" />
<ProjectReference Include="..\..\message\Tnb.Message.Interfaces\Tnb.Message.Interfaces.csproj" />
<ProjectReference Include="..\..\system\Tnb.Systems.Interfaces\Tnb.Systems.Interfaces.csproj" />
<ProjectReference Include="..\..\workflow\Tnb.WorkFlow.Interfaces\Tnb.WorkFlow.Interfaces.csproj" />
<ProjectReference Include="..\Tnb.VisualDev.Engine\Tnb.VisualDev.Engine.csproj" />
<ProjectReference Include="..\Tnb.VisualDev.Interfaces\Tnb.VisualDev.Interfaces.csproj" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,488 @@
using JNPF.Common.Configuration;
using JNPF.Common.Core.Manager;
using JNPF.Common.Core.Manager.Files;
using JNPF.Common.Dtos.VisualDev;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Filter;
using JNPF.Common.Models.NPOI;
using JNPF.Common.Security;
using JNPF.DatabaseAccessor;
using JNPF.DataEncryption;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.VisualDev.Engine;
using JNPF.VisualDev.Engine.Core;
using JNPF.VisualDev.Engine.Security;
using JNPF.VisualDev.Entitys;
using JNPF.VisualDev.Entitys.Dto.VisualDevModelData;
using JNPF.VisualDev.Interfaces;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Yitter.IdGenerator;
namespace JNPF.VisualDev;
/// <summary>
/// 可视化开发APP基础.
/// </summary>
[ApiDescriptionSettings(Tag = "VisualDev", Name = "App", Order = 175)]
[Route("api/visualdev/OnlineDev/[controller]")]
public class VisualdevModelAppService : IDynamicApiController, ITransient
{
/// <summary>
/// 可视化开发基础.
/// </summary>
private readonly IVisualDevService _visualDevService;
/// <summary>
/// 在线开发运行服务.
/// </summary>
private readonly IRunService _runService;
/// <summary>
/// 用户管理.
/// </summary>
private readonly IUserManager _userManager;
/// <summary>
/// 文件服务.
/// </summary>
private readonly IFileManager _fileManager;
/// <summary>
/// 初始化一个<see cref="VisualdevModelAppService"/>类型的新实例.
/// </summary>
public VisualdevModelAppService(
IVisualDevService visualDevService,
IRunService runService,
IUserManager userManager,
IFileManager fileManager)
{
_visualDevService = visualDevService;
_runService = runService;
_userManager = userManager;
_fileManager = fileManager;
}
#region Get
/// <summary>
/// 获取列表表单配置JSON.
/// </summary>
/// <param name="modelId">主键id.</param>
/// <param name="type">1 线上版本, 0 草稿版本.</param>
/// <returns></returns>
[HttpGet("{modelId}/Config")]
[NonUnify]
public async Task<dynamic> GetData(string modelId, string type)
{
if (type.IsNullOrEmpty()) type = "1";
VisualDevEntity? data = await _visualDevService.GetInfoById(modelId, type.Equals("1"));
if (data == null) return new { code = 400, msg = "未找到该模板!" };
if (data.EnableFlow.Equals(1) && data.FlowId.IsNullOrWhiteSpace()) return new { code = 400, msg = "该流程功能未绑定流程!" };
if (data.WebType.Equals(1) && data.FormData.IsNullOrWhiteSpace()) return new { code = 400, msg = "该模板内表单内容为空,无法预览!" };
else if (data.WebType.Equals(2) && data.ColumnData.IsNullOrWhiteSpace()) return new { code = 400, msg = "该模板内列表内容为空,无法预览!" };
return new { code = 200, data = data.Adapt<VisualDevModelDataConfigOutput>() };
}
/// <summary>
/// 获取列表配置JSON.
/// </summary>
/// <param name="modelId">主键id.</param>
/// <returns></returns>
[HttpGet("{modelId}/ColumnData")]
public async Task<dynamic> GetColumnData(string modelId)
{
VisualDevEntity? data = await _visualDevService.GetInfoById(modelId);
return new { columnData = data.ColumnData };
}
/// <summary>
/// 获取列表配置JSON.
/// </summary>
/// <param name="modelId">主键id.</param>
/// <returns></returns>
[HttpGet("{modelId}/FormData")]
public async Task<dynamic> GetFormData(string modelId)
{
VisualDevEntity? data = await _visualDevService.GetInfoById(modelId);
return new { formData = data.FormData };
}
/// <summary>
/// 获取列表配置JSON.
/// </summary>
/// <param name="modelId">主键id.</param>
/// <returns></returns>
[HttpGet("{modelId}/FlowTemplate")]
public async Task<dynamic> GetFlowTemplate(string modelId)
{
VisualDevEntity? data = await _visualDevService.GetInfoById(modelId);
return new { flowTemplateJson = data.FlowTemplateJson };
}
/// <summary>
/// 获取数据信息.
/// </summary>
/// <param name="id"></param>
/// <param name="modelId"></param>
/// <returns></returns>
[HttpGet("{modelId}/{id}")]
public async Task<dynamic> GetInfo(string id, string modelId)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); // 模板实体
if (!string.IsNullOrEmpty(templateEntity.Tables) && !"[]".Equals(templateEntity.Tables))
return new { id = id, data = (await _runService.GetHaveTableInfo(id, templateEntity)).ToJsonString() }; // 有表
else
return null;
}
/// <summary>
/// 获取详情.
/// </summary>
/// <param name="id"></param>
/// <param name="modelId"></param>
/// <returns></returns>
[HttpGet("{modelId}/{id}/DataChange")]
public async Task<dynamic> GetDetails(string id, string modelId)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); // 模板实体
if (!string.IsNullOrEmpty(templateEntity.Tables) && !"[]".Equals(templateEntity.Tables))
return new { id = id, data = await _runService.GetHaveTableInfoDetails(id, templateEntity) }; // 有表
else
return null;
}
#endregion
#region Post
/// <summary>
/// 功能导出.
/// </summary>
/// <param name="modelId"></param>
/// <returns></returns>
[HttpPost("{modelId}/Actions/ExportData")]
public async Task<dynamic> ActionsExportData(string modelId)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId); // 模板实体
if (templateEntity.State.Equals(1))
{
var vREntity = await _visualDevService.GetInfoById(modelId, true);
templateEntity = vREntity.Adapt<VisualDevEntity>();
templateEntity.State = 0;
}
string? jsonStr = templateEntity.ToJsonString();
return await _fileManager.Export(jsonStr, templateEntity.FullName, ExportFileType.va);
}
/// <summary>
/// 导入.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("Model/Actions/ImportData")]
public async Task ActionsActionsImport(IFormFile file)
{
string? fileType = Path.GetExtension(file.FileName).Replace(".", string.Empty);
if (!fileType.ToLower().Equals(ExportFileType.va.ToString())) throw Oops.Oh(ErrorCode.D3006);
string? josn = _fileManager.Import(file);
VisualDevEntity? templateEntity;
try
{
templateEntity = josn.ToObject<VisualDevEntity>();
}
catch
{
throw Oops.Oh(ErrorCode.D3006);
}
if (templateEntity == null || templateEntity.Type.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.D3006);
else if (templateEntity.Type != 2) throw Oops.Oh(ErrorCode.D3009);
if (await _visualDevService.GetDataExists(templateEntity.EnCode, templateEntity.FullName))
throw Oops.Oh(ErrorCode.D1400);
await _visualDevService.CreateImportData(templateEntity);
}
/// <summary>
/// 获取数据列表.
/// </summary>
/// <param name="modelId">主键id.</param>
/// <param name="input">分页查询条件.</param>
/// <returns></returns>
[HttpPost("{modelId}/List")]
public async Task<dynamic> List(string modelId, [FromBody] VisualDevModelListQueryInput input)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true);
return await _runService.GetListResult(templateEntity, input);
}
/// <summary>
/// 创建数据.
/// </summary>
/// <param name="modelId"></param>
/// <param name="visualdevModelDataCrForm"></param>
/// <returns></returns>
[HttpPost("{modelId}")]
public async Task Create(string modelId, [FromBody] VisualDevModelDataCrInput visualdevModelDataCrForm)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true);
await _runService.Create(templateEntity, visualdevModelDataCrForm);
}
/// <summary>
/// 修改数据.
/// </summary>
/// <param name="modelId"></param>
/// <param name="id"></param>
/// <param name="visualdevModelDataUpForm"></param>
/// <returns></returns>
[HttpPut("{modelId}/{id}")]
public async Task Update(string modelId, string id, [FromBody] VisualDevModelDataUpInput visualdevModelDataUpForm)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true);
await _runService.Update(id, templateEntity, visualdevModelDataUpForm);
}
/// <summary>
/// 删除数据.
/// </summary>
/// <param name="id"></param>
/// <param name="modelId"></param>
/// <returns></returns>
[HttpDelete("{modelId}/{id}")]
public async Task Delete(string id, string modelId)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true);
if (!string.IsNullOrEmpty(templateEntity.Tables) && !"[]".Equals(templateEntity.Tables))
await _runService.DelHaveTableInfo(id, templateEntity);
}
/// <summary>
/// 批量删除.
/// </summary>
/// <param name="modelId"></param>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("batchDelete/{modelId}")]
public async Task BatchDelete(string modelId, [FromBody] VisualDevModelDataBatchDelInput input)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true);
if (!string.IsNullOrEmpty(templateEntity.Tables) && !"[]".Equals(templateEntity.Tables))
await _runService.BatchDelHaveTableData(input.ids, templateEntity);
}
/// <summary>
/// 导出.
/// </summary>
/// <returns></returns>
[HttpPost("{modelId}/Actions/Export")]
public async Task<dynamic> Export(string modelId, [FromBody] VisualDevModelListQueryInput input)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true);
List<VisualDevModelDataEntity> list = new List<VisualDevModelDataEntity>();
PageResult<Dictionary<string, object>>? pageList = await _runService.GetListResult(templateEntity, input);
#region
ColumnDesignModel? ColumnData = templateEntity.ColumnData.ToObject<ColumnDesignModel>(); // 列配置模型
if (ColumnData.type == 3)
{
List<Dictionary<string, object>>? newValueList = new List<Dictionary<string, object>>();
pageList.list.ForEach(item =>
{
List<Dictionary<string, object>>? tt = item["children"].ToJsonString().ToObject<List<Dictionary<string, object>>>();
newValueList.AddRange(tt);
});
pageList.list = newValueList;
}
#endregion
List<Dictionary<string, object>> realList = pageList.list.Copy();
var templateInfo = new TemplateParsingBase(templateEntity);
var res = GetCreateFirstColumnsHeader(input.selectKey, realList, templateInfo);
var firstColumns = res.First().ToObject<Dictionary<string, int>>();
var resultList = res.Last().ToObject<List<Dictionary<string, object>>>();
var newResultList = new List<Dictionary<string, object>>();
resultList.ForEach(row =>
{
foreach (var item in input.selectKey)
{
if (row[item].IsNotEmptyOrNull())
{
newResultList.Add(row);
break;
}
}
});
return firstColumns.Any() ? await ExcelCreateModel(templateInfo, resultList, input.selectKey, null, firstColumns) : await ExcelCreateModel(templateInfo, resultList, input.selectKey);
}
#endregion
#region PublicMethod
/// <summary>
/// Excel 转输出 Model.
/// </summary>
/// <param name="templateInfo">模板.</param>
/// <param name="realList">数据列表.</param>
/// <param name="keys"></param>
/// <param name="excelName">导出文件名称.</param>
/// <param name="firstColumns">手动输入第一行(合并主表列和各个子表列).</param>
/// <returns>VisualDevModelDataExportOutput.</returns>
public async Task<VisualDevModelDataExportOutput> ExcelCreateModel(TemplateParsingBase templateInfo, List<Dictionary<string, object>> realList, List<string> keys, string excelName = null, Dictionary<string, int> firstColumns = null)
{
List<ExcelTemplateModel> templateList = new List<ExcelTemplateModel>();
VisualDevModelDataExportOutput output = new VisualDevModelDataExportOutput();
List<string> columnList = new List<string>();
try
{
ExcelConfig excelconfig = new ExcelConfig();
excelconfig.FileName = (excelName.IsNullOrEmpty() ? SnowflakeIdHelper.NextId() : excelName) + ".xls";
excelconfig.HeadFont = "微软雅黑";
excelconfig.HeadPoint = 10;
excelconfig.IsAllSizeColumn = true;
excelconfig.ColumnModel = new List<ExcelColumnModel>();
foreach (string? item in keys)
{
FieldsModel? excelColumn = templateInfo.AllFieldsModel.Find(t => t.__vModel__ == item);
if (excelColumn != null)
{
excelconfig.ColumnModel.Add(new ExcelColumnModel() { Column = item, ExcelColumn = excelColumn.__config__.label });
columnList.Add(excelColumn.__config__.label);
}
}
string? addPath = Path.Combine(FileVariable.TemporaryFilePath, excelconfig.FileName);
var fs = firstColumns == null ? ExcelExportHelper<Dictionary<string, object>>.ExportMemoryStream(realList, excelconfig, columnList) : ExcelExportHelper<Dictionary<string, object>>.ExportMemoryStream(realList, excelconfig, columnList, firstColumns);
var flag = await _fileManager.UploadFileByType(fs, FileVariable.TemporaryFilePath, excelconfig.FileName);
if (flag)
{
fs.Flush();
fs.Close();
}
output.name = excelconfig.FileName;
output.url = "/api/file/Download?encryption=" + DESCEncryption.Encrypt(_userManager.UserId + "|" + excelconfig.FileName + "|" + addPath, "JNPF");
return output;
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 组装导出带子表得数据,返回 第一个合并行标头,第二个导出数据.
/// </summary>
/// <param name="selectKey">导出选择列.</param>
/// <param name="realList">原数据集合.</param>
/// <param name="templateInfo">模板信息.</param>
/// <returns>第一行标头 , 导出数据.</returns>
public object[] GetCreateFirstColumnsHeader(List<string> selectKey, List<Dictionary<string, object>> realList, TemplateParsingBase templateInfo)
{
selectKey.ForEach(item =>
{
realList.ForEach(it =>
{
if (!it.ContainsKey(item)) it.Add(item, string.Empty);
});
});
var newRealList = realList.Copy();
realList.ForEach(items =>
{
var rowChildDatas = new Dictionary<string, List<Dictionary<string, object>>>();
foreach (var item in items)
{
if (item.Value != null && item.Key.ToLower().Contains("tablefield") && item.Value is List<Dictionary<string, object>>)
{
var ctList = item.Value.ToObject<List<Dictionary<string, object>>>();
rowChildDatas.Add(item.Key, ctList);
}
}
var len = rowChildDatas.Select(x => x.Value.Count()).OrderByDescending(x => x).FirstOrDefault();
if (len != null && len > 0)
{
for (int i = 0; i < len; i++)
{
if (i == 0)
{
var newRealItem = newRealList.Find(x => x["id"].Equals(items["id"]));
foreach (var cData in rowChildDatas)
{
var itemData = cData.Value.FirstOrDefault();
if (itemData != null)
{
foreach (var key in itemData)
if (newRealItem.ContainsKey(cData.Key + "-" + key.Key)) newRealItem[cData.Key + "-" + key.Key] = key.Value;
}
}
}
else
{
var newRealItem = new Dictionary<string, object>();
foreach (var it in items)
{
if (it.Key.Equals("id")) newRealItem.Add(it.Key, it.Value);
else newRealItem.Add(it.Key, string.Empty);
}
foreach (var cData in rowChildDatas)
{
if (cData.Value.Count > i)
{
foreach (var it in cData.Value[i])
if (newRealItem.ContainsKey(cData.Key + "-" + it.Key)) newRealItem[cData.Key + "-" + it.Key] = it.Value;
}
}
newRealList.Add(newRealItem);
}
}
}
});
var resultList = new List<Dictionary<string, object>>();
newRealList.ForEach(newRealItem =>
{
if (!resultList.Any(x => x["id"].Equals(newRealItem["id"]))) resultList.AddRange(newRealList.Where(x => x["id"].Equals(newRealItem["id"])).ToList());
});
var firstColumns = new Dictionary<string, int>();
if (selectKey.Any(x => x.Contains("-") && x.Contains("tableField")))
{
var empty = string.Empty;
var keyList = selectKey.Select(x => x.Split("-").First()).Distinct().ToList();
var mainFieldIndex = 1;
keyList.ForEach(item =>
{
if (item.Contains("tableField"))
{
var title = templateInfo.AllFieldsModel.FirstOrDefault(x => x.__vModel__.Equals(item))?.__config__.label;
firstColumns.Add(title + empty, selectKey.Count(x => x.Contains(item)));
empty += " ";
mainFieldIndex = 1;
}
else
{
if (mainFieldIndex == 1) empty += " ";
if (!firstColumns.ContainsKey(empty)) firstColumns.Add(empty, mainFieldIndex);
else firstColumns[empty] = mainFieldIndex;
mainFieldIndex++;
}
});
}
return new object[] { firstColumns, resultList };
}
#endregion
}