Files
tnb.server/workflow/Tnb.WorkFlow/Service/FlowFormService.cs
2023-11-06 19:35:59 +08:00

502 lines
21 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.Security;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.Systems.Entitys.Model.DataBase;
using JNPF.Systems.Entitys.Permission;
using JNPF.Systems.Entitys.System;
using JNPF.VisualDev.Engine.Core;
using JNPF.VisualDev.Engine.Model;
using JNPF.VisualDev.Interfaces;
using JNPF.WorkFlow.Entitys.Dto.FlowEngine;
using JNPF.WorkFlow.Entitys.Dto.FlowForm;
using JNPF.WorkFlow.Entitys.Entity;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
namespace JNPF.WorkFlow.Service;
/// <summary>
/// 流程设计.
/// </summary>
[ApiDescriptionSettings(Tag = "FlowForm", Name = "Form", Order = 301)]
[Route("api/flowForm/Form")]
public class FlowFormService : IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository<FlowFormEntity> _repository;
private readonly IRunService _runService;
private readonly IVisualDevService _visualDevService;
private readonly IUserManager _userManager;
private readonly IFileManager _fileManager;
private readonly IDataBaseManager _dataBaseManager;
private readonly ITenant _db;
public FlowFormService(
ISqlSugarRepository<FlowFormEntity> repository,
IRunService runService,
IVisualDevService visualDevService,
IUserManager userManager,
IFileManager fileManager,
IDataBaseManager dataBaseManager,
ISqlSugarClient context)
{
_repository = repository;
_runService = runService;
_visualDevService = visualDevService;
_userManager = userManager;
_fileManager = fileManager;
_dataBaseManager = dataBaseManager;
_db = context.AsTenant();
}
#region GET
/// <summary>
/// 列表.
/// </summary>
/// <param name="input">请求参数.</param>
/// <returns></returns>
[HttpGet("")]
public async Task<dynamic> GetList([FromQuery] FlowEngineListInput input)
{
var list = await _repository.AsQueryable()
.Where(a => a.DeleteMark == null && !(a.FormType == 2 && a.FlowType == 1))
.WhereIF(input.category.IsNotEmptyOrNull(), a => a.Category == input.category)
.WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword))
.Select(a => new FlowFormListOutput
{
id = a.Id,
creatorTime = a.CreatorTime,
creatorUser = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == a.CreatorUserId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)),
enCode = a.EnCode,
enabledMark = a.EnabledMark,
fullName = a.FullName,
formType = a.FormType,
flowType = a.FlowType,
lastModifyTime = a.LastModifyTime,
sortCode = a.SortCode,
}).MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc)
.OrderByIF(!string.IsNullOrEmpty(input.keyword), t => t.lastModifyTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize);
return PageResult<FlowFormListOutput>.SqlSugarPageResult(list);
}
/// <summary>
/// 信息.
/// </summary>
/// <param name="id">主键值.</param>
/// <returns></returns>
[HttpGet("{id}")]
public async Task<dynamic> GetInfo_Api(string id)
{
var entity = await GetInfo(id);
var res = entity.Adapt<FlowFormListOutput>();
var draft = entity.DraftJson?.ToObject<FlowFormEntity>().Adapt<FlowFormListOutput>();
res.propertyJson = entity.PropertyJson;
res.draftJson = draft != null && draft.propertyJson.IsNotEmptyOrNull() ? draft?.propertyJson : entity.PropertyJson;
return res;
}
/// <summary>
/// 列表(下拉).
/// </summary>
/// <param name="type">(预留字段).</param>
/// <returns></returns>
[HttpGet("Select")]
public async Task<dynamic> Select([FromQuery] FlowEngineListInput input)
{
var list = await _repository.AsSugarClient().Queryable<FlowFormEntity>()
.Where(a => a.DeleteMark == null && a.EnabledMark.Equals(1) && a.FlowType == input.flowType)
.WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword))
.Select(a => new FlowFormListOutput
{
category = SqlFunc.Subqueryable<DictionaryDataEntity>().Where(it => it.EnCode.Equals(a.Category)).Select(it => it.FullName),
id = a.Id,
description = a.Description,
creatorTime = a.CreatorTime,
enCode = a.EnCode,
enabledMark = a.EnabledMark,
fullName = a.FullName,
formType = a.FormType,
flowType = a.FlowType,
sortCode = a.SortCode,
}).MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize);
return PageResult<FlowFormListOutput>.SqlSugarPageResult(list);
}
/// <summary>
/// 导出.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}/Actions/ExportData")]
public async Task<dynamic> ActionsExport(string id)
{
var info = await GetInfo(id);
info.DraftJson = info.ToJsonString();
var jsonStr = info.ToJsonString();
return await _fileManager.Export(jsonStr, info.FullName, ExportFileType.fff);
}
/// <summary>
/// 复制.
/// </summary>
/// <param name="id">主键值.</param>
/// <returns></returns>
[HttpGet("{id}/Actions/Copy")]
public async Task ActionsCopy(string id)
{
var entity = await GetInfo(id);
var random = RandomExtensions.NextLetterAndNumberString(new Random(), 5).ToLower();
entity.Id = SnowflakeIdHelper.NextId();
entity.FullName = string.Format("{0}副本{1}", entity.FullName, random);
entity.EnCode = string.Format("{0}{1}", entity.EnCode, random);
if (entity.FullName.Length >= 50 || entity.EnCode.Length >= 50)
throw Oops.Oh(ErrorCode.COM1009);
entity.EnabledMark = 0;
//entity.TableJson = "[]";
entity.DraftJson = entity.ToJsonString();
entity.LastModifyTime = null;
var result = await _repository.AsSugarClient().Insertable(entity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
_ = result ?? throw Oops.Oh(ErrorCode.WF0002);
}
/// <summary>
/// 根据表单Id 获取流程信息.
/// </summary>
/// <param name="id">主键值.</param>
/// <returns></returns>
[HttpGet("GetFormById/{id}")]
public async Task<dynamic> GetFormById(string id)
{
var model = new { id = string.Empty, enCode = string.Empty, enabledMark = 0 };
var form = await GetInfo(id);
if (form == null) throw Oops.Oh(ErrorCode.COM1019);
if (form != null && form.FlowId.IsNotEmptyOrNull())
model = _repository.AsSugarClient().Queryable<FlowTemplateEntity>().Where(x => x.Id.Equals(form.FlowId)).Select(x => new { id = x.Id, enCode = x.EnCode, enabledMark = (int)x.EnabledMark }).First();
if (model == null || model.id.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.COM1016);
if (form.FlowType == 1 && form.FormType == 1 && model.enabledMark != 1)
{
// 代码生成的功能流程需要判断流程是否启用。
throw Oops.Oh(ErrorCode.COM1017);
}
return model;
}
#endregion
#region POST
/// <summary>
/// 删除.
/// </summary>
/// <param name="id">主键值.</param>
/// <returns></returns>
[HttpDelete("{id}")]
public async Task Delete(string id)
{
var flowFormEntity = await GetInfo(id);
if (flowFormEntity == null)
throw Oops.Oh(ErrorCode.COM1005);
if (await _repository.AsSugarClient().Queryable<FlowFormRelationEntity>().Where(x => x.FormId.Equals(id)).AnyAsync())
throw Oops.Oh(ErrorCode.COM1012);
var isOk = await _repository.AsSugarClient().Updateable(flowFormEntity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandHasChangeAsync();
await _repository.AsSugarClient().Deleteable<FlowFormRelationEntity>().Where(x => x.FormId.Equals(id)).ExecuteCommandAsync();
if (!isOk)
throw Oops.Oh(ErrorCode.COM1002);
}
/// <summary>
/// 新建.
/// </summary>
/// <param name="input">请求参数.</param>
/// <returns></returns>
[HttpPost("")]
public async Task Create([FromBody] FlowEngineCrInput input)
{
if (await _repository.IsAnyAsync(x => (x.EnCode == input.enCode || x.FullName == input.fullName) && x.DeleteMark == null))
throw Oops.Oh(ErrorCode.COM1004);
var flowFormEntity = input.Adapt<FlowFormEntity>();
flowFormEntity.Id = SnowflakeIdHelper.NextId();
flowFormEntity.EnabledMark = 0;
flowFormEntity.PropertyJson = flowFormEntity.DraftJson;
flowFormEntity.DraftJson = flowFormEntity.ToJsonString();
if (input.formType.Equals(2) && input.draftJson.IsNotEmptyOrNull())
{
TemplateParsingBase? tInfo = new TemplateParsingBase(flowFormEntity.PropertyJson, flowFormEntity.TableJson); // 解析模板
if (!tInfo.VerifyTemplate()) throw Oops.Oh(ErrorCode.D1401); // 验证模板
await VerifyPrimaryKeyPolicy(tInfo, flowFormEntity.DbLinkId); // 验证雪花Id 和自增长Id 主键是否支持
}
var result = await _repository.AsSugarClient().Insertable(flowFormEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
_ = result ?? throw Oops.Oh(ErrorCode.COM1000);
}
/// <summary>
/// 更新.
/// </summary>
/// <param name="id">主键值.</param>
/// <param name="input">请求参数.</param>
/// <returns></returns>
[HttpPut("")]
public async Task Update([FromBody] FlowEngineUpInput input)
{
if (await _repository.IsAnyAsync(x => x.Id != input.id && (x.EnCode == input.enCode || x.FullName == input.fullName) && x.DeleteMark == null))
throw Oops.Oh(ErrorCode.COM1004);
if (await _repository.AsQueryable().AnyAsync(x => x.Id.Equals(input.id) && x.EnabledMark.Equals(1) && x.FormType == 2))
{
if (input.tableJson.IsNullOrWhiteSpace() || input.tableJson.Equals("[]"))
throw Oops.Oh(ErrorCode.D1416); // 已发布的模板 表不能为空.
input.enabledMark = 1;
}
var isOk = false;
var fEntity = input.Adapt<FlowFormEntity>();
if (fEntity != null)
{
if (input.formType.Equals(2) && input.draftJson.IsNotEmptyOrNull())
{
TemplateParsingBase? tInfo = new TemplateParsingBase(fEntity.DraftJson, fEntity.TableJson); // 解析模板
if (!tInfo.VerifyTemplate()) throw Oops.Oh(ErrorCode.D1401); // 验证模板
await VerifyPrimaryKeyPolicy(tInfo, fEntity.DbLinkId); // 验证雪花Id 和自增长Id 主键是否支持
}
// EnabledMark=0 未发布EnabledMark=1 已发布
if (fEntity.EnabledMark.Equals(0))
{
fEntity.PropertyJson = fEntity.DraftJson;
fEntity.DraftJson = fEntity.ToJsonString();
// 修改流程表单
isOk = await _repository.AsSugarClient().Updateable(fEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync();
}
else
{
var nEntity = await _repository.AsSugarClient().Queryable<FlowFormEntity>().Where(x => x.Id.Equals(input.id)).FirstAsync();
fEntity.PropertyJson = fEntity.DraftJson;
nEntity.DraftJson = fEntity.ToJsonString();
nEntity.FullName = fEntity.FullName;
nEntity.EnCode = fEntity.EnCode;
nEntity.SortCode = fEntity.SortCode;
nEntity.Description = fEntity.Description;
nEntity.TableJson = fEntity.TableJson;
nEntity.DbLinkId = fEntity.DbLinkId;
nEntity.AppUrlAddress = fEntity.AppUrlAddress;
nEntity.UrlAddress = fEntity.UrlAddress;
nEntity.InterfaceUrl = fEntity.InterfaceUrl;
// 修改流程表单
isOk = await _repository.AsSugarClient().Updateable(nEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync();
}
}
if (!isOk)
throw Oops.Oh(ErrorCode.COM1001);
}
/// <summary>
/// 导入.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("Actions/ImportData")]
public async Task ActionsImport(IFormFile file)
{
var fileType = Path.GetExtension(file.FileName).Replace(".", string.Empty);
if (!fileType.ToLower().Equals(ExportFileType.fff.ToString()))
throw Oops.Oh(ErrorCode.D3006);
var josn = _fileManager.Import(file);
var model = new FlowFormEntity();
try
{
model = josn.ToObject<FlowFormEntity>();
}
catch
{
throw Oops.Oh(ErrorCode.D3006);
}
if (model == null)
throw Oops.Oh(ErrorCode.D3006);
await ImportData(model);
}
/// <summary>
/// 发布.
/// </summary>
/// <param name="id">主键值.</param>
/// <returns></returns>
[HttpPost("Release/{id}")]
public async Task Release(string id, [FromQuery] int isRelease)
{
var entity = await GetInfo(id);
// 0 回滚表单 , 1 发布表单.
if (isRelease.Equals(0))
{
if (entity == null) throw Oops.Oh(ErrorCode.COM1005);
var isOk = await _repository.AsSugarClient().Updateable<FlowFormEntity>().SetColumns(it => it.DraftJson == entity.ToJsonString()).Where(it => it.Id == id).ExecuteCommandHasChangeAsync();
if (!isOk) throw Oops.Oh(ErrorCode.COM1003);
}
else
{
if (entity == null || entity.PropertyJson.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.COM1013);
var newEntity = entity.DraftJson.ToObject<FlowFormEntity>();
if (newEntity == null)
{
newEntity = entity;
}
entity.TableJson = newEntity.TableJson;
entity.PropertyJson = newEntity.PropertyJson;
if (entity.FormType == 2)
{
// 无表转有表
if (entity.TableJson.IsNullOrEmpty() || entity.TableJson == "[]")
{
// 主表名称
var mTableName = "wf_" + entity.EnCode;
if (mTableName.Length > 24) mTableName = "wf_" + SnowflakeIdHelper.NextId();
var devEntity = new VisualDev.Entitys.VisualDevEntity()
{
Id = entity.Id,
State = 1,
WebType = 3,
EnableFlow = 1,
FullName = entity.FullName,
EnCode = entity.EnCode,
FormData = entity.PropertyJson
};
var res = await _visualDevService.NoTblToTable(devEntity, mTableName);
if (res == null) throw Oops.Oh(ErrorCode.COM1000);
entity.TableJson = res.Tables;
entity.PropertyJson = res.FormData;
//await _repository.AsSugarClient().Insertable(res).CallEntityMethod(m => m.Create()).ExecuteCommandAsync();
}
//else if (await _repository.AsSugarClient().Queryable<VisualDev.Entitys.VisualDevEntity>().Where(x => x.Id.Equals(id)).AnyAsync())
//await _repository.AsSugarClient().Updateable<VisualDev.Entitys.VisualDevEntity>().SetColumns(it => it.IsRelease == 1).Where(it => it.Id == id).ExecuteCommandHasChangeAsync();
}
var dbLink = await _runService.GetDbLink(newEntity.DbLinkId);
var MainTable = newEntity.TableJson.ToList<TableModel>().Find(m => m.typeId.Equals("1")); // 主表
if (MainTable != null)
{
if (!_dataBaseManager.IsAnyColumn(dbLink, MainTable?.table, "f_flowtaskid"))
{
var pFieldList = new List<DbTableFieldModel>() { new DbTableFieldModel() { field = "F_FlowTaskId", fieldName = "流程任务Id", dataType = "varchar", dataLength = "50", allowNull = 1 } };
_dataBaseManager.AddTableColumn(dbLink, MainTable?.table, pFieldList);
}
if (!_dataBaseManager.IsAnyColumn(dbLink, MainTable?.table, "f_flowid"))
{
var pFieldList = new List<DbTableFieldModel>() { new DbTableFieldModel() { field = "F_FlowId", fieldName = "流程引擎Id", dataType = "varchar", dataLength = "50", allowNull = 1 } };
_dataBaseManager.AddTableColumn(dbLink, MainTable?.table, pFieldList);
}
}
entity.DraftJson = entity.ToJsonString();
entity.EnabledMark = 1;
var isOk = await _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(x => x.LastModify()).ExecuteCommandHasChangeAsync();
if (!isOk) throw Oops.Oh(ErrorCode.COM1003);
}
}
/// <summary>
/// 回滚.
/// </summary>
/// <param name="id">主键值.</param>
/// <returns></returns>
[HttpPost("Stop/{id}")]
public async Task Stop(string id)
{
var entity = await GetInfo(id);
}
#endregion
#region PrivateMethod
/// <summary>
/// 详情.
/// </summary>
/// <param name="id">主键.</param>
/// <returns></returns>
[NonAction]
private async Task<FlowFormEntity> GetInfo(string id)
{
return await _repository.GetFirstAsync(a => a.Id == id && a.DeleteMark == null);
}
/// <summary>
/// 导入数据.
/// </summary>
/// <param name="model">导入实例.</param>
/// <returns></returns>
private async Task ImportData(FlowFormEntity entity)
{
if (await _repository.IsAnyAsync(x => (x.EnCode.Equals(entity.EnCode) || x.FullName.Equals(entity.FullName)) && x.DeleteMark == null)) throw Oops.Oh(ErrorCode.COM1004);
// 在线开发生成导入版本自带ID
//entity.Id = SnowflakeIdHelper.NextId();
try
{
_db.BeginTran();
// 存在更新不存在插入 根据主键
var stor = _repository.AsSugarClient().Storageable(entity).Saveable().ToStorage();
// 执行插入
await stor.AsInsertable.ExecuteCommandAsync();
// await stor.AsUpdateable.ExecuteCommandAsync(); //执行更新停用原因Oracle 数据库环境会抛异常ora-01704: 字符串文字太长
// 执行更新
await _repository.AsSugarClient().Updateable(entity).ExecuteCommandAsync();
_db.CommitTran();
}
catch (Exception ex)
{
_db.RollbackTran();
throw Oops.Oh(ErrorCode.D3006);
}
}
/// <summary>
/// 验证主键策略 数据库表是否支持.
/// </summary>
/// <param name="tInfo">模板信息.</param>
/// <param name="dbLinkId">数据库连接id.</param>
private async Task VerifyPrimaryKeyPolicy(TemplateParsingBase tInfo, string dbLinkId)
{
if (tInfo.IsHasTable)
{
DbLinkEntity link = await _runService.GetDbLink(dbLinkId);
tInfo.AllTable.ForEach(item =>
{
var tableList = _dataBaseManager.GetFieldList(link, item.table); // 获取主表所有列
var mainPrimary = tableList.Find(t => t.primaryKey); // 主表主键
if (mainPrimary == null) throw Oops.Oh(ErrorCode.D1409, "主键为空", item.table);
if (tInfo.FormModel.primaryKeyPolicy.Equals(2) && !mainPrimary.identity)
{
throw Oops.Oh(ErrorCode.D1409, "自增长ID,没有自增标识", item.table);
}
if (tInfo.FormModel.primaryKeyPolicy.Equals(1) && !(mainPrimary.dataType.ToLower().Equals("string") || mainPrimary.dataType.ToLower().Equals("varchar") || mainPrimary.dataType.ToLower().Equals("nvarchar")))
throw Oops.Oh(ErrorCode.D1409, "雪花ID", item.table);
});
_dataBaseManager.ChangeDataBase(_dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName));
}
}
#endregion
}