diff --git a/EquipMgr/Tnb.EquipMgr.Entities/Consts/MoldUseStatus.cs b/EquipMgr/Tnb.EquipMgr.Entities/Consts/MoldUseStatus.cs index db9570c7..a27c20bf 100644 --- a/EquipMgr/Tnb.EquipMgr.Entities/Consts/MoldUseStatus.cs +++ b/EquipMgr/Tnb.EquipMgr.Entities/Consts/MoldUseStatus.cs @@ -11,6 +11,10 @@ namespace Tnb.EquipMgr.Entities.Consts /// /// 模具使用状态在库状态ID /// - public const string MOLDUSESTATUSZKID = "26149307089941"; + public const string MOLD_USE_STATUS_ZK_ID = "26149307089941"; + /// + /// 模具使用状态-保养Id + /// + public const string MOLD_USE_STATUS_MAINTAIN_ID = "26149311082005"; } } diff --git a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainItem.cs b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainItem.cs index b4d9e4e4..a6aa168a 100644 --- a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainItem.cs +++ b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainItem.cs @@ -66,6 +66,10 @@ public partial class ToolMoldMaintainItem : BaseEntity /// /// 保养项完成状态 0,未完成,1,已完成 /// - public int? status { get; set; } + public int status { get; set; } = 0; + /// + /// 模具id + /// + public string mold_id { get; set; } } diff --git a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainItemRecord.cs b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainItemRecord.cs new file mode 100644 index 00000000..34f90a71 --- /dev/null +++ b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainItemRecord.cs @@ -0,0 +1,46 @@ +using JNPF.Common.Contracts; +using JNPF.Common.Security; +using SqlSugar; + +namespace Tnb.EquipMgr.Entities; + +/// +/// 模具保养 +/// +[SugarTable("tool_mold_maintain_item_record")] +public partial class ToolMoldMaintainItemRecord : BaseEntity +{ + public ToolMoldMaintainItemRecord() + { + id = SnowflakeIdHelper.NextId(); + } + /// + /// 保养项 保养状态 0 未完成,1 已完成 + /// + public int status { get; set; } + + /// + /// 保养组Id + /// + public string? item_group_id { get; set; } + + /// + /// 保养组名称 + /// + public string? item_group_name { get; set; } + + /// + /// 保养项Id + /// + public string? item_id { get; set; } + + /// + /// 保养项名称 + /// + public string? item_name { get; set; } + /// + /// 模具ID + /// + public string mold_id { get; set; } + +} diff --git a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainRunRecord.cs b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainRunRecord.cs index 6f2679d2..4f4b51bf 100644 --- a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainRunRecord.cs +++ b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainRunRecord.cs @@ -59,26 +59,6 @@ public partial class ToolMoldMaintainRunRecord : BaseEntity /// public string? eqp_name { get; set; } - /// - /// 保养组编码 - /// - public string? group_code { get; set; } - - /// - /// 保养组名称 - /// - public string? group_name { get; set; } - - /// - /// 保养项编号 - /// - public string? check_item_code { get; set; } - - /// - /// 保养项名称 - /// - public string? check_item_name { get; set; } - /// /// 计划开始时间 /// @@ -94,4 +74,14 @@ public partial class ToolMoldMaintainRunRecord : BaseEntity /// public decimal? plan_time { get; set; } + /// + /// 维保人 + /// + public string? maintain_person { get; set; } + + /// + /// 异常记录 + /// + public string? exception_record { get; set; } + } diff --git a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainRunRecordD.cs b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainRunRecordD.cs new file mode 100644 index 00000000..04a23a42 --- /dev/null +++ b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMoldMaintainRunRecordD.cs @@ -0,0 +1,42 @@ +using JNPF.Common.Contracts; +using JNPF.Common.Security; +using SqlSugar; + +namespace Tnb.EquipMgr.Entities; + +/// +/// 模具保养计划记录表子表 +/// +[SugarTable("tool_mold_maintain_run_record_d")] +public partial class ToolMoldMaintainRunRecordD : BaseEntity +{ + public ToolMoldMaintainRunRecordD() + { + id = SnowflakeIdHelper.NextId(); + } + /// + /// 模具编号 + /// + public string? mold_id { get; set; } + + /// + /// 保养组编码 + /// + public string? group_id { get; set; } + + /// + /// 保养组名称 + /// + public string? group_name { get; set; } + + /// + /// 保养项编号 + /// + public string? check_item_id { get; set; } + + /// + /// 保养项名称 + /// + public string? check_item_name { get; set; } + +} diff --git a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMolds.cs b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMolds.cs index b0f50a5b..c93b2913 100644 --- a/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMolds.cs +++ b/EquipMgr/Tnb.EquipMgr.Entities/Entity/ToolMolds.cs @@ -133,5 +133,9 @@ public partial class ToolMolds : BaseEntity /// 模具型号 /// public string? mold_type_code { get; set; } + /// + /// 关联保养项信息 + /// + public string item_json { get; set; } } diff --git a/EquipMgr/Tnb.EquipMgr.Interfaces/IEqpEquipFileService.cs b/EquipMgr/Tnb.EquipMgr.Interfaces/IEqpEquipFileService.cs index 258e6439..6f685177 100644 --- a/EquipMgr/Tnb.EquipMgr.Interfaces/IEqpEquipFileService.cs +++ b/EquipMgr/Tnb.EquipMgr.Interfaces/IEqpEquipFileService.cs @@ -5,11 +5,11 @@ namespace Tnb.EquipMgr.Interfaces { public interface IEqpEquipFileService { - /// - /// 上传附件 - /// - /// - /// - public Task Upload(string equip_id,IFormFile file); + ///// + ///// 上传附件 + ///// + ///// + ///// + //public Task Upload(string equip_id,IFormFile file); } } \ No newline at end of file diff --git a/EquipMgr/Tnb.EquipMgr/EqpEquipFileService.cs b/EquipMgr/Tnb.EquipMgr/EqpEquipFileService.cs index b664448f..3367ffc3 100644 --- a/EquipMgr/Tnb.EquipMgr/EqpEquipFileService.cs +++ b/EquipMgr/Tnb.EquipMgr/EqpEquipFileService.cs @@ -1,6 +1,7 @@ using JNPF.Common.Core.Manager; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Enums; +using JNPF.Common.Models; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; @@ -10,6 +11,7 @@ using JNPF.Systems.Interfaces.Common; using JNPF.VisualDev; using JNPF.VisualDev.Entitys; using JNPF.VisualDev.Interfaces; +using Microsoft.AspNetCore.Components.Forms; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; @@ -41,16 +43,16 @@ namespace Tnb.EquipMgr } [HttpPost] - public async Task Upload([FromForm]string equip_id,[FromForm]IFormFile file) + public async Task Upload([FromForm]string equip_id,[FromForm] ChunkModel input) { string msg = ""; try { - var attachment = await _fileService.Uploader("annexpic", file); + var attachment = await _fileService.Uploader("annexpic", input); EqpEquipFile eqpEquipFile = new EqpEquipFile() { - file_name = file.FileName, + file_name = input.file.FileName, equip_id = equip_id, create_id = _userManager.UserId, create_time = DateTime.Now, diff --git a/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainGroupService.cs b/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainGroupService.cs index 20d67e21..4cfb0c2d 100644 --- a/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainGroupService.cs +++ b/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainGroupService.cs @@ -19,6 +19,8 @@ using JNPF.Common.Contracts; using Tnb.EquipMgr.Entities; using Tnb.EquipMgr.Entities.Dto; using Tnb.EquipMgr.Interfaces; +using Senparc.Weixin.MP.AdvancedAPIs.GroupMessage; +using Aop.Api.Domain; namespace Tnb.EquipMgr { @@ -79,8 +81,60 @@ namespace Tnb.EquipMgr /// /// [HttpPost] - public async Task RelevanceMaintianGroupAndItem(MoldMaintainGroupItemInput input) => - await Relevance(input, nameof(ToolMoldMaintainGroupItem.item_group_id), nameof(ToolMoldMaintainGroupItem.item_id), it => it.item_group_id == input.id); + public async Task RelevanceMaintianGroupAndItem(MoldMaintainGroupItemInput input) + { + try + { + await _db.Ado.BeginTranAsync(); + + if (input.ids == null || input.ids.Count == 0) throw new ArgumentException($"parameter {nameof(input.ids)} not be null or count not be zero"); + await Relevance(input, nameof(ToolMoldMaintainGroupItem.item_group_id), nameof(ToolMoldMaintainGroupItem.item_id), it => it.item_group_id == input.id); + List itemRecords = new(); + var grpIds = await _db.Queryable().Where(it => input.ids.Contains(it.item_id)).Select(it => it.item_group_id).Distinct().ToListAsync(); + if (grpIds?.Count > 0) + { + var grps = await _db.Queryable().Where(it => grpIds.Contains(it.id)).ToListAsync(); + foreach (var grp in grps) + { + var molds = await _db.Queryable().Where(it => it.item_group_id == grp.id).ToListAsync(); + if (molds?.Count > 0) + { + foreach (var mold in molds) + { + var dbItIds = await _db.Queryable().Where(it => it.mold_id == mold.id && it.item_group_id == grp.id && input.ids.Contains(it.id)).Select(it => it.item_id).ToListAsync(); + input.ids = input.ids.Except(dbItIds).ToList(); + if (input.ids?.Count > 0) + { + var items = await _db.Queryable().Where(it => input.ids.Contains(it.id)).ToListAsync(); + if (items?.Count > 0) + { + foreach (var item in items) + { + ToolMoldMaintainItemRecord record = new(); + record.mold_id = mold.id; + record.item_group_id = grp.id; + record.item_group_name = grp.name; + record.item_id = item.id; + record.item_name = item.name; + record.status = 0; + itemRecords.Add(record); + } + } + } + } + } + } + await _db.Insertable(itemRecords).ExecuteCommandAsync(); + } + + await _db.Ado.CommitTranAsync(); + } + catch (Exception ex) + { + await _db.Ado.RollbackTranAsync(); + throw; + } + } /// /// 关联项目组与模具 @@ -88,8 +142,45 @@ namespace Tnb.EquipMgr /// /// [HttpPost] - public async Task RelevanceMaintianGroupAndMold(MoldMaintainGroupItemRelationInput input) => + public async Task RelevanceMaintianGroupAndMold(MoldMaintainGroupItemRelationInput input) + { await Relevance(input, nameof(ToolMoldMaintainGroupRelation.item_group_id), nameof(ToolMoldMaintainGroupRelation.mold_id), it => it.item_group_id == input.id); + List itemRecords = new(); + foreach (var moldId in input.ids) + { + var grpIds = await _db.Queryable().Where(it => it.mold_id == moldId).Select(it => it.item_group_id).Distinct().ToListAsync(); + if (grpIds?.Count > 0) + { + var grps = await _db.Queryable().Where(it => grpIds.Contains(it.id)).ToListAsync(); + foreach (var grp in grps) + { + var itemIds = await _db.Queryable().Where(it => it.item_group_id == grp.id).Select(it => it.item_id).ToListAsync(); + if (itemIds?.Count > 0) + { + var dbItemIds = await _db.Queryable().Where(it => it.mold_id == moldId && it.item_group_id == grp.id && itemIds.Contains(it.item_id)).Select(it => it.item_id).ToListAsync(); + itemIds = itemIds.Except(dbItemIds).ToList(); + if (itemIds?.Count > 0) + { + var items = await _db.Queryable().Where(it => itemIds.Contains(it.id)).ToListAsync(); + foreach (var item in items) + { + ToolMoldMaintainItemRecord record = new(); + record.mold_id = moldId; + record.item_group_id = grp.id; + record.item_group_name = grp.name; + record.item_id = item.id; + record.item_name = item.name; + record.status = 0; + itemRecords.Add(record); + } + } + } + } + } + } + await _db.Insertable(itemRecords).ExecuteCommandAsync(); + + } /// /// 删除项目组与模具检查项信息 /// @@ -98,14 +189,15 @@ namespace Tnb.EquipMgr [HttpPost] public async Task Delete(MoldMaintainDelInput input) { - if (input.table_name == "item") { await Delete(it => it.item_group_id == input.id && input.ids.Contains(it.item_id)); + await Delete(it => it.item_group_id == input.id && input.ids.Contains(it.item_id)); } else { await Delete(it => it.item_group_id == input.id && input.ids.Contains(it.mold_id)); + await Delete(it => it.item_group_id == input.id && input.ids.Contains(it.mold_id)); } } diff --git a/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs b/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs index 970ce20d..ce87a030 100644 --- a/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs +++ b/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Aspose.Cells.Drawing; +using DingTalk.Api.Request; using JNPF.Common.Core.Manager; using JNPF.Common.Enums; using JNPF.Common.Extension; @@ -14,6 +15,7 @@ using JNPF.FriendlyException; using JNPF.Logging; using JNPF.Systems.Interfaces.System; using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; using SqlSugar; using StackExchange.Profiling.Internal; using Tnb.BasicData; @@ -51,8 +53,8 @@ namespace Tnb.EquipMgr [HttpGet] public async Task GetMaintainInfoFromByPlanId([FromRoute] string planId) { - dynamic info = new ExpandoObject(); - var planMoldRelation = await _db.Queryable() + List result = new(); + var planMoldRelations = await _db.Queryable() .LeftJoin((a, b) => a.maintain_plan_id == b.id)//ToolMoldMaintainPlan .LeftJoin((a, b, c) => b.plan_code == c.plan_code) .Where(a => a.maintain_plan_id == planId) @@ -61,27 +63,35 @@ namespace Tnb.EquipMgr mold_id = a.mold_id, plan_start_time = c.plan_start_time, }) - .FirstAsync(); - if (planMoldRelation != null) + .ToListAsync(); + if (planMoldRelations?.Count > 0) { - var mold = await _db.Queryable().FirstAsync(it => it.id == planMoldRelation.mold_id); - if (mold != null) + var mids = planMoldRelations.Select(x => x.mold_id).ToList(); + var molds = await _db.Queryable().Where(it => mids.Contains(it.id)).ToListAsync(); + if (molds?.Count > 0) { - info.mold_code = mold.mold_code; - info.mold_name = mold.mold_name; - info.mold_status = (await _dictionaryDataService.GetInfo(mold.mold_status))?.FullName; - info.maintain_qty = mold.maintain_qty; - info.plan_start_time = planMoldRelation.plan_start_time; - var moldEqpRelation = await _db.Queryable().FirstAsync(it => it.mold_id == mold.id); - if (moldEqpRelation != null) + for (int i = 0, cnt = molds.Count; i < cnt; i++) { - var eqp = await _db.Queryable().FirstAsync(it => it.id == moldEqpRelation.equipment_id); - info.eqp_code = eqp.code; - info.eqp_name = eqp.name; + var mold = molds[i]; + dynamic info = new ExpandoObject(); + info.mold_id = mold.id; + info.mold_code = mold.mold_code; + info.mold_name = mold.mold_name; + info.mold_status = (await _dictionaryDataService.GetInfo(mold.mold_status))?.FullName; + info.maintain_qty = mold.maintain_qty; + info.plan_start_time = planMoldRelations[i].plan_start_time; + var moldEqpRelation = await _db.Queryable().FirstAsync(it => it.mold_id == mold.id); + if (moldEqpRelation != null) + { + var eqp = await _db.Queryable().FirstAsync(it => it.id == moldEqpRelation.equipment_id); + info.eqp_code = eqp.code; + info.eqp_name = eqp.name; + } + result.Add(info); } } } - return info; + return result; } /// /// 根据模具ID获取,保养组及项目信息 @@ -92,23 +102,32 @@ namespace Tnb.EquipMgr public async Task GetCheckItemAndGrpByMoldId([FromRoute] string moldId) { if (moldId.IsNullOrEmpty()) throw new ArgumentException($"parameter {nameof(moldId)} not be null or empty"); - - var itemGroupRelation = await _db.Queryable().FirstAsync(it => it.mold_id == moldId); - if (itemGroupRelation != null) { - var checkItems = await _db.Queryable((a, b, c) => new JoinQueryInfos - ( - JoinType.Left, a.id == b.item_group_id, - JoinType.Left, b.item_id == c.id - )) - .Where(a => a.id == itemGroupRelation.item_group_id) - .Select((a, b, c) => new - { - item_group_id = a.id, - item_group_name = a.name, - item_id = c.id, - item_name = c.name, - }).ToListAsync(); + + var checkItems = await _db.Queryable().Where(it => it.mold_id == moldId).Select(it => new + { + item_group_id = it.item_group_id, + item_group_name = it.item_group_name, + item_id = it.item_id, + item_name = it.item_name, + status = it.status, + }).ToListAsync(); + + //var checkItems = await _db.Queryable((a, b, c, d) => new JoinQueryInfos + // ( + // JoinType.Inner, a.item_group_id == b.id, + // JoinType.Inner, b.id == c.item_group_id, + // JoinType.Inner, c.item_id == d.id + // )) + // .Where(a => a.mold_id == moldId) + // .Select((a, b, c, d) => new + // { + // item_group_id = b.id, + // item_group_name = b.name, + // item_id = d.id, + // item_name = d.name, + // status = d.status, + // }).ToListAsync(); return checkItems; } return Enumerable.Empty(); @@ -127,48 +146,67 @@ namespace Tnb.EquipMgr [HttpPost] public async Task MaintainStart(MoldMaintainRunUpInput input) { + if (input == null) throw new ArgumentNullException("input"); try { await _db.Ado.BeginTranAsync(); var dic = await _dictionaryDataService.GetDicByTypeId(DictConst.MaintainStatusTypeId); - var plan = await _db.Queryable().FirstAsync(it => it.id == input.plan_id); - if (plan != null) + var mold = await _db.Queryable().FirstAsync(it => it.id == input.mold_id); + if (mold != null) { - plan.status = DictConst.MoldMaintainStatusDBYCode; - var row = await _db.Updateable(plan).ExecuteCommandAsync(); - if (row < 1) throw Oops.Oh(ErrorCode.COM1001); - ToolMoldMaintainRunRecord record = new(); - record.plan_code = plan.plan_code; - record.mode = plan.mode; - record.plan_status = dic.ContainsKey(plan.plan_code) ? dic[plan.plan_code].ToString() : ""; - record.designer = _userManager.RealName; - record.designer_time = DateTime.Now; - var moldPlanRelation = await _db.Queryable().FirstAsync(it => it.maintain_plan_id == input.plan_id); - if (moldPlanRelation != null) + mold.mold_status = MoldUseStatus.MOLD_USE_STATUS_MAINTAIN_ID; + var isOk = await _db.Updateable(mold).Where(it => it.id == input.mold_id).ExecuteCommandHasChangeAsync(); + if (!isOk) throw Oops.Oh(ErrorCode.COM1001); + var plan = await _db.Queryable().LeftJoin((a, b) => a.maintain_plan_id == b.id) + .Where(a => a.mold_id == input.mold_id).Select((a, b) => b).FirstAsync(); + + if (plan is not null) { - var mold = await _db.Queryable().FirstAsync(it => it.id == moldPlanRelation.mold_id); - record.mold_code = mold?.mold_code; - record.mold_name = mold?.mold_name; - var moldGroupRelation = await _db.Queryable().FirstAsync(it => it.mold_id == mold.id); - if (moldGroupRelation != null) - { - var maintainGroup = await _db.Queryable().FirstAsync(it => it.id == moldGroupRelation.item_group_id); - record.group_name = maintainGroup.name; - var itemGrpRelation = await _db.Queryable().FirstAsync(it => it.item_group_id == maintainGroup.id); - if (itemGrpRelation != null) + //插入保养计划记录 + ToolMoldMaintainRunRecord record = new(); + record.plan_code = plan.plan_code; + record.mode = plan.mode; + record.plan_status = dic.ContainsKey(plan.plan_code) ? dic[plan.plan_code].ToString() : ""; + record.designer = _userManager.RealName; + record.designer_time = DateTime.Now; + record.mold_code = mold.mold_code; + record.mold_name = mold.mold_name; + record.plan_start_time = DateTime.Now; + var row = await _db.Insertable(record).ExecuteCommandAsync(); + if (row < 1) throw Oops.Oh(ErrorCode.COM1001); + + var maintainInfos = await _db.Queryable() + .LeftJoin((a, b) => a.item_group_id == b.id) + .LeftJoin((a, b, c) => b.id == c.item_group_id) + .LeftJoin((a, b, c, d) => c.item_id == d.id) + .Where(a => a.mold_id == input.mold_id) + .Select((a, b, c, d) => new { - var checkItem = await _db.Queryable().FirstAsync(it => it.id == itemGrpRelation.item_id); - record.check_item_name = checkItem.name; + group_id = b.id, + group_name = b.name, + check_item_id = d.id, + check_item_name = d.name + }) + .ToListAsync(); + if (maintainInfos?.Count > 0) + { + List recordDs = new(); + foreach (var info in maintainInfos) + { + ToolMoldMaintainRunRecordD record_d = new(); + record_d.group_id = info.group_id; + record_d.group_name = info.group_name; + record_d.check_item_id = info.check_item_id; + record_d.check_item_name = info.check_item_name; + recordDs.Add(record_d); } + row = await _db.Insertable(recordDs).ExecuteCommandAsync(); + if (row < 1) throw Oops.Oh(ErrorCode.COM1001); } } - record.plan_start_time = DateTime.Now; - row = await _db.Insertable(record).ExecuteCommandAsync(); - if (row < 1) throw Oops.Oh(ErrorCode.COM1001); - - await _db.Ado.CommitTranAsync(); } + await _db.Ado.CommitTranAsync(); } catch (Exception ex) { @@ -183,9 +221,10 @@ namespace Tnb.EquipMgr { if (input == null) throw new ArgumentNullException("input"); if (input.itemIds == null || input.itemIds.Count == 0) throw new ArgumentException($"parameter {nameof(input.itemIds)} not be null or empty"); - var row = await _db.Updateable().SetColumns(it => new ToolMoldMaintainItem { status = input.status }).Where(it => input.itemIds.Contains(it.id)).ExecuteCommandAsync(); + var row = await _db.Updateable().SetColumns(it => new ToolMoldMaintainItemRecord { status = 1 }).Where(it => input.itemIds.Contains(it.id)).ExecuteCommandAsync(); if (row < 1) throw Oops.Oh(ErrorCode.COM1001); } + /// /// 模具保养计划执行-保养完成 /// @@ -204,18 +243,18 @@ namespace Tnb.EquipMgr var itemIds = await _db.Queryable().Where(it => grpIds.Contains(it.item_group_id)).Select(it => it.item_id).ToListAsync(); if (itemIds?.Count > 0) { - var items = await _db.Queryable().Where(it => itemIds.Contains(it.id) && it.status.HasValue && it.status.Value == 1).ToListAsync(); + var items = await _db.Queryable().Where(it => it.mold_id == input.mold_id && it.status == 1).ToListAsync(); if (items?.Count < itemIds.Count) { throw new AppFriendlyException("当前模具有未完成的保养项目", 500); } - var row = await _db.Updateable().SetColumns(it => new ToolMolds { mold_status = MoldUseStatus.MOLDUSESTATUSZKID }).Where(it => it.id == input.mold_id).ExecuteCommandAsync(); + var row = await _db.Updateable().SetColumns(it => new ToolMolds { mold_status = MoldUseStatus.MOLD_USE_STATUS_ZK_ID }).Where(it => it.id == input.mold_id).ExecuteCommandAsync(); if (row < 1) throw Oops.Oh(ErrorCode.COM1001); var allMoldStatus = await _db.Queryable().InnerJoin((a, b) => a.mold_id == b.id) .Where((a, b) => a.maintain_plan_id == input.plan_id) .Select((a, b) => b.mold_status) .ToListAsync(); - if (allMoldStatus?.Count > 0 && allMoldStatus.All(x => x == MoldUseStatus.MOLDUSESTATUSZKID)) + if (allMoldStatus?.Count > 0 && allMoldStatus.All(x => x == MoldUseStatus.MOLD_USE_STATUS_ZK_ID)) { row = await _db.Updateable().SetColumns(it => new ToolMoldMaintainPlan { status = MoldPlanMaintainStatus.MOLDPLAN_MAINTAIN_STATUS_COMPLETED_CODE }).Where(it => it.id == input.plan_id).ExecuteCommandAsync(); } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/ExChangeCarryInput.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/ExChangeCarryInput.cs new file mode 100644 index 00000000..cc68bf46 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/ExChangeCarryInput.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Entities.Dto +{ + /// + /// 更换载具输入参数 + /// + + public class ExChangeCarryInput + { + /// + /// 老载具ID + /// + public string old_carry_id { get; set; } + /// + /// 新载具ID + /// + public string new_carry_id { get; set; } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryCode.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryCode.cs index b71ca2b2..84d8360b 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryCode.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryCode.cs @@ -97,12 +97,12 @@ public partial class WmsCarryCode : BaseEntity /// /// 创建用户 /// - public string create_id { get; set; } = string.Empty; + public string? create_id { get; set; } /// /// 创建时间 /// - public DateTime create_time { get; set; } = DateTime.Now; + public DateTime? create_time { get; set; } /// /// 修改用户 diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryD.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryD.cs index 0bfbdd28..553c5500 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryD.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryD.cs @@ -42,12 +42,12 @@ public partial class WmsCarryD : BaseEntity /// /// 创建用户 /// - public string create_id { get; set; } = string.Empty; + public string? create_id { get; set; } /// /// 创建时间 /// - public DateTime create_time { get; set; } = DateTime.Now; + public DateTime? create_time { get; set; } /// /// 最后修改人员ID diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryH.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryH.cs index 30b9e324..76092322 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryH.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryH.cs @@ -42,7 +42,7 @@ public partial class WmsCarryH : BaseEntity /// /// 载具状态 /// - public string carry_status { get; set; } = string.Empty; + public int carry_status { get; set; }; /// /// 载具分类ID @@ -114,4 +114,19 @@ public partial class WmsCarryH : BaseEntity /// public DateTime? timestamp { get; set; } + /// + /// 打包号 + /// + public string? bale_num { get; set; } + + /// + /// 齐套搭配方案ID + /// + public string? collocation_scheme_id { get; set; } + + /// + /// 齐套搭配方案编号 + /// + public string? collocation_scheme_code { get; set; } + } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryMat.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryMat.cs index e1d544cc..283918af 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryMat.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryMat.cs @@ -82,12 +82,12 @@ public partial class WmsCarryMat : BaseEntity /// /// 时间戳 /// - public DateTime time_stamp { get; set; } = DateTime.Now; + public DateTime? time_stamp { get; set; } /// /// 创建用户 /// - public string create_id { get; set; } = string.Empty; + public string? create_id { get; set; } /// /// 创建时间 diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceCode.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceCode.cs index 2575f6af..1656af9f 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceCode.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceCode.cs @@ -77,12 +77,12 @@ public partial class WmsCarryReplaceCode : BaseEntity /// /// 创建用户 /// - public string create_id { get; set; } = string.Empty; + public string? create_id { get; set; } /// /// 创建时间 /// - public DateTime create_time { get; set; } = DateTime.Now; + public DateTime? create_time { get; set; } /// /// 修改用户 @@ -94,9 +94,4 @@ public partial class WmsCarryReplaceCode : BaseEntity /// public DateTime? modify_time { get; set; } - /// - /// 行号 - /// - public int no { get; set; } - } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceH.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceH.cs index f2d39eae..1ebfc67c 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceH.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsCarryReplaceH.cs @@ -17,7 +17,7 @@ public partial class WmsCarryReplaceH : BaseEntity /// /// 租户ID /// - public string tenant_id { get; set; } = string.Empty; + public string? tenant_id { get; set; } /// /// 所属组织ID diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Enums/EnumCarryStatus.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Enums/EnumCarryStatus.cs new file mode 100644 index 00000000..c7bbef14 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Enums/EnumCarryStatus.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Entities.Enums +{ + /// + /// 载具状态枚举 + /// + public enum EnumCarryStatus + { + 空闲 = 0, + 占用 = 1, + 齐套 = 3, + 寄存 = 4, + 齐套分拣 = 5, + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Enums/EnumOutStatus.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Enums/EnumOutStatus.cs new file mode 100644 index 00000000..f13e2e51 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Enums/EnumOutStatus.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Entities.Enums +{ + /// + /// 出库状态 + /// + public enum EnumOutStatus + { + 正常 = 0, + 全部出 = 1, + 分拣出 = 2, + 齐套出 = 3, + 寄存出 = 4, + 齐套分拣出 = 5, + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/Class1.cs b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/Class1.cs deleted file mode 100644 index 8c120287..00000000 --- a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Tnb.WarehouseMgr.Interfaces -{ - public class Class1 - { - - } -} \ No newline at end of file diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCarryEntity.cs b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCarryEntity.cs new file mode 100644 index 00000000..f2d71a03 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCarryEntity.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Interfaces +{ + public class IWmsCarryEntity + { + string carry_id { get; set; } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCarryService.cs b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCarryService.cs new file mode 100644 index 00000000..4eeff321 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCarryService.cs @@ -0,0 +1,17 @@ +using Tnb.WarehouseMgr.Entities; + +namespace Tnb.WarehouseMgr.Interfaces +{ + /// + /// 载具服务接口 + /// + public interface IWmsCarryService + { + /// + /// 更新空载具 + /// + /// + /// + Task UpdateNullCarry(WmsCarryH carryObj); + } +} \ No newline at end of file diff --git a/WarehouseMgr/Tnb.WarehouseMgr/Class1.cs b/WarehouseMgr/Tnb.WarehouseMgr/Class1.cs deleted file mode 100644 index b5b0a256..00000000 --- a/WarehouseMgr/Tnb.WarehouseMgr/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Tnb.WarehouseMgr -{ - public class Class1 - { - - } -} \ No newline at end of file diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmsCarryService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmsCarryService.cs new file mode 100644 index 00000000..5fede318 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmsCarryService.cs @@ -0,0 +1,137 @@ +using JNPF.Common.Core.Manager; +using JNPF.Common.Enums; +using JNPF.DependencyInjection; +using JNPF.DynamicApiController; +using JNPF.FriendlyException; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.Common.Utils; +using Tnb.WarehouseMgr.Entities; +using Tnb.WarehouseMgr.Entities.Dto; +using Tnb.WarehouseMgr.Entities.Enums; +using Tnb.WarehouseMgr.Interfaces; + +namespace Tnb.WarehouseMgr +{ + /// + /// 载具服务 + /// + [ApiDescriptionSettings(Tag = ModuleConsts.Tag, Area = ModuleConsts.Area, Order = 700)] + [Route("api/[area]/[controller]/[action]")] + + public class WmsCarryService : IWmsCarryService, IDynamicApiController, ITransient + { + private readonly ISqlSugarClient _db; + private readonly IUserManager _userManager; + public WmsCarryService(ISqlSugarRepository repository, IUserManager userManager) + { + _db = repository.AsSugarClient(); + _userManager = userManager; + } + /// + /// 更换载具 + /// + /// + /// 输入参数: + ///
{ + ///
old_carry_id:老载具id + ///
new_carry_id:新载具ID + ///
} + /// + /// + /// + [HttpPost] + public async Task Exchange(ExChangeCarryInput input) + { + var row = -1; + if (input == null) throw new ArgumentNullException("input"); + var oldCarry = await _db.Queryable().FirstAsync(it => it.id == input.old_carry_id && it.is_lock == 0 && it.status == 0 && it.carry_status != 0); + var newCarry = await _db.Queryable().FirstAsync(it => it.id == input.new_carry_id && it.is_lock == 0 && it.status == 0 && it.carry_status == 0); + if (oldCarry != null && newCarry != null) + { + var subCarrys = await _db.Queryable().Where(it => it.carry_id == oldCarry.id).ToListAsync(); + if (subCarrys?.Count > 0) + { + List newSubCarrys = DeepCopyHelper.DeepCopyList(subCarrys); + if (newSubCarrys?.Count > 0) + { + newSubCarrys.ForEach(x => x.carry_id = newCarry.id); + row = await _db.Insertable(newSubCarrys).ExecuteCommandAsync(); + } + if (row > 0) + { + row = await _db.Deleteable(subCarrys).ExecuteCommandAsync(); + } + } + var subCarryMats = await _db.Queryable().Where(it => it.carry_id == oldCarry.id).ToListAsync(); + if (subCarryMats?.Count > 0) + { + List newCarryMats = DeepCopyHelper.DeepCopyList(subCarryMats); + if (newCarryMats?.Count > 0) + { + newCarryMats.ForEach(x => x.carry_id = newCarry.id); + row = await _db.Insertable(newCarryMats).ExecuteCommandAsync(); + } + if (row > 0) + { + row = await _db.Deleteable(subCarryMats).ExecuteCommandAsync(); + } + } + var subCarryCodes = await _db.Queryable().Where(it => it.carry_id == oldCarry.id).ToListAsync(); + if (subCarryCodes?.Count > 0) + { + List newCarrayCodes = DeepCopyHelper.DeepCopyList(subCarryCodes); + if (newCarrayCodes?.Count > 0) + { + newCarrayCodes.ForEach(x => x.carry_id = newCarry.id); + row = await _db.Insertable(newCarrayCodes).ExecuteCommandAsync(); + } + if (row > 0) + { + row = await _db.Deleteable(subCarryCodes).ExecuteCommandAsync(); + } + } + if (row > 0) + { + newCarry.carry_name = oldCarry.carry_name; + newCarry.status = oldCarry.status; + newCarry.carry_status = oldCarry.carry_status; + newCarry.carrystd_id = oldCarry.carrystd_id; + newCarry.location_id = oldCarry.location_id; + newCarry.carry_code = oldCarry.location_code; + newCarry.is_lock = oldCarry.is_lock; + newCarry.out_status = oldCarry.out_status; + newCarry.is_check = oldCarry.is_check; + newCarry.bale_num = oldCarry.bale_num; + newCarry.collocation_scheme_id = oldCarry.collocation_scheme_id; + newCarry.collocation_scheme_code = oldCarry.collocation_scheme_code; + newCarry.source_id = oldCarry.source_id; + newCarry.source_code = oldCarry.source_code; + newCarry.create_id = _userManager.UserId; + newCarry.create_time = DateTime.Now; + row = await _db.Updateable(newCarry).ExecuteCommandAsync(); + row = await UpdateNullCarry(oldCarry); + } + } + if (row < 1) throw Oops.Oh(ErrorCode.COM1001); + } + + public Task UpdateNullCarry(WmsCarryH carryObj) + { + carryObj.carry_name = null; + carryObj.status = 0; + carryObj.carry_status = 0; + carryObj.carrystd_id = null; + carryObj.location_id = null; + carryObj.carry_code = null; + carryObj.out_status = null; + carryObj.is_check = 0; + carryObj.bale_num = null; + carryObj.collocation_scheme_id = null; + carryObj.collocation_scheme_code = null; + carryObj.source_id = null; + carryObj.source_code = null; + return _db.Updateable(carryObj).ExecuteCommandAsync(); + } + } +} \ No newline at end of file diff --git a/apihost/Tnb.API.Entry/Configurations/App.json b/apihost/Tnb.API.Entry/Configurations/App.json index b0b35652..88325a5f 100644 --- a/apihost/Tnb.API.Entry/Configurations/App.json +++ b/apihost/Tnb.API.Entry/Configurations/App.json @@ -4,15 +4,88 @@ //系统文件路径 "SystemPath": "D:\\ToTong\\tnb\\Resources", //微信公众号允许上传文件类型 - "MPUploadFileType": [ "bmp", "png", "jpeg", "jpg", "gif", "mp3", "wma", "wav", "amr", "mp4" ], + "MPUploadFileType": [ + "bmp", + "png", + "jpeg", + "jpg", + "gif", + "mp3", + "wma", + "wav", + "amr", + "mp4" + ], //微信允许上传文件类型 - "WeChatUploadFileType": [ "jpg", "png", "doc", "docx", "ppt", "pptx", "xls", "xlsx", "pdf", "txt", "rar", "zip", "csv", "amr", "mp4" ], + "WeChatUploadFileType": [ + "jpg", + "png", + "doc", + "docx", + "ppt", + "pptx", + "xls", + "xlsx", + "pdf", + "txt", + "rar", + "zip", + "csv", + "amr", + "mp4" + ], //允许图片类型 - "AllowUploadImageType": [ "jpg", "gif", "png", "bmp", "jpeg", "tiff", "psd", "swf", "svg", "pcx", "dxf", "wmf", "emf", "lic", "eps", "tga" ], + "AllowUploadImageType": [ + "jpg", + "gif", + "png", + "bmp", + "jpeg", + "tiff", + "psd", + "swf", + "svg", + "pcx", + "dxf", + "wmf", + "emf", + "lic", + "eps", + "tga" + ], //允许上传文件类型 - "AllowUploadFileType": [ "jpg", "mp3", "gif", "png", "bmp", "jpeg", "doc", "docx", "ppt", "pptx", "xls", "xlsx", "pdf", "txt", "rar", "zip", "csv" ], + "AllowUploadFileType": [ + "jpg", + "mp3", + "gif", + "png", + "bmp", + "jpeg", + "doc", + "docx", + "ppt", + "pptx", + "xls", + "xlsx", + "pdf", + "txt", + "rar", + "zip", + "csv" + ], //过滤上传文件名称特殊字符 - "SpecialString": [ "/", "<", ">", "|", "?", "\\", ":", "\"", "*", "_" ], + "SpecialString": [ + "/", + "<", + ">", + "|", + "?", + "\\", + ":", + "\"", + "*", + "_" + ], "PreviewType": "kkfile", //文件预览方式 (kkfile,yozo)默认使用kkfile "KKFileDomain": "http://127.0.0.1:30090/FileServer", "Domain": "http://yinmai.tpddns.cn:7772", @@ -21,18 +94,52 @@ "domainKey": "57462250284462899305150", "UploadAPI": "http://dmc.yozocloud.cn/api/file/http?fileUrl={0}&appId={1}&sign={2}", //上传接口 "DownloadAPI": "http://eic.yozocloud.cn/api/view/file?fileVersionId={0}&appId={1}&sign={2}", //预览接口 - "AppId": "yozoAQh5dPSt6063", //应用Id - "AppKey": "6365bfbd733fce644fd7ac0aaeca" //签名 + "AppId": "yozoAQh5dPSt6063", // 应用Id + "AppKey": "6365bfbd733fce644fd7ac0aaeca" // 签名 }, - //================== 系统错误邮件报告反馈相关 ============================== --> - //软件的错误报告 + // ================== 系统错误邮件报告反馈相关 ============================== --> + // 软件的错误报告 "ErrorReport": false, //软件的错误报告发给谁 "ErrorReportTo": "tuotong_tech@163.com" }, + // ================== 单点登录配置(和其他登录方式 只能二选一) ============================== --> + "OAuth": { + "Enabled": false, // 开启后将支持单点登录, 前端与后端都不可使用普通模式登录 + "LoginPath": "http://192.168.20.119:5000/api/oauth/Login", // 前端登录页面访问登录接口进行单点登录页面跳转, 需要与身份管理系统中的 JNPF-Auth2、JNPF-CAS中的认证地址一致 + "SucessFrontUrl": "http://192.168.20.119:3000/sso", // 从单点登录中心直接访问JNPF时登录成功后跳转的前端页面 + "DefaultSSO": "auth2", // 默认接口 + "TicketTimeout": 5, // 缓存过期时间 / 分钟 + "TicketOutMessage": false, // 是否前端输出消息 + "SSO": { + "auth2": { + "enabled": true, + "clientId": "747887288041603072", + "clientSecret": "MYgMMjIwNzIwMjIxNTU4MTAxNzQlKQ", + "authorizeUrl": "https://192.168.20.133:8527/sign/authz/oauth/v20/authorize", + "accessTokenUrl": "https://192.168.20.133:8527/sign/authz/oauth/v20/token", + "userInfoUrl": "https://192.168.20.133:8527/sign/api/oauth/v20/me" + }, + "cas": { + "enabled": true, + "serverLoginUrl": "https://sso.test.jnpf.work/sign/authz/cas/login", + "serverValidateUrl": "https://sso.test.jnpf.work/sign/authz/cas" + } + }, + "Pull": { + "Enabled": true, + "CreateRestAddress": "http://192.168.20.133:9526/sso-mgt-api/api/idm/Account", + "ReplaceRestAddress": "http://192.168.20.133:9526/sso-mgt-api/api/idm/Account", + "ChangePasswordRestAddress": "http://192.168.20.133:9526/sso-mgt-api/api/idm/Account/changePassword", + "DeleteRestAddress": "http://192.168.20.133:9526/sso-mgt-api/api/idm/Account", + "CredentialType": "Basic", + "UserName": "747887288041603072", + "Password": "MYgMMjIwNzIwMjIxNTU4MTAxNzQlKQ" + } + }, //================== 第三方登录配置 ============================== --> "Socials": { - "SocialsEnabled": true, + "SocialsEnabled": false, "DoMain": "https://562f45p309.goho.co/dev", // 外网能访问的地址(域名), 回调的时候拼接接口地址用 "Config": [ { @@ -76,8 +183,9 @@ }, //================== 消息跳转配置 ============================== --> "Message": { - "DoMainPc": "http://127.0.0.1:3000", // 前端PC外网能访问的地址(域名), 回调的时候拼接接口地址用 - "DoMainApp": "http://127.0.0.1:3000", // 前端App外网能访问的地址(域名), 回调的时候拼接接口地址用 + "ApiDoMain": "http://localhost:5000", // 后端Api路径 (发布时与DoMainPc一致) + "DoMainPc": "http://localhost:3000", // 前端PC外网能访问的地址(域名), 回调的时候拼接接口地址用 + "DoMainApp": "http://localhost:8081", // 前端App外网能访问的地址(域名), 回调的时候拼接接口地址用 "AppPushUrl": "https://8e84eea8-6922-4033-8e86-67ad7442e692.bspapp.com/unipush" } } \ No newline at end of file diff --git a/apihost/Tnb.API.Entry/Configurations/EventBus.json b/apihost/Tnb.API.Entry/Configurations/EventBus.json new file mode 100644 index 00000000..8600f134 --- /dev/null +++ b/apihost/Tnb.API.Entry/Configurations/EventBus.json @@ -0,0 +1,8 @@ +{ + "EventBus": { + "EventBusType": "Memory", //Memory,RabbitMQ + "HostName": "192.168.0.232", + "UserName": "jnpf", + "Password": "jnpf@2019" + } +} \ No newline at end of file diff --git a/apihost/Tnb.API.Entry/Configurations/JWT.json b/apihost/Tnb.API.Entry/Configurations/JWT.json index 10b5e739..cf2e1415 100644 --- a/apihost/Tnb.API.Entry/Configurations/JWT.json +++ b/apihost/Tnb.API.Entry/Configurations/JWT.json @@ -1,7 +1,7 @@ { "JWTSettings": { "ValidateIssuerSigningKey": true, // 是否验证密钥,bool 类型,默认true - "IssuerSigningKey": "7k5yOxSMHVdYjs61gkgUY3W9DHbgk7tokaZlP3QIlfk34D1H7jYEOcLybClW1aKl", // 密钥,string 类型,必须是复杂密钥,长度大于16 + "IssuerSigningKey": "RkayGi4ltkMWrSQKsQTWic1VnakqsQfaJOmJIBUWE1gxGaS0IrJHxa9anjVAwuew", // 密钥,string 类型,必须是复杂密钥,长度大于16 "ValidateIssuer": true, // 是否验证签发方,bool 类型,默认true "ValidIssuer": "tuotong", // 签发方,string 类型 "ValidateAudience": true, // 是否验证签收方,bool 类型,默认true diff --git a/apihost/Tnb.API.Entry/Configurations/JobConnectionStrings.json b/apihost/Tnb.API.Entry/Configurations/JobConnectionStrings.json new file mode 100644 index 00000000..aa92ddf2 --- /dev/null +++ b/apihost/Tnb.API.Entry/Configurations/JobConnectionStrings.json @@ -0,0 +1,23 @@ +{ + "JobConnectionStrings": { + "ConfigId": "JNPF-Job",// 不可修改 + "DBName": "jnpf_sundial", + "DBType": "SqlServer", //MySql;SqlServer;Oracle;PostgreSQL;Dm;Kdbndp;Sqlite; + "Host": "192.168.0.214", + "Port": "1433", + "UserName": "sa", + "Password": "kMaeMP8Yck6b6wA", + //SqlServer + "DefaultConnection": "Data Source=192.168.0.214;Initial Catalog={0};User ID=sa;Password=kMaeMP8Yck6b6wA;MultipleActiveResultSets=true" + //Kdbndp + //"DefaultConnection": "Server=192.168.0.103;Port=54321;UID=YANYU;PWD=123456;database=YANSOURCE" + //Dm + //"DefaultConnection": "Server=192.168.0.50; User Id=JNPFTEST; PWD=I97eH!bRfy55qGzF;DATABASE=JNPFTEST" + //Oracle + //"DefaultConnection": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.19)(PORT=1521))(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME=JNPFCLOUD)));User Id=JNPFCLOUD;Password=JNPFCLOUD" + //PostgreSQL + //"DefaultConnection": "PORT=5432;DATABASE=java_boot_dev_postgresql;HOST=192.168.0.103;PASSWORD=123456;USER ID=postgres" + //MySql + //"DefaultConnection": "server=192.168.0.10;Database=netcore_test;Uid=netcore_test;Pwd=jhpGB3A88CF57fBC;AllowLoadLocalInfile=true" + } +} \ No newline at end of file diff --git a/apihost/Tnb.API.Entry/Configurations/Swagger.json b/apihost/Tnb.API.Entry/Configurations/Swagger.json index e6a1899c..9f45fc4e 100644 --- a/apihost/Tnb.API.Entry/Configurations/Swagger.json +++ b/apihost/Tnb.API.Entry/Configurations/Swagger.json @@ -8,7 +8,7 @@ "Group": "Default", "Title": "ToTong Next Builder", "Description": "", - "Version": "3.4.5" + "Version": "3.4.6" } ], "LoginInfo": { diff --git a/apihost/Tnb.API.Entry/Extensions/ConfigureEventBusExtensions.cs b/apihost/Tnb.API.Entry/Extensions/ConfigureEventBusExtensions.cs index 180ede3a..214f6c8a 100644 --- a/apihost/Tnb.API.Entry/Extensions/ConfigureEventBusExtensions.cs +++ b/apihost/Tnb.API.Entry/Extensions/ConfigureEventBusExtensions.cs @@ -1,4 +1,5 @@ using JNPF; +using JNPF.Common.Core; using JNPF.Common.Options; using JNPF.EventHandler; using OnceMi.AspNetCore.OSS; @@ -17,40 +18,53 @@ public static class ConfigureEventBusExtensions /// public static IServiceCollection ConfigureEventBus(this IServiceCollection services) { - // 注册EventBus服务 - services.AddEventBus(options => - { - //// 创建连接工厂 - //var factory = new RabbitMQ.Client.ConnectionFactory - //{ - // // 设置主机名 - // HostName = "192.168.0.232", + // 注册EventBus服务 + // 注册EventBus服务 + services.AddEventBus(options => + { + var config = App.GetOptions(); - // // 用户名 - // UserName = "jnpf", + if (config.EventBusType != EventBusType.Memory) + { + switch (config.EventBusType) + { + case EventBusType.RabbitMQ: + // 创建连接工厂 + var factory = new RabbitMQ.Client.ConnectionFactory + { + // 设置主机名 + HostName = config.HostName, - // // 密码 - // Password = "jnpf@2019", - //}; + // 用户名 + UserName = config.UserName, - //// 创建默认内存通道事件源对象,可自定义队列路由key,比如这里是 eventbus - //var rbmqEventSourceStorer = new RabbitMQEventSourceStorer(factory, "eventbus", 3000); + // 密码 + Password = config.Password, + }; - //// 替换默认事件总线存储器 - //options.ReplaceStorer(serviceProvider => - //{ - // return rbmqEventSourceStorer; - //}); + // 创建默认内存通道事件源对象,可自定义队列路由key,比如这里是 eventbus + var rbmqEventSourceStorer = new RabbitMQEventSourceStorer(factory, "eventbus", 3000); - options.UseUtcTimestamp = false; + // 替换默认事件总线存储器 + options.ReplaceStorer(serviceProvider => + { + return rbmqEventSourceStorer; + }); + break; + } + } - // 不启用事件日志 - options.LogEnabled = false; + options.UseUtcTimestamp = false; - // 事件执行器(失败重试) - options.AddExecutor(); - }); + // 不启用事件日志 + options.LogEnabled = false; - return services; + // 事件执行器(失败重试) + options.AddExecutor(); + }); + + services.AddConfigurableOptions(); + + return services; } } \ No newline at end of file diff --git a/apihost/Tnb.API.Entry/Extensions/ConfigureMvcControllerExtensions.cs b/apihost/Tnb.API.Entry/Extensions/ConfigureMvcControllerExtensions.cs index 4dc1208b..f783c29d 100644 --- a/apihost/Tnb.API.Entry/Extensions/ConfigureMvcControllerExtensions.cs +++ b/apihost/Tnb.API.Entry/Extensions/ConfigureMvcControllerExtensions.cs @@ -10,6 +10,7 @@ using Newtonsoft.Json; using OnceMi.AspNetCore.OSS; using JNPF.API.Entry.Handlers; using JNPF.Common.Cache; +using Microsoft.AspNetCore.Authentication.JwtBearer; namespace Microsoft.Extensions.DependencyInjection; @@ -18,60 +19,108 @@ namespace Microsoft.Extensions.DependencyInjection; ///
public static class ConfigureMvcControllerExtensions { - /// - /// OSS服务配置. - /// - /// - /// - public static IServiceCollection ConfigureMvcController(this IServiceCollection services) - { - services.AddControllers() - .AddMvcFilter() - .AddInjectWithUnifyResult() - .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null) - .AddNewtonsoftJson(options => + /// + /// OSS服务配置. + /// + /// + /// + public static IServiceCollection ConfigureMvcController(this IServiceCollection services) + { + services.AddControllers() + .AddMvcFilter() + .AddInjectWithUnifyResult() + .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null) + .AddNewtonsoftJson(options => + { + // 默认命名规则 + options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + + // 设置时区为 UTC + options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; + + // 格式化json输出的日期格式 + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + + // 忽略空值 + // options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; + + // 忽略循环引用 + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + + // 格式化json输出的日期格式为时间戳 + options.SerializerSettings.Converters.Add(new NewtonsoftDateTimeJsonConverter()); + }); + + services.AddUnifyJsonOptions("special", new JsonSerializerSettings { - // 默认命名规则 - options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + // 默认命名规则 + ContractResolver = new DefaultContractResolver(), - // 设置时区为 UTC - options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; + // 设置时区为 UTC + DateTimeZoneHandling = DateTimeZoneHandling.Utc, - // 格式化json输出的日期格式 - options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; - - // 忽略空值 - // options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; - - // 忽略循环引用 - options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; - - // 格式化json输出的日期格式为时间戳 - options.SerializerSettings.Converters.Add(new NewtonsoftDateTimeJsonConverter()); + // 格式化json输出的日期格式 + DateFormatString = "yyyy-MM-dd HH:mm:ss", }); - // 配置Nginx转发获取客户端真实IP - // 注1:如果负载均衡不是在本机通过 Loopback 地址转发请求的,一定要加上options.KnownNetworks.Clear()和options.KnownProxies.Clear() - // 注2:如果设置环境变量 ASPNETCORE_FORWARDEDHEADERS_ENABLED 为 True,则不需要下面的配置代码 - services.Configure(options => - { - options.ForwardedHeaders = ForwardedHeaders.All; - options.KnownNetworks.Clear(); - options.KnownProxies.Clear(); - }); + // 配置Nginx转发获取客户端真实IP + // 注1:如果负载均衡不是在本机通过 Loopback 地址转发请求的,一定要加上options.KnownNetworks.Clear()和options.KnownProxies.Clear() + // 注2:如果设置环境变量 ASPNETCORE_FORWARDEDHEADERS_ENABLED 为 True,则不需要下面的配置代码 + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.All; + options.KnownNetworks.Clear(); + options.KnownProxies.Clear(); + }); - // Jwt处理程序 - services.AddJwt(enableGlobalAuthorize: true); + // Jwt处理程序 + services.AddJwt(enableGlobalAuthorize: true, jwtBearerConfigure: options => + { + // 实现 JWT 身份验证过程控制 + options.Events = new JwtBearerEvents + { + // 添加读取 Token 的方式 + OnMessageReceived = context => + { + var httpContext = context.HttpContext; - // 跨域 - services.AddCorsAccessor(); + // 判断请求是否包含 token 参数,如果有就设置给 Token + if (httpContext.Request.Query.ContainsKey("token")) + { + // 设置 Token + context.Token = httpContext.Request.Query["token"]; + } - services.AddConfigurableOptions(); - services.AddSession(); - services.AddMemoryCache(); // 使用本地缓存必须添加 + return Task.CompletedTask; + }, - services.AddSingleton(); + // Token 验证通过处理 + OnTokenValidated = context => + { + return Task.CompletedTask; + }, + }; + }); - return services; - } + // 跨域 + services.AddCorsAccessor(); + + // 注册远程请求 + services.AddRemoteRequest(); + + // 视图引擎 + services.AddViewEngine(); + + // 脱敏词汇检测 + services.AddSensitiveDetection(); + + // WebSocket服务 + services.AddWebSocketManager(); + + services.AddSession(); + + services.AddSingleton(); + + return services; + } } \ No newline at end of file diff --git a/apihost/Tnb.API.Entry/Extensions/ConfigureSqlSugarExtensions.cs b/apihost/Tnb.API.Entry/Extensions/ConfigureSqlSugarExtensions.cs index 3b269846..7f7378b4 100644 --- a/apihost/Tnb.API.Entry/Extensions/ConfigureSqlSugarExtensions.cs +++ b/apihost/Tnb.API.Entry/Extensions/ConfigureSqlSugarExtensions.cs @@ -23,7 +23,7 @@ public static class ConfigureSqlSugarExtensions // 默认数据库 connectConfigList.Add(new ConnectionConfig { - ConnectionString = string.Format(conn.DefaultConnection, conn.Host, conn.Port, conn.DBName, conn.UserName, conn.Password), + ConnectionString = conn.ConnectString, DbType = DBType, IsAutoCloseConnection = true, ConfigId = conn.ConfigId, @@ -62,10 +62,9 @@ public static class ConfigureSqlSugarExtensions //}; }); }); + services.AddUnitOfWork(); services.AddConfigurableOptions(); services.AddConfigurableOptions(); - services.AddUnitOfWork(); - return services; } diff --git a/apihost/Tnb.API.Entry/Program.cs b/apihost/Tnb.API.Entry/Program.cs index 6b43488e..5dfadd09 100644 --- a/apihost/Tnb.API.Entry/Program.cs +++ b/apihost/Tnb.API.Entry/Program.cs @@ -7,15 +7,15 @@ public class WebComponent : IWebComponent { public void Load(WebApplicationBuilder builder, ComponentContext componentContext) { - //// ־ + builder.Host.UseWindowsService(); + //// 日志过滤 //builder.Logging.AddFilter((provider, category, logLevel) => //{ // return !new[] { "Microsoft.Hosting", "Microsoft.AspNetCore" }.Any(u => category.StartsWith(u)) && logLevel >= LogLevel.Information; //}); - builder.Host.UseWindowsService(); builder.WebHost.ConfigureKestrel(options => { - // òҪ null + // 长度最好不要设置 null options.Limits.MaxRequestBodySize = 52428800; }); diff --git a/apihost/Tnb.API.Entry/Startup.cs b/apihost/Tnb.API.Entry/Startup.cs index ff4902ac..f8da43b2 100644 --- a/apihost/Tnb.API.Entry/Startup.cs +++ b/apihost/Tnb.API.Entry/Startup.cs @@ -1,6 +1,7 @@ using IGeekFan.AspNetCore.Knife4jUI; using JNPF.API.Entry.Handlers; using JNPF.Common.Cache; +using JNPF.Common.Core; using JNPF.Common.Core.Filter; using JNPF.Common.Core.Handlers; using JNPF.Common.Security; @@ -26,87 +27,88 @@ namespace JNPF.API.Entry; public class Startup : AppStartup { - public void ConfigureServices(IServiceCollection services) - { - services.ConfigureMvcController(); - - // SqlSugar - //services.SqlSugarConfigure(); - services.ConfigureSqlSugar(); - - // 注册EventBus服务 - services.ConfigureEventBus(); - - // 注册远程请求 - services.AddRemoteRequest(); - - // 视图引擎 - services.AddViewEngine(); - - // 任务调度 - services.AddTaskScheduler(); - - // 脱敏词汇检测 - services.AddSensitiveDetection(); - - // WebSocket服务 - services.AddWebSocketManager(); - - // 微信 - services.AddSenparcGlobalServices(App.Configuration) // Senparc.CO2NET 全局注册 - .AddSenparcWeixinServices(App.Configuration); // Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加) - - services.ConfigureLogging(); - services.ConfigureOSSService(); - - services.AddSchedule(); - - services.AddOverideVisualDev(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider, IOptions senparcSetting, IOptions senparcWeixinSetting) - { - // 添加状态码拦截中间件 - app.UseUnifyResultStatusCodes(); - - // app.UseHttpsRedirection(); // 强制https - app.UseStaticFiles(); - - #region 微信 - IRegisterService register = RegisterService.Start(senparcSetting.Value).UseSenparcGlobal();//启动 CO2NET 全局注册,必须! - register.UseSenparcWeixin(senparcWeixinSetting.Value, senparcSetting.Value);//微信全局注册,必须! - #endregion - - app.UseWebSockets(); - - app.UseRouting(); - - app.UseCorsAccessor(); - - app.UseAuthentication(); - app.UseAuthorization(); - - app.UseKnife4UI(options => + public void ConfigureServices(IServiceCollection services) { - options.RoutePrefix = "newapi"; // 配置 Knife4UI 路由地址,现在是 /newapi - foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups()) - { - options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title); - } - }); + // 注册和配置Mvc和api服务 + services.ConfigureMvcController(); - app.UseInject(string.Empty); + // 注册和配置SqlSugar + services.ConfigureSqlSugar(); - //app.MapWebSocketManager("/api/message/websocket", serviceProvider.GetService()); - app.MapWebSocketManager("/websocket", serviceProvider.GetRequiredService()); + // 注册EventBus服务 + services.ConfigureEventBus(); - app.UseEndpoints(endpoints => + // 注册和配置日志服务 + services.ConfigureLogging(); + + // 注册和配置存储服务 + services.ConfigureOSSService(); + + // 任务调度 + //services.AddSchedule(options => + //{ + // options.AddPersistence(); + //}); + + // 任务调度 + services.AddTaskScheduler(); + + services.AddMemoryCache(); // 使用本地缓存必须添加 + services.AddConfigurableOptions(); + + // 微信 + services.AddSenparcGlobalServices(App.Configuration) // Senparc.CO2NET 全局注册 + .AddSenparcWeixinServices(App.Configuration); // Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加) + + services.AddOverideVisualDev(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider, IOptions senparcSetting, IOptions senparcWeixinSetting) { - endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); - }); + // 添加状态码拦截中间件 + app.UseUnifyResultStatusCodes(); - SnowflakeIdHelper.InitYitIdWorker(); + // app.UseHttpsRedirection(); // 强制https + app.UseStaticFiles(); - //serviceProvider.GetRequiredService().StartTimerJob(); - } + #region 微信 + IRegisterService register = RegisterService.Start(senparcSetting.Value).UseSenparcGlobal();//启动 CO2NET 全局注册,必须! + register.UseSenparcWeixin(senparcWeixinSetting.Value, senparcSetting.Value);//微信全局注册,必须! + #endregion + + app.UseWebSockets(); + + app.UseRouting(); + + app.UseCorsAccessor(); + + app.UseAuthentication(); + app.UseAuthorization(); + + // 任务调度看板 + app.UseScheduleUI(); + + app.UseKnife4UI(options => + { + options.RoutePrefix = "newapi"; // 配置 Knife4UI 路由地址,现在是 /newapi + foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups()) + { + options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title); + } + }); + + app.UseInject(string.Empty); + + //app.MapWebSocketManager("/api/message/websocket", serviceProvider.GetService()); + app.MapWebSocketManager("/websocket", serviceProvider.GetRequiredService()); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); + }); + + SnowflakeIdHelper.InitYitIdWorker(); + + //serviceProvider.GetRequiredService().StartTimerJob(); + } } \ No newline at end of file diff --git a/common/Tnb.CollectiveOAuth/Enums/EnumHelper/EnumExtensions.cs b/common/Tnb.CollectiveOAuth/Enums/EnumHelper/EnumExtensions.cs index ec0ecded..0fee4d6c 100644 --- a/common/Tnb.CollectiveOAuth/Enums/EnumHelper/EnumExtensions.cs +++ b/common/Tnb.CollectiveOAuth/Enums/EnumHelper/EnumExtensions.cs @@ -112,7 +112,7 @@ public static class EnumExtensions { if (field.FieldType.IsEnum) { - strValue = ((int?)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null)).ToString(); + strValue = ((int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null)).ToString(); object[] arr = field.GetCustomAttributes(typeDescription, true); if (arr.Length > 0) { diff --git a/common/Tnb.CollectiveOAuth/Tnb.CollectiveOAuth.csproj b/common/Tnb.CollectiveOAuth/Tnb.CollectiveOAuth.csproj index 015ae7e0..8a42c1fd 100644 --- a/common/Tnb.CollectiveOAuth/Tnb.CollectiveOAuth.csproj +++ b/common/Tnb.CollectiveOAuth/Tnb.CollectiveOAuth.csproj @@ -11,7 +11,6 @@ - diff --git a/common/Tnb.Common.Core/EventBus/EventBusOptions.cs b/common/Tnb.Common.Core/EventBus/EventBusOptions.cs new file mode 100644 index 00000000..c77b2a65 --- /dev/null +++ b/common/Tnb.Common.Core/EventBus/EventBusOptions.cs @@ -0,0 +1,55 @@ +using JNPF.ConfigurableOptions; + +namespace JNPF.Common.Core; + +/// +/// 事件总线配置. +/// +public class EventBusOptions : IConfigurableOptions +{ + /// + /// 事件总线类型. + /// + public EventBusType EventBusType { get; set; } + + /// + /// 服务器地址. + /// + public string HostName { get; set; } + + /// + /// 账号. + /// + public string UserName { get; set; } + + /// + /// 密码. + /// + public string Password { get; set; } +} + +/// +/// 事件总线自定义事件源存储器类型. +/// +public enum EventBusType +{ + /// + /// 内存. + /// + Memory, + + /// + /// RabbitMQ. + /// + RabbitMQ, + + /// + /// Redis. + /// + Redis, + + /// + /// Kafka. + /// + Kafka, +} \ No newline at end of file diff --git a/common/Tnb.Common.Core/EventBus/LogEventSubscriber.cs b/common/Tnb.Common.Core/EventBus/LogEventSubscriber.cs index 6ef1575c..a9a47d5c 100644 --- a/common/Tnb.Common.Core/EventBus/LogEventSubscriber.cs +++ b/common/Tnb.Common.Core/EventBus/LogEventSubscriber.cs @@ -42,7 +42,7 @@ public class LogEventSubscriber : IEventSubscriber, ISingleton _sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId); } - await _sqlSugarClient.Insertable(log.Entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync(); + await _sqlSugarClient.CopyNew().Insertable(log.Entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync(); } /// @@ -61,6 +61,6 @@ public class LogEventSubscriber : IEventSubscriber, ISingleton _sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId); } - await _sqlSugarClient.Insertable(log.Entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync(); + await _sqlSugarClient.CopyNew().Insertable(log.Entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync(); } } \ No newline at end of file diff --git a/common/Tnb.Common.Core/EventBus/Sources/TaskEventSource.cs b/common/Tnb.Common.Core/EventBus/Sources/TaskEventSource.cs index c54b727c..f4217a6d 100644 --- a/common/Tnb.Common.Core/EventBus/Sources/TaskEventSource.cs +++ b/common/Tnb.Common.Core/EventBus/Sources/TaskEventSource.cs @@ -1,5 +1,5 @@ -using JNPF.Systems.Entitys.System; -using JNPF.EventBus; +using JNPF.EventBus; +using JNPF.TaskScheduler.Entitys; using SqlSugar; namespace JNPF.EventHandler; diff --git a/common/Tnb.Common.Core/EventBus/Sources/TaskLogEventSource.cs b/common/Tnb.Common.Core/EventBus/Sources/TaskLogEventSource.cs index b0754aef..90d3c0dc 100644 --- a/common/Tnb.Common.Core/EventBus/Sources/TaskLogEventSource.cs +++ b/common/Tnb.Common.Core/EventBus/Sources/TaskLogEventSource.cs @@ -1,5 +1,5 @@ -using JNPF.Systems.Entitys.System; -using JNPF.EventBus; +using JNPF.EventBus; +using JNPF.TaskScheduler.Entitys; using SqlSugar; namespace JNPF.EventHandler; diff --git a/common/Tnb.Common.Core/EventBus/Storers/RabbitMQEventSourceStorer.cs b/common/Tnb.Common.Core/EventBus/Storers/RabbitMQEventSourceStorer.cs index 7847fc4e..016b366e 100644 --- a/common/Tnb.Common.Core/EventBus/Storers/RabbitMQEventSourceStorer.cs +++ b/common/Tnb.Common.Core/EventBus/Storers/RabbitMQEventSourceStorer.cs @@ -1,4 +1,5 @@ -using JNPF.Common.Security; +using JNPF.Common.Extension; +using JNPF.Common.Security; using JNPF.EventBus; using JNPF.Logging; using RabbitMQ.Client; @@ -59,8 +60,6 @@ public sealed class RabbitMQEventSourceStorer : IEventSourceStorer, IDisposable // 创建通道 _model = _connection.CreateModel(); - string ExchangeName = "MXK_IDENTITY_MAIN_TOPIC"; - /* * 声明路由队列 * 队列可以重复声明,但是声明所使用的参数必须一致,否则会抛出异常 @@ -77,7 +76,7 @@ public sealed class RabbitMQEventSourceStorer : IEventSourceStorer, IDisposable _model.QueueDeclare(queue: routeKey, durable: false, exclusive: false, autoDelete: false, arguments: null); // 将MaxKey 交换机绑定到 路由中 - _model.QueueBind(queue: routeKey, exchange: ExchangeName, routingKey: "#"); + // _model.QueueBind(queue: routeKey, exchange: "MXK_IDENTITY_MAIN_TOPIC", routingKey: "#"); // 字节限制,一次接收的消息数,全局/ // 据说prefetchSize 和global这两项,rabbitmq没有实现,暂且不研究 @@ -95,6 +94,9 @@ public sealed class RabbitMQEventSourceStorer : IEventSourceStorer, IDisposable // 转换为 IEventSource,这里可以选择自己喜欢的序列化工具,如果自定义了 EventSource,注意属性是可读可写 var eventSource = JsonSerializer.Deserialize(stringEventSource); + // 判断到是单点登录服务端信息 + if (eventSource.EventId.IsNullOrEmpty()) eventSource = new ChannelEventSource("User:Maxkey_Identity", stringEventSource); + Log.Information($"- 接收到消息:{eventSource.ToJsonString()}"); // 写入内存管道存储器 @@ -105,7 +107,7 @@ public sealed class RabbitMQEventSourceStorer : IEventSourceStorer, IDisposable }; // 启动消费者 设置为手动应答消息 - _model.BasicConsume(queue: routeKey, autoAck: true, consumer: consumer); + _model.BasicConsume(queue: routeKey, autoAck: false, consumer: consumer); } /// @@ -122,7 +124,7 @@ public sealed class RabbitMQEventSourceStorer : IEventSourceStorer, IDisposable throw new ArgumentNullException(nameof(eventSource)); } - // 这里判断是否是 ChannelEventSource 或者 自定义的 EventSouce + // 这里判断是否是 ChannelEventSource 或者 自定义的 EventSource if (eventSource is ChannelEventSource source) { // 序列化,这里可以选择自己喜欢的序列化工具 @@ -146,7 +148,8 @@ public sealed class RabbitMQEventSourceStorer : IEventSourceStorer, IDisposable public async ValueTask ReadAsync(CancellationToken cancellationToken) { // 读取一条事件源 - return await _channel.Reader.ReadAsync(cancellationToken); + var eventSource = await _channel.Reader.ReadAsync(cancellationToken); + return eventSource; } /// diff --git a/common/Tnb.Common.Core/EventBus/TaskEventSubscriber.cs b/common/Tnb.Common.Core/EventBus/TaskEventSubscriber.cs index de71532f..5f0ceb4f 100644 --- a/common/Tnb.Common.Core/EventBus/TaskEventSubscriber.cs +++ b/common/Tnb.Common.Core/EventBus/TaskEventSubscriber.cs @@ -1,7 +1,7 @@ using JNPF.Common.Configuration; using JNPF.DependencyInjection; using JNPF.EventBus; -using JNPF.Systems.Entitys.System; +using JNPF.TaskScheduler.Entitys; using SqlSugar; namespace JNPF.EventHandler; @@ -40,7 +40,7 @@ public class TaskEventSubscriber : IEventSubscriber, ISingleton _sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId); } - await _sqlSugarClient.Updateable().SetColumns(x => new TimeTaskEntity() + await _sqlSugarClient.CopyNew().Updateable().SetColumns(x => new TimeTaskEntity() { RunCount = x.RunCount + 1, LastRunTime = DateTime.Now, diff --git a/common/Tnb.Common.Core/EventBus/UserEventSubscriber.cs b/common/Tnb.Common.Core/EventBus/UserEventSubscriber.cs index 2eee34be..ee1becc0 100644 --- a/common/Tnb.Common.Core/EventBus/UserEventSubscriber.cs +++ b/common/Tnb.Common.Core/EventBus/UserEventSubscriber.cs @@ -1,6 +1,7 @@ using JNPF.Common.Configuration; using JNPF.DependencyInjection; using JNPF.EventBus; +using JNPF.Systems.Interfaces.Permission; using SqlSugar; namespace JNPF.EventHandler; @@ -15,12 +16,20 @@ public class UserEventSubscriber : IEventSubscriber, ISingleton /// private static SqlSugarScope? _sqlSugarClient; + /// + /// 用户服务. + /// + private readonly IUsersService _usersService; + /// /// 构造函数. /// - public UserEventSubscriber(ISqlSugarClient context) + public UserEventSubscriber( + ISqlSugarClient context, + IUsersService usersService) { _sqlSugarClient = (SqlSugarScope)context; + _usersService = usersService; } /// @@ -39,7 +48,7 @@ public class UserEventSubscriber : IEventSubscriber, ISingleton _sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId); } - await _sqlSugarClient.Updateable(log.Entity).UpdateColumns(m => new { m.FirstLogIP, m.FirstLogTime, m.PrevLogTime, m.PrevLogIP, m.LastLogTime, m.LastLogIP, m.LogSuccessCount }).ExecuteCommandAsync(); + await _sqlSugarClient.CopyNew().Updateable(log.Entity).UpdateColumns(m => new { m.FirstLogIP, m.FirstLogTime, m.PrevLogTime, m.PrevLogIP, m.LastLogTime, m.LastLogIP, m.LogSuccessCount }).ExecuteCommandAsync(); } /// @@ -47,9 +56,10 @@ public class UserEventSubscriber : IEventSubscriber, ISingleton /// /// /// - [EventSubscribe("User:maxkey_identity")] + [EventSubscribe("User:Maxkey_Identity")] public async Task ReceiveUserInfo(EventHandlerExecutingContext context) { - var log = (UserEventSource)context.Source; + var log = context.Source.Payload; + await _usersService.Receive(log.ToString()); } } \ No newline at end of file diff --git a/common/Tnb.Common.Core/Filter/LogExceptionHandler.cs b/common/Tnb.Common.Core/Filter/LogExceptionHandler.cs index 3160111c..2c019ac4 100644 --- a/common/Tnb.Common.Core/Filter/LogExceptionHandler.cs +++ b/common/Tnb.Common.Core/Filter/LogExceptionHandler.cs @@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Mvc.Filters; using JNPF.Systems.Entitys.System; using System.Security.Claims; using SqlSugar; -using MimeKit; namespace JNPF.Common.Core.Filter; @@ -21,58 +20,57 @@ namespace JNPF.Common.Core.Filter; /// public class LogExceptionHandler : IGlobalExceptionHandler, ISingleton { - private readonly IEventPublisher _eventPublisher; + private readonly IEventPublisher _eventPublisher; - public LogExceptionHandler(IEventPublisher eventPublisher) - { - _eventPublisher = eventPublisher; - } - - /// - /// 异步写入异常日记. - /// - /// - /// - public async Task OnExceptionAsync(ExceptionContext context) - { - var userContext = App.User; - var httpContext = context.HttpContext; - var httpRequest = httpContext?.Request; - var headers = httpRequest?.Headers; - UserAgent userAgent = new UserAgent(httpContext); - - if (!context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(IgnoreLogAttribute))) + public LogExceptionHandler(IEventPublisher eventPublisher) { - ConnectionConfigOptions options = userContext?.FindFirstValue(ClaimConst.CONNECTIONCONFIG)?.ToObject(); - string userId = userContext?.FindFirstValue(ClaimConst.CLAINMUSERID); - string userName = userContext?.FindFirstValue(ClaimConst.CLAINMREALNAME); - - if (!App.HttpContext.Request.Headers.ContainsKey("Authorization")) - { - var bearer = App.HttpContext.Request.QueryString.Value.Matches(@"[?&]token=Bearer%20([\w\.-]+)($|&)"); - if (bearer.Count() > 0) - { - string token = bearer.Last(); - IEnumerable claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims; - options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject(); - userId = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMUSERID)?.Value; - userName = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMREALNAME)?.Value; - } - } - - await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateExLog", options, new SysLogEntity - { - Id = SnowflakeIdHelper.NextId(), - UserId = userId, - UserName = userName, - Category = 4, - IPAddress = NetHelper.Ip, - RequestURL = httpRequest.Path, - RequestMethod = httpRequest.Method, - Json = context.Exception.Message + "\n" + context.Exception.StackTrace + "\n" + context.Exception.TargetSite.GetParameters().ToString(), - PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue), - CreatorTime = DateTime.Now - })); + _eventPublisher = eventPublisher; + } + + /// + /// 异步写入异常日记. + /// + /// + /// + public async Task OnExceptionAsync(ExceptionContext context) + { + var userContext = App.User; + var httpContext = context.HttpContext; + var httpRequest = httpContext?.Request; + var headers = httpRequest?.Headers; + UserAgent userAgent = new UserAgent(httpContext); + + if (!context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(IgnoreLogAttribute))) + { + ConnectionConfigOptions options = userContext?.FindFirstValue(ClaimConst.CONNECTIONCONFIG)?.ToObject(); + string userId = userContext?.FindFirstValue(ClaimConst.CLAINMUSERID); + string userName = userContext?.FindFirstValue(ClaimConst.CLAINMREALNAME); + + if (!App.HttpContext.Request.Headers.ContainsKey("Authorization")) + { + string token = App.HttpContext.Request.QueryString.Value.Matches(@"[?&]token=Bearer%20([\w\.-]+)($|&)").LastOrDefault(); + if (!string.IsNullOrEmpty(token)) + { + IEnumerable claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims; + options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject(); + userId = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMUSERID)?.Value; + userName = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMREALNAME)?.Value; + } + } + + await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateExLog", options, new SysLogEntity + { + Id = SnowflakeIdHelper.NextId(), + UserId = userId, + UserName = userName, + Category = 4, + IPAddress = NetHelper.Ip, + RequestURL = httpRequest.Path, + RequestMethod = httpRequest.Method, + Json = context.Exception.Message + "\n" + context.Exception.StackTrace + "\n" + context.Exception.TargetSite.GetParameters().ToString(), + PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue), + CreatorTime = DateTime.Now + })); + } } - } } \ No newline at end of file diff --git a/common/Tnb.Common.Core/Filter/RequestActionFilter.cs b/common/Tnb.Common.Core/Filter/RequestActionFilter.cs index 9fdaa517..10cb0f5d 100644 --- a/common/Tnb.Common.Core/Filter/RequestActionFilter.cs +++ b/common/Tnb.Common.Core/Filter/RequestActionFilter.cs @@ -22,93 +22,92 @@ namespace JNPF.Common.Core.Filter; /// public class RequestActionFilter : IAsyncActionFilter { - private readonly IEventPublisher _eventPublisher; + private readonly IEventPublisher _eventPublisher; - public RequestActionFilter(IEventPublisher eventPublisher) - { - _eventPublisher = eventPublisher; - } - - /// - /// 请求日记写入. - /// - /// - /// - /// - public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) - { - var userContext = App.User; - var httpContext = context.HttpContext; - var httpRequest = httpContext.Request; - UserAgent userAgent = new UserAgent(httpContext); - var actionDes = (ControllerActionDescriptor)context.ActionDescriptor; - var actionName = $"{actionDes.ControllerTypeInfo.FullName}.{actionDes.MethodInfo.Name}"; - var ignoreLog = actionDes.EndpointMetadata.Any(m => m.GetType() == typeof(IgnoreLogAttribute)); - - Stopwatch sw = new Stopwatch(); - if (!ignoreLog) Log.Information("Action Starting: {0}({1})", actionName, context.ActionArguments.ToJsonString()); - sw.Start(); - var actionContext = await next(); - sw.Stop(); - // 判断是否请求成功(没有异常就是请求成功) - var isRequestSucceed = actionContext.Exception == null; - //var headers = httpRequest.Headers; - if (!ignoreLog && isRequestSucceed) + public RequestActionFilter(IEventPublisher eventPublisher) { - Log.Information("Action Finished: {0}() - Elapsed: {1:F2}ms", actionName, sw.ElapsedMilliseconds); - ConnectionConfigOptions options = userContext?.FindFirstValue(ClaimConst.CONNECTIONCONFIG)?.ToObject(); - var userId = userContext?.FindFirstValue(ClaimConst.CLAINMUSERID); - var userName = userContext?.FindFirstValue(ClaimConst.CLAINMREALNAME); - if (!App.HttpContext.Request.Headers.ContainsKey("Authorization")) - { - var bearer = App.HttpContext.Request.QueryString.Value.Matches(@"[?&]token=Bearer%20([\w\.-]+)($|&)"); - if (bearer.Count() > 0) - { - string token = bearer.Last(); - IEnumerable claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims; - options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject(); - userId = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMUSERID)?.Value; - userName = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMREALNAME)?.Value; - } - } - - await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateReLog", options, new SysLogEntity - { - Id = SnowflakeIdHelper.NextId(), - UserId = userId, - UserName = userName, - Category = 5, - IPAddress = NetHelper.Ip, - RequestURL = httpRequest.Path, - RequestDuration = (int)sw.ElapsedMilliseconds, - RequestMethod = httpRequest.Method, - PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue), - CreatorTime = DateTime.Now - })); - - var module = actionDes.EndpointMetadata.Where(x => x.GetType() == typeof(OperateLogAttribute)).FirstOrDefault() as OperateLogAttribute; - if (module != null) - { - // 操作参数 - var args = context.ActionArguments.ToJsonString(); - var result = (actionContext.Result as JsonResult)?.Value; - - await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateOpLog", options, new SysLogEntity - { - Id = SnowflakeIdHelper.NextId(), - UserId = userId, - UserName = userName, - Category = 3, - IPAddress = NetHelper.Ip, - RequestURL = httpRequest.Path, - RequestDuration = (int)sw.ElapsedMilliseconds, - RequestMethod = module.Action, - PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue), - CreatorTime = DateTime.Now, - ModuleName = module.ModuleName, - Json = string.Format("{0}应用【{1}】【{2}】", module.Action, args, result?.ToJsonString()) - })); - } + _eventPublisher = eventPublisher; + } + + /// + /// 请求日记写入. + /// + /// + /// + /// + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var userContext = App.User; + var httpContext = context.HttpContext; + var httpRequest = httpContext.Request; + UserAgent userAgent = new UserAgent(httpContext); + var actionDes = (ControllerActionDescriptor)context.ActionDescriptor; + var actionName = $"{actionDes.ControllerTypeInfo.FullName}.{actionDes.MethodInfo.Name}"; + var ignoreLog = actionDes.EndpointMetadata.Any(m => m.GetType() == typeof(IgnoreLogAttribute)); + + Stopwatch sw = new Stopwatch(); + if (!ignoreLog) Log.Information("Action Starting: {0}({1})", actionName, context.ActionArguments.ToJsonString()); + sw.Start(); + var actionContext = await next(); + sw.Stop(); + // 判断是否请求成功(没有异常就是请求成功) + var isRequestSucceed = actionContext.Exception == null; + //var headers = httpRequest.Headers; + if (!ignoreLog && isRequestSucceed) + { + Log.Information("Action Finished: {0}() - Elapsed: {1:F2}ms", actionName, sw.ElapsedMilliseconds); + ConnectionConfigOptions options = userContext?.FindFirstValue(ClaimConst.CONNECTIONCONFIG)?.ToObject(); + var userId = userContext?.FindFirstValue(ClaimConst.CLAINMUSERID); + var userName = userContext?.FindFirstValue(ClaimConst.CLAINMREALNAME); + if (!App.HttpContext.Request.Headers.ContainsKey("Authorization")) + { + var token = App.HttpContext.Request.QueryString.Value.Matches(@"[?&]token=Bearer%20([\w\.-]+)($|&)").LastOrDefault(); + if (!string.IsNullOrEmpty(token)) + { + IEnumerable claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims; + options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject(); + userId = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMUSERID)?.Value; + userName = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMREALNAME)?.Value; + } + } + + await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateReLog", options, new SysLogEntity + { + Id = SnowflakeIdHelper.NextId(), + UserId = userId, + UserName = userName, + Category = 5, + IPAddress = NetHelper.Ip, + RequestURL = httpRequest.Path, + RequestDuration = (int)sw.ElapsedMilliseconds, + RequestMethod = httpRequest.Method, + PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue), + CreatorTime = DateTime.Now + })); + + var module = actionDes.EndpointMetadata.Where(x => x.GetType() == typeof(OperateLogAttribute)).FirstOrDefault() as OperateLogAttribute; + if (module != null) + { + // 操作参数 + var args = context.ActionArguments.ToJsonString(); + var result = (actionContext.Result as JsonResult)?.Value; + + await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateOpLog", options, new SysLogEntity + { + Id = SnowflakeIdHelper.NextId(), + UserId = userId, + UserName = userName, + Category = 3, + IPAddress = NetHelper.Ip, + RequestURL = httpRequest.Path, + RequestDuration = (int)sw.ElapsedMilliseconds, + RequestMethod = module.Action, + PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue), + CreatorTime = DateTime.Now, + ModuleName = module.ModuleName, + Json = string.Format("{0}应用【{1}】【{2}】", module.Action, args, result?.ToJsonString()) + })); + } + } } - } } \ No newline at end of file diff --git a/common/Tnb.Common.Core/Handlers/IMHandler.cs b/common/Tnb.Common.Core/Handlers/IMHandler.cs index 06c30585..1e8e5bba 100644 --- a/common/Tnb.Common.Core/Handlers/IMHandler.cs +++ b/common/Tnb.Common.Core/Handlers/IMHandler.cs @@ -1,6 +1,4 @@ -using System.Net.Sockets; -using System.Net.WebSockets; -using Aop.Api.Domain; +using System.Net.WebSockets; using JNPF.Common.Configuration; using JNPF.Common.Const; using JNPF.Common.Enums; @@ -76,6 +74,7 @@ public class IMHandler : WebSocketHandler client.LoginIpAddress = client.LoginIpAddress; client.Token = message.token; client.IsMobileDevice = message.mobileDevice; + client.onlineTicket = claims.FirstOrDefault(e => e.Type == ClaimConst.OnlineTicket)?.Value; if (client.WebSocket.State != WebSocketState.Open) return; await OnConnected(client.ConnectionId, client); WebSocketConnectionManager.AddToTenant(client.ConnectionId, client.ConnectionConfig?.ConfigId); @@ -177,7 +176,8 @@ public class IMHandler : WebSocketHandler tenantId = client.ConnectionConfig.ConfigId, lastLoginPlatForm = client.LoginPlatForm, isMobileDevice = client.IsMobileDevice, - token = message.token + token = message.token, + onlineTicket = client.onlineTicket }); await SetOnlineUserList(client.ConnectionConfig.ConfigId, list); } @@ -201,7 +201,8 @@ public class IMHandler : WebSocketHandler tenantId = client.ConnectionConfig.ConfigId, lastLoginPlatForm = client.LoginPlatForm, isMobileDevice = client.IsMobileDevice, - token = message.token + token = message.token, + onlineTicket = client.onlineTicket }); await SetOnlineUserList(client.ConnectionConfig.ConfigId, list); } @@ -230,7 +231,8 @@ public class IMHandler : WebSocketHandler tenantId = client.ConnectionConfig.ConfigId, lastLoginPlatForm = client.LoginPlatForm, isMobileDevice = client.IsMobileDevice, - token = message.token + token = message.token, + onlineTicket = client.onlineTicket }); await SetOnlineUserList(client.ConnectionConfig.ConfigId, list); @@ -263,10 +265,11 @@ public class IMHandler : WebSocketHandler } var unreadNoticeCount = await _sqlSugarClient.Queryable((m, mr) => new JoinQueryInfos(JoinType.Left, m.Id == mr.MessageId)).Where((m, mr) => m.Type == 1 && m.DeleteMark == null && mr.UserId == client.UserId && mr.IsRead == 0).Select((m, mr) => new { mr.Id, mr.UserId, mr.IsRead, m.Type, m.DeleteMark }).CountAsync(); var unreadMessageCount = await _sqlSugarClient.Queryable((m, mr) => new JoinQueryInfos(JoinType.Left, m.Id == mr.MessageId)).Select((m, mr) => new { mr.Id, mr.UserId, mr.IsRead, m.Type, m.DeleteMark }).MergeTable().Where(x => x.Type == 2 && x.DeleteMark == null && x.UserId == client.UserId && x.IsRead == 0).CountAsync(); - var messageDefault = await _sqlSugarClient.Queryable().Where(x => x.DeleteMark == null && x.EnabledMark == 1).OrderBy(x => x.CreatorTime, OrderByType.Desc).FirstAsync(); + var unreadSystemMessageCount = await _sqlSugarClient.Queryable((m, mr) => new JoinQueryInfos(JoinType.Left, m.Id == mr.MessageId)).Select((m, mr) => new { mr.Id, mr.UserId, mr.IsRead, m.Type, m.DeleteMark }).MergeTable().Where(x => x.Type == 3 && x.DeleteMark == null && x.UserId == client.UserId && x.IsRead == 0).CountAsync(); + var messageDefault = await _sqlSugarClient.Queryable((m, mr) => new JoinQueryInfos(JoinType.Left, m.Id == mr.MessageId)).Where((m, mr) => m.DeleteMark == null && mr.UserId == client.UserId).OrderBy((m, mr) => m.LastModifyTime, OrderByType.Desc).FirstAsync(); var messageDefaultText = messageDefault == null ? string.Empty : messageDefault.Title; var messageDefaultTime = messageDefault == null ? DateTime.Now : messageDefault.CreatorTime; - await SendMessageAsync(client.ConnectionId, new { method = MessageSendType.initMessage.ToString(), onlineUserList, unreadNums, unreadNoticeCount, unreadMessageCount, messageDefaultText, messageDefaultTime }.ToJsonString()); + await SendMessageAsync(client.ConnectionId, new { method = MessageSendType.initMessage.ToString(), onlineUserList, unreadNums, unreadNoticeCount, unreadMessageCount, messageDefaultText, messageDefaultTime, unreadSystemMessageCount }.ToJsonString()); await SendMessageToTenantAsync(client.ConnectionConfig.ConfigId, new { method = MessageSendType.online.ToString(), userId = client.UserId }.ToJsonString(), client.ConnectionId); } diff --git a/common/Tnb.Common.Core/Job/DbJobPersistence.cs b/common/Tnb.Common.Core/Job/DbJobPersistence.cs new file mode 100644 index 00000000..e4b0d60d --- /dev/null +++ b/common/Tnb.Common.Core/Job/DbJobPersistence.cs @@ -0,0 +1,199 @@ +using JNPF.Schedule; +using JNPF.TaskScheduler.Entitys; +using JNPF.TaskScheduler.Entitys.Enum; +using Mapster; +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; + +namespace JNPF.Common.Core; + +/// +/// 作业持久化(数据库). +/// +public class DbJobPersistence : IJobPersistence +{ + private readonly IServiceScopeFactory _serviceScopeFactory; + + public DbJobPersistence(IServiceScopeFactory serviceScopeFactory) + { + _serviceScopeFactory = serviceScopeFactory; + } + + /// + /// 作业调度服务启动时. + /// + /// + public IEnumerable Preload() + { + using var scope = _serviceScopeFactory.CreateScope(); + var sqlSugarClient = scope.ServiceProvider.GetRequiredService(); + + // 获取到对应库连接 + var sqlSugarScope = sqlSugarClient.AsTenant().GetConnectionScopeWithAttr(); + var dynamicJobCompiler = scope.ServiceProvider.GetRequiredService(); + + // 获取所有定义的作业 + var allJobs = App.EffectiveTypes.ScanToBuilders().ToList(); + + //// 若数据库不存在任何作业,则直接返回 + if (!sqlSugarScope.Queryable().Any(u => true)) return allJobs; + + // 遍历所有定义的作业 + foreach (var schedulerBuilder in allJobs) + { + // 获取作业信息构建器 + var jobBuilder = schedulerBuilder.GetJobBuilder(); + + // 加载数据库数据 + var dbDetail = sqlSugarScope.Queryable().First(u => u.JobId == jobBuilder.JobId); + if (dbDetail == null) continue; + + // 同步数据库数据 + jobBuilder.LoadFrom(dbDetail); + + // 获取作业的所有数据库的触发器 + var dbTriggers = sqlSugarScope.Queryable().Where(u => u.JobId == jobBuilder.JobId).ToArray(); + + // 遍历所有作业触发器 + foreach (var (_, triggerBuilder) in schedulerBuilder.GetEnumerable()) + { + // 加载数据库数据 + var dbTrigger = dbTriggers.FirstOrDefault(u => u.JobId == jobBuilder.JobId && u.TriggerId == triggerBuilder.TriggerId); + if (dbTrigger == null) continue; + + triggerBuilder.LoadFrom(dbTrigger).Updated(); // 标记更新 + } + + // 遍历所有非编译时定义的触发器加入到作业中 + foreach (var dbTrigger in dbTriggers) + { + if (schedulerBuilder.GetTriggerBuilder(dbTrigger.TriggerId)?.JobId == jobBuilder.JobId) continue; + var triggerBuilder = TriggerBuilder.Create(dbTrigger.TriggerId).LoadFrom(dbTrigger); + schedulerBuilder.AddTriggerBuilder(triggerBuilder); // 先添加 + triggerBuilder.Updated(); // 再标记更新 + } + + // 标记更新 + schedulerBuilder.Updated(); + } + + // 获取数据库所有通过脚本创建的作业 + var allDbScriptJobs = sqlSugarScope.Queryable().Where(u => u.CreateType != RequestTypeEnum.BuiltIn).ToList(); + foreach (var dbDetail in allDbScriptJobs) + { + // 动态创建作业 + Type jobType; + switch (dbDetail.CreateType) + { + case RequestTypeEnum.Script: + jobType = dynamicJobCompiler.BuildJob(dbDetail.ScriptCode); + break; + + case RequestTypeEnum.Http: + jobType = typeof(HttpJob); + break; + + default: + throw new NotSupportedException(); + } + + var jobBuilder = JobBuilder.Create(jobType).LoadFrom(dbDetail); + + // 强行设置为不扫描 IJob 实现类 [Trigger] 特性触发器,否则 SchedulerBuilder.Create 会再次扫描,导致重复添加同名触发器 + jobBuilder.SetIncludeAnnotations(false); + + // 获取作业的所有数据库的触发器加入到作业中 + var dbTriggers = sqlSugarScope.Queryable().Where(u => u.JobId == jobBuilder.JobId).ToArray(); + var triggerBuilders = dbTriggers.Select(u => TriggerBuilder.Create(u.TriggerId).LoadFrom(u).Updated()); + var schedulerBuilder = SchedulerBuilder.Create(jobBuilder, triggerBuilders.ToArray()); + + // 标记更新 + schedulerBuilder.Updated(); + + allJobs.Add(schedulerBuilder); + } + + return allJobs; + } + + /// + /// 作业计划初始化通知. + /// + /// + /// + public SchedulerBuilder OnLoading(SchedulerBuilder builder) + { + return builder; + } + + /// + /// 作业计划Scheduler的JobDetail变化时. + /// + /// + public void OnChanged(PersistenceContext context) + { + using var scope = _serviceScopeFactory.CreateScope(); + var sqlSugarClient = scope.ServiceProvider.GetRequiredService(); + + // 获取到对应库连接 + var sqlSugarScope = sqlSugarClient.AsTenant().GetConnectionScopeWithAttr(); + + var jobDetail = context.JobDetail.Adapt(); + + // 忽略记载作业组 + var ignoreRecordingTasks = new List() { "schedule" }; + + if (!ignoreRecordingTasks.Contains(context.JobDetail.GroupName)) + { + switch (context.Behavior) + { + case PersistenceBehavior.Appended: + sqlSugarScope.Insertable(jobDetail).ExecuteCommand(); + break; + + case PersistenceBehavior.Updated: + sqlSugarScope.Updateable(jobDetail).WhereColumns(u => new { u.JobId }).IgnoreColumns(u => new { u.Id, u.CreateType, u.ScriptCode }).ExecuteCommand(); + break; + + case PersistenceBehavior.Removed: + sqlSugarScope.Deleteable().Where(u => u.JobId == jobDetail.JobId).ExecuteCommand(); + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + /// + /// 作业计划Scheduler的触发器Trigger变化时. + /// + /// + public void OnTriggerChanged(PersistenceTriggerContext context) + { + using var scope = _serviceScopeFactory.CreateScope(); + var sqlSugarClient = scope.ServiceProvider.GetRequiredService(); + + // 获取到对应库连接 + var sqlSugarScope = sqlSugarClient.AsTenant().GetConnectionScopeWithAttr(); + + var jobTrigger = context.Trigger.Adapt(); + switch (context.Behavior) + { + case PersistenceBehavior.Appended: + sqlSugarScope.Insertable(jobTrigger).ExecuteCommand(); + break; + + case PersistenceBehavior.Updated: + sqlSugarScope.Updateable(jobTrigger).WhereColumns(u => new { u.TriggerId, u.JobId }).IgnoreColumns(u => new { u.Id }).ExecuteCommand(); + break; + + case PersistenceBehavior.Removed: + sqlSugarScope.Deleteable().Where(u => u.TriggerId == jobTrigger.TriggerId && u.JobId == jobTrigger.JobId).ExecuteCommand(); + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } +} \ No newline at end of file diff --git a/common/Tnb.Common.Core/Job/DynamicJobCompiler.cs b/common/Tnb.Common.Core/Job/DynamicJobCompiler.cs new file mode 100644 index 00000000..a760ca3f --- /dev/null +++ b/common/Tnb.Common.Core/Job/DynamicJobCompiler.cs @@ -0,0 +1,31 @@ +using JNPF.DependencyInjection; +using JNPF.Schedule; + +namespace JNPF.Common.Core; + +/// +/// 动态作业编译. +/// +public class DynamicJobCompiler : ISingleton +{ + /// + /// 编译代码并返回其中实现 IJob 的类型. + /// + /// 动态编译的作业代码 + /// + public Type BuildJob(string script) + { + // 初始化 + NatashaInitializer.Preheating(); + + // 动态创建作业 + var builder = new AssemblyCSharpBuilder("JNPF.Common.Core") + { + Domain = DomainManagement.Random() + }; + + builder.Add(script); + + return builder.GetAssembly().GetTypes().FirstOrDefault(u => typeof(IJob).IsAssignableFrom(u)); + } +} \ No newline at end of file diff --git a/common/Tnb.Common.Core/Manager/DataBase/DataBaseManager.cs b/common/Tnb.Common.Core/Manager/DataBase/DataBaseManager.cs index e97480ee..2ce7223d 100644 --- a/common/Tnb.Common.Core/Manager/DataBase/DataBaseManager.cs +++ b/common/Tnb.Common.Core/Manager/DataBase/DataBaseManager.cs @@ -9,6 +9,7 @@ using JNPF.Common.Models; using JNPF.Common.Models.VisualDev; using JNPF.Common.Security; using JNPF.DependencyInjection; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using JNPF.FriendlyException; using JNPF.Logging; using JNPF.Systems.Entitys.Dto.Database; @@ -29,7 +30,7 @@ public class DataBaseManager : IDataBaseManager, ITransient /// /// 初始化客户端. /// - private static SqlSugarScope _sqlSugarClient; + private static SqlSugarScope? _sqlSugarClient; /// /// 用户管理器. @@ -41,17 +42,24 @@ public class DataBaseManager : IDataBaseManager, ITransient /// private readonly ConnectionStringsOptions _connectionStrings; + /// + /// 多租户配置选项. + /// + private readonly TenantOptions _tenant; + /// /// 构造函数. /// public DataBaseManager( IOptions connectionOptions, IUserManager userManager, + IOptions tenantOptions, ISqlSugarClient context) { _sqlSugarClient = (SqlSugarScope)context; _userManager = userManager; _connectionStrings = connectionOptions.Value; + _tenant = tenantOptions.Value; } /// @@ -61,46 +69,66 @@ public class DataBaseManager : IDataBaseManager, ITransient /// 切库后的SqlSugarClient. public SqlSugarScope ChangeDataBase(DbLinkEntity link) { - if (_sqlSugarClient.AsTenant().IsAnyConnection(link.Id)) + if (!"default".Equals(link.Id) && _tenant.MultiTenancyType.Equals("COLUMN")) { - _sqlSugarClient.ChangeDatabase(link.Id); + _sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == link.Id); } else { - _sqlSugarClient.AddConnection(new ConnectionConfig() + if (_sqlSugarClient.AsTenant().IsAnyConnection(link.Id)) { - ConfigId = link.Id, - DbType = ToDbType(link.DbType), - ConnectionString = ToConnectionString(link), - InitKeyType = InitKeyType.Attribute, - IsAutoCloseConnection = true - }); - var db = _sqlSugarClient.GetConnectionScope(link.Id); - - // 设置超时时间 - db.Ado.CommandTimeOut = 30; - db.Aop.OnLogExecuted = (sql, pars) => + _sqlSugarClient.ChangeDatabase(link.Id); + } + else { - var oldColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Green; - var finalSql = UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, sql, pars); - Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}——SQL执行完成】{db.Ado.SqlExecutionTime.TotalMilliseconds} ms"); - Console.WriteLine(finalSql); - Console.ForegroundColor = oldColor; - if (db.Ado.SqlExecutionTime.TotalMilliseconds > 3000) + _sqlSugarClient.AddConnection(new ConnectionConfig() { - Log.Warning($"慢查询: {db.Ado.SqlExecutionTime.TotalMilliseconds}ms, SQL: " + finalSql); + ConfigId = link.Id, + DbType = ToDbType(link.DbType), + ConnectionString = ToConnectionString(link), + InitKeyType = InitKeyType.Attribute, + IsAutoCloseConnection = true + }); + + _sqlSugarClient.Ado.CommandTimeOut = 30; + + _sqlSugarClient.Aop.OnLogExecuted = (sql, pars) => + { + var oldColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Green; + var finalSql = UtilMethods.GetSqlString(_sqlSugarClient.CurrentConnectionConfig.DbType, sql, pars); + Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}——SQL执行完成】{_sqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds} ms"); + Console.WriteLine(finalSql); + Console.ForegroundColor = oldColor; + if (_sqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds > 3000) + { + Log.Warning($"慢查询: {_sqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}ms, SQL: " + finalSql); + } + Console.WriteLine(); + }; + _sqlSugarClient.Aop.OnError = (ex) => + { + Log.Error(UtilMethods.GetSqlString(_sqlSugarClient.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres)); + }; + + if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle) + { + _sqlSugarClient.Aop.OnExecutingChangeSql = (sql, pars) => + { + if (pars != null) + { + foreach (var item in pars) + { + // 如果是DbTppe=string设置成OracleDbType.Nvarchar2 + item.IsNvarchar2 = true; + } + }; + return new KeyValuePair(sql, pars); + }; } - Console.WriteLine(); - }; - db.Aop.OnError = (ex) => - { - Log.Error(UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres)); - }; - - _sqlSugarClient.ChangeDatabase(link.Id); + _sqlSugarClient.ChangeDatabase(link.Id); + } } - return _sqlSugarClient; } @@ -141,6 +169,7 @@ public class DataBaseManager : IDataBaseManager, ITransient else flag = await _sqlSugarClient.Ado.ExecuteCommandAsync(strSql); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return flag; } @@ -155,7 +184,9 @@ public class DataBaseManager : IDataBaseManager, ITransient if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); - return _sqlSugarClient.Ado.SqlQuery(strSql).Count > 0; + var data = _sqlSugarClient.Ado.SqlQuery(strSql).Count > 0; + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -180,6 +211,7 @@ public class DataBaseManager : IDataBaseManager, ITransient { foreach (var item in dicList) flag = await _sqlSugarClient.Updateable(item).AS(table).WhereColumns(primaryField).ExecuteCommandAsync(); } + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return flag; } @@ -200,6 +232,7 @@ public class DataBaseManager : IDataBaseManager, ITransient if (string.IsNullOrEmpty(primaryField)) flag = await _sqlSugarClient.Insertable(dicList).AS(table).ExecuteReturnIdentityAsync(); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return flag; } @@ -215,6 +248,7 @@ public class DataBaseManager : IDataBaseManager, ITransient if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); CreateTable(tableModel, tableFieldList); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return true; } @@ -239,6 +273,7 @@ public class DataBaseManager : IDataBaseManager, ITransient } //if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.MySql) // AddColumnMySql(tableName, tableFieldList); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); } catch (Exception ex) { @@ -260,6 +295,7 @@ public class DataBaseManager : IDataBaseManager, ITransient try { _sqlSugarClient.DbMaintenance.DropTable(table); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return true; } catch (Exception) @@ -284,6 +320,7 @@ public class DataBaseManager : IDataBaseManager, ITransient try { CreateTable(tableModel, tableFieldList); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); } catch (Exception ex) { @@ -309,15 +346,18 @@ public class DataBaseManager : IDataBaseManager, ITransient var sidx = pageInput.sidx.IsNotEmptyOrNull() && pageInput.sort.IsNotEmptyOrNull(); // 按前端参数排序 var defaultSidx = columnDesign.defaultSidx.IsNotEmptyOrNull() && columnDesign.sort.IsNotEmptyOrNull(); // 按模板默认排序 + var dataRuleJson = new List(); + if (pageInput.dataRuleJson.IsNotEmptyOrNull()) dataRuleJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.dataRuleJson); + var querJson = new List(); if (pageInput.queryJson.IsNotEmptyOrNull()) querJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.queryJson); var superQueryJson = new List(); if (pageInput.superQueryJson.IsNotEmptyOrNull()) superQueryJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.superQueryJson); // var sql = _sqlSugarClient.SqlQueryable(strSql) - // .Where(querJson).Where(superQueryJson).Where(dataPermissions).ToSqlString(); + // .Where(dataRuleJson).Where(querJson).Where(superQueryJson).Where(dataPermissions).ToSqlString(); DataTable dt = _sqlSugarClient.SqlQueryable(strSql) - .Where(querJson).Where(superQueryJson).Where(dataPermissions) + .Where(dataRuleJson).Where(querJson).Where(superQueryJson).Where(dataPermissions) .OrderByIF(sidx, pageInput.sidx + " " + pageInput.sort).OrderByIF(!sidx && defaultSidx, columnDesign.defaultSidx + " " + columnDesign.sort) .ToDataTablePage(pageInput.currentPage, pageInput.pageSize, ref total); @@ -329,7 +369,7 @@ public class DataBaseManager : IDataBaseManager, ITransient dt.Columns[i].ColumnName = outColumnName.TryGetValue(dt.Columns[i].ColumnName.ToUpper(), out resultKey) == true ? outColumnName[dt.Columns[i].ColumnName.ToUpper()] : dt.Columns[i].ColumnName.ToUpper(); } - return new PageResult>() + var data = new PageResult>() { pagination = new PageResult() { @@ -339,6 +379,10 @@ public class DataBaseManager : IDataBaseManager, ITransient }, list = dt.ToObject>>().ToObject>>() }; + + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + + return data; //} //catch (Exception ex) //{ @@ -357,7 +401,26 @@ public class DataBaseManager : IDataBaseManager, ITransient if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); - return _sqlSugarClient.DbMaintenance.IsAnyTable(table, false); + var data = _sqlSugarClient.DbMaintenance.IsAnyTable(table, false); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + + return data; + } + + /// + /// 表是否存在数据. + /// + /// 数据连接. + /// 表名. + /// + public bool IsAnyData(DbLinkEntity link, string table) + { + if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) + _sqlSugarClient = ChangeDataBase(link); + + var data = _sqlSugarClient.Queryable().AS(table).Any(); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -372,7 +435,10 @@ public class DataBaseManager : IDataBaseManager, ITransient if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); - return _sqlSugarClient.DbMaintenance.IsAnyColumn(table, column, false); + var data = _sqlSugarClient.DbMaintenance.IsAnyColumn(table, column, false); + + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -385,41 +451,20 @@ public class DataBaseManager : IDataBaseManager, ITransient { if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); - List list; - if (link.DbType == SqlSugar.DbType.PostgreSQL.ToString()) - { - var sql = @"SELECT pcolumn.table_name AS tableName,pcolumn.column_name AS field,pcolumn.udt_name AS dataType, -pcolumn.column_default as defaults,col_description(pclass.oid, pcolumn.ordinal_position) AS fieldName, -CASE WHEN pcolumn.numeric_scale>0 THEN pcolumn.numeric_precision ELSE COALESCE(pcolumn.character_maximum_length,0) END AS dataLength, -CASE WHEN pcolumn.is_nullable = 'YES' THEN 1 ELSE 0 END AS allowNull, -CASE WHEN pcolumn.column_default LIKE 'nextval%' THEN true ELSE false END AS identity, -CASE WHEN pkey.colname = pcolumn.column_name THEN true ELSE false END AS primaryKey -FROM information_schema.columns pcolumn -INNER JOIN pg_class pclass ON pcolumn.table_name = pclass.relname -LEFT JOIN ( - SELECT pg_class.relname,pg_attribute.attname AS colname FROM - pg_constraint INNER JOIN pg_class - ON pg_constraint.conrelid = pg_class.oid - INNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid - and pg_attribute.attnum = pg_constraint.conkey[1] - INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid - where pg_constraint.contype='p' -) pkey ON pcolumn.table_name = pkey.relname -WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; - list = _sqlSugarClient.SqlQueryable(string.Format(sql, tableName)).ToList(); - } - else - { - list = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt>(); - } - return list; + var list = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(tableName, false); + + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return list.Adapt>(); } - - public List GetPrimaries(DbLinkEntity? link, string tableName) + + public List GetPrimaries(DbLinkEntity? link, string tableName) { - if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); + if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) + _sqlSugarClient = ChangeDataBase(link); - return _sqlSugarClient.DbMaintenance.GetPrimaries(tableName); + var data = _sqlSugarClient.DbMaintenance.GetPrimaries(tableName); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -432,7 +477,9 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; { if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); - return _sqlSugarClient.Queryable().AS(tableName).ToDataTable(); + var data = _sqlSugarClient.Queryable().AS(tableName).ToDataTable(); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -452,7 +499,37 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle) strSql = strSql.Replace(";", string.Empty); - return _sqlSugarClient.Ado.GetDataTable(strSql, parameters); + var data = _sqlSugarClient.Ado.GetDataTable(strSql, parameters); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; + } + catch (Exception) + { + + throw Oops.Oh(ErrorCode.D1511); + } + } + + /// + /// 根据链接获取数据. + /// + /// 数据连接. + /// sql语句. + /// 参数. + /// + public DataTable GetInterFaceDataCopyNew(DbLinkEntity link, string strSql, params SugarParameter[] parameters) + { + try + { + if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) + _sqlSugarClient = ChangeDataBase(link); + + if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle) + strSql = strSql.Replace(";", string.Empty); + + var data = _sqlSugarClient.CopyNew().Ado.GetDataTable(strSql, parameters); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } catch (Exception) { @@ -475,7 +552,9 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle) strSql = strSql.Replace(";", string.Empty); - _sqlSugarClient.Ado.ExecuteCommand(strSql, parameters); + _sqlSugarClient.CopyNew().Ado.ExecuteCommand(strSql, parameters); + + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); } /// @@ -498,6 +577,8 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; data.tableFieldList = ViewDataTypeConversion(data.tableFieldList, _sqlSugarClient.CurrentConnectionConfig.DbType); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } @@ -516,6 +597,7 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; //var modelList = _sqlSugarClient.Ado.SqlQuery(sql).ToList(); var modelList = _sqlSugarClient.Ado.SqlQuery(sql).ToList(); //return modelList.Select(x => new DatabaseTableListOutput { table = x.F_TABLE, tableName = x.F_TABLENAME, sum = x.F_SUM.ParseToInt() }).ToList(); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return modelList; } @@ -529,7 +611,9 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); - return _sqlSugarClient.DbMaintenance.GetTableInfoList(false); + var data = _sqlSugarClient.DbMaintenance.GetTableInfoList(false); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -547,8 +631,7 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; RefAsync totalNumber = 0; var list = await _sqlSugarClient.SqlQueryable(dbSql).ToDataTablePageAsync(pageIndex, pageSize, totalNumber); - - return PageResult.SqlSugarPageResult(new SqlSugarPagedList() + var data = PageResult.SqlSugarPageResult(new SqlSugarPagedList() { list = ToDynamicList(list), pagination = new Pagination() @@ -558,6 +641,8 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; Total = totalNumber } }); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -573,7 +658,9 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link); - return await _sqlSugarClient.Queryable().ToPageListAsync(pageIndex, pageSize); + var data = await _sqlSugarClient.Queryable().ToPageListAsync(pageIndex, pageSize); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); + return data; } /// @@ -590,6 +677,7 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; List> dc = _sqlSugarClient.Utilities.DataTableToDictionaryList(dt); // 5.0.23版本支持 var isOk = await _sqlSugarClient.Insertable(dc).AS(table).ExecuteCommandAsync(); + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return isOk > 0; } @@ -626,6 +714,7 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; } break; } + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); } catch (Exception ex) { @@ -658,9 +747,15 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position"; _sqlSugarClient = ChangeDataBase(link); if (_sqlSugarClient.Ado.IsValidConnection()) + { + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return true; + } else + { + _sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId); return false; + } } /// diff --git a/common/Tnb.Common.Core/Manager/DataBase/IDataBaseManager.cs b/common/Tnb.Common.Core/Manager/DataBase/IDataBaseManager.cs index 93d25396..baeba4e2 100644 --- a/common/Tnb.Common.Core/Manager/DataBase/IDataBaseManager.cs +++ b/common/Tnb.Common.Core/Manager/DataBase/IDataBaseManager.cs @@ -15,255 +15,272 @@ namespace JNPF.Common.Core.Manager; /// public interface IDataBaseManager { - /// - /// 获取多租户Link. - /// - /// 租户ID. - /// 租户数据库. - /// 租户的DBLink实体对象. - DbLinkEntity GetTenantDbLink(string tenantId, string tenantName); + /// + /// 获取多租户Link. + /// + /// 租户ID. + /// 租户数据库. + /// 租户的DBLink实体对象. + DbLinkEntity GetTenantDbLink(string tenantId, string tenantName); - /// - /// 数据库切换. - /// - /// 数据连接. - /// 切库后的SqlSugarClient. - SqlSugarScope ChangeDataBase(DbLinkEntity link); + /// + /// 数据库切换. + /// + /// 数据连接. + /// 切库后的SqlSugarClient. + SqlSugarScope ChangeDataBase(DbLinkEntity link); - /// - /// 执行Sql(查询). - /// - /// 数据连接. - /// sql语句. - /// - Task ExecuteSql(DbLinkEntity link, string strSql); + /// + /// 执行Sql(查询). + /// + /// 数据连接. + /// sql语句. + /// + Task ExecuteSql(DbLinkEntity link, string strSql); - /// - /// 条件动态过滤. - /// - /// 数据连接. - /// sql语句. - /// 条件是否成立. - bool WhereDynamicFilter(DbLinkEntity link, string strSql); + /// + /// 条件动态过滤. + /// + /// 数据连接. + /// sql语句. + /// 条件是否成立. + bool WhereDynamicFilter(DbLinkEntity link, string strSql); - /// - /// 执行Sql(新增、修改). - /// - /// 数据连接. - /// 表名. - /// 数据. - /// 主键字段. - /// - Task ExecuteSql(DbLinkEntity link, string table, List> dicList, string primaryField = ""); + /// + /// 执行Sql(新增、修改). + /// + /// 数据连接. + /// 表名. + /// 数据. + /// 主键字段. + /// + Task ExecuteSql(DbLinkEntity link, string table, List> dicList, string primaryField = ""); - /// - /// 执行Sql 新增 并返回自增长Id. - /// - /// 数据连接. - /// 表名. - /// 数据. - /// 主键字段. - /// - Task ExecuteReturnIdentityAsync(DbLinkEntity link, string table, List> dicList, string primaryField = ""); + /// + /// 执行Sql 新增 并返回自增长Id. + /// + /// 数据连接. + /// 表名. + /// 数据. + /// 主键字段. + /// + Task ExecuteReturnIdentityAsync(DbLinkEntity link, string table, List> dicList, string primaryField = ""); - /// - /// 创建表. - /// - /// 数据连接. - /// 表对象. - /// 字段对象. - /// - Task Create(DbLinkEntity link, DbTableModel tableModel, List tableFieldList); + /// + /// 创建表. + /// + /// 数据连接. + /// 表对象. + /// 字段对象. + /// + Task Create(DbLinkEntity link, DbTableModel tableModel, List tableFieldList); - /// - /// sqlsugar添加表字段. - /// - /// 表名. - /// 表字段集合. - void AddTableColumn(DbLinkEntity link, string tableName, List tableFieldList); + /// + /// sqlsugar添加表字段. + /// + /// 表名. + /// 表字段集合. + void AddTableColumn(DbLinkEntity link ,string tableName, List tableFieldList); - /// - /// 删除表. - /// - /// 数据连接. - /// 表名. - /// - bool Delete(DbLinkEntity link, string table); + /// + /// 删除表. + /// + /// 数据连接. + /// 表名. + /// + bool Delete(DbLinkEntity link, string table); - /// - /// 修改表. - /// - /// 数据连接. - /// 旧表名称. - /// 表对象. - /// 字段对象. - /// - Task Update(DbLinkEntity link, string oldTable, DbTableModel tableModel, List tableFieldList); + /// + /// 修改表. + /// + /// 数据连接. + /// 旧表名称. + /// 表对象. + /// 字段对象. + /// + Task Update(DbLinkEntity link, string oldTable, DbTableModel tableModel, List tableFieldList); - /// - /// 根据链接获取分页数据. - /// - /// 数据连接. - /// Sql语句. - /// 页数. - /// 列配置. - /// 数据权限. - /// 输出列名称. - /// - PageResult> GetInterFaceData(DbLinkEntity link, string strSql, VisualDevModelListQueryInput pageInput, MainBeltViceQueryModel columnDesign, List dataPermissions, Dictionary outColumnName = null); + /// + /// 根据链接获取分页数据. + /// + /// 数据连接. + /// Sql语句. + /// 页数. + /// 列配置. + /// 数据权限. + /// 输出列名称. + /// + PageResult> GetInterFaceData(DbLinkEntity link, string strSql, VisualDevModelListQueryInput pageInput, MainBeltViceQueryModel columnDesign, List dataPermissions, Dictionary outColumnName = null); - /// - /// 表是否存在. - /// - /// 数据连接. - /// 表名. - /// - bool IsAnyTable(DbLinkEntity link, string table); + /// + /// 表是否存在. + /// + /// 数据连接. + /// 表名. + /// + bool IsAnyTable(DbLinkEntity link, string table); - /// - /// 表字段是否存在. - /// - /// 数据连接. - /// 表名. - /// 表字段名. - /// - bool IsAnyColumn(DbLinkEntity link, string table, string column); + /// + /// 表是否存在数据. + /// + /// 数据连接. + /// 表名. + /// + bool IsAnyData(DbLinkEntity link, string table); - /// - /// 获取表字段列表. - /// - /// 数据连接. - /// 表名. - /// - List GetFieldList(DbLinkEntity? link, string? tableName); + /// + /// 表字段是否存在. + /// + /// 数据连接. + /// 表名. + /// 表字段名. + /// + bool IsAnyColumn(DbLinkEntity link, string table, string column); - /// - /// 获取表的主键 - /// - /// - /// - /// - List GetPrimaries(DbLinkEntity? link, string tableName); + /// + /// 获取表字段列表. + /// + /// 数据连接. + /// 表名. + /// + List GetFieldList(DbLinkEntity? link, string? tableName); - /// - /// 获取表数据. - /// - /// 数据连接. - /// 表名. - /// - DataTable GetData(DbLinkEntity link, string tableName); + /// + /// 获取表数据. + /// + /// 数据连接. + /// 表名. + /// + DataTable GetData(DbLinkEntity link, string tableName); - /// - /// 根据链接获取数据. - /// - /// 数据连接. - /// Sql语句. - /// 参数. - /// - DataTable GetInterFaceData(DbLinkEntity link, string strSql, params SugarParameter[] parameters); + /// + /// 根据链接获取数据. + /// + /// 数据连接. + /// Sql语句. + /// 参数. + /// + DataTable GetInterFaceData(DbLinkEntity link, string strSql, params SugarParameter[] parameters); - /// - /// 获取表信息. - /// - /// 数据连接. - /// 表名. - /// - DatabaseTableInfoOutput GetDataBaseTableInfo(DbLinkEntity link, string tableName); + /// + /// 根据链接获取数据. + /// + /// 数据连接. + /// sql语句. + /// 参数. + /// + public DataTable GetInterFaceDataCopyNew(DbLinkEntity link, string strSql, params SugarParameter[] parameters); - /// - /// 获取数据库表信息. - /// - /// 数据连接. - /// - List GetDBTableList(DbLinkEntity link); + /// + /// 获取表信息. + /// + /// 数据连接. + /// 表名. + /// + DatabaseTableInfoOutput GetDataBaseTableInfo(DbLinkEntity link, string tableName); - /// - /// 获取数据库表信息. - /// - /// 数据连接. - /// - List GetTableInfos(DbLinkEntity link); + /// + /// 获取数据库表信息. + /// + /// 数据连接. + /// + List GetDBTableList(DbLinkEntity link); - /// - /// 获取数据表分页(SQL语句). - /// - /// 数据连接. - /// 数据SQL. - /// 页数. - /// 条数. - /// - Task GetDataTablePage(DbLinkEntity link, string dbSql, int pageIndex, int pageSize); + /// + /// 获取数据库表信息. + /// + /// 数据连接. + /// + List GetTableInfos(DbLinkEntity link); - /// - /// 获取数据表分页(实体). - /// - /// T. - /// 数据连接. - /// 页数. - /// 条数. - /// - Task> GetDataTablePage(DbLinkEntity link, int pageIndex, int pageSize); + /// + /// 获取数据表分页(SQL语句). + /// + /// 数据连接. + /// 数据SQL. + /// 页数. + /// 条数. + /// + Task GetDataTablePage(DbLinkEntity link, string dbSql, int pageIndex, int pageSize); - /// - /// 使用存储过程. - /// - /// 数据连接. - /// 存储过程名称. - /// 参数. - void UseStoredProcedure(DbLinkEntity link, string stored, List parameters); + /// + /// 获取数据表分页(实体). + /// + /// T. + /// 数据连接. + /// 页数. + /// 条数. + /// + Task> GetDataTablePage(DbLinkEntity link, int pageIndex, int pageSize); - /// - /// 测试数据库连接. - /// - /// 数据连接. - /// - bool IsConnection(DbLinkEntity link); + /// + /// 使用存储过程. + /// + /// 数据连接. + /// 存储过程名称. + /// 参数. + void UseStoredProcedure(DbLinkEntity link, string stored, List parameters); - /// - /// 同步数据. - /// - /// 数据连接. - /// 同步数据. - /// 表. - /// - Task SyncData(DbLinkEntity link, DataTable dt, string table); + /// + /// 测试数据库连接. + /// + /// 数据连接. + /// + bool IsConnection(DbLinkEntity link); - /// - /// 同步表操作. - /// - /// 原数据库. - /// 目前数据库. - /// 表名称. - /// 操作类型. - /// 数据类型. - void SyncTable(DbLinkEntity linkFrom, DbLinkEntity linkTo, string table, int type, Dictionary fieldType); + /// + /// 同步数据. + /// + /// 数据连接. + /// 同步数据. + /// 表. + /// + Task SyncData(DbLinkEntity link, DataTable dt, string table); - /// - /// 视图数据类型转换. - /// - /// 字段数据. - /// 数据库类型. - List ViewDataTypeConversion(List fields, SqlSugar.DbType databaseType); + /// + /// 同步表操作. + /// + /// 原数据库. + /// 目前数据库. + /// 表名称. + /// 操作类型. + /// 数据类型. + void SyncTable(DbLinkEntity linkFrom, DbLinkEntity linkTo, string table, int type, Dictionary fieldType); - /// - /// 转换数据库类型. - /// - /// 数据库类型. - /// - SqlSugar.DbType ToDbType(string dbType); + /// + /// 视图数据类型转换. + /// + /// 字段数据. + /// 数据库类型. + List ViewDataTypeConversion(List fields, SqlSugar.DbType databaseType); - /// - /// 转换连接字符串. - /// - /// 数据连接. - /// - string ToConnectionString(DbLinkEntity dbLinkEntity); + /// + /// 转换数据库类型. + /// + /// 数据库类型. + /// + SqlSugar.DbType ToDbType(string dbType); - /// - /// 执行增删改sql. - /// - /// 数据连接. - /// sql语句. - /// 参数. - void ExecuteCommand(DbLinkEntity link, string strSql, params SugarParameter[] parameters); + /// + /// 转换连接字符串. + /// + /// 数据连接. + /// + string ToConnectionString(DbLinkEntity dbLinkEntity); + + /// + /// 执行增删改sql. + /// + /// 数据连接. + /// sql语句. + /// 参数. + void ExecuteCommand(DbLinkEntity link, string strSql, params SugarParameter[] parameters); + + /// + /// 获取表的主键 + /// + /// + /// + /// + List GetPrimaries(DbLinkEntity? link, string tableName); } \ No newline at end of file diff --git a/common/Tnb.Common.Core/Manager/Files/FileManager.cs b/common/Tnb.Common.Core/Manager/Files/FileManager.cs index 000d21ce..b96df78c 100644 --- a/common/Tnb.Common.Core/Manager/Files/FileManager.cs +++ b/common/Tnb.Common.Core/Manager/Files/FileManager.cs @@ -91,6 +91,7 @@ namespace JNPF.Common.Core.Manager.Files { try { + filePath = filePath.Replace(@",", "/"); switch (KeyVariable.FileStoreType) { case OSSProviderType.Invalid: @@ -169,6 +170,7 @@ namespace JNPF.Common.Core.Manager.Files { try { + filePath = filePath.Replace(@",", "/"); switch (KeyVariable.FileStoreType) { case OSSProviderType.Invalid: @@ -196,6 +198,7 @@ namespace JNPF.Common.Core.Manager.Files { try { + filePath = filePath.Replace(@",", "/"); switch (KeyVariable.FileStoreType) { case OSSProviderType.Invalid: @@ -221,6 +224,7 @@ namespace JNPF.Common.Core.Manager.Files { try { + filePath = filePath.Replace(@",", "/"); switch (KeyVariable.FileStoreType) { case OSSProviderType.Invalid: @@ -248,6 +252,7 @@ namespace JNPF.Common.Core.Manager.Files { try { + filePath = filePath.Replace(@",", "/"); switch (KeyVariable.FileStoreType) { case OSSProviderType.Invalid: @@ -266,6 +271,36 @@ namespace JNPF.Common.Core.Manager.Files throw Oops.Oh(ErrorCode.D1804); } } + + /// + /// 复制文件. + /// + /// 源文件地址. + /// 剪切地址. + /// + public async Task CopyFile(string filePath, string toFilePath) + { + try + { + filePath = filePath.Replace(@",", "/"); + switch (KeyVariable.FileStoreType) + { + case OSSProviderType.Invalid: + FileHelper.CopyFile(filePath, toFilePath); + break; + default: + filePath = filePath.Replace(@"\", "/"); + var bucketName = KeyVariable.BucketName; + await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).CopyObjectAsync(bucketName, filePath, bucketName, toFilePath); + await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).RemoveObjectAsync(bucketName, filePath); + break; + } + } + catch (AppFriendlyException ex) + { + throw Oops.Oh(ErrorCode.D1804); + } + } #endregion #region 导入导出(json文件) @@ -286,8 +321,7 @@ namespace JNPF.Common.Core.Manager.Files var stream = new MemoryStream(byteList); await UploadFileByType(stream, _filePath, _fileName); _cacheManager.Set(_fileName, string.Empty); - return new - { + return new { name = _fileName, url = string.Format("/api/file/Download?encryption={0}", DESCEncryption.Encrypt(string.Format("{0}|{1}|json", _userManager.UserId, _fileName), "JNPF")) }; @@ -375,7 +409,8 @@ namespace JNPF.Common.Core.Manager.Files fs.Flush(); fs.Close(); Stream stream = new FileStream(Path.Combine(directoryPath, saveFileName), FileMode.Open, FileAccess.Read, FileShare.Read); - var flag = await UploadFileByType(stream, GetPathByType(input.type), saveFileName); + GetChunkModel(input, saveFileName); + var flag = await UploadFileByType(stream, input.folder, saveFileName); var fileSize = stream.Length; if (flag) { @@ -383,7 +418,7 @@ namespace JNPF.Common.Core.Manager.Files stream.Close(); FileHelper.DeleteDirectory(directoryPath); } - return new FileControlsModel { name = saveFileName, url = string.Format("/api/file/Image/annex/{0}", saveFileName), fileExtension = input.extension, fileSize = input.fileSize.ParseToLong() }; + return new FileControlsModel { name = input.fileName, url = string.Format("/api/file/Image/annex/{0}", input.fileName), fileExtension = input.extension, fileSize = input.fileSize.ParseToLong(), fileName = input.fileName }; } catch (AppFriendlyException ex) { @@ -467,5 +502,39 @@ namespace JNPF.Common.Core.Manager.Files } return fileName; } + + /// + /// 获取地址和文件名. + /// + /// + /// + public void GetChunkModel(ChunkModel input, string saveFileName) + { + var floder = GetPathByType(input.type); + var fileNameStr = string.Empty; + // 自定义路径 + if (input.pathType.Equals("selfPath")) + { + if (input.isAccount.Equals("1")) + { + floder = Path.Combine(floder, _userManager.User.Account); + fileNameStr = Path.Combine(fileNameStr, _userManager.User.Account); + } + if (input.folder.IsNotEmptyOrNull()) + { + floder = Path.Combine(floder, input.folder.Trim('/')); + fileNameStr = Path.Combine(fileNameStr, input.folder); + } + fileNameStr = Path.Combine(fileNameStr, saveFileName); + fileNameStr = fileNameStr.Replace("\\", ","); + fileNameStr = fileNameStr.Replace("/", ","); + } + else + { + fileNameStr = saveFileName; + } + input.fileName = fileNameStr; + input.folder = floder; + } } } \ No newline at end of file diff --git a/common/Tnb.Common.Core/Manager/Files/IFileManager.cs b/common/Tnb.Common.Core/Manager/Files/IFileManager.cs index e54d61ea..de71948b 100644 --- a/common/Tnb.Common.Core/Manager/Files/IFileManager.cs +++ b/common/Tnb.Common.Core/Manager/Files/IFileManager.cs @@ -80,6 +80,14 @@ namespace JNPF.Common.Core.Manager.Files /// 剪切地址. /// Task MoveFile(string filePath, string toFilePath); + + /// + /// 复制文件. + /// + /// 源文件地址. + /// 剪切地址. + /// + Task CopyFile(string filePath, string toFilePath); #endregion /// @@ -109,5 +117,12 @@ namespace JNPF.Common.Core.Manager.Files /// /// string GetFileSize(long size); + + /// + /// 获取地址和文件名. + /// + /// + /// + void GetChunkModel(ChunkModel input, string saveFileName); } } diff --git a/common/Tnb.Common.Core/Manager/User/IUserManager.cs b/common/Tnb.Common.Core/Manager/User/IUserManager.cs index e1fcfaa3..639ff2f8 100644 --- a/common/Tnb.Common.Core/Manager/User/IUserManager.cs +++ b/common/Tnb.Common.Core/Manager/User/IUserManager.cs @@ -145,4 +145,16 @@ public interface IUserManager /// 组织Id. /// Task> GetUserOrgRoleIds(string roleIds, string organizeId); + + /// + /// 判断是否管理员. + /// + /// + /// + bool IsAdmin(string userId); + + /// + /// 获取管理员用户id. + /// + string GetAdminUserId(); } \ No newline at end of file diff --git a/common/Tnb.Common.Core/Manager/User/UserManager.cs b/common/Tnb.Common.Core/Manager/User/UserManager.cs index 0d8f67ac..aeae4c52 100644 --- a/common/Tnb.Common.Core/Manager/User/UserManager.cs +++ b/common/Tnb.Common.Core/Manager/User/UserManager.cs @@ -11,6 +11,7 @@ using JNPF.DependencyInjection; using JNPF.Systems.Entitys.Entity.Permission; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; +using Mapster; using Microsoft.AspNetCore.Http; using SqlSugar; using System.Security.Claims; @@ -118,7 +119,7 @@ public class UserManager : IUserManager, IScoped /// public string ToKen { - get => String.IsNullOrEmpty(App.HttpContext?.Request.Headers["Authorization"]) ? App.HttpContext?.Request.Query["token"] : App.HttpContext?.Request.Headers["Authorization"]; + get => string.IsNullOrEmpty(App.HttpContext?.Request.Headers["Authorization"]) ? App.HttpContext?.Request.Query["token"] : App.HttpContext?.Request.Headers["Authorization"]; } /// @@ -134,7 +135,7 @@ public class UserManager : IUserManager, IScoped /// public string TenantId { - get => ConnectionConfig.ConfigId; + get => ConnectionConfig?.ConfigId; } /// @@ -142,7 +143,7 @@ public class UserManager : IUserManager, IScoped /// public string TenantDbName { - get => ConnectionConfig.ConfigList.Find(it => it.IsMaster.Equals(true)).ServiceName; + get => ConnectionConfig?.ConfigList?.Find(it => it.IsMaster.Equals(true)).ServiceName; } /// @@ -215,9 +216,11 @@ public class UserManager : IUserManager, IScoped { UserAgent userAgent = new UserAgent(_httpContext); var data = new UserInfoModel(); + var userCache = string.Format("{0}:{1}:{2}", TenantId, CommonConst.CACHEKEYUSER, UserId); + var userDataScope = await GetUserDataScopeAsync(UserId); + var ipAddress = NetHelper.Ip; //var ipAddressName = await NetHelper.GetLocation(ipAddress); - var userDataScope = await GetUserDataScopeAsync(UserId); var sysConfigInfo = await _repository.AsSugarClient().Queryable().FirstAsync(s => s.Category.Equals("SysConfig") && s.Key.ToLower().Equals("tokentimeout")); data = await _repository.AsQueryable().Where(it => it.Id == UserId) .Select(a => new UserInfoModel @@ -246,11 +249,14 @@ public class UserManager : IUserManager, IScoped birthday = a.Birthday, systemId = a.SystemId, signImg = SqlFunc.Subqueryable().Where(a => a.CreatorUserId == UserId && a.IsDefault == 1).Select(a => a.SignImg), + changePasswordDate = a.ChangePasswordDate, + loginTime = DateTime.Now, }).FirstAsync(); if (data.portalId.IsNullOrWhiteSpace()) data.portalId = string.Empty; if (data != null && data.organizeName.IsNotEmptyOrNull()) { var orgIdTree = data?.organizeName?.Split(','); + data.organizeIdList = orgIdTree.ToList(); var organizeName = await _repository.AsSugarClient().Queryable().Where(x => orgIdTree.Contains(x.Id)).OrderBy(x => x.SortCode).OrderBy(x => x.CreatorTime).Select(x => x.FullName).ToListAsync(); data.organizeName = string.Join("/", organizeName); } @@ -258,8 +264,6 @@ public class UserManager : IUserManager, IScoped { data.organizeName = data.departmentName; } - - data.loginTime = DateTime.Now; data.prevLogin = (await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Category.Equals("SysConfig") && x.Key.ToLower().Equals("lastlogintimeswitch"))).Value.ParseToInt(); data.loginIPAddress = ipAddress; //data.loginIPAddressName = ipAddressName; @@ -288,7 +292,8 @@ public class UserManager : IUserManager, IScoped data.tenantDbName = TenantDbName; // 根据系统配置过期时间自动过期 - await SetUserInfo(string.Format("{0}{1}_{2}", CommonConst.CACHEKEYUSER, TenantId, UserId), data, TimeSpan.FromMinutes(sysConfigInfo.Value.ParseToDouble())); + await SetUserInfo(userCache, data, TimeSpan.FromMinutes(sysConfigInfo.Value.ParseToDouble())); + return data; } @@ -1583,7 +1588,7 @@ public class UserManager : IUserManager, IScoped ids.AddRange(Subsidiary); for (int i = 0; i < ids.Count; i++) { - if(i == 0) + if (i == 0) { switch (conditionItem.Logic) { @@ -1633,7 +1638,7 @@ public class UserManager : IUserManager, IScoped } else { - if(itemMethod.Equals(QueryType.NotEqual) || itemMethod.Equals(QueryType.NotIncluded)) + if (itemMethod.Equals(QueryType.NotEqual) || itemMethod.Equals(QueryType.NotIncluded)) conditionalList.Add(new { Key = (int)WhereType.And, Value = new { FieldName = itemField, FieldValue = ids[i], ConditionalType = (int)cmodel.ConditionalType } }); else conditionalList.Add(new { Key = (int)WhereType.Or, Value = new { FieldName = itemField, FieldValue = ids[i], ConditionalType = (int)cmodel.ConditionalType } }); @@ -2020,6 +2025,16 @@ public class UserManager : IUserManager, IScoped } } + /// + /// 会否存在用户缓存. + /// + /// + /// + private async Task ExistsUserInfo(string cacheKey) + { + return await _cacheManager.ExistsAsync(cacheKey); + } + /// /// 保存用户登录信息. /// @@ -2031,4 +2046,35 @@ public class UserManager : IUserManager, IScoped { return await _cacheManager.SetAsync(cacheKey, userInfo, timeSpan); } + + /// + /// 获取用户登录信息. + /// + /// key. + /// + private async Task GetUserInfo(string cacheKey) + { + return (await _cacheManager.GetAsync(cacheKey)).Adapt(); + } + + /// + /// 判断是否管理员. + /// + /// + /// + public bool IsAdmin(string userId) + { + if (userId == "admin") return true; + return _repository.AsSugarClient().Queryable().Any(x => x.Id == userId && x.Account == "admin" && x.DeleteMark == null); + } + + /// + /// 获取管理员用户id. + /// + public string GetAdminUserId() + { + var user = _repository.AsSugarClient().Queryable().First(x => x.Account == "admin" && x.DeleteMark == null); + if (user.IsNotEmptyOrNull()) return user.Id; + return string.Empty; + } } \ No newline at end of file diff --git a/common/Tnb.Common.Core/Tnb.Common.Core.csproj b/common/Tnb.Common.Core/Tnb.Common.Core.csproj index d7c75c81..5f5fed19 100644 --- a/common/Tnb.Common.Core/Tnb.Common.Core.csproj +++ b/common/Tnb.Common.Core/Tnb.Common.Core.csproj @@ -12,11 +12,13 @@ + - + + diff --git a/common/Tnb.Common/Configuration/KeyVariable.cs b/common/Tnb.Common/Configuration/KeyVariable.cs index b0ca68c0..d40ec5b0 100644 --- a/common/Tnb.Common/Configuration/KeyVariable.cs +++ b/common/Tnb.Common/Configuration/KeyVariable.cs @@ -28,6 +28,17 @@ public class KeyVariable } } + /// + /// 多租户模式. + /// + public static string MultiTenancyType + { + get + { + return _tenant.MultiTenancyType; + } + } + /// /// 系统文件路径. /// diff --git a/common/Tnb.Common/Const/ClaimConst.cs b/common/Tnb.Common/Const/ClaimConst.cs index 1a7e7388..da5ac70b 100644 --- a/common/Tnb.Common/Const/ClaimConst.cs +++ b/common/Tnb.Common/Const/ClaimConst.cs @@ -42,4 +42,9 @@ public class ClaimConst /// 单一登录方式(1:后登录踢出先登录 2:同时登录). /// public const string SINGLELOGIN = "SingleLogin"; + + /// + /// 单点登录标识. + /// + public const string OnlineTicket = "OnlineTicket"; } \ No newline at end of file diff --git a/common/Tnb.Common/Const/CommonConst.cs b/common/Tnb.Common/Const/CommonConst.cs index d6c567a4..f22392fa 100644 --- a/common/Tnb.Common/Const/CommonConst.cs +++ b/common/Tnb.Common/Const/CommonConst.cs @@ -17,7 +17,7 @@ public class CommonConst ContractResolver = new DefaultContractResolver(), // 设置时区为 UTC - DateTimeZoneHandling = DateTimeZoneHandling.Utc, + DateTimeZoneHandling = DateTimeZoneHandling.Local, // 格式化json输出的日期格式 DateFormatString = "yyyy-MM-dd HH:mm:ss", @@ -41,7 +41,7 @@ public class CommonConst /// /// 用户缓存. /// - public const string CACHEKEYUSER = "user_"; + public const string CACHEKEYUSER = "jnpf:permission:user"; /// /// 菜单缓存. @@ -102,4 +102,19 @@ public class CommonConst /// 第三方登录 票据缓存key. /// public const string PARAMS_JNPF_TICKET = "jnpf_ticket"; + + /// + /// Cas Key. + /// + public const string CAS_Ticket = "ticket"; + + /// + /// Code. + /// + public const string Code = "code"; + + /// + /// 外链密码开关(1:开 , 0:关). + /// + public const int OnlineDevData_State_Enable = 1; } \ No newline at end of file diff --git a/common/Tnb.Common/Contracts/CDEntityBase.cs b/common/Tnb.Common/Contracts/CDEntityBase.cs index 2c7d7009..b17f6c96 100644 --- a/common/Tnb.Common/Contracts/CDEntityBase.cs +++ b/common/Tnb.Common/Contracts/CDEntityBase.cs @@ -52,7 +52,7 @@ public abstract class CDEntityBase : EntityBase, ICreatorTime, IDeleteTi /// public virtual void Creator() { - var userId = App.User.FindFirst(ClaimConst.CLAINMUSERID)?.Value; + var userId = App.User?.FindFirst(ClaimConst.CLAINMUSERID)?.Value; this.CreatorTime = DateTime.Now; this.Id = SnowflakeIdHelper.NextId(); this.EnabledMark = this.EnabledMark == null ? 1 : this.EnabledMark; @@ -67,7 +67,7 @@ public abstract class CDEntityBase : EntityBase, ICreatorTime, IDeleteTi /// public virtual void Create() { - var userId = App.User.FindFirst(ClaimConst.CLAINMUSERID)?.Value; + var userId = App.User?.FindFirst(ClaimConst.CLAINMUSERID)?.Value; this.CreatorTime = DateTime.Now; this.Id = this.Id == null ? SnowflakeIdHelper.NextId() : this.Id; this.EnabledMark = this.EnabledMark == null ? 1 : this.EnabledMark; diff --git a/common/Tnb.Common/Contracts/CEntityBase.cs b/common/Tnb.Common/Contracts/CEntityBase.cs index cb24eb8d..da3cbe15 100644 --- a/common/Tnb.Common/Contracts/CEntityBase.cs +++ b/common/Tnb.Common/Contracts/CEntityBase.cs @@ -1,6 +1,7 @@ using JNPF.Common.Const; using JNPF.Common.Security; using JNPF.DependencyInjection; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using SqlSugar; namespace JNPF.Common.Contracts; @@ -28,7 +29,7 @@ public abstract class CEntityBase : EntityBase, ICreatorTime /// public virtual void Creator() { - var userId = App.User.FindFirst(ClaimConst.CLAINMUSERID)?.Value; + var userId = App.User?.FindFirst(ClaimConst.CLAINMUSERID)?.Value; this.CreatorTime = DateTime.Now; this.Id = SnowflakeIdHelper.NextId(); if (!string.IsNullOrEmpty(userId)) diff --git a/common/Tnb.Common/Contracts/CLDEntityBase.cs b/common/Tnb.Common/Contracts/CLDEntityBase.cs index ec1aee27..5cfdf7bd 100644 --- a/common/Tnb.Common/Contracts/CLDEntityBase.cs +++ b/common/Tnb.Common/Contracts/CLDEntityBase.cs @@ -64,7 +64,7 @@ public abstract class CLDEntityBase : EntityBase, ICreatorTime, IDeleteT /// public virtual void Creator() { - var userId = App.User.FindFirst(ClaimConst.CLAINMUSERID)?.Value; + var userId = App.User?.FindFirst(ClaimConst.CLAINMUSERID)?.Value; this.CreatorTime = DateTime.Now; this.Id = SnowflakeIdHelper.NextId(); this.EnabledMark = this.EnabledMark == null ? 1 : this.EnabledMark; diff --git a/common/Tnb.Common/Contracts/CLEntityBase.cs b/common/Tnb.Common/Contracts/CLEntityBase.cs index 97c2d932..3a08de71 100644 --- a/common/Tnb.Common/Contracts/CLEntityBase.cs +++ b/common/Tnb.Common/Contracts/CLEntityBase.cs @@ -40,7 +40,7 @@ public class CLEntityBase : EntityBase, ICreatorTime /// public virtual void Creator() { - var userId = App.User.FindFirst(ClaimConst.CLAINMUSERID)?.Value; + var userId = App.User?.FindFirst(ClaimConst.CLAINMUSERID)?.Value; this.CreatorTime = DateTime.Now; this.Id = SnowflakeIdHelper.NextId(); if (!string.IsNullOrEmpty(userId)) diff --git a/common/Tnb.Common/Contracts/EntityBase.cs b/common/Tnb.Common/Contracts/EntityBase.cs index 72ff0bdb..e6cfc892 100644 --- a/common/Tnb.Common/Contracts/EntityBase.cs +++ b/common/Tnb.Common/Contracts/EntityBase.cs @@ -1,4 +1,5 @@ using JNPF.DependencyInjection; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using SqlSugar; namespace JNPF.Common.Contracts; @@ -7,7 +8,7 @@ namespace JNPF.Common.Contracts; /// 实体类基类. /// [SuppressSniffer] -public abstract class EntityBase : IEntity +public abstract class EntityBase : ITenantFilter, IEntity where TKey : IEquatable { /// @@ -15,4 +16,10 @@ public abstract class EntityBase : IEntity /// [SugarColumn(ColumnName = "F_Id", ColumnDescription = "主键", IsPrimaryKey = true)] public TKey Id { get; set; } + + /// + /// 获取或设置 租户id. + /// + [SugarColumn(ColumnName = "F_TenantId", ColumnDescription = "租户id")] + public string TenantId { get; set; } } \ No newline at end of file diff --git a/common/Tnb.Common/Enums/ErrorCode.cs b/common/Tnb.Common/Enums/ErrorCode.cs index 39315888..bb17c0b8 100644 --- a/common/Tnb.Common/Enums/ErrorCode.cs +++ b/common/Tnb.Common/Enums/ErrorCode.cs @@ -670,6 +670,11 @@ public enum ErrorCode [ErrorCodeItemMetadata("第三方登录未配置!")] D5025, + /// + /// 修改失败,新建密码不能与旧密码一样. + /// + [ErrorCodeItemMetadata("修改失败,新建密码不能与旧密码一样")] + D5026, #endregion #region 岗位 6 @@ -968,6 +973,11 @@ public enum ErrorCode [ErrorCodeItemMetadata("验证码限定范围:3 - 6位")] D9009, + /// + /// 打印模板不存在. + /// + [ErrorCodeItemMetadata("打印模板不存在")] + D9010, #endregion #region 单据规则 10 @@ -1107,12 +1117,28 @@ public enum ErrorCode D1417, /// - /// 该功能不存在,可能已被删除. + /// 密码错误. /// - [ErrorCodeItemMetadata("该功能( id: {0} )不存在,可能已被删除")] + [ErrorCodeItemMetadata("密码错误")] D1418, + /// + /// 缺少租户信息. + /// + [ErrorCodeItemMetadata("缺少租户信息")] + D1419, + /// + /// 无效链接. + /// + [ErrorCodeItemMetadata("无效链接")] + D1420, + + /// + /// 发布失败,流程未设计. + /// + [ErrorCodeItemMetadata("发布失败,流程未设计")] + D1421, #endregion #region 数据建模 15 @@ -1201,6 +1227,18 @@ public enum ErrorCode [ErrorCodeItemMetadata("Sql不能为空")] D1513, + /// + /// 表名超过规定长度. + /// + [ErrorCodeItemMetadata("表名超过规定长度")] + D1514, + + /// + /// 列名超过规定长度. + /// + [ErrorCodeItemMetadata("列名超过规定长度")] + D1515, + #endregion #region 角色 16 @@ -1425,9 +1463,9 @@ public enum ErrorCode D2104, /// - /// 表缺失流程Id. + /// 表缺失流程Id字段. /// - [ErrorCodeItemMetadata("表缺失流程Id")] + [ErrorCodeItemMetadata("表缺失流程Id字段:F_FLowId")] D2105, /// @@ -1454,6 +1492,12 @@ public enum ErrorCode [ErrorCodeItemMetadata("模板主键策略与表主键策略不同")] D2109, + /// + /// 表缺失逻辑删除字段. + /// + [ErrorCodeItemMetadata("表缺失逻辑删除字段:F_DeleteMark")] + D2110, + #endregion #region 大屏 22 @@ -1772,11 +1816,46 @@ public enum ErrorCode WF0045, /// - /// 退回至您的审批,不能再撤回审批. + /// 此流程已被挂起,无法操作!. /// - [ErrorCodeItemMetadata("退回至您的审批,不能再撤回审批!")] + [ErrorCodeItemMetadata("流程处于挂起状态,不可操作!")] WF0046, + /// + /// {0}流程已被挂起,无法操作!. + /// + [ErrorCodeItemMetadata("{0}流程已被挂起不能删除!")] + WF0047, + + /// + /// 退回至您的审批,不能再撤回审批. + /// + [ErrorCodeItemMetadata("退回至您的审批,不能再撤回审批!")] + WF0048, + + /// + /// 您没有该流程的发起权限. + /// + [ErrorCodeItemMetadata("您没有该流程的发起权限")] + WF0049, + + /// + /// 下一节点已审批,不能撤回! + /// + [ErrorCodeItemMetadata("下一节点已审批,不能撤回!")] + WF0050, + + /// + /// 流程已撤回,不能重复操作!. + /// + [ErrorCodeItemMetadata("流程已撤回,不能重复操作!")] + WF0051, + + /// + /// 该流程由在线开发生成的,无法直接删除,请在功能设计中删除相关功能!. + /// + [ErrorCodeItemMetadata("该流程由在线开发生成的,无法直接删除,请在功能设计中删除相关功能!")] + WF0052, #endregion #region 扩展 Ex @@ -2018,9 +2097,9 @@ public enum ErrorCode COM1015, /// - /// 未找到流程引擎. + /// 流程未设计,请先设计流程. /// - [ErrorCodeItemMetadata("未找到流程引擎")] + [ErrorCodeItemMetadata("流程未设计,请先设计流程")] COM1016, /// @@ -2028,5 +2107,23 @@ public enum ErrorCode /// [ErrorCodeItemMetadata("该功能配置的流程处于停用状态")] COM1017, + + /// + /// 该功能配置的流程处于停用状态. + /// + [ErrorCodeItemMetadata("接口请求失败")] + COM1018, + + /// + /// 该功能未导入流程表单!. + /// + [ErrorCodeItemMetadata("该功能未导入流程表单!")] + COM1019, + + /// + /// 接口数据异常!. + /// + [ErrorCodeItemMetadata("接口数据异常!")] + COM1020, #endregion } \ No newline at end of file diff --git a/common/Tnb.Common/Enums/RouteType.cs b/common/Tnb.Common/Enums/RouteType.cs deleted file mode 100644 index 4580837b..00000000 --- a/common/Tnb.Common/Enums/RouteType.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tnb.Common.Enums -{ - /// - /// 工艺路线类型 - /// - public enum RouteType - { - /// - /// 标准途程 - /// - [Description("标准途程")] - Standard=1, - /// - /// 返工途程 - /// - [Description("返工途程")] - Rework=2, - /// - /// 试制途程 - /// - [Description("试制途程")] - Trial=4, - /// - /// 返修途程 - /// - [Description("返修途程")] - RMA =8, - } -} diff --git a/common/Tnb.Common/Extension/BooleanExtensions.cs b/common/Tnb.Common/Extension/BooleanExtensions.cs index 5feffa27..c163c4f9 100644 --- a/common/Tnb.Common/Extension/BooleanExtensions.cs +++ b/common/Tnb.Common/Extension/BooleanExtensions.cs @@ -31,7 +31,7 @@ public static class BooleanExtensions /// private static bool? GetBool(this object data) { - switch (data.ToString()?.Trim().ToLower()) + switch (data.ToString().Trim().ToLower()) { case "0": return false; diff --git a/common/Tnb.Common/Extension/DictionaryExtensions.cs b/common/Tnb.Common/Extension/DictionaryExtensions.cs index 750a273e..742d8e57 100644 --- a/common/Tnb.Common/Extension/DictionaryExtensions.cs +++ b/common/Tnb.Common/Extension/DictionaryExtensions.cs @@ -18,7 +18,7 @@ public static class DictionaryExtensions /// 要操作的字典. /// 指定键名. /// 获取到的值. - public static TValue? GetOrDefault(this IDictionary dictionary, TKey key) + public static TValue GetOrDefault(this IDictionary dictionary, TKey key) { return dictionary.TryGetValue(key, out TValue value) ? value : default(TValue); } diff --git a/common/Tnb.Common/Extension/Extensions.cs b/common/Tnb.Common/Extension/Extensions.cs index a46b4e1d..31a2e9a4 100644 --- a/common/Tnb.Common/Extension/Extensions.cs +++ b/common/Tnb.Common/Extension/Extensions.cs @@ -693,4 +693,25 @@ public static partial class Extensions } #endregion + + #region List + + /// + /// 嵌套List解析 + /// 仅限于列表查询条件多选. + /// + /// + /// + public static List ParseToNestedList(this List> list) + { + List result = new List(); + if (list != null && list.Count > 0) + { + foreach (var item in list) + result.Add(item.Last()); + } + return result; + } + + #endregion } \ No newline at end of file diff --git a/common/Tnb.Common/Extension/RandomExtensions.cs b/common/Tnb.Common/Extension/RandomExtensions.cs index b8466442..dd93fe88 100644 --- a/common/Tnb.Common/Extension/RandomExtensions.cs +++ b/common/Tnb.Common/Extension/RandomExtensions.cs @@ -67,7 +67,7 @@ public static class RandomExtensions public static T NextItem(this Random random, T[] items) { if (items == null || items.Length == 0) - return default(T)!; + return default(T); return items[random.Next(items.Length)]; } diff --git a/common/Tnb.Common/Extension/StringExtensions.cs b/common/Tnb.Common/Extension/StringExtensions.cs index 02cce18e..a11cbfd1 100644 --- a/common/Tnb.Common/Extension/StringExtensions.cs +++ b/common/Tnb.Common/Extension/StringExtensions.cs @@ -354,7 +354,7 @@ public static class StringExtensions /// 指示指定的字符串是 null、空或者仅由空白字符组成. /// [DebuggerStepThrough] - public static bool IsNullOrWhiteSpace(this string value) + public static bool IsNullOrWhiteSpace(this string? value) { return string.IsNullOrWhiteSpace(value); } diff --git a/common/Tnb.Common/Models/Authorize/CodeGenAuthorizeModuleResourceModel.cs b/common/Tnb.Common/Models/Authorize/CodeGenAuthorizeModuleResourceModel.cs index 7d9652d7..8b83c4e5 100644 --- a/common/Tnb.Common/Models/Authorize/CodeGenAuthorizeModuleResourceModel.cs +++ b/common/Tnb.Common/Models/Authorize/CodeGenAuthorizeModuleResourceModel.cs @@ -41,4 +41,20 @@ public class CodeGenAuthorizeModuleResource /// 权限条件. /// public List conditionalModel { get; set; } +} + +/// +/// 代码生成 数据过滤. +/// +public class CodeGenDataRuleModuleResourceModel : CodeGenAuthorizeModuleResourceModel +{ + /// + /// 请求类型 pc 和 app. + /// + public string UserOrigin { get; set; } + + /// + /// 权限条件 json. + /// + public string conditionalModelJson { get; set; } } \ No newline at end of file diff --git a/common/Tnb.Common/Models/ChunkModel.cs b/common/Tnb.Common/Models/ChunkModel.cs index 87cfc266..7e47314a 100644 --- a/common/Tnb.Common/Models/ChunkModel.cs +++ b/common/Tnb.Common/Models/ChunkModel.cs @@ -86,4 +86,19 @@ public class ChunkModel /// 文件. /// public IFormFile file { get; set; } + + /// + /// 路径类型 defaultPath(默认路径) selfPath(自定义路径). + /// + public string pathType { get; set; } = "defaultPath"; + + /// + /// 是否用户存储(0否1是). + /// + public string isAccount { get; set; } = "0"; + + /// + /// 自定义文件夹路径. + /// + public string folder { get; set; } } diff --git a/common/Tnb.Common/Models/FileControlsModel.cs b/common/Tnb.Common/Models/FileControlsModel.cs index cdf11305..b667fffd 100644 --- a/common/Tnb.Common/Models/FileControlsModel.cs +++ b/common/Tnb.Common/Models/FileControlsModel.cs @@ -32,4 +32,9 @@ public class FileControlsModel /// 文件后缀. /// public string? fileExtension { get; set; } + + /// + /// 文件名称. + /// + public string? fileName { get; set; } } \ No newline at end of file diff --git a/common/Tnb.Common/Models/NPOI/ExcelColumnModel.cs b/common/Tnb.Common/Models/NPOI/ExcelColumnModel.cs index afb658ca..394a2a52 100644 --- a/common/Tnb.Common/Models/NPOI/ExcelColumnModel.cs +++ b/common/Tnb.Common/Models/NPOI/ExcelColumnModel.cs @@ -6,7 +6,8 @@ namespace JNPF.Common.Models.NPOI; /// /// Excel导出列名 /// 版 本:V3.0.0 -/// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) +/// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) +/// 作 者:JNPF开发平台组 /// 日 期:2017.03.09. /// [SuppressSniffer] diff --git a/common/Tnb.Common/Models/NPOI/ExcelConfig.cs b/common/Tnb.Common/Models/NPOI/ExcelConfig.cs index 6da01730..8f215a02 100644 --- a/common/Tnb.Common/Models/NPOI/ExcelConfig.cs +++ b/common/Tnb.Common/Models/NPOI/ExcelConfig.cs @@ -6,7 +6,8 @@ namespace JNPF.Common.Models.NPOI; /// /// Excel导出配置 /// 版 本:V3.0.0 -/// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) +/// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) +/// 作 者:JNPF开发平台组 /// 日 期:2017.03.09. /// [SuppressSniffer] diff --git a/common/Tnb.Common/Models/NPOI/ExcelTemplateModel.cs b/common/Tnb.Common/Models/NPOI/ExcelTemplateModel.cs index 357a4e01..ce795303 100644 --- a/common/Tnb.Common/Models/NPOI/ExcelTemplateModel.cs +++ b/common/Tnb.Common/Models/NPOI/ExcelTemplateModel.cs @@ -5,7 +5,8 @@ namespace JNPF.Common.Models.NPOI; /// /// Excel导出模板 /// 版 本:V3.0.0 -/// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) +/// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) +/// 作 者:JNPF开发平台组 /// 日 期:2017.03.09. /// [SuppressSniffer] diff --git a/common/Tnb.Common/Models/User/UserInfoModel.cs b/common/Tnb.Common/Models/User/UserInfoModel.cs index 9299aa6d..909727f7 100644 --- a/common/Tnb.Common/Models/User/UserInfoModel.cs +++ b/common/Tnb.Common/Models/User/UserInfoModel.cs @@ -5,7 +5,7 @@ namespace JNPF.Common.Models.User /// /// 登录者信息 /// 版 本:V3.2.0 - /// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) + /// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) /// 作 者:JNPF开发平台组. /// [SuppressSniffer] @@ -51,6 +51,11 @@ namespace JNPF.Common.Models.User /// public string organizeId { get; set; } + /// + /// 所属组织 Id 树. + /// + public List organizeIdList { get; set; } + /// /// 组织名称. /// @@ -225,6 +230,11 @@ namespace JNPF.Common.Models.User /// public string signImg { get; set; } + /// + /// 默认签名. + /// + public DateTime? changePasswordDate { get; set; } + /// /// 系统集合. /// diff --git a/common/Tnb.Common/Models/User/UserOnlineModel.cs b/common/Tnb.Common/Models/User/UserOnlineModel.cs index dd96d3c6..65ba4e0b 100644 --- a/common/Tnb.Common/Models/User/UserOnlineModel.cs +++ b/common/Tnb.Common/Models/User/UserOnlineModel.cs @@ -53,6 +53,11 @@ public class UserOnlineModel /// public string token { get; set; } + /// + /// 单点登录标识. + /// + public string onlineTicket { get; set; } + /// /// 是否移动端. /// diff --git a/common/Tnb.Common/Models/WorkFlow/FlowJsonModel.cs b/common/Tnb.Common/Models/WorkFlow/FlowJsonModel.cs index c3fb5a7d..cd00df37 100644 --- a/common/Tnb.Common/Models/WorkFlow/FlowJsonModel.cs +++ b/common/Tnb.Common/Models/WorkFlow/FlowJsonModel.cs @@ -46,5 +46,10 @@ /// 流程类型. /// public int? type { get; set; } + + /// + /// 所属流程名称. + /// + public string? flowName { get; set; } } } diff --git a/common/Tnb.Common/Options/OauthOptions.cs b/common/Tnb.Common/Options/OauthOptions.cs new file mode 100644 index 00000000..c6017eb2 --- /dev/null +++ b/common/Tnb.Common/Options/OauthOptions.cs @@ -0,0 +1,103 @@ +using Aspose.Cells; +using JNPF.Common.Enums; +using JNPF.ConfigurableOptions; +using NPOI.SS.Formula.Functions; + +namespace JNPF.Common.Options; + +/// +/// 单点登录配置. +/// +public sealed class OauthOptions : IConfigurableOptions +{ + /// + /// 是否启用. + /// + public bool Enabled { get; set; } + + /// + /// 前端登录页面访问登录接口进行单点登录页面跳转, 需要与身份管理系统中的 JNPF-Auth2、JNPF-CAS中的认证地址一致. + /// + public string LoginPath { get; set; } + + /// + /// 从单点登录中心直接访问JNPF时登录成功后跳转的前端页面. + /// + public string SucessFrontUrl { get; set; } + + /// + /// 默认接口. + /// + public string DefaultSSO { get; set; } + + /// + /// 缓存过期时间 / 分钟. + /// + public int TicketTimeout { get; set; } + + /// + /// 是否前端输出消息. + /// + public bool TicketOutMessage { get; set; } + + /// + /// 登录模式. + /// + public SSO SSO { get; set; } + + /// + /// 用户推送. + /// + public Pull Pull { get; set; } +} + +public class SSO +{ + public Auth2 Auth2 { get; set; } + + public Cas Cas { get; set; } +} + +public class Auth2 +{ + public bool Enabled { get; set; } + + public string ClientId { get; set; } + + public string ClientSecret { get; set; } + + public string AuthorizeUrl { get; set; } + + public string AccessTokenUrl { get; set; } + + public string UserInfoUrl { get; set; } +} + +public class Cas +{ + public bool Enabled { get; set; } + + public string ServerLoginUrl { get; set; } + + public string ServerValidateUrl { get; set; } +} + +public class Pull +{ + public bool Enabled { get; set; } + + public string CreateRestAddress { get; set; } + + public string ReplaceRestAddress { get; set; } + + public string ChangePasswordRestAddress { get; set; } + + public string DeleteRestAddress { get; set; } + + public string CredentialType { get; set; } + + public string UserName { get; set; } + + public string Password { get; set; } + +} \ No newline at end of file diff --git a/common/Tnb.Common/Security/CodeGenExportDataHelper.cs b/common/Tnb.Common/Security/CodeGenExportDataHelper.cs index 11141240..61b8e36a 100644 --- a/common/Tnb.Common/Security/CodeGenExportDataHelper.cs +++ b/common/Tnb.Common/Security/CodeGenExportDataHelper.cs @@ -54,7 +54,7 @@ public static class CodeGenExportDataHelper var len = rowChildDatas.Select(x => x.Value.Count()).OrderByDescending(x => x).FirstOrDefault(); - if (len > 0) + if (len != null && len > 0) { for (int i = 0; i < len; i++) { diff --git a/common/Tnb.Common/Security/CodeGenHelper.cs b/common/Tnb.Common/Security/CodeGenHelper.cs index 5bf8591d..aa75e88c 100644 --- a/common/Tnb.Common/Security/CodeGenHelper.cs +++ b/common/Tnb.Common/Security/CodeGenHelper.cs @@ -160,6 +160,79 @@ public static class CodeGenHelper } } + /// + /// 数据列表生成树形表格. + /// + /// 数据列表. + /// 树形父级字段. + /// 树形显示字段. + /// + public static List> GetTreeList(List> realList, string parentField, string treeShowField) + { + var res = new List>(); + if (realList.Any()) + { + var parentFieldId = SnowflakeIdHelper.NextId(); + + foreach (var item in realList) + { + if (realList.Any(x => x["id"].Equals(item[parentField]))) item[parentFieldId] = item[parentField]; + else item[parentFieldId] = null; + item[parentField] = realList.Find(x => x["id"] == item["id"])[treeShowField]; + } + var parentFieldRep = parentField.Substring(0, parentField.Length - 4); + for (int i = 0; i < realList.Count; i++) + { + if (realList[i][parentFieldId].IsNullOrEmpty()) + { + if (realList[i][parentFieldRep] == null) realList[i][parentFieldRep] = realList[i][treeShowField]; + var childList = realList.Where(x => x[parentFieldId] != null && x[parentFieldId].Equals(realList[i]["id"])).ToList(); + if (childList.Any()) GetTreeList(realList, realList[i], parentFieldId); + res.Add(realList[i]); + } + } + } + return res; + } + + private static void GetTreeList(List> allList, Dictionary currentItem, string pId) + { + var childList = allList.Where(x => x[pId] != null && x[pId].Equals(currentItem["id"])).ToList(); + if (childList.Any()) childList.ForEach(x => GetTreeList(allList, x, pId)); + if (childList.Any()) + { + var item = allList.Find(x => x["id"].Equals(currentItem["id"])); + item["children"] = childList; + } + } + + /// + /// 根据集合捞取所有子集id. + /// + /// key : 主键Id , value : 父亲Id. + /// 当前id. + /// res. + public static List GetChildIdList(Dictionary allList, string currentId, List resList) + { + if (resList == null) resList = new List() { currentId }; + else resList.Add(currentId); + if (allList.Any()) + { + var cItemList = allList.Where(x => x.Value.IsNotEmptyOrNull() && x.Value.Equals(currentId)).ToList(); + if (cItemList.Any()) + { + foreach (var item in cItemList) + { + var cIdList = GetChildIdList(allList, item.Key, resList); + resList.Add(item.Key); + if (cIdList.Any()) resList.AddRange(cIdList); + } + } + } + + return resList; + } + /// /// 获取排序真实字段. /// @@ -190,7 +263,7 @@ public static class CodeGenHelper field = entityInfo.Columns.Find(it => it.PropertyName.Equals(sort.ToUpperCase()))?.DbColumnName; break; } - return string.IsNullOrEmpty(field) ? "" : field; + return string.IsNullOrEmpty(field) ? null : field; } /// diff --git a/common/Tnb.Common/Security/ExcelExportHelper.cs b/common/Tnb.Common/Security/ExcelExportHelper.cs index 0a34dfe4..4c3c7fa2 100644 --- a/common/Tnb.Common/Security/ExcelExportHelper.cs +++ b/common/Tnb.Common/Security/ExcelExportHelper.cs @@ -1,7 +1,6 @@ using System.Drawing; using System.Reflection; using System.Text; -using JNPF.Common.Helper; using JNPF.Common.Models.NPOI; using JNPF.DependencyInjection; using NPOI.HPSF; @@ -9,8 +8,6 @@ using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.SS.Util; using NPOI.XSSF.UserModel; -using Spire.Doc; -using static Microsoft.AspNetCore.Razor.Language.TagHelperMetadata; namespace JNPF.Common.Security; diff --git a/common/Tnb.Common/Security/JsonHelper.cs b/common/Tnb.Common/Security/JsonHelper.cs index 0128eecc..dc9f8913 100644 --- a/common/Tnb.Common/Security/JsonHelper.cs +++ b/common/Tnb.Common/Security/JsonHelper.cs @@ -49,6 +49,17 @@ public static class JsonHelper return _jsonSerializer.Deserialize(json); } + /// + /// JSON 字符串转 Object. + /// + /// 动态类型. + /// 对象. + /// + public static T ToObjectOld(this string json) + { + return _ = JsonConvert.DeserializeObject(json) ?? default(T); + } + /// /// JSON 字符串转 Object. /// diff --git a/common/Tnb.Common/Security/NetHelper.cs b/common/Tnb.Common/Security/NetHelper.cs index 90e0c2aa..6424734f 100644 --- a/common/Tnb.Common/Security/NetHelper.cs +++ b/common/Tnb.Common/Security/NetHelper.cs @@ -28,7 +28,9 @@ public static class NetHelper string result = string.Empty; if (App.HttpContext != null) result = GetWebClientIp(); - return result.Equals("::1") ? "127.0.0.1" : result; + result = result.Equals("::1") ? "127.0.0.1" : result; + result = result.Replace(":", string.Empty).Replace("ffff", string.Empty); + return result; } } diff --git a/common/Tnb.Common/Security/PinyinHelper.cs b/common/Tnb.Common/Security/PinyinHelper.cs index cc19afef..fe4ea1c5 100644 --- a/common/Tnb.Common/Security/PinyinHelper.cs +++ b/common/Tnb.Common/Security/PinyinHelper.cs @@ -12,101 +12,101 @@ namespace JNPF.Common.Security; [SuppressSniffer] public class PinyinHelper { - #region 获取汉字转换拼音 首字母 + #region 获取汉字转换拼音 首字母 - /// - /// 获取汉字转换拼音 首字母. - /// - /// 汉字字符串 - /// - public static string PinyinString(string HanZiStr) - { - int i, j, k, m; - string tmpStr; - - // 返回最终结果的字符串 - string returnStr = string.Empty; - string[] tmpArr; - for (i = 0; i < HanZiStr.Length; i++) + /// + /// 获取汉字转换拼音 首字母. + /// + /// 汉字字符串 + /// + public static string PinyinString(string HanZiStr) { - // 处理汉字字符串,对每个汉字的首字母进行一次循环 - tmpStr = GetPinyin((char)HanZiStr[i]); + int i, j, k, m; + string tmpStr; - // 获取第i个汉字的拼音首字母,可能为1个或多个 - if (tmpStr.Length > 0) - { - // 汉字的拼音首字母存在的情况才进行操作 - if (returnStr != string.Empty) + // 返回最终结果的字符串 + string returnStr = string.Empty; + string[] tmpArr; + for (i = 0; i < HanZiStr.Length; i++) { - // 不是第一个汉字 - Regex regex = new Regex(","); - tmpArr = regex.Split(returnStr); - returnStr = string.Empty; - for (k = 0; k < tmpArr.Length; k++) - { - // 对返回的每个首字母进行拼接 - for (j = 0; j < tmpStr.Length; j++) - { - // 取出第j个拼音字母 - string charcode = tmpStr[j].ToString(); - returnStr += tmpArr[k] + charcode + ","; - } - } + // 处理汉字字符串,对每个汉字的首字母进行一次循环 + tmpStr = GetPinyin((char)HanZiStr[i]); - if (returnStr != string.Empty) - returnStr = returnStr.Substring(0, returnStr.Length - 1); + // 获取第i个汉字的拼音首字母,可能为1个或多个 + if (tmpStr.Length > 0) + { + // 汉字的拼音首字母存在的情况才进行操作 + if (returnStr != string.Empty) + { + // 不是第一个汉字 + Regex regex = new Regex(","); + tmpArr = regex.Split(returnStr); + returnStr = string.Empty; + for (k = 0; k < tmpArr.Length; k++) + { + // 对返回的每个首字母进行拼接 + for (j = 0; j < tmpStr.Length; j++) + { + // 取出第j个拼音字母 + string charcode = tmpStr[j].ToString(); + returnStr += tmpArr[k] + charcode + ","; + } + } + + if (returnStr != string.Empty) + returnStr = returnStr.Substring(0, returnStr.Length - 1); + } + else + { + // 构造第一个汉字返回结果 + for (m = 0; m < tmpStr.Length - 1; m++) + returnStr += tmpStr[m] + ","; + returnStr += tmpStr[tmpStr.Length - 1]; + } + } + } + + // 返回处理结果字符串,以,分隔每个拼音组合 + return returnStr; + } + + private static string GetPinyin(char HanZi) + + // 获取单个汉字对应的拼音首字符字符串 + { + // 汉字拼音首字母列表 本列表包含了20902个汉字,收录的字符的Unicode编码范围为19968至40869 + + string strChineseFirstPY = "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJGYZZJJFKCCLZDHWDWZJLJPFYYNWJJTMYHZWZHFLZPPQHGSCYYYNJQYXXGJHHSDSJNKKTMOMLCRXYPSNQSECCQZGGLLYJLMYZZSECYKYYHQWJSSGGYXYZYJWWKDJHYCHMYXJTLXJYQBYXZLDWRDJRWYSRLDZJPCBZJJBRCFTLECZSTZFXXZHTRQHYBDLYCZSSYMMRFMYQZPWWJJYFCRWFDFZQPYDDWYXKYJAWJFFXYPSFTZYHHYZYSWCJYXSCLCXXWZZXNBGNNXBXLZSZSBSGPYSYZDHMDZBQBZCWDZZYYTZHBTSYYBZGNTNXQYWQSKBPHHLXGYBFMJEBJHHGQTJCYSXSTKZHLYCKGLYSMZXYALMELDCCXGZYRJXSDLTYZCQKCNNJWHJTZZCQLJSTSTBNXBTYXCEQXGKWJYFLZQLYHYXSPSFXLMPBYSXXXYDJCZYLLLSJXFHJXPJBTFFYABYXBHZZBJYZLWLCZGGBTSSMDTJZXPTHYQTGLJSCQFZKJZJQNLZWLSLHDZBWJNCJZYZSQQYCQYRZCJJWYBRTWPYFTWEXCSKDZCTBZHYZZYYJXZCFFZZMJYXXSDZZOTTBZLQWFCKSZSXFYRLNYJMBDTHJXSQQCCSBXYYTSYFBXDZTGBCNSLCYZZPSAZYZZSCJCSHZQYDXLBPJLLMQXTYDZXSQJTZPXLCGLQTZWJBHCTSYJSFXYEJJTLBGXSXJMYJQQPFZASYJNTYDJXKJCDJSZCBARTDCLYJQMWNQNCLLLKBYBZZSYHQQLTWLCCXTXLLZNTYLNEWYZYXCZXXGRKRMTCNDNJTSYYSSDQDGHSDBJGHRWRQLYBGLXHLGTGXBQJDZPYJSJYJCTMRNYMGRZJCZGJMZMGXMPRYXKJNYMSGMZJYMKMFXMLDTGFBHCJHKYLPFMDXLQJJSMTQGZSJLQDLDGJYCALCMZCSDJLLNXDJFFFFJCZFMZFFPFKHKGDPSXKTACJDHHZDDCRRCFQYJKQCCWJDXHWJLYLLZGCFCQDSMLZPBJJPLSBCJGGDCKKDEZSQCCKJGCGKDJTJDLZYCXKLQSCGJCLTFPCQCZGWPJDQYZJJBYJHSJDZWGFSJGZKQCCZLLPSPKJGQJHZZLJPLGJGJJTHJJYJZCZMLZLYQBGJWMLJKXZDZNJQSYZMLJLLJKYWXMKJLHSKJGBMCLYYMKXJQLBMLLKMDXXKWYXYSLMLPSJQQJQXYXFJTJDXMXXLLCXQBSYJBGWYMBGGBCYXPJYGPEPFGDJGBHBNSQJYZJKJKHXQFGQZKFHYGKHDKLLSDJQXPQYKYBNQSXQNSZSWHBSXWHXWBZZXDMNSJBSBKBBZKLYLXGWXDRWYQZMYWSJQLCJXXJXKJEQXSCYETLZHLYYYSDZPAQYZCMTLSHTZCFYZYXYLJSDCJQAGYSLCQLYYYSHMRQQKLDXZSCSSSYDYCJYSFSJBFRSSZQSBXXPXJYSDRCKGJLGDKZJZBDKTCSYQPYHSTCLDJDHMXMCGXYZHJDDTMHLTXZXYLYMOHYJCLTYFBQQXPFBDFHHTKSQHZYYWCNXXCRWHOWGYJLEGWDQCWGFJYCSNTMYTOLBYGWQWESJPWNMLRYDZSZTXYQPZGCWXHNGPYXSHMYQJXZTDPPBFYHZHTJYFDZWKGKZBLDNTSXHQEEGZZYLZMMZYJZGXZXKHKSTXNXXWYLYAPSTHXDWHZYMPXAGKYDXBHNHXKDPJNMYHYLPMGOCSLNZHKXXLPZZLBMLSFBHHGYGYYGGBHSCYAQTYWLXTZQCEZYDQDQMMHTKLLSZHLSJZWFYHQSWSCWLQAZYNYTLSXTHAZNKZZSZZLAXXZWWCTGQQTDDYZTCCHYQZFLXPSLZYGPZSZNGLNDQTBDLXGTCTAJDKYWNSYZLJHHZZCWNYYZYWMHYCHHYXHJKZWSXHZYXLYSKQYSPSLYZWMYPPKBYGLKZHTYXAXQSYSHXASMCHKDSCRSWJPWXSGZJLWWSCHSJHSQNHCSEGNDAQTBAALZZMSSTDQJCJKTSCJAXPLGGXHHGXXZCXPDMMHLDGTYBYSJMXHMRCPXXJZCKZXSHMLQXXTTHXWZFKHCCZDYTCJYXQHLXDHYPJQXYLSYYDZOZJNYXQEZYSQYAYXWYPDGXDDXSPPYZNDLTWRHXYDXZZJHTCXMCZLHPYYYYMHZLLHNXMYLLLMDCPPXHMXDKYCYRDLTXJCHHZZXZLCCLYLNZSHZJZZLNNRLWHYQSNJHXYNTTTKYJPYCHHYEGKCTTWLGQRLGGTGTYGYHPYHYLQYQGCWYQKPYYYTTTTLHYHLLTYTTSPLKYZXGZWGPYDSSZZDQXSKCQNMJJZZBXYQMJRTFFBTKHZKBXLJJKDXJTLBWFZPPTKQTZTGPDGNTPJYFALQMKGXBDCLZFHZCLLLLADPMXDJHLCCLGYHDZFGYDDGCYYFGYDXKSSEBDHYKDKDKHNAXXYBPBYYHXZQGAFFQYJXDMLJCSQZLLPCHBSXGJYNDYBYQSPZWJLZKSDDTACTBXZDYZYPJZQSJNKKTKNJDJGYYPGTLFYQKASDNTCYHBLWDZHBBYDWJRYGKZYHEYYFJMSDTYFZJJHGCXPLXHLDWXXJKYTCYKSSSMTWCTTQZLPBSZDZWZXGZAGYKTYWXLHLSPBCLLOQMMZSSLCMBJCSZZKYDCZJGQQDSMCYTZQQLWZQZXSSFPTTFQMDDZDSHDTDWFHTDYZJYQJQKYPBDJYYXTLJHDRQXXXHAYDHRJLKLYTWHLLRLLRCXYLBWSRSZZSYMKZZHHKYHXKSMDSYDYCJPBZBSQLFCXXXNXKXWYWSDZYQOGGQMMYHCDZTTFJYYBGSTTTYBYKJDHKYXBELHTYPJQNFXFDYKZHQKZBYJTZBXHFDXKDASWTAWAJLDYJSFHBLDNNTNQJTJNCHXFJSRFWHZFMDRYJYJWZPDJKZYJYMPCYZNYNXFBYTFYFWYGDBNZZZDNYTXZEMMQBSQEHXFZMBMFLZZSRXYMJGSXWZJSPRYDJSJGXHJJGLJJYNZZJXHGXKYMLPYYYCXYTWQZSWHWLYRJLPXSLSXMFSWWKLCTNXNYNPSJSZHDZEPTXMYYWXYYSYWLXJQZQXZDCLEEELMCPJPCLWBXSQHFWWTFFJTNQJHJQDXHWLBYZNFJLALKYYJLDXHHYCSTYYWNRJYXYWTRMDRQHWQCMFJDYZMHMYYXJWMYZQZXTLMRSPWWCHAQBXYGZYPXYYRRCLMPYMGKSJSZYSRMYJSNXTPLNBAPPYPYLXYYZKYNLDZYJZCZNNLMZHHARQMPGWQTZMXXMLLHGDZXYHXKYXYCJMFFYYHJFSBSSQLXXNDYCANNMTCJCYPRRNYTYQNYYMBMSXNDLYLYSLJRLXYSXQMLLYZLZJJJKYZZCSFBZXXMSTBJGNXYZHLXNMCWSCYZYFZLXBRNNNYLBNRTGZQYSATSWRYHYJZMZDHZGZDWYBSSCSKXSYHYTXXGCQGXZZSHYXJSCRHMKKBXCZJYJYMKQHZJFNBHMQHYSNJNZYBKNQMCLGQHWLZNZSWXKHLJHYYBQLBFCDSXDLDSPFZPSKJYZWZXZDDXJSMMEGJSCSSMGCLXXKYYYLNYPWWWGYDKZJGGGZGGSYCKNJWNJPCXBJJTQTJWDSSPJXZXNZXUMELPXFSXTLLXCLJXJJLJZXCTPSWXLYDHLYQRWHSYCSQYYBYAYWJJJQFWQCQQCJQGXALDBZZYJGKGXPLTZYFXJLTPADKYQHPMATLCPDCKBMTXYBHKLENXDLEEGQDYMSAWHZMLJTWYGXLYQZLJEEYYBQQFFNLYXRDSCTGJGXYYNKLLYQKCCTLHJLQMKKZGCYYGLLLJDZGYDHZWXPYSJBZKDZGYZZHYWYFQYTYZSZYEZZLYMHJJHTSMQWYZLKYYWZCSRKQYTLTDXWCTYJKLWSQZWBDCQYNCJSRSZJLKCDCDTLZZZACQQZZDDXYPLXZBQJYLZLLLQDDZQJYJYJZYXNYYYNYJXKXDAZWYRDLJYYYRJLXLLDYXJCYWYWNQCCLDDNYYYNYCKCZHXXCCLGZQJGKWPPCQQJYSBZZXYJSQPXJPZBSBDSFNSFPZXHDWZTDWPPTFLZZBZDMYYPQJRSDZSQZSQXBDGCPZSWDWCSQZGMDHZXMWWFYBPDGPHTMJTHZSMMBGZMBZJCFZWFZBBZMQCFMBDMCJXLGPNJBBXGYHYYJGPTZGZMQBQTCGYXJXLWZKYDPDYMGCFTPFXYZTZXDZXTGKMTYBBCLBJASKYTSSQYYMSZXFJEWLXLLSZBQJJJAKLYLXLYCCTSXMCWFKKKBSXLLLLJYXTYLTJYYTDPJHNHNNKBYQNFQYYZBYYESSESSGDYHFHWTCJBSDZZTFDMXHCNJZYMQWSRYJDZJQPDQBBSTJGGFBKJBXTGQHNGWJXJGDLLTHZHHYYYYYYSXWTYYYCCBDBPYPZYCCZYJPZYWCBDLFWZCWJDXXHYHLHWZZXJTCZLCDPXUJCZZZLYXJJTXPHFXWPYWXZPTDZZBDZCYHJHMLXBQXSBYLRDTGJRRCTTTHYTCZWMXFYTWWZCWJWXJYWCSKYBZSCCTZQNHXNWXXKHKFHTSWOCCJYBCMPZZYKBNNZPBZHHZDLSYDDYTYFJPXYNGFXBYQXCBHXCPSXTYZDMKYSNXSXLHKMZXLYHDHKWHXXSSKQYHHCJYXGLHZXCSNHEKDTGZXQYPKDHEXTYKCNYMYYYPKQYYYKXZLTHJQTBYQHXBMYHSQCKWWYLLHCYYLNNEQXQWMCFBDCCMLJGGXDQKTLXKGNQCDGZJWYJJLYHHQTTTNWCHMXCXWHWSZJYDJCCDBQCDGDNYXZTHCQRXCBHZTQCBXWGQWYYBXHMBYMYQTYEXMQKYAQYRGYZSLFYKKQHYSSQYSHJGJCNXKZYCXSBXYXHYYLSTYCXQTHYSMGSCPMMGCCCCCMTZTASMGQZJHKLOSQYLSWTMXSYQKDZLJQQYPLSYCZTCQQPBBQJZCLPKHQZYYXXDTDDTSJCXFFLLCHQXMJLWCJCXTSPYCXNDTJSHJWXDQQJSKXYAMYLSJHMLALYKXCYYDMNMDQMXMCZNNCYBZKKYFLMCHCMLHXRCJJHSYLNMTJZGZGYWJXSRXCWJGJQHQZDQJDCJJZKJKGDZQGJJYJYLXZXXCDQHHHEYTMHLFSBDJSYYSHFYSTCZQLPBDRFRZTZYKYWHSZYQKWDQZRKMSYNBCRXQBJYFAZPZZEDZCJYWBCJWHYJBQSZYWRYSZPTDKZPFPBNZTKLQYHBBZPNPPTYZZYBQNYDCPJMMCYCQMCYFZZDCMNLFPBPLNGQJTBTTNJZPZBBZNJKLJQYLNBZQHKSJZNGGQSZZKYXSHPZSNBCGZKDDZQANZHJKDRTLZLSWJLJZLYWTJNDJZJHXYAYNCBGTZCSSQMNJPJYTYSWXZFKWJQTKHTZPLBHSNJZSYZBWZZZZLSYLSBJHDWWQPSLMMFBJDWAQYZTCJTBNNWZXQXCDSLQGDSDPDZHJTQQPSWLYYJZLGYXYZLCTCBJTKTYCZJTQKBSJLGMGZDMCSGPYNJZYQYYKNXRPWSZXMTNCSZZYXYBYHYZAXYWQCJTLLCKJJTJHGDXDXYQYZZBYWDLWQCGLZGJGQRQZCZSSBCRPCSKYDZNXJSQGXSSJMYDNSTZTPBDLTKZWXQWQTZEXNQCZGWEZKSSBYBRTSSSLCCGBPSZQSZLCCGLLLZXHZQTHCZMQGYZQZNMCOCSZJMMZSQPJYGQLJYJPPLDXRGZYXCCSXHSHGTZNLZWZKJCXTCFCJXLBMQBCZZWPQDNHXLJCTHYZLGYLNLSZZPCXDSCQQHJQKSXZPBAJYEMSMJTZDXLCJYRYYNWJBNGZZTMJXLTBSLYRZPYLSSCNXPHLLHYLLQQZQLXYMRSYCXZLMMCZLTZSDWTJJLLNZGGQXPFSKYGYGHBFZPDKMWGHCXMSGDXJMCJZDYCABXJDLNBCDQYGSKYDQTXDJJYXMSZQAZDZFSLQXYJSJZYLBTXXWXQQZBJZUFBBLYLWDSLJHXJYZJWTDJCZFQZQZZDZSXZZQLZCDZFJHYSPYMPQZMLPPLFFXJJNZZYLSJEYQZFPFZKSYWJJJHRDJZZXTXXGLGHYDXCSKYSWMMZCWYBAZBJKSHFHJCXMHFQHYXXYZFTSJYZFXYXPZLCHMZMBXHZZSXYFYMNCWDABAZLXKTCSHHXKXJJZJSTHYGXSXYYHHHJWXKZXSSBZZWHHHCWTZZZPJXSNXQQJGZYZYWLLCWXZFXXYXYHXMKYYSWSQMNLNAYCYSPMJKHWCQHYLAJJMZXHMMCNZHBHXCLXTJPLTXYJHDYYLTTXFSZHYXXSJBJYAYRSMXYPLCKDUYHLXRLNLLSTYZYYQYGYHHSCCSMZCTZQXKYQFPYYRPFFLKQUNTSZLLZMWWTCQQYZWTLLMLMPWMBZSSTZRBPDDTLQJJBXZCSRZQQYGWCSXFWZLXCCRSZDZMCYGGDZQSGTJSWLJMYMMZYHFBJDGYXCCPSHXNZCSBSJYJGJMPPWAFFYFNXHYZXZYLREMZGZCYZSSZDLLJCSQFNXZKPTXZGXJJGFMYYYSNBTYLBNLHPFZDCYFBMGQRRSSSZXYSGTZRNYDZZCDGPJAFJFZKNZBLCZSZPSGCYCJSZLMLRSZBZZLDLSLLYSXSQZQLYXZLSKKBRXBRBZCYCXZZZEEYFGKLZLYYHGZSGZLFJHGTGWKRAAJYZKZQTSSHJJXDCYZUYJLZYRZDQQHGJZXSSZBYKJPBFRTJXLLFQWJHYLQTYMBLPZDXTZYGBDHZZRBGXHWNJTJXLKSCFSMWLSDQYSJTXKZSCFWJLBXFTZLLJZLLQBLSQMQQCGCZFPBPHZCZJLPYYGGDTGWDCFCZQYYYQYSSCLXZSKLZZZGFFCQNWGLHQYZJJCZLQZZYJPJZZBPDCCMHJGXDQDGDLZQMFGPSYTSDYFWWDJZJYSXYYCZCYHZWPBYKXRYLYBHKJKSFXTZJMMCKHLLTNYYMSYXYZPYJQYCSYCWMTJJKQYRHLLQXPSGTLYYCLJSCPXJYZFNMLRGJJTYZBXYZMSJYJHHFZQMSYXRSZCWTLRTQZSSTKXGQKGSPTGCZNJSJCQCXHMXGGZTQYDJKZDLBZSXJLHYQGGGTHQSZPYHJHHGYYGKGGCWJZZYLCZLXQSFTGZSLLLMLJSKCTBLLZZSZMMNYTPZSXQHJCJYQXYZXZQZCPSHKZZYSXCDFGMWQRLLQXRFZTLYSTCTMJCXJJXHJNXTNRZTZFQYHQGLLGCXSZSJDJLJCYDSJTLNYXHSZXCGJZYQPYLFHDJSBPCCZHJJJQZJQDYBSSLLCMYTTMQTBHJQNNYGKYRQYQMZGCJKPDCGMYZHQLLSLLCLMHOLZGDYYFZSLJCQZLYLZQJESHNYLLJXGJXLYSYYYXNBZLJSSZCQQCJYLLZLTJYLLZLLBNYLGQCHXYYXOXCXQKYJXXXYKLXSXXYQXCYKQXQCSGYXXYQXYGYTQOHXHXPYXXXULCYEYCHZZCBWQBBWJQZSCSZSSLZYLKDESJZWMYMCYTSDSXXSCJPQQSQYLYYZYCMDJDZYWCBTJSYDJKCYDDJLBDJJSODZYSYXQQYXDHHGQQYQHDYXWGMMMAJDYBBBPPBCMUUPLJZSMTXERXJMHQNUTPJDCBSSMSSSTKJTSSMMTRCPLZSZMLQDSDMJMQPNQDXCFYNBFSDQXYXHYAYKQYDDLQYYYSSZBYDSLNTFQTZQPZMCHDHCZCWFDXTMYQSPHQYYXSRGJCWTJTZZQMGWJJTJHTQJBBHWZPXXHYQFXXQYWYYHYSCDYDHHQMNMTMWCPBSZPPZZGLMZFOLLCFWHMMSJZTTDHZZYFFYTZZGZYSKYJXQYJZQBHMBZZLYGHGFMSHPZFZSNCLPBQSNJXZSLXXFPMTYJYGBXLLDLXPZJYZJYHHZCYWHJYLSJEXFSZZYWXKZJLUYDTMLYMQJPWXYHXSKTQJEZRPXXZHHMHWQPWQLYJJQJJZSZCPHJLCHHNXJLQWZJHBMZYXBDHHYPZLHLHLGFWLCHYYTLHJXCJMSCPXSTKPNHQXSRTYXXTESYJCTLSSLSTDLLLWWYHDHRJZSFGXTSYCZYNYHTDHWJSLHTZDQDJZXXQHGYLTZPHCSQFCLNJTCLZPFSTPDYNYLGMJLLYCQHYSSHCHYLHQYQTMZYPBYWRFQYKQSYSLZDQJMPXYYSSRHZJNYWTQDFZBWWTWWRXCWHGYHXMKMYYYQMSMZHNGCEPMLQQMTCWCTMMPXJPJJHFXYYZSXZHTYBMSTSYJTTQQQYYLHYNPYQZLCYZHZWSMYLKFJXLWGXYPJYTYSYXYMZCKTTWLKSMZSYLMPWLZWXWQZSSAQSYXYRHSSNTSRAPXCPWCMGDXHXZDZYFJHGZTTSBJHGYZSZYSMYCLLLXBTYXHBBZJKSSDMALXHYCFYGMQYPJYCQXJLLLJGSLZGQLYCJCCZOTYXMTMTTLLWTGPXYMZMKLPSZZZXHKQYSXCTYJZYHXSHYXZKXLZWPSQPYHJWPJPWXQQYLXSDHMRSLZZYZWTTCYXYSZZSHBSCCSTPLWSSCJCHNLCGCHSSPHYLHFHHXJSXYLLNYLSZDHZXYLSXLWZYKCLDYAXZCMDDYSPJTQJZLNWQPSSSWCTSTSZLBLNXSMNYYMJQBQHRZWTYYDCHQLXKPZWBGQYBKFCMZWPZLLYYLSZYDWHXPSBCMLJBSCGBHXLQHYRLJXYSWXWXZSLDFHLSLYNJLZYFLYJYCDRJLFSYZFSLLCQYQFGJYHYXZLYLMSTDJCYHBZLLNWLXXYGYYHSMGDHXXHHLZZJZXCZZZCYQZFNGWPYLCPKPYYPMCLQKDGXZGGWQBDXZZKZFBXXLZXJTPJPTTBYTSZZDWSLCHZHSLTYXHQLHYXXXYYZYSWTXZKHLXZXZPYHGCHKCFSYHUTJRLXFJXPTZTWHPLYXFCRHXSHXKYXXYHZQDXQWULHYHMJTBFLKHTXCWHJFWJCFPQRYQXCYYYQYGRPYWSGSUNGWCHKZDXYFLXXHJJBYZWTSXXNCYJJYMSWZJQRMHXZWFQSYLZJZGBHYNSLBGTTCSYBYXXWXYHXYYXNSQYXMQYWRGYQLXBBZLJSYLPSYTJZYHYZAWLRORJMKSCZJXXXYXCHDYXRYXXJDTSQFXLYLTSFFYXLMTYJMJUYYYXLTZCSXQZQHZXLYYXZHDNBRXXXJCTYHLBRLMBRLLAXKYLLLJLYXXLYCRYLCJTGJCMTLZLLCYZZPZPCYAWHJJFYBDYYZSMPCKZDQYQPBPCJPDCYZMDPBCYYDYCNNPLMTMLRMFMMGWYZBSJGYGSMZQQQZTXMKQWGXLLPJGZBQCDJJJFPKJKCXBLJMSWMDTQJXLDLPPBXCWRCQFBFQJCZAHZGMYKPHYYHZYKNDKZMBPJYXPXYHLFPNYYGXJDBKXNXHJMZJXSTRSTLDXSKZYSYBZXJLXYSLBZYSLHXJPFXPQNBYLLJQKYGZMCYZZYMCCSLCLHZFWFWYXZMWSXTYNXJHPYYMCYSPMHYSMYDYSHQYZCHMJJMZCAAGCFJBBHPLYZYLXXSDJGXDHKXXTXXNBHRMLYJSLTXMRHNLXQJXYZLLYSWQGDLBJHDCGJYQYCMHWFMJYBMBYJYJWYMDPWHXQLDYGPDFXXBCGJSPCKRSSYZJMSLBZZJFLJJJLGXZGYXYXLSZQYXBEXYXHGCXBPLDYHWETTWWCJMBTXCHXYQXLLXFLYXLLJLSSFWDPZSMYJCLMWYTCZPCHQEKCQBWLCQYDPLQPPQZQFJQDJHYMMCXTXDRMJWRHXCJZYLQXDYYNHYYHRSLSRSYWWZJYMTLTLLGTQCJZYABTCKZCJYCCQLJZQXALMZYHYWLWDXZXQDLLQSHGPJFJLJHJABCQZDJGTKHSSTCYJLPSWZLXZXRWGLDLZRLZXTGSLLLLZLYXXWGDZYGBDPHZPBRLWSXQBPFDWOFMWHLYPCBJCCLDMBZPBZZLCYQXLDOMZBLZWPDWYYGDSTTHCSQSCCRSSSYSLFYBFNTYJSZDFNDPDHDZZMBBLSLCMYFFGTJJQWFTMTPJWFNLBZCMMJTGBDZLQLPYFHYYMJYLSDCHDZJWJCCTLJCLDTLJJCPDDSQDSSZYBNDBJLGGJZXSXNLYCYBJXQYCBYLZCFZPPGKCXZDZFZTJJFJSJXZBNZYJQTTYJYHTYCZHYMDJXTTMPXSPLZCDWSLSHXYPZGTFMLCJTYCBPMGDKWYCYZCDSZZYHFLYCTYGWHKJYYLSJCXGYWJCBLLCSNDDBTZBSCLYZCZZSSQDLLMQYYHFSLQLLXFTYHABXGWNYWYYPLLSDLDLLBJCYXJZMLHLJDXYYQYTDLLLBUGBFDFBBQJZZMDPJHGCLGMJJPGAEHHBWCQXAXHHHZCHXYPHJAXHLPHJPGPZJQCQZGJJZZUZDMQYYBZZPHYHYBWHAZYJHYKFGDPFQSDLZMLJXKXGALXZDAGLMDGXMWZQYXXDXXPFDMMSSYMPFMDMMKXKSYZYSHDZKXSYSMMZZZMSYDNZZCZXFPLSTMZDNMXCKJMZTYYMZMZZMSXHHDCZJEMXXKLJSTLWLSQLYJZLLZJSSDPPMHNLZJCZYHMXXHGZCJMDHXTKGRMXFWMCGMWKDTKSXQMMMFZZYDKMSCLCMPCGMHSPXQPZDSSLCXKYXTWLWJYAHZJGZQMCSNXYYMMPMLKJXMHLMLQMXCTKZMJQYSZJSYSZHSYJZJCDAJZYBSDQJZGWZQQXFKDMSDJLFWEHKZQKJPEYPZYSZCDWYJFFMZZYLTTDZZEFMZLBNPPLPLPEPSZALLTYLKCKQZKGENQLWAGYXYDPXLHSXQQWQCQXQCLHYXXMLYCCWLYMQYSKGCHLCJNSZKPYZKCQZQLJPDMDZHLASXLBYDWQLWDNBQCRYDDZTJYBKBWSZDXDTNPJDTCTQDFXQQMGNXECLTTBKPWSLCTYQLPWYZZKLPYGZCQQPLLKCCYLPQMZCZQCLJSLQZDJXLDDHPZQDLJJXZQDXYZQKZLJCYQDYJPPYPQYKJYRMPCBYMCXKLLZLLFQPYLLLMBSGLCYSSLRSYSQTMXYXZQZFDZUYSYZTFFMZZSMZQHZSSCCMLYXWTPZGXZJGZGSJSGKDDHTQGGZLLBJDZLCBCHYXYZHZFYWXYZYMSDBZZYJGTSMTFXQYXQSTDGSLNXDLRYZZLRYYLXQHTXSRTZNGZXBNQQZFMYKMZJBZYMKBPNLYZPBLMCNQYZZZSJZHJCTZKHYZZJRDYZHNPXGLFZTLKGJTCTSSYLLGZRZBBQZZKLPKLCZYSSUYXBJFPNJZZXCDWXZYJXZZDJJKGGRSRJKMSMZJLSJYWQSKYHQJSXPJZZZLSNSHRNYPZTWCHKLPSRZLZXYJQXQKYSJYCZTLQZYBBYBWZPQDWWYZCYTJCJXCKCWDKKZXSGKDZXWWYYJQYYTCYTDLLXWKCZKKLCCLZCQQDZLQLCSFQCHQHSFSMQZZLNBJJZBSJHTSZDYSJQJPDLZCDCWJKJZZLPYCGMZWDJJBSJQZSYZYHHXJPBJYDSSXDZNCGLQMBTSFSBPDZDLZNFGFJGFSMPXJQLMBLGQCYYXBQKDJJQYRFKZTJDHCZKLBSDZCFJTPLLJGXHYXZCSSZZXSTJYGKGCKGYOQXJPLZPBPGTGYJZGHZQZZLBJLSQFZGKQQJZGYCZBZQTLDXRJXBSXXPZXHYZYCLWDXJJHXMFDZPFZHQHQMQGKSLYHTYCGFRZGNQXCLPDLBZCSCZQLLJBLHBZCYPZZPPDYMZZSGYHCKCPZJGSLJLNSCDSLDLXBMSTLDDFJMKDJDHZLZXLSZQPQPGJLLYBDSZGQLBZLSLKYYHZTTNTJYQTZZPSZQZTLLJTYYLLQLLQYZQLBDZLSLYYZYMDFSZSNHLXZNCZQZPBWSKRFBSYZMTHBLGJPMCZZLSTLXSHTCSYZLZBLFEQHLXFLCJLYLJQCBZLZJHHSSTBRMHXZHJZCLXFNBGXGTQJCZTMSFZKJMSSNXLJKBHSJXNTNLZDNTLMSJXGZJYJCZXYJYJWRWWQNZTNFJSZPZSHZJFYRDJSFSZJZBJFZQZZHZLXFYSBZQLZSGYFTZDCSZXZJBQMSZKJRHYJZCKMJKHCHGTXKXQGLXPXFXTRTYLXJXHDTSJXHJZJXZWZLCQSBTXWXGXTXXHXFTSDKFJHZYJFJXRZSDLLLTQSQQZQWZXSYQTWGWBZCGZLLYZBCLMQQTZHZXZXLJFRMYZFLXYSQXXJKXRMQDZDMMYYBSQBHGZMWFWXGMXLZPYYTGZYCCDXYZXYWGSYJYZNBHPZJSQSYXSXRTFYZGRHZTXSZZTHCBFCLSYXZLZQMZLMPLMXZJXSFLBYZMYQHXJSXRXSQZZZSSLYFRCZJRCRXHHZXQYDYHXSJJHZCXZBTYNSYSXJBQLPXZQPYMLXZKYXLXCJLCYSXXZZLXDLLLJJYHZXGYJWKJRWYHCPSGNRZLFZWFZZNSXGXFLZSXZZZBFCSYJDBRJKRDHHGXJLJJTGXJXXSTJTJXLYXQFCSGSWMSBCTLQZZWLZZKXJMLTMJYHSDDBXGZHDLBMYJFRZFSGCLYJBPMLYSMSXLSZJQQHJZFXGFQFQBPXZGYYQXGZTCQWYLTLGWSGWHRLFSFGZJMGMGBGTJFSYZZGZYZAFLSSPMLPFLCWBJZCLJJMZLPJJLYMQDMYYYFBGYGYZMLYZDXQYXRQQQHSYYYQXYLJTYXFSFSLLGNQCYHYCWFHCCCFXPYLYPLLZYXXXXXKQHHXSHJZCFZSCZJXCPZWHHHHHAPYLQALPQAFYHXDYLUKMZQGGGDDESRNNZLTZGCHYPPYSQJJHCLLJTOLNJPZLJLHYMHEYDYDSQYCDDHGZUNDZCLZYZLLZNTNYZGSLHSLPJJBDGWXPCDUTJCKLKCLWKLLCASSTKZZDNQNTTLYYZSSYSSZZRYLJQKCQDHHCRXRZYDGRGCWCGZQFFFPPJFZYNAKRGYWYQPQXXFKJTSZZXSWZDDFBBXTBGTZKZNPZZPZXZPJSZBMQHKCYXYLDKLJNYPKYGHGDZJXXEAHPNZKZTZCMXCXMMJXNKSZQNMNLWBWWXJKYHCPSTMCSQTZJYXTPCTPDTNNPGLLLZSJLSPBLPLQHDTNJNLYYRSZFFJFQWDPHZDWMRZCCLODAXNSSNYZRESTYJWJYJDBCFXNMWTTBYLWSTSZGYBLJPXGLBOCLHPCBJLTMXZLJYLZXCLTPNCLCKXTPZJSWCYXSFYSZDKNTLBYJCYJLLSTGQCBXRYZXBXKLYLHZLQZLNZCXWJZLJZJNCJHXMNZZGJZZXTZJXYCYYCXXJYYXJJXSSSJSTSSTTPPGQTCSXWZDCSYFPTFBFHFBBLZJCLZZDBXGCXLQPXKFZFLSYLTUWBMQJHSZBMDDBCYSCCLDXYCDDQLYJJWMQLLCSGLJJSYFPYYCCYLTJANTJJPWYCMMGQYYSXDXQMZHSZXPFTWWZQSWQRFKJLZJQQYFBRXJHHFWJJZYQAZMYFRHCYYBYQWLPEXCCZSTYRLTTDMQLYKMBBGMYYJPRKZNPBSXYXBHYZDJDNGHPMFSGMWFZMFQMMBCMZZCJJLCNUXYQLMLRYGQZCYXZLWJGCJCGGMCJNFYZZJHYCPRRCMTZQZXHFQGTJXCCJEAQCRJYHPLQLSZDJRBCQHQDYRHYLYXJSYMHZYDWLDFRYHBPYDTSSCNWBXGLPZMLZZTQSSCPJMXXYCSJYTYCGHYCJWYRXXLFEMWJNMKLLSWTXHYYYNCMMCWJDQDJZGLLJWJRKHPZGGFLCCSCZMCBLTBHBQJXQDSPDJZZGKGLFQYWBZYZJLTSTDHQHCTCBCHFLQMPWDSHYYTQWCNZZJTLBYMBPDYYYXSQKXWYYFLXXNCWCXYPMAELYKKJMZZZBRXYYQJFLJPFHHHYTZZXSGQQMHSPGDZQWBWPJHZJDYSCQWZKTXXSQLZYYMYSDZGRXCKKUJLWPYSYSCSYZLRMLQSYLJXBCXTLWDQZPCYCYKPPPNSXFYZJJRCEMHSZMSXLXGLRWGCSTLRSXBZGBZGZTCPLUJLSLYLYMTXMTZPALZXPXJTJWTCYYZLBLXBZLQMYLXPGHDSLSSDMXMBDZZSXWHAMLCZCPJMCNHJYSNSYGCHSKQMZZQDLLKABLWJXSFMOCDXJRRLYQZKJMYBYQLYHETFJZFRFKSRYXFJTWDSXXSYSQJYSLYXWJHSNLXYYXHBHAWHHJZXWMYLJCSSLKYDZTXBZSYFDXGXZJKHSXXYBSSXDPYNZWRPTQZCZENYGCXQFJYKJBZMLJCMQQXUOXSLYXXLYLLJDZBTYMHPFSTTQQWLHOKYBLZZALZXQLHZWRRQHLSTMYPYXJJXMQSJFNBXYXYJXXYQYLTHYLQYFMLKLJTMLLHSZWKZHLJMLHLJKLJSTLQXYLMBHHLNLZXQJHXCFXXLHYHJJGBYZZKBXSCQDJQDSUJZYYHZHHMGSXCSYMXFEBCQWWRBPYYJQTYZCYQYQQZYHMWFFHGZFRJFCDPXNTQYZPDYKHJLFRZXPPXZDBBGZQSTLGDGYLCQMLCHHMFYWLZYXKJLYPQHSYWMQQGQZMLZJNSQXJQSYJYCBEHSXFSZPXZWFLLBCYYJDYTDTHWZSFJMQQYJLMQXXLLDTTKHHYBFPWTYYSQQWNQWLGWDEBZWCMYGCULKJXTMXMYJSXHYBRWFYMWFRXYQMXYSZTZZTFYKMLDHQDXWYYNLCRYJBLPSXCXYWLSPRRJWXHQYPHTYDNXHHMMYWYTZCSQMTSSCCDALWZTCPQPYJLLQZYJSWXMZZMMYLMXCLMXCZMXMZSQTZPPQQBLPGXQZHFLJJHYTJSRXWZXSCCDLXTYJDCQJXSLQYCLZXLZZXMXQRJMHRHZJBHMFLJLMLCLQNLDXZLLLPYPSYJYSXCQQDCMQJZZXHNPNXZMEKMXHYKYQLXSXTXJYYHWDCWDZHQYYBGYBCYSCFGPSJNZDYZZJZXRZRQJJYMCANYRJTLDPPYZBSTJKXXZYPFDWFGZZRPYMTNGXZQBYXNBUFNQKRJQZMJEGRZGYCLKXZDSKKNSXKCLJSPJYYZLQQJYBZSSQLLLKJXTBKTYLCCDDBLSPPFYLGYDTZJYQGGKQTTFZXBDKTYYHYBBFYTYYBCLPDYTGDHRYRNJSPTCSNYJQHKLLLZSLYDXXWBCJQSPXBPJZJCJDZFFXXBRMLAZHCSNDLBJDSZBLPRZTSWSBXBCLLXXLZDJZSJPYLYXXYFTFFFBHJJXGBYXJPMMMPSSJZJMTLYZJXSWXTYLEDQPJMYGQZJGDJLQJWJQLLSJGJGYGMSCLJJXDTYGJQJQJCJZCJGDZZSXQGSJGGCXHQXSNQLZZBXHSGZXCXYLJXYXYYDFQQJHJFXDHCTXJYRXYSQTJXYEFYYSSYYJXNCYZXFXMSYSZXYYSCHSHXZZZGZZZGFJDLTYLNPZGYJYZYYQZPBXQBDZTZCZYXXYHHSQXSHDHGQHJHGYWSZTMZMLHYXGEBTYLZKQWYTJZRCLEKYSTDBCYKQQSAYXCJXWWGSBHJYZYDHCSJKQCXSWXFLTYNYZPZCCZJQTZWJQDZZZQZLJJXLSBHPYXXPSXSHHEZTXFPTLQYZZXHYTXNCFZYYHXGNXMYWXTZSJPTHHGYMXMXQZXTSBCZYJYXXTYYZYPCQLMMSZMJZZLLZXGXZAAJZYXJMZXWDXZSXZDZXLEYJJZQBHZWZZZQTZPSXZTDSXJJJZNYAZPHXYYSRNQDTHZHYYKYJHDZXZLSWCLYBZYECWCYCRYLCXNHZYDZYDYJDFRJJHTRSQTXYXJRJHOJYNXELXSFSFJZGHPZSXZSZDZCQZBYYKLSGSJHCZSHDGQGXYZGXCHXZJWYQWGYHKSSEQZZNDZFKWYSSTCLZSTSYMCDHJXXYWEYXCZAYDMPXMDSXYBSQMJMZJMTZQLPJYQZCGQHXJHHLXXHLHDLDJQCLDWBSXFZZYYSCHTYTYYBHECXHYKGJPXHHYZJFXHWHBDZFYZBCAPNPGNYDMSXHMMMMAMYNBYJTMPXYYMCTHJBZYFCGTYHWPHFTWZZEZSBZEGPFMTSKFTYCMHFLLHGPZJXZJGZJYXZSBBQSCZZLZCCSTPGXMJSFTCCZJZDJXCYBZLFCJSYZFGSZLYBCWZZBYZDZYPSWYJZXZBDSYUXLZZBZFYGCZXBZHZFTPBGZGEJBSTGKDMFHYZZJHZLLZZGJQZLSFDJSSCBZGPDLFZFZSZYZYZSYGCXSNXXCHCZXTZZLJFZGQSQYXZJQDCCZTQCDXZJYQJQCHXZTDLGSCXZSYQJQTZWLQDQZTQCHQQJZYEZZZPBWKDJFCJPZTYPQYQTTYNLMBDKTJZPQZQZZFPZSBNJLGYJDXJDZZKZGQKXDLPZJTCJDQBXDJQJSTCKNXBXZMSLYJCQMTJQWWCJQNJNLLLHJCWQTBZQYDZCZPZZDZYDDCYZZZCCJTTJFZDPRRTZTJDCQTQZDTJNPLZBCLLCTZSXKJZQZPZLBZRBTJDCXFCZDBCCJJLTQQPLDCGZDBBZJCQDCJWYNLLZYZCCDWLLXWZLXRXNTQQCZXKQLSGDFQTDDGLRLAJJTKUYMKQLLTZYTDYYCZGJWYXDXFRSKSTQTENQMRKQZHHQKDLDAZFKYPBGGPZREBZZYKZZSPEGJXGYKQZZZSLYSYYYZWFQZYLZZLZHWCHKYPQGNPGBLPLRRJYXCCSYYHSFZFYBZYYTGZXYLXCZWXXZJZBLFFLGSKHYJZEYJHLPLLLLCZGXDRZELRHGKLZZYHZLYQSZZJZQLJZFLNBHGWLCZCFJYSPYXZLZLXGCCPZBLLCYBBBBUBBCBPCRNNZCZYRBFSRLDCGQYYQXYGMQZWTZYTYJXYFWTEHZZJYWLCCNTZYJJZDEDPZDZTSYQJHDYMBJNYJZLXTSSTPHNDJXXBYXQTZQDDTJTDYYTGWSCSZQFLSHLGLBCZPHDLYZJYCKWTYTYLBNYTSDSYCCTYSZYYEBHEXHQDTWNYGYCLXTSZYSTQMYGZAZCCSZZDSLZCLZRQXYYELJSBYMXSXZTEMBBLLYYLLYTDQYSHYMRQWKFKBFXNXSBYCHXBWJYHTQBPBSBWDZYLKGZSKYHXQZJXHXJXGNLJKZLYYCDXLFYFGHLJGJYBXQLYBXQPQGZTZPLNCYPXDJYQYDYMRBESJYYHKXXSTMXRCZZYWXYQYBMCLLYZHQYZWQXDBXBZWZMSLPDMYSKFMZKLZCYQYCZLQXFZZYDQZPZYGYJYZMZXDZFYFYTTQTZHGSPCZMLCCYTZXJCYTJMKSLPZHYSNZLLYTPZCTZZCKTXDHXXTQCYFKSMQCCYYAZHTJPCYLZLYJBJXTPNYLJYYNRXSYLMMNXJSMYBCSYSYLZYLXJJQYLDZLPQBFZZBLFNDXQKCZFYWHGQMRDSXYCYTXNQQJZYYPFZXDYZFPRXEJDGYQBXRCNFYYQPGHYJDYZXGRHTKYLNWDZNTSMPKLBTHBPYSZBZTJZSZZJTYYXZPHSSZZBZCZPTQFZMYFLYPYBBJQXZMXXDJMTSYSKKBJZXHJCKLPSMKYJZCXTMLJYXRZZQSLXXQPYZXMKYXXXJCLJPRMYYGADYSKQLSNDHYZKQXZYZTCGHZTLMLWZYBWSYCTBHJHJFCWZTXWYTKZLXQSHLYJZJXTMPLPYCGLTBZZTLZJCYJGDTCLKLPLLQPJMZPAPXYZLKKTKDZCZZBNZDYDYQZJYJGMCTXLTGXSZLMLHBGLKFWNWZHDXUHLFMKYSLGXDTWWFRJEJZTZHYDXYKSHWFZCQSHKTMQQHTZHYMJDJSKHXZJZBZZXYMPAGQMSTPXLSKLZYNWRTSQLSZBPSPSGZWYHTLKSSSWHZZLYYTNXJGMJSZSUFWNLSOZTXGXLSAMMLBWLDSZYLAKQCQCTMYCFJBSLXCLZZCLXXKSBZQCLHJPSQPLSXXCKSLNHPSFQQYTXYJZLQLDXZQJZDYYDJNZPTUZDSKJFSLJHYLZSQZLBTXYDGTQFDBYAZXDZHZJNHHQBYKNXJJQCZMLLJZKSPLDYCLBBLXKLELXJLBQYCXJXGCNLCQPLZLZYJTZLJGYZDZPLTQCSXFDMNYCXGBTJDCZNBGBQYQJWGKFHTNPYQZQGBKPBBYZMTJDYTBLSQMPSXTBNPDXKLEMYYCJYNZCTLDYKZZXDDXHQSHDGMZSJYCCTAYRZLPYLTLKXSLZCGGEXCLFXLKJRTLQJAQZNCMBYDKKCXGLCZJZXJHPTDJJMZQYKQSECQZDSHHADMLZFMMZBGNTJNNLGBYJBRBTMLBYJDZXLCJLPLDLPCQDHLXZLYCBLCXZZJADJLNZMMSSSMYBHBSQKBHRSXXJMXSDZNZPXLGBRHWGGFCXGMSKLLTSJYYCQLTSKYWYYHYWXBXQYWPYWYKQLSQPTNTKHQCWDQKTWPXXHCPTHTWUMSSYHBWCRWXHJMKMZNGWTMLKFGHKJYLSYYCXWHYECLQHKQHTTQKHFZLDXQWYZYYDESBPKYRZPJFYYZJCEQDZZDLATZBBFJLLCXDLMJSSXEGYGSJQXCWBXSSZPDYZCXDNYXPPZYDLYJCZPLTXLSXYZYRXCYYYDYLWWNZSAHJSYQYHGYWWAXTJZDAXYSRLTDPSSYYFNEJDXYZHLXLLLZQZSJNYQYQQXYJGHZGZCYJCHZLYCDSHWSHJZYJXCLLNXZJJYYXNFXMWFPYLCYLLABWDDHWDXJMCXZTZPMLQZHSFHZYNZTLLDYWLSLXHYMMYLMBWWKYXYADTXYLLDJPYBPWUXJMWMLLSAFDLLYFLBHHHBQQLTZJCQJLDJTFFKMMMBYTHYGDCQRDDWRQJXNBYSNWZDBYYTBJHPYBYTTJXAAHGQDQTMYSTQXKBTZPKJLZRBEQQSSMJJBDJOTGTBXPGBKTLHQXJJJCTHXQDWJLWRFWQGWSHCKRYSWGFTGYGBXSDWDWRFHWYTJJXXXJYZYSLPYYYPAYXHYDQKXSHXYXGSKQHYWFDDDPPLCJLQQEEWXKSYYKDYPLTJTHKJLTCYYHHJTTPLTZZCDLTHQKZXQYSTEEYWYYZYXXYYSTTJKLLPZMCYHQGXYHSRMBXPLLNQYDQHXSXXWGDQBSHYLLPJJJTHYJKYPPTHYYKTYEZYENMDSHLCRPQFDGFXZPSFTLJXXJBSWYYSKSFLXLPPLBBBLBSFXFYZBSJSSYLPBBFFFFSSCJDSTZSXZRYYSYFFSYZYZBJTBCTSBSDHRTJJBYTCXYJEYLXCBNEBJDSYXYKGSJZBXBYTFZWGENYHHTHZHHXFWGCSTBGXKLSXYWMTMBYXJSTZSCDYQRCYTWXZFHMYMCXLZNSDJTTTXRYCFYJSBSDYERXJLJXBBDEYNJGHXGCKGSCYMBLXJMSZNSKGXFBNBPTHFJAAFXYXFPXMYPQDTZCXZZPXRSYWZDLYBBKTYQPQJPZYPZJZNJPZJLZZFYSBTTSLMPTZRTDXQSJEHBZYLZDHLJSQMLHTXTJECXSLZZSPKTLZKQQYFSYGYWPCPQFHQHYTQXZKRSGTTSQCZLPTXCDYYZXSQZSLXLZMYCPCQBZYXHBSXLZDLTCDXTYLZJYYZPZYZLTXJSJXHLPMYTXCQRBLZSSFJZZTNJYTXMYJHLHPPLCYXQJQQKZZSCPZKSWALQSBLCCZJSXGWWWYGYKTJBBZTDKHXHKGTGPBKQYSLPXPJCKBMLLXDZSTBKLGGQKQLSBKKTFXRMDKBFTPZFRTBBRFERQGXYJPZSSTLBZTPSZQZSJDHLJQLZBPMSMMSXLQQNHKNBLRDDNXXDHDDJCYYGYLXGZLXSYGMQQGKHBPMXYXLYTQWLWGCPBMQXCYZYDRJBHTDJYHQSHTMJSBYPLWHLZFFNYPMHXXHPLTBQPFBJWQDBYGPNZTPFZJGSDDTQSHZEAWZZYLLTYYBWJKXXGHLFKXDJTMSZSQYNZGGSWQSPHTLSSKMCLZXYSZQZXNCJDQGZDLFNYKLJCJLLZLMZZNHYDSSHTHZZLZZBBHQZWWYCRZHLYQQJBEYFXXXWHSRXWQHWPSLMSSKZTTYGYQQWRSLALHMJTQJSMXQBJJZJXZYZKXBYQXBJXSHZTSFJLXMXZXFGHKZSZGGYLCLSARJYHSLLLMZXELGLXYDJYTLFBHBPNLYZFBBHPTGJKWETZHKJJXZXXGLLJLSTGSHJJYQLQZFKCGNNDJSSZFDBCTWWSEQFHQJBSAQTGYPQLBXBMMYWXGSLZHGLZGQYFLZBYFZJFRYSFMBYZHQGFWZSYFYJJPHZBYYZFFWODGRLMFTWLBZGYCQXCDJYGZYYYYTYTYDWEGAZYHXJLZYYHLRMGRXXZCLHNELJJTJTPWJYBJJBXJJTJTEEKHWSLJPLPSFYZPQQBDLQJJTYYQLYZKDKSQJYYQZLDQTGJQYZJSUCMRYQTHTEJMFCTYHYPKMHYZWJDQFHYYXWSHCTXRLJHQXHCCYYYJLTKTTYTMXGTCJTZAYYOCZLYLBSZYWJYTSJYHBYSHFJLYGJXXTMZYYLTXXYPZLXYJZYZYYPNHMYMDYYLBLHLSYYQQLLNJJYMSOYQBZGDLYXYLCQYXTSZEGXHZGLHWBLJHEYXTWQMAKBPQCGYSHHEGQCMWYYWLJYJHYYZLLJJYLHZYHMGSLJLJXCJJYCLYCJPCPZJZJMMYLCQLNQLJQJSXYJMLSZLJQLYCMMHCFMMFPQQMFYLQMCFFQMMMMHMZNFHHJGTTHHKHSLNCHHYQDXTMMQDCYZYXYQMYQYLTDCYYYZAZZCYMZYDLZFFFMMYCQZWZZMABTBYZTDMNZZGGDFTYPCGQYTTSSFFWFDTZQSSYSTWXJHXYTSXXYLBYQHWWKXHZXWZNNZZJZJJQJCCCHYYXBZXZCYZTLLCQXYNJYCYYCYNZZQYYYEWYCZDCJYCCHYJLBTZYYCQWMPWPYMLGKDLDLGKQQBGYCHJXY"; + + // 此处收录了375个多音字 + string multiPinyin = "19969:DZ,19975:WM,19988:QJ,20048:YL,20056:SC,20060:NM,20094:QG,20127:QJ,20167:QC,20193:YG,20250:KH,20256:ZC,20282:SC,20285:QJG,20291:TD,20314:YD,20340:NE,20375:TD,20389:YJ,20391:CZ,20415:PB,20446:YS,20447:SQ,20504:TC,20608:KG,20854:QJ,20857:ZC,20911:PF,20504:TC,20608:KG,20854:QJ,20857:ZC,20911:PF,20985:AW,21032:PB,21048:XQ,21049:SC,21089:YS,21119:JC,21242:SB,21273:SC,21305:YP,21306:QO,21330:ZC,21333:SDC,21345:QK,21378:CA,21397:SC,21414:XS,21442:SC,21477:JG,21480:TD,21484:ZS,21494:YX,21505:YX,21512:HG,21523:XH,21537:PB,21542:PF,21549:KH,21571:E,21574:DA,21588:TD,21589:O,21618:ZC,21621:KHA,21632:ZJ,21654:KG,21679:LKG,21683:KH,21710:A,21719:YH,21734:WOE,21769:A,21780:WN,21804:XH,21834:A,21899:ZD,21903:RN,21908:WO,21939:ZC,21956:SA,21964:YA,21970:TD,22003:A,22031:JG,22040:XS,22060:ZC,22066:ZC,22079:MH,22129:XJ,22179:XA,22237:NJ,22244:TD,22280:JQ,22300:YH,22313:XW,22331:YQ,22343:YJ,22351:PH,22395:DC,22412:TD,22484:PB,22500:PB,22534:ZD,22549:DH,22561:PB,22612:TD,22771:KQ,22831:HB,22841:JG,22855:QJ,22865:XQ,23013:ML,23081:WM,23487:SX,23558:QJ,23561:YW,23586:YW,23614:YW,23615:SN,23631:PB,23646:ZS,23663:ZT,23673:YG,23762:TD,23769:ZS,23780:QJ,23884:QK,24055:XH,24113:DC,24162:ZC,24191:GA,24273:QJ,24324:NL,24377:TD,24378:QJ,24439:PF,24554:ZS,24683:TD,24694:WE,24733:LK,24925:TN,25094:ZG,25100:XQ,25103:XH,25153:PB,25170:PB,25179:KG,25203:PB,25240:ZS,25282:FB,25303:NA,25324:KG,25341:ZY,25373:WZ,25375:XJ,25384:A,25457:A,25528:SD,25530:SC,25552:TD,25774:ZC,25874:ZC,26044:YW,26080:WM,26292:PB,26333:PB,26355:ZY,26366:CZ,26397:ZC,26399:QJ,26415:ZS,26451:SB,26526:ZC,26552:JG,26561:TD,26588:JG,26597:CZ,26629:ZS,26638:YL,26646:XQ,26653:KG,26657:XJ,26727:HG,26894:ZC,26937:ZS,26946:ZC,26999:KJ,27099:KJ,27449:YQ,27481:XS,27542:ZS,27663:ZS,27748:TS,27784:SC,27788:ZD,27795:TD,27812:O,27850:PB,27852:MB,27895:SL,27898:PL,27973:QJ,27981:KH,27986:HX,27994:XJ,28044:YC,28065:WG,28177:SM,28267:QJ,28291:KH,28337:ZQ,28463:TL,28548:DC,28601:TD,28689:PB,28805:JG,28820:QG,28846:PB,28952:TD,28975:ZC,29100:A,29325:QJ,29575:SL,29602:FB,30010:TD,30044:CX,30058:PF,30091:YSP,30111:YN,30229:XJ,30427:SC,30465:SX,30631:YQ,30655:QJ,30684:QJG,30707:SD,30729:XH,30796:LG,30917:PB,31074:NM,31085:JZ,31109:SC,31181:ZC,31192:MLB,31293:JQ,31400:YX,31584:YJ,31896:ZN,31909:ZY,31995:XJ,32321:PF,32327:ZY,32418:HG,32420:XQ,32421:HG,32438:LG,32473:GJ,32488:TD,32521:QJ,32527:PB,32562:ZSQ,32564:JZ,32735:ZD,32793:PB,33071:PF,33098:XL,33100:YA,33152:PB,33261:CX,33324:BP,33333:TD,33406:YA,33426:WM,33432:PB,33445:JG,33486:ZN,33493:TS,33507:QJ,33540:QJ,33544:ZC,33564:XQ,33617:YT,33632:QJ,33636:XH,33637:YX,33694:WG,33705:PF,33728:YW,33882:SR,34067:WM,34074:YW,34121:QJ,34255:ZC,34259:XL,34425:JH,34430:XH,34485:KH,34503:YS,34532:HG,34552:XS,34558:YE,34593:ZL,34660:YQ,34892:XH,34928:SC,34999:QJ,35048:PB,35059:SC,35098:ZC,35203:TQ,35265:JX,35299:JX,35782:SZ,35828:YS,35830:E,35843:TD,35895:YG,35977:MH,36158:JG,36228:QJ,36426:XQ,36466:DC,36710:JC,36711:ZYG,36767:PB,36866:SK,36951:YW,37034:YX,37063:XH,37218:ZC,37325:ZC,38063:PB,38079:TD,38085:QY,38107:DC,38116:TD,38123:YD,38224:HG,38241:XTC,38271:ZC,38415:YE,38426:KH,38461:YD,38463:AE,38466:PB,38477:XJ,38518:YT,38551:WK,38585:ZC,38704:XS,38739:LJ,38761:GJ,38808:SQ,39048:JG,39049:XJ,39052:HG,39076:CZ,39271:XT,39534:TD,39552:TD,39584:PB,39647:SB,39730:LG,39748:TPB,40109:ZQ,40479:ND,40516:HG,40536:HG,40583:QJ,40765:YQ,40784:QJ,40840:YK,40863:QJG,"; + string resStr = string.Empty; + int i, j, uni; + uni = HanZi; + if (uni > 40869 || uni < 19968) + return resStr; + + // 返回该字符在Unicode字符集中的编码值 + i = multiPinyin.IndexOf(uni.ToString()); + + // 检查是否是多音字,是按多音字处理,不是就直接在strChineseFirstPY字符串中找对应的首字母 + if (i < 0) + { + // 获取非多音字汉字首字母 + resStr = strChineseFirstPY[uni - 19968].ToString(); } else { - // 构造第一个汉字返回结果 - for (m = 0; m < tmpStr.Length - 1; m++) - returnStr += tmpStr[m] + ","; - returnStr += tmpStr[tmpStr.Length - 1]; + // 获取多音字汉字首字母 + j = multiPinyin.IndexOf(",", i); + resStr = multiPinyin.Substring(i + 6, j - i - 6); } - } + + return resStr; } + #endregion - // 返回处理结果字符串,以,分隔每个拼音组合 - return returnStr; - } - - private static string GetPinyin(char HanZi) - - // 获取单个汉字对应的拼音首字符字符串 - { - // 汉字拼音首字母列表 本列表包含了20902个汉字,收录的字符的Unicode编码范围为19968至40869 - - string strChineseFirstPY = "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJGYZZJJFKCCLZDHWDWZJLJPFYYNWJJTMYHZWZHFLZPPQHGSCYYYNJQYXXGJHHSDSJNKKTMOMLCRXYPSNQSECCQZGGLLYJLMYZZSECYKYYHQWJSSGGYXYZYJWWKDJHYCHMYXJTLXJYQBYXZLDWRDJRWYSRLDZJPCBZJJBRCFTLECZSTZFXXZHTRQHYBDLYCZSSYMMRFMYQZPWWJJYFCRWFDFZQPYDDWYXKYJAWJFFXYPSFTZYHHYZYSWCJYXSCLCXXWZZXNBGNNXBXLZSZSBSGPYSYZDHMDZBQBZCWDZZYYTZHBTSYYBZGNTNXQYWQSKBPHHLXGYBFMJEBJHHGQTJCYSXSTKZHLYCKGLYSMZXYALMELDCCXGZYRJXSDLTYZCQKCNNJWHJTZZCQLJSTSTBNXBTYXCEQXGKWJYFLZQLYHYXSPSFXLMPBYSXXXYDJCZYLLLSJXFHJXPJBTFFYABYXBHZZBJYZLWLCZGGBTSSMDTJZXPTHYQTGLJSCQFZKJZJQNLZWLSLHDZBWJNCJZYZSQQYCQYRZCJJWYBRTWPYFTWEXCSKDZCTBZHYZZYYJXZCFFZZMJYXXSDZZOTTBZLQWFCKSZSXFYRLNYJMBDTHJXSQQCCSBXYYTSYFBXDZTGBCNSLCYZZPSAZYZZSCJCSHZQYDXLBPJLLMQXTYDZXSQJTZPXLCGLQTZWJBHCTSYJSFXYEJJTLBGXSXJMYJQQPFZASYJNTYDJXKJCDJSZCBARTDCLYJQMWNQNCLLLKBYBZZSYHQQLTWLCCXTXLLZNTYLNEWYZYXCZXXGRKRMTCNDNJTSYYSSDQDGHSDBJGHRWRQLYBGLXHLGTGXBQJDZPYJSJYJCTMRNYMGRZJCZGJMZMGXMPRYXKJNYMSGMZJYMKMFXMLDTGFBHCJHKYLPFMDXLQJJSMTQGZSJLQDLDGJYCALCMZCSDJLLNXDJFFFFJCZFMZFFPFKHKGDPSXKTACJDHHZDDCRRCFQYJKQCCWJDXHWJLYLLZGCFCQDSMLZPBJJPLSBCJGGDCKKDEZSQCCKJGCGKDJTJDLZYCXKLQSCGJCLTFPCQCZGWPJDQYZJJBYJHSJDZWGFSJGZKQCCZLLPSPKJGQJHZZLJPLGJGJJTHJJYJZCZMLZLYQBGJWMLJKXZDZNJQSYZMLJLLJKYWXMKJLHSKJGBMCLYYMKXJQLBMLLKMDXXKWYXYSLMLPSJQQJQXYXFJTJDXMXXLLCXQBSYJBGWYMBGGBCYXPJYGPEPFGDJGBHBNSQJYZJKJKHXQFGQZKFHYGKHDKLLSDJQXPQYKYBNQSXQNSZSWHBSXWHXWBZZXDMNSJBSBKBBZKLYLXGWXDRWYQZMYWSJQLCJXXJXKJEQXSCYETLZHLYYYSDZPAQYZCMTLSHTZCFYZYXYLJSDCJQAGYSLCQLYYYSHMRQQKLDXZSCSSSYDYCJYSFSJBFRSSZQSBXXPXJYSDRCKGJLGDKZJZBDKTCSYQPYHSTCLDJDHMXMCGXYZHJDDTMHLTXZXYLYMOHYJCLTYFBQQXPFBDFHHTKSQHZYYWCNXXCRWHOWGYJLEGWDQCWGFJYCSNTMYTOLBYGWQWESJPWNMLRYDZSZTXYQPZGCWXHNGPYXSHMYQJXZTDPPBFYHZHTJYFDZWKGKZBLDNTSXHQEEGZZYLZMMZYJZGXZXKHKSTXNXXWYLYAPSTHXDWHZYMPXAGKYDXBHNHXKDPJNMYHYLPMGOCSLNZHKXXLPZZLBMLSFBHHGYGYYGGBHSCYAQTYWLXTZQCEZYDQDQMMHTKLLSZHLSJZWFYHQSWSCWLQAZYNYTLSXTHAZNKZZSZZLAXXZWWCTGQQTDDYZTCCHYQZFLXPSLZYGPZSZNGLNDQTBDLXGTCTAJDKYWNSYZLJHHZZCWNYYZYWMHYCHHYXHJKZWSXHZYXLYSKQYSPSLYZWMYPPKBYGLKZHTYXAXQSYSHXASMCHKDSCRSWJPWXSGZJLWWSCHSJHSQNHCSEGNDAQTBAALZZMSSTDQJCJKTSCJAXPLGGXHHGXXZCXPDMMHLDGTYBYSJMXHMRCPXXJZCKZXSHMLQXXTTHXWZFKHCCZDYTCJYXQHLXDHYPJQXYLSYYDZOZJNYXQEZYSQYAYXWYPDGXDDXSPPYZNDLTWRHXYDXZZJHTCXMCZLHPYYYYMHZLLHNXMYLLLMDCPPXHMXDKYCYRDLTXJCHHZZXZLCCLYLNZSHZJZZLNNRLWHYQSNJHXYNTTTKYJPYCHHYEGKCTTWLGQRLGGTGTYGYHPYHYLQYQGCWYQKPYYYTTTTLHYHLLTYTTSPLKYZXGZWGPYDSSZZDQXSKCQNMJJZZBXYQMJRTFFBTKHZKBXLJJKDXJTLBWFZPPTKQTZTGPDGNTPJYFALQMKGXBDCLZFHZCLLLLADPMXDJHLCCLGYHDZFGYDDGCYYFGYDXKSSEBDHYKDKDKHNAXXYBPBYYHXZQGAFFQYJXDMLJCSQZLLPCHBSXGJYNDYBYQSPZWJLZKSDDTACTBXZDYZYPJZQSJNKKTKNJDJGYYPGTLFYQKASDNTCYHBLWDZHBBYDWJRYGKZYHEYYFJMSDTYFZJJHGCXPLXHLDWXXJKYTCYKSSSMTWCTTQZLPBSZDZWZXGZAGYKTYWXLHLSPBCLLOQMMZSSLCMBJCSZZKYDCZJGQQDSMCYTZQQLWZQZXSSFPTTFQMDDZDSHDTDWFHTDYZJYQJQKYPBDJYYXTLJHDRQXXXHAYDHRJLKLYTWHLLRLLRCXYLBWSRSZZSYMKZZHHKYHXKSMDSYDYCJPBZBSQLFCXXXNXKXWYWSDZYQOGGQMMYHCDZTTFJYYBGSTTTYBYKJDHKYXBELHTYPJQNFXFDYKZHQKZBYJTZBXHFDXKDASWTAWAJLDYJSFHBLDNNTNQJTJNCHXFJSRFWHZFMDRYJYJWZPDJKZYJYMPCYZNYNXFBYTFYFWYGDBNZZZDNYTXZEMMQBSQEHXFZMBMFLZZSRXYMJGSXWZJSPRYDJSJGXHJJGLJJYNZZJXHGXKYMLPYYYCXYTWQZSWHWLYRJLPXSLSXMFSWWKLCTNXNYNPSJSZHDZEPTXMYYWXYYSYWLXJQZQXZDCLEEELMCPJPCLWBXSQHFWWTFFJTNQJHJQDXHWLBYZNFJLALKYYJLDXHHYCSTYYWNRJYXYWTRMDRQHWQCMFJDYZMHMYYXJWMYZQZXTLMRSPWWCHAQBXYGZYPXYYRRCLMPYMGKSJSZYSRMYJSNXTPLNBAPPYPYLXYYZKYNLDZYJZCZNNLMZHHARQMPGWQTZMXXMLLHGDZXYHXKYXYCJMFFYYHJFSBSSQLXXNDYCANNMTCJCYPRRNYTYQNYYMBMSXNDLYLYSLJRLXYSXQMLLYZLZJJJKYZZCSFBZXXMSTBJGNXYZHLXNMCWSCYZYFZLXBRNNNYLBNRTGZQYSATSWRYHYJZMZDHZGZDWYBSSCSKXSYHYTXXGCQGXZZSHYXJSCRHMKKBXCZJYJYMKQHZJFNBHMQHYSNJNZYBKNQMCLGQHWLZNZSWXKHLJHYYBQLBFCDSXDLDSPFZPSKJYZWZXZDDXJSMMEGJSCSSMGCLXXKYYYLNYPWWWGYDKZJGGGZGGSYCKNJWNJPCXBJJTQTJWDSSPJXZXNZXUMELPXFSXTLLXCLJXJJLJZXCTPSWXLYDHLYQRWHSYCSQYYBYAYWJJJQFWQCQQCJQGXALDBZZYJGKGXPLTZYFXJLTPADKYQHPMATLCPDCKBMTXYBHKLENXDLEEGQDYMSAWHZMLJTWYGXLYQZLJEEYYBQQFFNLYXRDSCTGJGXYYNKLLYQKCCTLHJLQMKKZGCYYGLLLJDZGYDHZWXPYSJBZKDZGYZZHYWYFQYTYZSZYEZZLYMHJJHTSMQWYZLKYYWZCSRKQYTLTDXWCTYJKLWSQZWBDCQYNCJSRSZJLKCDCDTLZZZACQQZZDDXYPLXZBQJYLZLLLQDDZQJYJYJZYXNYYYNYJXKXDAZWYRDLJYYYRJLXLLDYXJCYWYWNQCCLDDNYYYNYCKCZHXXCCLGZQJGKWPPCQQJYSBZZXYJSQPXJPZBSBDSFNSFPZXHDWZTDWPPTFLZZBZDMYYPQJRSDZSQZSQXBDGCPZSWDWCSQZGMDHZXMWWFYBPDGPHTMJTHZSMMBGZMBZJCFZWFZBBZMQCFMBDMCJXLGPNJBBXGYHYYJGPTZGZMQBQTCGYXJXLWZKYDPDYMGCFTPFXYZTZXDZXTGKMTYBBCLBJASKYTSSQYYMSZXFJEWLXLLSZBQJJJAKLYLXLYCCTSXMCWFKKKBSXLLLLJYXTYLTJYYTDPJHNHNNKBYQNFQYYZBYYESSESSGDYHFHWTCJBSDZZTFDMXHCNJZYMQWSRYJDZJQPDQBBSTJGGFBKJBXTGQHNGWJXJGDLLTHZHHYYYYYYSXWTYYYCCBDBPYPZYCCZYJPZYWCBDLFWZCWJDXXHYHLHWZZXJTCZLCDPXUJCZZZLYXJJTXPHFXWPYWXZPTDZZBDZCYHJHMLXBQXSBYLRDTGJRRCTTTHYTCZWMXFYTWWZCWJWXJYWCSKYBZSCCTZQNHXNWXXKHKFHTSWOCCJYBCMPZZYKBNNZPBZHHZDLSYDDYTYFJPXYNGFXBYQXCBHXCPSXTYZDMKYSNXSXLHKMZXLYHDHKWHXXSSKQYHHCJYXGLHZXCSNHEKDTGZXQYPKDHEXTYKCNYMYYYPKQYYYKXZLTHJQTBYQHXBMYHSQCKWWYLLHCYYLNNEQXQWMCFBDCCMLJGGXDQKTLXKGNQCDGZJWYJJLYHHQTTTNWCHMXCXWHWSZJYDJCCDBQCDGDNYXZTHCQRXCBHZTQCBXWGQWYYBXHMBYMYQTYEXMQKYAQYRGYZSLFYKKQHYSSQYSHJGJCNXKZYCXSBXYXHYYLSTYCXQTHYSMGSCPMMGCCCCCMTZTASMGQZJHKLOSQYLSWTMXSYQKDZLJQQYPLSYCZTCQQPBBQJZCLPKHQZYYXXDTDDTSJCXFFLLCHQXMJLWCJCXTSPYCXNDTJSHJWXDQQJSKXYAMYLSJHMLALYKXCYYDMNMDQMXMCZNNCYBZKKYFLMCHCMLHXRCJJHSYLNMTJZGZGYWJXSRXCWJGJQHQZDQJDCJJZKJKGDZQGJJYJYLXZXXCDQHHHEYTMHLFSBDJSYYSHFYSTCZQLPBDRFRZTZYKYWHSZYQKWDQZRKMSYNBCRXQBJYFAZPZZEDZCJYWBCJWHYJBQSZYWRYSZPTDKZPFPBNZTKLQYHBBZPNPPTYZZYBQNYDCPJMMCYCQMCYFZZDCMNLFPBPLNGQJTBTTNJZPZBBZNJKLJQYLNBZQHKSJZNGGQSZZKYXSHPZSNBCGZKDDZQANZHJKDRTLZLSWJLJZLYWTJNDJZJHXYAYNCBGTZCSSQMNJPJYTYSWXZFKWJQTKHTZPLBHSNJZSYZBWZZZZLSYLSBJHDWWQPSLMMFBJDWAQYZTCJTBNNWZXQXCDSLQGDSDPDZHJTQQPSWLYYJZLGYXYZLCTCBJTKTYCZJTQKBSJLGMGZDMCSGPYNJZYQYYKNXRPWSZXMTNCSZZYXYBYHYZAXYWQCJTLLCKJJTJHGDXDXYQYZZBYWDLWQCGLZGJGQRQZCZSSBCRPCSKYDZNXJSQGXSSJMYDNSTZTPBDLTKZWXQWQTZEXNQCZGWEZKSSBYBRTSSSLCCGBPSZQSZLCCGLLLZXHZQTHCZMQGYZQZNMCOCSZJMMZSQPJYGQLJYJPPLDXRGZYXCCSXHSHGTZNLZWZKJCXTCFCJXLBMQBCZZWPQDNHXLJCTHYZLGYLNLSZZPCXDSCQQHJQKSXZPBAJYEMSMJTZDXLCJYRYYNWJBNGZZTMJXLTBSLYRZPYLSSCNXPHLLHYLLQQZQLXYMRSYCXZLMMCZLTZSDWTJJLLNZGGQXPFSKYGYGHBFZPDKMWGHCXMSGDXJMCJZDYCABXJDLNBCDQYGSKYDQTXDJJYXMSZQAZDZFSLQXYJSJZYLBTXXWXQQZBJZUFBBLYLWDSLJHXJYZJWTDJCZFQZQZZDZSXZZQLZCDZFJHYSPYMPQZMLPPLFFXJJNZZYLSJEYQZFPFZKSYWJJJHRDJZZXTXXGLGHYDXCSKYSWMMZCWYBAZBJKSHFHJCXMHFQHYXXYZFTSJYZFXYXPZLCHMZMBXHZZSXYFYMNCWDABAZLXKTCSHHXKXJJZJSTHYGXSXYYHHHJWXKZXSSBZZWHHHCWTZZZPJXSNXQQJGZYZYWLLCWXZFXXYXYHXMKYYSWSQMNLNAYCYSPMJKHWCQHYLAJJMZXHMMCNZHBHXCLXTJPLTXYJHDYYLTTXFSZHYXXSJBJYAYRSMXYPLCKDUYHLXRLNLLSTYZYYQYGYHHSCCSMZCTZQXKYQFPYYRPFFLKQUNTSZLLZMWWTCQQYZWTLLMLMPWMBZSSTZRBPDDTLQJJBXZCSRZQQYGWCSXFWZLXCCRSZDZMCYGGDZQSGTJSWLJMYMMZYHFBJDGYXCCPSHXNZCSBSJYJGJMPPWAFFYFNXHYZXZYLREMZGZCYZSSZDLLJCSQFNXZKPTXZGXJJGFMYYYSNBTYLBNLHPFZDCYFBMGQRRSSSZXYSGTZRNYDZZCDGPJAFJFZKNZBLCZSZPSGCYCJSZLMLRSZBZZLDLSLLYSXSQZQLYXZLSKKBRXBRBZCYCXZZZEEYFGKLZLYYHGZSGZLFJHGTGWKRAAJYZKZQTSSHJJXDCYZUYJLZYRZDQQHGJZXSSZBYKJPBFRTJXLLFQWJHYLQTYMBLPZDXTZYGBDHZZRBGXHWNJTJXLKSCFSMWLSDQYSJTXKZSCFWJLBXFTZLLJZLLQBLSQMQQCGCZFPBPHZCZJLPYYGGDTGWDCFCZQYYYQYSSCLXZSKLZZZGFFCQNWGLHQYZJJCZLQZZYJPJZZBPDCCMHJGXDQDGDLZQMFGPSYTSDYFWWDJZJYSXYYCZCYHZWPBYKXRYLYBHKJKSFXTZJMMCKHLLTNYYMSYXYZPYJQYCSYCWMTJJKQYRHLLQXPSGTLYYCLJSCPXJYZFNMLRGJJTYZBXYZMSJYJHHFZQMSYXRSZCWTLRTQZSSTKXGQKGSPTGCZNJSJCQCXHMXGGZTQYDJKZDLBZSXJLHYQGGGTHQSZPYHJHHGYYGKGGCWJZZYLCZLXQSFTGZSLLLMLJSKCTBLLZZSZMMNYTPZSXQHJCJYQXYZXZQZCPSHKZZYSXCDFGMWQRLLQXRFZTLYSTCTMJCXJJXHJNXTNRZTZFQYHQGLLGCXSZSJDJLJCYDSJTLNYXHSZXCGJZYQPYLFHDJSBPCCZHJJJQZJQDYBSSLLCMYTTMQTBHJQNNYGKYRQYQMZGCJKPDCGMYZHQLLSLLCLMHOLZGDYYFZSLJCQZLYLZQJESHNYLLJXGJXLYSYYYXNBZLJSSZCQQCJYLLZLTJYLLZLLBNYLGQCHXYYXOXCXQKYJXXXYKLXSXXYQXCYKQXQCSGYXXYQXYGYTQOHXHXPYXXXULCYEYCHZZCBWQBBWJQZSCSZSSLZYLKDESJZWMYMCYTSDSXXSCJPQQSQYLYYZYCMDJDZYWCBTJSYDJKCYDDJLBDJJSODZYSYXQQYXDHHGQQYQHDYXWGMMMAJDYBBBPPBCMUUPLJZSMTXERXJMHQNUTPJDCBSSMSSSTKJTSSMMTRCPLZSZMLQDSDMJMQPNQDXCFYNBFSDQXYXHYAYKQYDDLQYYYSSZBYDSLNTFQTZQPZMCHDHCZCWFDXTMYQSPHQYYXSRGJCWTJTZZQMGWJJTJHTQJBBHWZPXXHYQFXXQYWYYHYSCDYDHHQMNMTMWCPBSZPPZZGLMZFOLLCFWHMMSJZTTDHZZYFFYTZZGZYSKYJXQYJZQBHMBZZLYGHGFMSHPZFZSNCLPBQSNJXZSLXXFPMTYJYGBXLLDLXPZJYZJYHHZCYWHJYLSJEXFSZZYWXKZJLUYDTMLYMQJPWXYHXSKTQJEZRPXXZHHMHWQPWQLYJJQJJZSZCPHJLCHHNXJLQWZJHBMZYXBDHHYPZLHLHLGFWLCHYYTLHJXCJMSCPXSTKPNHQXSRTYXXTESYJCTLSSLSTDLLLWWYHDHRJZSFGXTSYCZYNYHTDHWJSLHTZDQDJZXXQHGYLTZPHCSQFCLNJTCLZPFSTPDYNYLGMJLLYCQHYSSHCHYLHQYQTMZYPBYWRFQYKQSYSLZDQJMPXYYSSRHZJNYWTQDFZBWWTWWRXCWHGYHXMKMYYYQMSMZHNGCEPMLQQMTCWCTMMPXJPJJHFXYYZSXZHTYBMSTSYJTTQQQYYLHYNPYQZLCYZHZWSMYLKFJXLWGXYPJYTYSYXYMZCKTTWLKSMZSYLMPWLZWXWQZSSAQSYXYRHSSNTSRAPXCPWCMGDXHXZDZYFJHGZTTSBJHGYZSZYSMYCLLLXBTYXHBBZJKSSDMALXHYCFYGMQYPJYCQXJLLLJGSLZGQLYCJCCZOTYXMTMTTLLWTGPXYMZMKLPSZZZXHKQYSXCTYJZYHXSHYXZKXLZWPSQPYHJWPJPWXQQYLXSDHMRSLZZYZWTTCYXYSZZSHBSCCSTPLWSSCJCHNLCGCHSSPHYLHFHHXJSXYLLNYLSZDHZXYLSXLWZYKCLDYAXZCMDDYSPJTQJZLNWQPSSSWCTSTSZLBLNXSMNYYMJQBQHRZWTYYDCHQLXKPZWBGQYBKFCMZWPZLLYYLSZYDWHXPSBCMLJBSCGBHXLQHYRLJXYSWXWXZSLDFHLSLYNJLZYFLYJYCDRJLFSYZFSLLCQYQFGJYHYXZLYLMSTDJCYHBZLLNWLXXYGYYHSMGDHXXHHLZZJZXCZZZCYQZFNGWPYLCPKPYYPMCLQKDGXZGGWQBDXZZKZFBXXLZXJTPJPTTBYTSZZDWSLCHZHSLTYXHQLHYXXXYYZYSWTXZKHLXZXZPYHGCHKCFSYHUTJRLXFJXPTZTWHPLYXFCRHXSHXKYXXYHZQDXQWULHYHMJTBFLKHTXCWHJFWJCFPQRYQXCYYYQYGRPYWSGSUNGWCHKZDXYFLXXHJJBYZWTSXXNCYJJYMSWZJQRMHXZWFQSYLZJZGBHYNSLBGTTCSYBYXXWXYHXYYXNSQYXMQYWRGYQLXBBZLJSYLPSYTJZYHYZAWLRORJMKSCZJXXXYXCHDYXRYXXJDTSQFXLYLTSFFYXLMTYJMJUYYYXLTZCSXQZQHZXLYYXZHDNBRXXXJCTYHLBRLMBRLLAXKYLLLJLYXXLYCRYLCJTGJCMTLZLLCYZZPZPCYAWHJJFYBDYYZSMPCKZDQYQPBPCJPDCYZMDPBCYYDYCNNPLMTMLRMFMMGWYZBSJGYGSMZQQQZTXMKQWGXLLPJGZBQCDJJJFPKJKCXBLJMSWMDTQJXLDLPPBXCWRCQFBFQJCZAHZGMYKPHYYHZYKNDKZMBPJYXPXYHLFPNYYGXJDBKXNXHJMZJXSTRSTLDXSKZYSYBZXJLXYSLBZYSLHXJPFXPQNBYLLJQKYGZMCYZZYMCCSLCLHZFWFWYXZMWSXTYNXJHPYYMCYSPMHYSMYDYSHQYZCHMJJMZCAAGCFJBBHPLYZYLXXSDJGXDHKXXTXXNBHRMLYJSLTXMRHNLXQJXYZLLYSWQGDLBJHDCGJYQYCMHWFMJYBMBYJYJWYMDPWHXQLDYGPDFXXBCGJSPCKRSSYZJMSLBZZJFLJJJLGXZGYXYXLSZQYXBEXYXHGCXBPLDYHWETTWWCJMBTXCHXYQXLLXFLYXLLJLSSFWDPZSMYJCLMWYTCZPCHQEKCQBWLCQYDPLQPPQZQFJQDJHYMMCXTXDRMJWRHXCJZYLQXDYYNHYYHRSLSRSYWWZJYMTLTLLGTQCJZYABTCKZCJYCCQLJZQXALMZYHYWLWDXZXQDLLQSHGPJFJLJHJABCQZDJGTKHSSTCYJLPSWZLXZXRWGLDLZRLZXTGSLLLLZLYXXWGDZYGBDPHZPBRLWSXQBPFDWOFMWHLYPCBJCCLDMBZPBZZLCYQXLDOMZBLZWPDWYYGDSTTHCSQSCCRSSSYSLFYBFNTYJSZDFNDPDHDZZMBBLSLCMYFFGTJJQWFTMTPJWFNLBZCMMJTGBDZLQLPYFHYYMJYLSDCHDZJWJCCTLJCLDTLJJCPDDSQDSSZYBNDBJLGGJZXSXNLYCYBJXQYCBYLZCFZPPGKCXZDZFZTJJFJSJXZBNZYJQTTYJYHTYCZHYMDJXTTMPXSPLZCDWSLSHXYPZGTFMLCJTYCBPMGDKWYCYZCDSZZYHFLYCTYGWHKJYYLSJCXGYWJCBLLCSNDDBTZBSCLYZCZZSSQDLLMQYYHFSLQLLXFTYHABXGWNYWYYPLLSDLDLLBJCYXJZMLHLJDXYYQYTDLLLBUGBFDFBBQJZZMDPJHGCLGMJJPGAEHHBWCQXAXHHHZCHXYPHJAXHLPHJPGPZJQCQZGJJZZUZDMQYYBZZPHYHYBWHAZYJHYKFGDPFQSDLZMLJXKXGALXZDAGLMDGXMWZQYXXDXXPFDMMSSYMPFMDMMKXKSYZYSHDZKXSYSMMZZZMSYDNZZCZXFPLSTMZDNMXCKJMZTYYMZMZZMSXHHDCZJEMXXKLJSTLWLSQLYJZLLZJSSDPPMHNLZJCZYHMXXHGZCJMDHXTKGRMXFWMCGMWKDTKSXQMMMFZZYDKMSCLCMPCGMHSPXQPZDSSLCXKYXTWLWJYAHZJGZQMCSNXYYMMPMLKJXMHLMLQMXCTKZMJQYSZJSYSZHSYJZJCDAJZYBSDQJZGWZQQXFKDMSDJLFWEHKZQKJPEYPZYSZCDWYJFFMZZYLTTDZZEFMZLBNPPLPLPEPSZALLTYLKCKQZKGENQLWAGYXYDPXLHSXQQWQCQXQCLHYXXMLYCCWLYMQYSKGCHLCJNSZKPYZKCQZQLJPDMDZHLASXLBYDWQLWDNBQCRYDDZTJYBKBWSZDXDTNPJDTCTQDFXQQMGNXECLTTBKPWSLCTYQLPWYZZKLPYGZCQQPLLKCCYLPQMZCZQCLJSLQZDJXLDDHPZQDLJJXZQDXYZQKZLJCYQDYJPPYPQYKJYRMPCBYMCXKLLZLLFQPYLLLMBSGLCYSSLRSYSQTMXYXZQZFDZUYSYZTFFMZZSMZQHZSSCCMLYXWTPZGXZJGZGSJSGKDDHTQGGZLLBJDZLCBCHYXYZHZFYWXYZYMSDBZZYJGTSMTFXQYXQSTDGSLNXDLRYZZLRYYLXQHTXSRTZNGZXBNQQZFMYKMZJBZYMKBPNLYZPBLMCNQYZZZSJZHJCTZKHYZZJRDYZHNPXGLFZTLKGJTCTSSYLLGZRZBBQZZKLPKLCZYSSUYXBJFPNJZZXCDWXZYJXZZDJJKGGRSRJKMSMZJLSJYWQSKYHQJSXPJZZZLSNSHRNYPZTWCHKLPSRZLZXYJQXQKYSJYCZTLQZYBBYBWZPQDWWYZCYTJCJXCKCWDKKZXSGKDZXWWYYJQYYTCYTDLLXWKCZKKLCCLZCQQDZLQLCSFQCHQHSFSMQZZLNBJJZBSJHTSZDYSJQJPDLZCDCWJKJZZLPYCGMZWDJJBSJQZSYZYHHXJPBJYDSSXDZNCGLQMBTSFSBPDZDLZNFGFJGFSMPXJQLMBLGQCYYXBQKDJJQYRFKZTJDHCZKLBSDZCFJTPLLJGXHYXZCSSZZXSTJYGKGCKGYOQXJPLZPBPGTGYJZGHZQZZLBJLSQFZGKQQJZGYCZBZQTLDXRJXBSXXPZXHYZYCLWDXJJHXMFDZPFZHQHQMQGKSLYHTYCGFRZGNQXCLPDLBZCSCZQLLJBLHBZCYPZZPPDYMZZSGYHCKCPZJGSLJLNSCDSLDLXBMSTLDDFJMKDJDHZLZXLSZQPQPGJLLYBDSZGQLBZLSLKYYHZTTNTJYQTZZPSZQZTLLJTYYLLQLLQYZQLBDZLSLYYZYMDFSZSNHLXZNCZQZPBWSKRFBSYZMTHBLGJPMCZZLSTLXSHTCSYZLZBLFEQHLXFLCJLYLJQCBZLZJHHSSTBRMHXZHJZCLXFNBGXGTQJCZTMSFZKJMSSNXLJKBHSJXNTNLZDNTLMSJXGZJYJCZXYJYJWRWWQNZTNFJSZPZSHZJFYRDJSFSZJZBJFZQZZHZLXFYSBZQLZSGYFTZDCSZXZJBQMSZKJRHYJZCKMJKHCHGTXKXQGLXPXFXTRTYLXJXHDTSJXHJZJXZWZLCQSBTXWXGXTXXHXFTSDKFJHZYJFJXRZSDLLLTQSQQZQWZXSYQTWGWBZCGZLLYZBCLMQQTZHZXZXLJFRMYZFLXYSQXXJKXRMQDZDMMYYBSQBHGZMWFWXGMXLZPYYTGZYCCDXYZXYWGSYJYZNBHPZJSQSYXSXRTFYZGRHZTXSZZTHCBFCLSYXZLZQMZLMPLMXZJXSFLBYZMYQHXJSXRXSQZZZSSLYFRCZJRCRXHHZXQYDYHXSJJHZCXZBTYNSYSXJBQLPXZQPYMLXZKYXLXCJLCYSXXZZLXDLLLJJYHZXGYJWKJRWYHCPSGNRZLFZWFZZNSXGXFLZSXZZZBFCSYJDBRJKRDHHGXJLJJTGXJXXSTJTJXLYXQFCSGSWMSBCTLQZZWLZZKXJMLTMJYHSDDBXGZHDLBMYJFRZFSGCLYJBPMLYSMSXLSZJQQHJZFXGFQFQBPXZGYYQXGZTCQWYLTLGWSGWHRLFSFGZJMGMGBGTJFSYZZGZYZAFLSSPMLPFLCWBJZCLJJMZLPJJLYMQDMYYYFBGYGYZMLYZDXQYXRQQQHSYYYQXYLJTYXFSFSLLGNQCYHYCWFHCCCFXPYLYPLLZYXXXXXKQHHXSHJZCFZSCZJXCPZWHHHHHAPYLQALPQAFYHXDYLUKMZQGGGDDESRNNZLTZGCHYPPYSQJJHCLLJTOLNJPZLJLHYMHEYDYDSQYCDDHGZUNDZCLZYZLLZNTNYZGSLHSLPJJBDGWXPCDUTJCKLKCLWKLLCASSTKZZDNQNTTLYYZSSYSSZZRYLJQKCQDHHCRXRZYDGRGCWCGZQFFFPPJFZYNAKRGYWYQPQXXFKJTSZZXSWZDDFBBXTBGTZKZNPZZPZXZPJSZBMQHKCYXYLDKLJNYPKYGHGDZJXXEAHPNZKZTZCMXCXMMJXNKSZQNMNLWBWWXJKYHCPSTMCSQTZJYXTPCTPDTNNPGLLLZSJLSPBLPLQHDTNJNLYYRSZFFJFQWDPHZDWMRZCCLODAXNSSNYZRESTYJWJYJDBCFXNMWTTBYLWSTSZGYBLJPXGLBOCLHPCBJLTMXZLJYLZXCLTPNCLCKXTPZJSWCYXSFYSZDKNTLBYJCYJLLSTGQCBXRYZXBXKLYLHZLQZLNZCXWJZLJZJNCJHXMNZZGJZZXTZJXYCYYCXXJYYXJJXSSSJSTSSTTPPGQTCSXWZDCSYFPTFBFHFBBLZJCLZZDBXGCXLQPXKFZFLSYLTUWBMQJHSZBMDDBCYSCCLDXYCDDQLYJJWMQLLCSGLJJSYFPYYCCYLTJANTJJPWYCMMGQYYSXDXQMZHSZXPFTWWZQSWQRFKJLZJQQYFBRXJHHFWJJZYQAZMYFRHCYYBYQWLPEXCCZSTYRLTTDMQLYKMBBGMYYJPRKZNPBSXYXBHYZDJDNGHPMFSGMWFZMFQMMBCMZZCJJLCNUXYQLMLRYGQZCYXZLWJGCJCGGMCJNFYZZJHYCPRRCMTZQZXHFQGTJXCCJEAQCRJYHPLQLSZDJRBCQHQDYRHYLYXJSYMHZYDWLDFRYHBPYDTSSCNWBXGLPZMLZZTQSSCPJMXXYCSJYTYCGHYCJWYRXXLFEMWJNMKLLSWTXHYYYNCMMCWJDQDJZGLLJWJRKHPZGGFLCCSCZMCBLTBHBQJXQDSPDJZZGKGLFQYWBZYZJLTSTDHQHCTCBCHFLQMPWDSHYYTQWCNZZJTLBYMBPDYYYXSQKXWYYFLXXNCWCXYPMAELYKKJMZZZBRXYYQJFLJPFHHHYTZZXSGQQMHSPGDZQWBWPJHZJDYSCQWZKTXXSQLZYYMYSDZGRXCKKUJLWPYSYSCSYZLRMLQSYLJXBCXTLWDQZPCYCYKPPPNSXFYZJJRCEMHSZMSXLXGLRWGCSTLRSXBZGBZGZTCPLUJLSLYLYMTXMTZPALZXPXJTJWTCYYZLBLXBZLQMYLXPGHDSLSSDMXMBDZZSXWHAMLCZCPJMCNHJYSNSYGCHSKQMZZQDLLKABLWJXSFMOCDXJRRLYQZKJMYBYQLYHETFJZFRFKSRYXFJTWDSXXSYSQJYSLYXWJHSNLXYYXHBHAWHHJZXWMYLJCSSLKYDZTXBZSYFDXGXZJKHSXXYBSSXDPYNZWRPTQZCZENYGCXQFJYKJBZMLJCMQQXUOXSLYXXLYLLJDZBTYMHPFSTTQQWLHOKYBLZZALZXQLHZWRRQHLSTMYPYXJJXMQSJFNBXYXYJXXYQYLTHYLQYFMLKLJTMLLHSZWKZHLJMLHLJKLJSTLQXYLMBHHLNLZXQJHXCFXXLHYHJJGBYZZKBXSCQDJQDSUJZYYHZHHMGSXCSYMXFEBCQWWRBPYYJQTYZCYQYQQZYHMWFFHGZFRJFCDPXNTQYZPDYKHJLFRZXPPXZDBBGZQSTLGDGYLCQMLCHHMFYWLZYXKJLYPQHSYWMQQGQZMLZJNSQXJQSYJYCBEHSXFSZPXZWFLLBCYYJDYTDTHWZSFJMQQYJLMQXXLLDTTKHHYBFPWTYYSQQWNQWLGWDEBZWCMYGCULKJXTMXMYJSXHYBRWFYMWFRXYQMXYSZTZZTFYKMLDHQDXWYYNLCRYJBLPSXCXYWLSPRRJWXHQYPHTYDNXHHMMYWYTZCSQMTSSCCDALWZTCPQPYJLLQZYJSWXMZZMMYLMXCLMXCZMXMZSQTZPPQQBLPGXQZHFLJJHYTJSRXWZXSCCDLXTYJDCQJXSLQYCLZXLZZXMXQRJMHRHZJBHMFLJLMLCLQNLDXZLLLPYPSYJYSXCQQDCMQJZZXHNPNXZMEKMXHYKYQLXSXTXJYYHWDCWDZHQYYBGYBCYSCFGPSJNZDYZZJZXRZRQJJYMCANYRJTLDPPYZBSTJKXXZYPFDWFGZZRPYMTNGXZQBYXNBUFNQKRJQZMJEGRZGYCLKXZDSKKNSXKCLJSPJYYZLQQJYBZSSQLLLKJXTBKTYLCCDDBLSPPFYLGYDTZJYQGGKQTTFZXBDKTYYHYBBFYTYYBCLPDYTGDHRYRNJSPTCSNYJQHKLLLZSLYDXXWBCJQSPXBPJZJCJDZFFXXBRMLAZHCSNDLBJDSZBLPRZTSWSBXBCLLXXLZDJZSJPYLYXXYFTFFFBHJJXGBYXJPMMMPSSJZJMTLYZJXSWXTYLEDQPJMYGQZJGDJLQJWJQLLSJGJGYGMSCLJJXDTYGJQJQJCJZCJGDZZSXQGSJGGCXHQXSNQLZZBXHSGZXCXYLJXYXYYDFQQJHJFXDHCTXJYRXYSQTJXYEFYYSSYYJXNCYZXFXMSYSZXYYSCHSHXZZZGZZZGFJDLTYLNPZGYJYZYYQZPBXQBDZTZCZYXXYHHSQXSHDHGQHJHGYWSZTMZMLHYXGEBTYLZKQWYTJZRCLEKYSTDBCYKQQSAYXCJXWWGSBHJYZYDHCSJKQCXSWXFLTYNYZPZCCZJQTZWJQDZZZQZLJJXLSBHPYXXPSXSHHEZTXFPTLQYZZXHYTXNCFZYYHXGNXMYWXTZSJPTHHGYMXMXQZXTSBCZYJYXXTYYZYPCQLMMSZMJZZLLZXGXZAAJZYXJMZXWDXZSXZDZXLEYJJZQBHZWZZZQTZPSXZTDSXJJJZNYAZPHXYYSRNQDTHZHYYKYJHDZXZLSWCLYBZYECWCYCRYLCXNHZYDZYDYJDFRJJHTRSQTXYXJRJHOJYNXELXSFSFJZGHPZSXZSZDZCQZBYYKLSGSJHCZSHDGQGXYZGXCHXZJWYQWGYHKSSEQZZNDZFKWYSSTCLZSTSYMCDHJXXYWEYXCZAYDMPXMDSXYBSQMJMZJMTZQLPJYQZCGQHXJHHLXXHLHDLDJQCLDWBSXFZZYYSCHTYTYYBHECXHYKGJPXHHYZJFXHWHBDZFYZBCAPNPGNYDMSXHMMMMAMYNBYJTMPXYYMCTHJBZYFCGTYHWPHFTWZZEZSBZEGPFMTSKFTYCMHFLLHGPZJXZJGZJYXZSBBQSCZZLZCCSTPGXMJSFTCCZJZDJXCYBZLFCJSYZFGSZLYBCWZZBYZDZYPSWYJZXZBDSYUXLZZBZFYGCZXBZHZFTPBGZGEJBSTGKDMFHYZZJHZLLZZGJQZLSFDJSSCBZGPDLFZFZSZYZYZSYGCXSNXXCHCZXTZZLJFZGQSQYXZJQDCCZTQCDXZJYQJQCHXZTDLGSCXZSYQJQTZWLQDQZTQCHQQJZYEZZZPBWKDJFCJPZTYPQYQTTYNLMBDKTJZPQZQZZFPZSBNJLGYJDXJDZZKZGQKXDLPZJTCJDQBXDJQJSTCKNXBXZMSLYJCQMTJQWWCJQNJNLLLHJCWQTBZQYDZCZPZZDZYDDCYZZZCCJTTJFZDPRRTZTJDCQTQZDTJNPLZBCLLCTZSXKJZQZPZLBZRBTJDCXFCZDBCCJJLTQQPLDCGZDBBZJCQDCJWYNLLZYZCCDWLLXWZLXRXNTQQCZXKQLSGDFQTDDGLRLAJJTKUYMKQLLTZYTDYYCZGJWYXDXFRSKSTQTENQMRKQZHHQKDLDAZFKYPBGGPZREBZZYKZZSPEGJXGYKQZZZSLYSYYYZWFQZYLZZLZHWCHKYPQGNPGBLPLRRJYXCCSYYHSFZFYBZYYTGZXYLXCZWXXZJZBLFFLGSKHYJZEYJHLPLLLLCZGXDRZELRHGKLZZYHZLYQSZZJZQLJZFLNBHGWLCZCFJYSPYXZLZLXGCCPZBLLCYBBBBUBBCBPCRNNZCZYRBFSRLDCGQYYQXYGMQZWTZYTYJXYFWTEHZZJYWLCCNTZYJJZDEDPZDZTSYQJHDYMBJNYJZLXTSSTPHNDJXXBYXQTZQDDTJTDYYTGWSCSZQFLSHLGLBCZPHDLYZJYCKWTYTYLBNYTSDSYCCTYSZYYEBHEXHQDTWNYGYCLXTSZYSTQMYGZAZCCSZZDSLZCLZRQXYYELJSBYMXSXZTEMBBLLYYLLYTDQYSHYMRQWKFKBFXNXSBYCHXBWJYHTQBPBSBWDZYLKGZSKYHXQZJXHXJXGNLJKZLYYCDXLFYFGHLJGJYBXQLYBXQPQGZTZPLNCYPXDJYQYDYMRBESJYYHKXXSTMXRCZZYWXYQYBMCLLYZHQYZWQXDBXBZWZMSLPDMYSKFMZKLZCYQYCZLQXFZZYDQZPZYGYJYZMZXDZFYFYTTQTZHGSPCZMLCCYTZXJCYTJMKSLPZHYSNZLLYTPZCTZZCKTXDHXXTQCYFKSMQCCYYAZHTJPCYLZLYJBJXTPNYLJYYNRXSYLMMNXJSMYBCSYSYLZYLXJJQYLDZLPQBFZZBLFNDXQKCZFYWHGQMRDSXYCYTXNQQJZYYPFZXDYZFPRXEJDGYQBXRCNFYYQPGHYJDYZXGRHTKYLNWDZNTSMPKLBTHBPYSZBZTJZSZZJTYYXZPHSSZZBZCZPTQFZMYFLYPYBBJQXZMXXDJMTSYSKKBJZXHJCKLPSMKYJZCXTMLJYXRZZQSLXXQPYZXMKYXXXJCLJPRMYYGADYSKQLSNDHYZKQXZYZTCGHZTLMLWZYBWSYCTBHJHJFCWZTXWYTKZLXQSHLYJZJXTMPLPYCGLTBZZTLZJCYJGDTCLKLPLLQPJMZPAPXYZLKKTKDZCZZBNZDYDYQZJYJGMCTXLTGXSZLMLHBGLKFWNWZHDXUHLFMKYSLGXDTWWFRJEJZTZHYDXYKSHWFZCQSHKTMQQHTZHYMJDJSKHXZJZBZZXYMPAGQMSTPXLSKLZYNWRTSQLSZBPSPSGZWYHTLKSSSWHZZLYYTNXJGMJSZSUFWNLSOZTXGXLSAMMLBWLDSZYLAKQCQCTMYCFJBSLXCLZZCLXXKSBZQCLHJPSQPLSXXCKSLNHPSFQQYTXYJZLQLDXZQJZDYYDJNZPTUZDSKJFSLJHYLZSQZLBTXYDGTQFDBYAZXDZHZJNHHQBYKNXJJQCZMLLJZKSPLDYCLBBLXKLELXJLBQYCXJXGCNLCQPLZLZYJTZLJGYZDZPLTQCSXFDMNYCXGBTJDCZNBGBQYQJWGKFHTNPYQZQGBKPBBYZMTJDYTBLSQMPSXTBNPDXKLEMYYCJYNZCTLDYKZZXDDXHQSHDGMZSJYCCTAYRZLPYLTLKXSLZCGGEXCLFXLKJRTLQJAQZNCMBYDKKCXGLCZJZXJHPTDJJMZQYKQSECQZDSHHADMLZFMMZBGNTJNNLGBYJBRBTMLBYJDZXLCJLPLDLPCQDHLXZLYCBLCXZZJADJLNZMMSSSMYBHBSQKBHRSXXJMXSDZNZPXLGBRHWGGFCXGMSKLLTSJYYCQLTSKYWYYHYWXBXQYWPYWYKQLSQPTNTKHQCWDQKTWPXXHCPTHTWUMSSYHBWCRWXHJMKMZNGWTMLKFGHKJYLSYYCXWHYECLQHKQHTTQKHFZLDXQWYZYYDESBPKYRZPJFYYZJCEQDZZDLATZBBFJLLCXDLMJSSXEGYGSJQXCWBXSSZPDYZCXDNYXPPZYDLYJCZPLTXLSXYZYRXCYYYDYLWWNZSAHJSYQYHGYWWAXTJZDAXYSRLTDPSSYYFNEJDXYZHLXLLLZQZSJNYQYQQXYJGHZGZCYJCHZLYCDSHWSHJZYJXCLLNXZJJYYXNFXMWFPYLCYLLABWDDHWDXJMCXZTZPMLQZHSFHZYNZTLLDYWLSLXHYMMYLMBWWKYXYADTXYLLDJPYBPWUXJMWMLLSAFDLLYFLBHHHBQQLTZJCQJLDJTFFKMMMBYTHYGDCQRDDWRQJXNBYSNWZDBYYTBJHPYBYTTJXAAHGQDQTMYSTQXKBTZPKJLZRBEQQSSMJJBDJOTGTBXPGBKTLHQXJJJCTHXQDWJLWRFWQGWSHCKRYSWGFTGYGBXSDWDWRFHWYTJJXXXJYZYSLPYYYPAYXHYDQKXSHXYXGSKQHYWFDDDPPLCJLQQEEWXKSYYKDYPLTJTHKJLTCYYHHJTTPLTZZCDLTHQKZXQYSTEEYWYYZYXXYYSTTJKLLPZMCYHQGXYHSRMBXPLLNQYDQHXSXXWGDQBSHYLLPJJJTHYJKYPPTHYYKTYEZYENMDSHLCRPQFDGFXZPSFTLJXXJBSWYYSKSFLXLPPLBBBLBSFXFYZBSJSSYLPBBFFFFSSCJDSTZSXZRYYSYFFSYZYZBJTBCTSBSDHRTJJBYTCXYJEYLXCBNEBJDSYXYKGSJZBXBYTFZWGENYHHTHZHHXFWGCSTBGXKLSXYWMTMBYXJSTZSCDYQRCYTWXZFHMYMCXLZNSDJTTTXRYCFYJSBSDYERXJLJXBBDEYNJGHXGCKGSCYMBLXJMSZNSKGXFBNBPTHFJAAFXYXFPXMYPQDTZCXZZPXRSYWZDLYBBKTYQPQJPZYPZJZNJPZJLZZFYSBTTSLMPTZRTDXQSJEHBZYLZDHLJSQMLHTXTJECXSLZZSPKTLZKQQYFSYGYWPCPQFHQHYTQXZKRSGTTSQCZLPTXCDYYZXSQZSLXLZMYCPCQBZYXHBSXLZDLTCDXTYLZJYYZPZYZLTXJSJXHLPMYTXCQRBLZSSFJZZTNJYTXMYJHLHPPLCYXQJQQKZZSCPZKSWALQSBLCCZJSXGWWWYGYKTJBBZTDKHXHKGTGPBKQYSLPXPJCKBMLLXDZSTBKLGGQKQLSBKKTFXRMDKBFTPZFRTBBRFERQGXYJPZSSTLBZTPSZQZSJDHLJQLZBPMSMMSXLQQNHKNBLRDDNXXDHDDJCYYGYLXGZLXSYGMQQGKHBPMXYXLYTQWLWGCPBMQXCYZYDRJBHTDJYHQSHTMJSBYPLWHLZFFNYPMHXXHPLTBQPFBJWQDBYGPNZTPFZJGSDDTQSHZEAWZZYLLTYYBWJKXXGHLFKXDJTMSZSQYNZGGSWQSPHTLSSKMCLZXYSZQZXNCJDQGZDLFNYKLJCJLLZLMZZNHYDSSHTHZZLZZBBHQZWWYCRZHLYQQJBEYFXXXWHSRXWQHWPSLMSSKZTTYGYQQWRSLALHMJTQJSMXQBJJZJXZYZKXBYQXBJXSHZTSFJLXMXZXFGHKZSZGGYLCLSARJYHSLLLMZXELGLXYDJYTLFBHBPNLYZFBBHPTGJKWETZHKJJXZXXGLLJLSTGSHJJYQLQZFKCGNNDJSSZFDBCTWWSEQFHQJBSAQTGYPQLBXBMMYWXGSLZHGLZGQYFLZBYFZJFRYSFMBYZHQGFWZSYFYJJPHZBYYZFFWODGRLMFTWLBZGYCQXCDJYGZYYYYTYTYDWEGAZYHXJLZYYHLRMGRXXZCLHNELJJTJTPWJYBJJBXJJTJTEEKHWSLJPLPSFYZPQQBDLQJJTYYQLYZKDKSQJYYQZLDQTGJQYZJSUCMRYQTHTEJMFCTYHYPKMHYZWJDQFHYYXWSHCTXRLJHQXHCCYYYJLTKTTYTMXGTCJTZAYYOCZLYLBSZYWJYTSJYHBYSHFJLYGJXXTMZYYLTXXYPZLXYJZYZYYPNHMYMDYYLBLHLSYYQQLLNJJYMSOYQBZGDLYXYLCQYXTSZEGXHZGLHWBLJHEYXTWQMAKBPQCGYSHHEGQCMWYYWLJYJHYYZLLJJYLHZYHMGSLJLJXCJJYCLYCJPCPZJZJMMYLCQLNQLJQJSXYJMLSZLJQLYCMMHCFMMFPQQMFYLQMCFFQMMMMHMZNFHHJGTTHHKHSLNCHHYQDXTMMQDCYZYXYQMYQYLTDCYYYZAZZCYMZYDLZFFFMMYCQZWZZMABTBYZTDMNZZGGDFTYPCGQYTTSSFFWFDTZQSSYSTWXJHXYTSXXYLBYQHWWKXHZXWZNNZZJZJJQJCCCHYYXBZXZCYZTLLCQXYNJYCYYCYNZZQYYYEWYCZDCJYCCHYJLBTZYYCQWMPWPYMLGKDLDLGKQQBGYCHJXY"; - - // 此处收录了375个多音字 - string multiPinyin = "19969:DZ,19975:WM,19988:QJ,20048:YL,20056:SC,20060:NM,20094:QG,20127:QJ,20167:QC,20193:YG,20250:KH,20256:ZC,20282:SC,20285:QJG,20291:TD,20314:YD,20340:NE,20375:TD,20389:YJ,20391:CZ,20415:PB,20446:YS,20447:SQ,20504:TC,20608:KG,20854:QJ,20857:ZC,20911:PF,20504:TC,20608:KG,20854:QJ,20857:ZC,20911:PF,20985:AW,21032:PB,21048:XQ,21049:SC,21089:YS,21119:JC,21242:SB,21273:SC,21305:YP,21306:QO,21330:ZC,21333:SDC,21345:QK,21378:CA,21397:SC,21414:XS,21442:SC,21477:JG,21480:TD,21484:ZS,21494:YX,21505:YX,21512:HG,21523:XH,21537:PB,21542:PF,21549:KH,21571:E,21574:DA,21588:TD,21589:O,21618:ZC,21621:KHA,21632:ZJ,21654:KG,21679:LKG,21683:KH,21710:A,21719:YH,21734:WOE,21769:A,21780:WN,21804:XH,21834:A,21899:ZD,21903:RN,21908:WO,21939:ZC,21956:SA,21964:YA,21970:TD,22003:A,22031:JG,22040:XS,22060:ZC,22066:ZC,22079:MH,22129:XJ,22179:XA,22237:NJ,22244:TD,22280:JQ,22300:YH,22313:XW,22331:YQ,22343:YJ,22351:PH,22395:DC,22412:TD,22484:PB,22500:PB,22534:ZD,22549:DH,22561:PB,22612:TD,22771:KQ,22831:HB,22841:JG,22855:QJ,22865:XQ,23013:ML,23081:WM,23487:SX,23558:QJ,23561:YW,23586:YW,23614:YW,23615:SN,23631:PB,23646:ZS,23663:ZT,23673:YG,23762:TD,23769:ZS,23780:QJ,23884:QK,24055:XH,24113:DC,24162:ZC,24191:GA,24273:QJ,24324:NL,24377:TD,24378:QJ,24439:PF,24554:ZS,24683:TD,24694:WE,24733:LK,24925:TN,25094:ZG,25100:XQ,25103:XH,25153:PB,25170:PB,25179:KG,25203:PB,25240:ZS,25282:FB,25303:NA,25324:KG,25341:ZY,25373:WZ,25375:XJ,25384:A,25457:A,25528:SD,25530:SC,25552:TD,25774:ZC,25874:ZC,26044:YW,26080:WM,26292:PB,26333:PB,26355:ZY,26366:CZ,26397:ZC,26399:QJ,26415:ZS,26451:SB,26526:ZC,26552:JG,26561:TD,26588:JG,26597:CZ,26629:ZS,26638:YL,26646:XQ,26653:KG,26657:XJ,26727:HG,26894:ZC,26937:ZS,26946:ZC,26999:KJ,27099:KJ,27449:YQ,27481:XS,27542:ZS,27663:ZS,27748:TS,27784:SC,27788:ZD,27795:TD,27812:O,27850:PB,27852:MB,27895:SL,27898:PL,27973:QJ,27981:KH,27986:HX,27994:XJ,28044:YC,28065:WG,28177:SM,28267:QJ,28291:KH,28337:ZQ,28463:TL,28548:DC,28601:TD,28689:PB,28805:JG,28820:QG,28846:PB,28952:TD,28975:ZC,29100:A,29325:QJ,29575:SL,29602:FB,30010:TD,30044:CX,30058:PF,30091:YSP,30111:YN,30229:XJ,30427:SC,30465:SX,30631:YQ,30655:QJ,30684:QJG,30707:SD,30729:XH,30796:LG,30917:PB,31074:NM,31085:JZ,31109:SC,31181:ZC,31192:MLB,31293:JQ,31400:YX,31584:YJ,31896:ZN,31909:ZY,31995:XJ,32321:PF,32327:ZY,32418:HG,32420:XQ,32421:HG,32438:LG,32473:GJ,32488:TD,32521:QJ,32527:PB,32562:ZSQ,32564:JZ,32735:ZD,32793:PB,33071:PF,33098:XL,33100:YA,33152:PB,33261:CX,33324:BP,33333:TD,33406:YA,33426:WM,33432:PB,33445:JG,33486:ZN,33493:TS,33507:QJ,33540:QJ,33544:ZC,33564:XQ,33617:YT,33632:QJ,33636:XH,33637:YX,33694:WG,33705:PF,33728:YW,33882:SR,34067:WM,34074:YW,34121:QJ,34255:ZC,34259:XL,34425:JH,34430:XH,34485:KH,34503:YS,34532:HG,34552:XS,34558:YE,34593:ZL,34660:YQ,34892:XH,34928:SC,34999:QJ,35048:PB,35059:SC,35098:ZC,35203:TQ,35265:JX,35299:JX,35782:SZ,35828:YS,35830:E,35843:TD,35895:YG,35977:MH,36158:JG,36228:QJ,36426:XQ,36466:DC,36710:JC,36711:ZYG,36767:PB,36866:SK,36951:YW,37034:YX,37063:XH,37218:ZC,37325:ZC,38063:PB,38079:TD,38085:QY,38107:DC,38116:TD,38123:YD,38224:HG,38241:XTC,38271:ZC,38415:YE,38426:KH,38461:YD,38463:AE,38466:PB,38477:XJ,38518:YT,38551:WK,38585:ZC,38704:XS,38739:LJ,38761:GJ,38808:SQ,39048:JG,39049:XJ,39052:HG,39076:CZ,39271:XT,39534:TD,39552:TD,39584:PB,39647:SB,39730:LG,39748:TPB,40109:ZQ,40479:ND,40516:HG,40536:HG,40583:QJ,40765:YQ,40784:QJ,40840:YK,40863:QJG,"; - string resStr = string.Empty; - int i, j, uni; - uni = HanZi; - if (uni > 40869 || uni < 19968) - return resStr; - - // 返回该字符在Unicode字符集中的编码值 - i = multiPinyin.IndexOf(uni.ToString()); - - // 检查是否是多音字,是按多音字处理,不是就直接在strChineseFirstPY字符串中找对应的首字母 - if (i < 0) - { - // 获取非多音字汉字首字母 - resStr = strChineseFirstPY[uni - 19968].ToString(); - } - else - { - // 获取多音字汉字首字母 - j = multiPinyin.IndexOf(",", i); - resStr = multiPinyin.Substring(i + 6, j - i - 6); - } - - return resStr; - } - #endregion - - #region 汉字转换成全拼的拼音 + #region 汉字转换成全拼的拼音 /// /// 汉字转换成全拼的拼音. @@ -191,81 +191,81 @@ public class PinyinHelper "Zhuang", "Zhui", "Zhun", "Zhuo", "Zi", "Zong", "Zou", "Zu", "Zuan", "Zui", "Zun", "Zuo" }; - // 验证是否输入汉字 - Regex reg = new Regex("^[\u4e00-\u9fa5]$"); - byte[] arr = new byte[2]; - string pystr = string.Empty; - int asc = 0, M1 = 0, M2 = 0; + // 验证是否输入汉字 + Regex reg = new Regex("^[\u4e00-\u9fa5]$"); + byte[] arr = new byte[2]; + string pystr = string.Empty; + int asc = 0, M1 = 0, M2 = 0; - // 获取汉字对应的字符数组 - char[] mChar = Chstr.ToCharArray(); - for (int j = 0; j < mChar.Length; j++) - { - // 如果输入的是汉字 - if (reg.IsMatch(mChar[j].ToString())) - { - arr = System.Text.Encoding.Default.GetBytes(mChar[j].ToString()); - M1 = (short)arr[0]; - M2 = (short)arr[1]; - asc = (M1 * 256) + M2 - 65536; - if (asc > 0 && asc < 160) + // 获取汉字对应的字符数组 + char[] mChar = Chstr.ToCharArray(); + for (int j = 0; j < mChar.Length; j++) { - pystr += mChar[j]; - } - else - { - switch (asc) - { - case -9254: - pystr += "Zhen"; break; - case -8985: - pystr += "Qian"; break; - case -5463: - pystr += "Jia"; break; - case -8274: - pystr += "Ge"; break; - case -5448: - pystr += "Ga"; break; - case -5447: - pystr += "La"; break; - case -4649: - pystr += "Chen"; break; - case -5436: - pystr += "Mao"; break; - case -5213: - pystr += "Mao"; break; - case -3597: - pystr += "Die"; break; - case -5659: - pystr += "Tian"; break; - default: - for (int i = getValue.Length - 1; i >= 0; i--) - { - // 判断汉字的拼音区编码是否在指定范围内 - if (getValue[i] <= asc) + // 如果输入的是汉字 + if (reg.IsMatch(mChar[j].ToString())) + { + arr = System.Text.Encoding.Default.GetBytes(mChar[j].ToString()); + M1 = (short)arr[0]; + M2 = (short)arr[1]; + asc = (M1 * 256) + M2 - 65536; + if (asc > 0 && asc < 160) { - // 如果不超出范围则获取对应的拼音 - pystr += getName[i]; - break; + pystr += mChar[j]; } - } + else + { + switch (asc) + { + case -9254: + pystr += "Zhen"; break; + case -8985: + pystr += "Qian"; break; + case -5463: + pystr += "Jia"; break; + case -8274: + pystr += "Ge"; break; + case -5448: + pystr += "Ga"; break; + case -5447: + pystr += "La"; break; + case -4649: + pystr += "Chen"; break; + case -5436: + pystr += "Mao"; break; + case -5213: + pystr += "Mao"; break; + case -3597: + pystr += "Die"; break; + case -5659: + pystr += "Tian"; break; + default: + for (int i = getValue.Length - 1; i >= 0; i--) + { + // 判断汉字的拼音区编码是否在指定范围内 + if (getValue[i] <= asc) + { + // 如果不超出范围则获取对应的拼音 + pystr += getName[i]; + break; + } + } - break; - } + break; + } + } + } + + // 如果不是汉字 + else + { + // 如果不是汉字则返回 + pystr += mChar[j].ToString(); + } } - } - // 如果不是汉字 - else - { - // 如果不是汉字则返回 - pystr += mChar[j].ToString(); - } + // 返回获取到的汉字拼音 + return pystr; } - // 返回获取到的汉字拼音 - return pystr; - } - - #endregion + #endregion } \ No newline at end of file diff --git a/common/Tnb.Common/Security/SuperQueryHelper.cs b/common/Tnb.Common/Security/SuperQueryHelper.cs index e42973c6..337aa93b 100644 --- a/common/Tnb.Common/Security/SuperQueryHelper.cs +++ b/common/Tnb.Common/Security/SuperQueryHelper.cs @@ -60,7 +60,23 @@ public class SuperQueryHelper { case JnpfKeyConst.COMINPUT: case JnpfKeyConst.TEXTAREA: - item.fieldValue = item.fieldValue?.ToString()?.Replace("\r\n", string.Empty); + case JnpfKeyConst.CHECKBOX: + case JnpfKeyConst.SELECT: + case JnpfKeyConst.TIME: + case JnpfKeyConst.DEPSELECT: + case JnpfKeyConst.GROUPSELECT: + case JnpfKeyConst.POSSELECT: + case JnpfKeyConst.USERSELECT: + case JnpfKeyConst.ROLESELECT: + case JnpfKeyConst.TREESELECT: + case JnpfKeyConst.RELATIONFORM: + case JnpfKeyConst.RELATIONFORMATTR: + case JnpfKeyConst.POPUPSELECT: + case JnpfKeyConst.POPUPATTR: + case JnpfKeyConst.CALCULATE: + case JnpfKeyConst.CREATEUSER: + case JnpfKeyConst.MODIFYUSER: + item.fieldValue = item.fieldValue?.ToString().Replace("\r\n", string.Empty); switch (item.symbol) { case "==": // 等于 @@ -91,228 +107,13 @@ public class SuperQueryHelper queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); switch (item.symbol) { - case "like": // 包含 - conditionalType = ConditionalType.NoLike; - break; case "notLike": // 不包含 - conditionalType = ConditionalType.Like; - break; case "<>": // 不等于 conditionalType = ConditionalType.IsNullOrEmpty; queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); break; } break; - case JnpfKeyConst.NUMINPUT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.SWITCH: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.RADIO: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.CHECKBOX: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.SELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.POPUPTABLESELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.CASCADER: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; case JnpfKeyConst.DATE: switch (item.symbol) { @@ -326,7 +127,7 @@ public class SuperQueryHelper conditionalType = ConditionalType.Equal; break; case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; + conditionalType = ConditionalType.LessThanOrEqual; break; case "<": // 小于 conditionalType = ConditionalType.LessThan; @@ -335,15 +136,23 @@ public class SuperQueryHelper conditionalType = ConditionalType.NoEqual; break; case "like": // 包含 - conditionalType = ConditionalType.Like; + conditionalType = ConditionalType.Equal; break; case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; + conditionalType = ConditionalType.NoEqual; + break; + } + queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ToObject().ToString(), conditionalType, true)); + switch (item.symbol) + { + case "notLike": // 不包含 + case "<>": // 不等于 + conditionalType = ConditionalType.IsNullOrEmpty; + queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); break; } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); break; - case JnpfKeyConst.TIME: + case JnpfKeyConst.CREATETIME: switch (item.symbol) { case ">=": // 大于等于 @@ -356,7 +165,7 @@ public class SuperQueryHelper conditionalType = ConditionalType.Equal; break; case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; + conditionalType = ConditionalType.LessThan; break; case "<": // 小于 conditionalType = ConditionalType.LessThan; @@ -365,15 +174,68 @@ public class SuperQueryHelper conditionalType = ConditionalType.NoEqual; break; case "like": // 包含 - conditionalType = ConditionalType.Like; + conditionalType = ConditionalType.Equal; break; case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; + conditionalType = ConditionalType.NoEqual; + break; + } + queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, string.Format("{0:yyyy-MM-dd HH:mm:ss}", item.fieldValue.ToObject()), conditionalType, true)); + switch (item.symbol) + { + case "notLike": // 不包含 + case "<>": // 不等于 + conditionalType = ConditionalType.IsNullOrEmpty; + queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); break; } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); break; + case JnpfKeyConst.MODIFYTIME: + switch (item.symbol) + { + case ">=": // 大于等于 + conditionalType = ConditionalType.GreaterThanOrEqual; + break; + case ">": // 大于 + conditionalType = ConditionalType.GreaterThan; + break; + case "==": // 等于 + conditionalType = ConditionalType.Equal; + break; + case "<=": // 小于等于 + conditionalType = ConditionalType.LessThanOrEqual; + break; + case "<": // 小于 + conditionalType = ConditionalType.LessThan; + break; + case "<>": // 不等于 + conditionalType = ConditionalType.NoEqual; + break; + case "like": // 包含 + conditionalType = ConditionalType.Equal; + break; + case "notLike": // 不包含 + conditionalType = ConditionalType.NoEqual; + break; + } + queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, string.Format("{0:yyyy-MM-dd HH:mm:ss}", item.fieldValue.ToObject()), conditionalType, true)); + switch (item.symbol) + { + case "notLike": // 不包含 + case "<>": // 不等于 + conditionalType = ConditionalType.IsNullOrEmpty; + queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); + break; + } + break; + case JnpfKeyConst.NUMINPUT: + case JnpfKeyConst.SWITCH: + case JnpfKeyConst.RADIO: + case JnpfKeyConst.POPUPTABLESELECT: case JnpfKeyConst.COMSELECT: + case JnpfKeyConst.BILLRULE: + case JnpfKeyConst.CURRDEPT: + case JnpfKeyConst.CURRPOSITION: switch (item.symbol) { case ">=": // 大于等于 @@ -386,97 +248,7 @@ public class SuperQueryHelper conditionalType = ConditionalType.Equal; break; case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.DEPSELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.POSSELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.USERSELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; + conditionalType = ConditionalType.LessThanOrEqual; break; case "<": // 小于 conditionalType = ConditionalType.LessThan; @@ -494,6 +266,8 @@ public class SuperQueryHelper queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); break; case JnpfKeyConst.USERSSELECT: + if (item.symbol.Equals("==")) item.symbol = "like"; + if (item.symbol.Equals("<>")) item.symbol = "notLike"; if (item.fieldValue != null && (item.symbol.Equals("like") || item.symbol.Equals("notLike"))) { var rIdList = GetUserRelationByUserId(item.fieldValue.ToString()); @@ -549,159 +323,10 @@ public class SuperQueryHelper queryOr.mainWhere = true; queryList.Add(queryOr); } - //modified by PhilPan - continue; } - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.ROLESELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.GROUPSELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.TREESELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.BILLRULE: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; + continue; case JnpfKeyConst.ADDRESS: + case JnpfKeyConst.CASCADER: switch (item.symbol) { case ">=": // 大于等于 @@ -712,266 +337,39 @@ public class SuperQueryHelper break; case "==": // 等于 conditionalType = ConditionalType.Equal; + item.fieldValue = item.fieldValue.ToObject>().ToJsonString(); break; case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; + conditionalType = ConditionalType.LessThanOrEqual; break; case "<": // 小于 conditionalType = ConditionalType.LessThan; break; case "<>": // 不等于 conditionalType = ConditionalType.NoEqual; + item.fieldValue = item.fieldValue.ToObject>().ToJsonString(); break; case "like": // 包含 conditionalType = ConditionalType.Like; + item.fieldValue = item.fieldValue.ToObject>().Last(); break; case "notLike": // 不包含 conditionalType = ConditionalType.NoLike; + item.fieldValue = item.fieldValue.ToObject>().Last(); break; } queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.RELATIONFORM: switch (item.symbol) { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; + case "notLike": // 不包含 + conditionalType = ConditionalType.IsNullOrEmpty; + queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); break; case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; + conditionalType = ConditionalType.IsNullOrEmpty; + queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); break; } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.POPUPSELECT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.CALCULATE: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.CREATEUSER: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.CREATETIME: - if (item.fieldValue.IsNotEmptyOrNull()) item.fieldValue = string.Format("{0:yyyy-MM-dd HH:mm:ss}", item.fieldValue?.ToString().TimeStampToDateTime()); - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.MODIFYUSER: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.MODIFYTIME: - if (item.fieldValue.IsNotEmptyOrNull()) item.fieldValue = string.Format("{0:yyyy-MM-dd HH:mm:ss}", item.fieldValue?.ToString().TimeStampToDateTime()); - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.CURRDEPT: - switch (item.symbol) - { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; - break; - case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; - break; - } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); break; case JnpfKeyConst.CURRORGANIZE: switch (item.symbol) @@ -984,54 +382,39 @@ public class SuperQueryHelper break; case "==": // 等于 conditionalType = ConditionalType.Equal; + item.fieldValue = item.fieldValue.ToObject>().Last(); break; case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; + conditionalType = ConditionalType.LessThanOrEqual; break; case "<": // 小于 conditionalType = ConditionalType.LessThan; break; case "<>": // 不等于 conditionalType = ConditionalType.NoEqual; + item.fieldValue = item.fieldValue.ToObject>().Last(); break; case "like": // 包含 - conditionalType = ConditionalType.Like; + conditionalType = ConditionalType.Equal; + item.fieldValue = item.fieldValue.ToObject>().Last(); break; case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; + conditionalType = ConditionalType.NoEqual; + item.fieldValue = item.fieldValue.ToObject>().Last(); break; } queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); - break; - case JnpfKeyConst.CURRPOSITION: switch (item.symbol) { - case ">=": // 大于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case ">": // 大于 - conditionalType = ConditionalType.GreaterThan; - break; - case "==": // 等于 - conditionalType = ConditionalType.Equal; - break; - case "<=": // 小于等于 - conditionalType = ConditionalType.GreaterThanOrEqual; - break; - case "<": // 小于 - conditionalType = ConditionalType.LessThan; + case "notLike": // 不包含 + conditionalType = ConditionalType.IsNullOrEmpty; + queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); break; case "<>": // 不等于 - conditionalType = ConditionalType.NoEqual; - break; - case "like": // 包含 - conditionalType = ConditionalType.Like; - break; - case "notLike": // 不包含 - conditionalType = ConditionalType.NoLike; + conditionalType = ConditionalType.IsNullOrEmpty; + queryList.Add(ControlAdvancedQueryAssembly(WhereType.Or, item.jnpfKey, field, null, conditionalType)); break; } - queryList.Add(ControlAdvancedQueryAssembly(whereType, item.jnpfKey, field, item.fieldValue.ParseToString(), conditionalType, true)); break; } } @@ -1039,7 +422,7 @@ public class SuperQueryHelper return queryList; } - public static ConvertSuperQuery ControlAdvancedQueryAssembly(WhereType whereType, string jnpfKey, string field, string fieldValue, ConditionalType conditionalType, bool mainWhere = false) + public static ConvertSuperQuery ControlAdvancedQueryAssembly(WhereType whereType, string jnpfKey, string field, string fieldValue, ConditionalType conditionalType, bool mainWhere = false, string symbol = "") { return new ConvertSuperQuery { @@ -1048,7 +431,8 @@ public class SuperQueryHelper field = field, fieldValue = fieldValue, conditionalType = conditionalType, - mainWhere = mainWhere + mainWhere = mainWhere, + symbol = symbol }; } @@ -1087,13 +471,13 @@ public class SuperQueryHelper private static List> GetUserRelationByUserId(string fieldValue) { // 获取数据库连接选项 - ConnectionStringsOptions conn = App.GetConfig("ConnectionStrings", true); + ConnectionStringsOptions connectionStrings = App.GetConfig("ConnectionStrings", true); SqlSugarClient db = new SqlSugarClient(new ConnectionConfig { - ConnectionString = string.Format(conn.DefaultConnection, conn.Host, conn.Port, conn.DBName, conn.UserName, conn.Password), - DbType = (DbType)Enum.Parse(typeof(DbType), conn.DBType), + ConnectionString = connectionStrings.ConnectString, // string.Format(connectionStrings.DefaultConnection, connectionStrings.DBName), + DbType = (DbType)Enum.Parse(typeof(DbType), connectionStrings.DBType), IsAutoCloseConnection = true, - ConfigId = conn.ConfigId, + ConfigId = connectionStrings.ConfigId, InitKeyType = InitKeyType.Attribute, MoreSettings = new ConnMoreSettings() { diff --git a/common/Tnb.Common/Security/XmlHelper.cs b/common/Tnb.Common/Security/XmlHelper.cs index bd6f45f6..accc0c1e 100644 --- a/common/Tnb.Common/Security/XmlHelper.cs +++ b/common/Tnb.Common/Security/XmlHelper.cs @@ -4,11 +4,11 @@ namespace JNPF.Common.Security; public static class XmlHelper { - /// - /// 反序列化 - /// - /// 类型 - /// XML字符串 + /// + /// 反序列化. + /// + /// 类型. + /// XML字符串. /// public static object Deserialize(Type type, string xml) { @@ -19,13 +19,12 @@ public static class XmlHelper } } - /// - /// 反序列化 - /// - /// - /// - /// - + /// + /// 反序列化. + /// + /// 类型. + /// XML流. + /// public static object Deserialize(Type type, Stream stream) { XmlSerializer xmldes = new XmlSerializer(type); diff --git a/common/Tnb.Common/Utils/DeepCopyHelper.cs b/common/Tnb.Common/Utils/DeepCopyHelper.cs new file mode 100644 index 00000000..1c4cc78c --- /dev/null +++ b/common/Tnb.Common/Utils/DeepCopyHelper.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.Common.Utils +{ + public class DeepCopyHelper where T : class, new() // 需要无参构造函数,构造表达式树的时候需要利用无参构造函数创建对象 + { + /// + /// 映射表达式,泛型缓存每个类型存一份 + /// + private static readonly Func s_CopyFunc = null; + + /// + /// 静态构造函数,每个泛型类型会且只会执行一次 + /// + static DeepCopyHelper() + { + BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "m"); // 参数m :m => + List memberBindingList = new List(); + foreach (var item in typeof(T).GetProperties(bindingFlags)) + { + if (!item.CanWrite) // 只读属性不拷贝 + { + continue; + } + MemberExpression property = Expression.Property(parameterExpression, item); // m.Name + MemberBinding memberBinding = Expression.Bind(item, property); // Name = m.Name + memberBindingList.Add(memberBinding); + } + foreach (var item in typeof(T).GetFields(bindingFlags)) + { + MemberExpression property = Expression.Field(parameterExpression, item); + MemberBinding memberBinding = Expression.Bind(item, property); + memberBindingList.Add(memberBinding); + } + MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(T)), memberBindingList.ToArray());// new T() {Name = m.Name} + Expression> lambda = Expression.Lambda>(memberInitExpression, new ParameterExpression[] + { + parameterExpression + }); // m => new T() {Name = m.Name} + + s_CopyFunc = lambda.Compile(); + } + + /// + /// 对象拷贝(拷贝private/public:实例成员、属性、静态成员) + /// + /// 源 + /// + public static T DeepCopy(T data) + { + return s_CopyFunc(data); + } + + /// + /// 集合拷贝(拷贝private/public:实例成员、属性、静态成员) + /// + /// 源 + /// + public static List DeepCopyList(List data) + { + if (data == null || data.Count < 1) + { + return Enumerable.Empty().ToList(); + } + return data.Select(a => DeepCopy(a)).ToList(); + } + } + +} diff --git a/common/Tnb.SqlSugar/Extensions/TenantLinkExtensions.cs b/common/Tnb.SqlSugar/Extensions/TenantLinkExtensions.cs index d9f39627..723aafd0 100644 --- a/common/Tnb.SqlSugar/Extensions/TenantLinkExtensions.cs +++ b/common/Tnb.SqlSugar/Extensions/TenantLinkExtensions.cs @@ -1,4 +1,5 @@ -using JNPF.DataEncryption; +using JNPF; +using JNPF.DataEncryption; using JNPF.Extras.DatabaseAccessor.SqlSugar; using JNPF.Extras.DatabaseAccessor.SqlSugar.Extensions; using Microsoft.Extensions.Configuration; @@ -11,8 +12,7 @@ namespace SqlSugar; /// public class JNPFTenantExtensions { - //public static IConfiguration _config { get; set; } - private static ConnectionStringsOptions _connOpt { get; } + public static IConfiguration _config { get; set; } public static string skey = "Vl4WTqna9aZCgswjieIP"; @@ -21,8 +21,7 @@ public class JNPFTenantExtensions /// static JNPFTenantExtensions() { - var config = new ConfigurationBuilder().AddJsonFile("Configurations/ConnectionStrings.json", true, true).Build(); - _connOpt = config.GetSection("ConnectionStrings").Get(); + _config = new ConfigurationBuilder().Add(new JsonConfigurationSource { Path = "Configurations/ConnectionStrings.json", ReloadOnChange = true }).Build(); } /// @@ -33,14 +32,15 @@ public class JNPFTenantExtensions /// public static ConnectionConfigOptions GetLinkToOrdinary(string configId, string tableName) { + ConnectionStringsOptions conn = App.GetConfig("ConnectionStrings", true); + List configList = new List(); - var connStr = string.Format(_connOpt.DefaultConnection, _connOpt.Host, _connOpt.Port, _connOpt.DBName, _connOpt.UserName, _connOpt.Password); configList.Add(new DBConnectionConfig() { IsMaster = true, ServiceName = tableName, - dbType = ToDbType(_connOpt.DBType), - connectionStr = DESCEncryption.Encrypt(connStr, skey) + dbType = (DbType)Enum.Parse(typeof(DbType), conn.DBType), + connectionStr = DESCEncryption.Encrypt(conn.ConnectString, skey) }); return new ConnectionConfigOptions() { diff --git a/common/Tnb.SqlSugar/Models/ITenantFilter.cs b/common/Tnb.SqlSugar/Models/ITenantFilter.cs new file mode 100644 index 00000000..8a92ca1d --- /dev/null +++ b/common/Tnb.SqlSugar/Models/ITenantFilter.cs @@ -0,0 +1,15 @@ +using SqlSugar; + +namespace JNPF.Extras.DatabaseAccessor.SqlSugar.Models; + +/// +/// 实体类基类. +/// +public interface ITenantFilter +{ + /// + /// 租户id. + /// + [SugarColumn(ColumnName = "F_TenantId", ColumnDescription = "租户id")] + string TenantId { get; set; } +} \ No newline at end of file diff --git a/common/Tnb.SqlSugar/Options/ConnectionStringsOptions.cs b/common/Tnb.SqlSugar/Options/ConnectionStringsOptions.cs index 0cffa04a..90bba155 100644 --- a/common/Tnb.SqlSugar/Options/ConnectionStringsOptions.cs +++ b/common/Tnb.SqlSugar/Options/ConnectionStringsOptions.cs @@ -46,4 +46,6 @@ public sealed class ConnectionStringsOptions : IConfigurableOptions /// 默认数据库连接字符串. /// public string DefaultConnection { get; set; } + + public string ConnectString { get { return string.Format(DefaultConnection, Host, Port, DBName, UserName, Password); } } } \ No newline at end of file diff --git a/common/Tnb.SqlSugar/Options/TenantOptions.cs b/common/Tnb.SqlSugar/Options/TenantOptions.cs index c22ef476..5ee2391f 100644 --- a/common/Tnb.SqlSugar/Options/TenantOptions.cs +++ b/common/Tnb.SqlSugar/Options/TenantOptions.cs @@ -12,6 +12,11 @@ public sealed class TenantOptions : IConfigurableOptions /// public bool MultiTenancy { get; set; } + /// + /// 数据隔离类型 SCHEMA:库隔离 COLUMN:字段隔离. + /// + public string MultiTenancyType { get; set; } + /// /// 多租户数据接口. /// diff --git a/common/Tnb.SqlSugar/Repositories/SqlSugarRepository.cs b/common/Tnb.SqlSugar/Repositories/SqlSugarRepository.cs index 41df7e6e..e24fece9 100644 --- a/common/Tnb.SqlSugar/Repositories/SqlSugarRepository.cs +++ b/common/Tnb.SqlSugar/Repositories/SqlSugarRepository.cs @@ -1,11 +1,11 @@ using JNPF; using JNPF.DataEncryption; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using JNPF.FriendlyException; using JNPF.JsonSerialization; using JNPF.Logging; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; -using System.Text.RegularExpressions; namespace SqlSugar; @@ -16,95 +16,98 @@ namespace SqlSugar; public partial class SqlSugarRepository : SimpleClient, ISqlSugarRepository where TEntity : class, new() { - /// - /// 构造函数 - /// - /// - public SqlSugarRepository(ISqlSugarClient context = null) : base(context) - { - // 获取数据库连接选项 - ConnectionStringsOptions connectionStrings = App.GetConfig("ConnectionStrings", true); - - // 获取多租户选项 - TenantOptions tenant = App.GetConfig("Tenant", true); - var httpContext = App.HttpContext; - - base.Context = (SqlSugarScope)context; - - string tenantId = connectionStrings.ConfigId; - - if (httpContext?.GetEndpoint()?.Metadata?.GetMetadata() == null || !string.IsNullOrEmpty(httpContext?.Request.Query["token"])) + /// + /// 构造函数 + /// + /// + public SqlSugarRepository(ISqlSugarClient context = null) : base(context) { - if (tenant.MultiTenancy && httpContext != null) - { - var connectionConfig = new ConnectionConfigOptions(); - if (httpContext.Request.Headers.ContainsKey("Authorization")) + // 获取数据库连接选项 + ConnectionStringsOptions connectionStrings = App.GetConfig("ConnectionStrings", true); + + // 获取多租户选项 + TenantOptions tenant = App.GetConfig("Tenant", true); + var httpContext = App.HttpContext; + + base.Context = (SqlSugarScope)context; + + string tenantId = connectionStrings.ConfigId; + string tenantDbName = string.Empty; + + if (httpContext?.GetEndpoint()?.Metadata?.GetMetadata() == null) { - connectionConfig = JSON.Deserialize(httpContext?.User.FindFirst("ConnectionConfig")?.Value); - tenantId = connectionConfig.ConfigId; + if (tenant.MultiTenancy && httpContext != null) + { + var connectionConfig = JSON.Deserialize(httpContext?.User.FindFirst("ConnectionConfig")?.Value); + tenantId = connectionConfig.ConfigId; + tenantDbName = connectionConfig.ConfigList.FirstOrDefault().ServiceName; + if (!base.Context.AsTenant().IsAnyConnection(connectionConfig.ConfigId)) + { + base.Context.AsTenant().AddConnection(JNPFTenantExtensions.GetConfig(connectionConfig)); + } + base.Context = base.Context.AsTenant().GetConnectionScope(connectionConfig.ConfigId); + + if (!base.Context.Ado.IsValidConnection()) + { + throw Oops.Oh("数据库连接错误"); + } + } + else + { + base.Context = base.Context.AsTenant().GetConnectionScope(tenantId); + } } - else if (!httpContext.Request.Headers.ContainsKey("Authorization")) + // 字段数据隔离 + if (!"default".Equals(tenantId) && tenant.MultiTenancyType.Equals("COLUMN")) { - var token = Regex.Match(httpContext.Request.QueryString.Value, @"[?&]token=Bearer%20([\w\.-]+)($|&)").Groups[1].Value; - var claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", "").Replace("bearer ", ""))?.Claims; - connectionConfig = JSON.Deserialize(claims.FirstOrDefault(e => e.Type == "ConnectionConfig").Value); - tenantId = connectionConfig.ConfigId; + base.Context.QueryFilter.AddTableFilter(it => it.TenantId == tenantDbName); + base.Context.Aop.DataExecuting = (oldValue, entityInfo) => + { + if (entityInfo.PropertyName == "TenantId" && entityInfo.OperationType == DataFilterType.InsertByObject) + { + entityInfo.SetValue(tenantDbName); + } + }; } - if (!base.Context.AsTenant().IsAnyConnection(connectionConfig.ConfigId)) + // 设置超时时间 + base.Context.Ado.CommandTimeOut = 30; + base.Context.Aop.OnLogExecuted = (sql, pars) => { - base.Context.AsTenant().AddConnection(JNPFTenantExtensions.GetConfig(connectionConfig)); - } - base.Context = base.Context.AsTenant().GetConnectionScope(connectionConfig.ConfigId); - - if (!base.Context.Ado.IsValidConnection()) - { - throw Oops.Oh("数据库连接错误"); - } - } - else - { - base.Context = base.Context.AsTenant().GetConnectionScope(tenantId); - } - } - - // 设置超时时间 - base.Context.Ado.CommandTimeOut = 30; - base.Context.Aop.OnLogExecuted = (sql, pars) => - { - var oldColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Green; - var finalSql = UtilMethods.GetSqlString(Context.CurrentConnectionConfig.DbType, sql, pars); - Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}——SQL执行完成】{Context.Ado.SqlExecutionTime.TotalMilliseconds} ms"); - Console.WriteLine(finalSql); - Console.ForegroundColor = oldColor; - if (Context.Ado.SqlExecutionTime.TotalMilliseconds > 3000) - { - Log.Warning($"慢查询: {Context.Ado.SqlExecutionTime.TotalMilliseconds}ms, SQL: " + finalSql); - } - Console.WriteLine(); - //App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + base.Context.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); - }; - base.Context.Aop.OnError = (ex) => - { - Log.Error("SQL执行错误: " + UtilMethods.GetSqlString(base.Context.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres)); - //App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}"); - }; - - if (base.Context.CurrentConnectionConfig.DbType == DbType.Oracle) - { - base.Context.Aop.OnExecutingChangeSql = (sql, pars) => - { - if (pars != null) - { - foreach (var item in pars) - { - //如果是DbTppe=string设置成OracleDbType.Nvarchar2 - item.IsNvarchar2 = true; - } + var oldColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Green; + var finalSql = UtilMethods.GetSqlString(Context.CurrentConnectionConfig.DbType, sql, pars); + Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}——SQL执行完成】{Context.Ado.SqlExecutionTime.TotalMilliseconds} ms"); + Console.WriteLine(finalSql); + Console.ForegroundColor = oldColor; + if (Context.Ado.SqlExecutionTime.TotalMilliseconds > 3000) + { + Log.Warning($"慢查询: {Context.Ado.SqlExecutionTime.TotalMilliseconds}ms, SQL: " + finalSql); + } + Console.WriteLine(); + //App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + base.Context.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); }; - return new KeyValuePair(sql, pars); - }; + base.Context.Aop.OnError = (ex) => + { + Log.Error("SQL执行错误: " + UtilMethods.GetSqlString(base.Context.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres)); + //App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}"); + }; + + + if (base.Context.CurrentConnectionConfig.DbType == DbType.Oracle) + { + base.Context.Aop.OnExecutingChangeSql = (sql, pars) => + { + if (pars != null) + { + foreach (var item in pars) + { + //如果是DbTppe=string设置成OracleDbType.Nvarchar2 + item.IsNvarchar2 = true; + } + }; + return new KeyValuePair(sql, pars); + }; + } } - } } \ No newline at end of file diff --git a/common/Tnb.SqlSugar/Tnb.SqlSugar.csproj b/common/Tnb.SqlSugar/Tnb.SqlSugar.csproj index 197c66e6..65402833 100644 --- a/common/Tnb.SqlSugar/Tnb.SqlSugar.csproj +++ b/common/Tnb.SqlSugar/Tnb.SqlSugar.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/common/Tnb.WebSockets/Models/WebSocketClient.cs b/common/Tnb.WebSockets/Models/WebSocketClient.cs index 7780d63d..f41ee5c7 100644 --- a/common/Tnb.WebSockets/Models/WebSocketClient.cs +++ b/common/Tnb.WebSockets/Models/WebSocketClient.cs @@ -64,6 +64,11 @@ public class WebSocketClient /// public LoginMethod SingleLogin { get; set; } + /// + /// 单点登录标识. + /// + public string onlineTicket { get; set; } + /// /// token. /// diff --git a/extend/Tnb.Extend.Entitys/Dto/Document/DocumentListOutput.cs b/extend/Tnb.Extend.Entitys/Dto/Document/DocumentListOutput.cs index 42a024f6..6ab9381b 100644 --- a/extend/Tnb.Extend.Entitys/Dto/Document/DocumentListOutput.cs +++ b/extend/Tnb.Extend.Entitys/Dto/Document/DocumentListOutput.cs @@ -47,4 +47,19 @@ public class DocumentListOutput /// 父级Id. /// public string? parentId { get; set; } + + /// + /// 文档下载地址. + /// + public string? uploaderUrl { get; set; } + + /// + /// 文件路径. + /// + public string? filePath { get; set; } + + /// + /// 是否支持预览. + /// + public string? isPreview { get; set; } } diff --git a/extend/Tnb.Extend.Entitys/Dto/Product/ProductCrInput.cs b/extend/Tnb.Extend.Entitys/Dto/Product/ProductCrInput.cs index 9bcb2455..01038191 100644 --- a/extend/Tnb.Extend.Entitys/Dto/Product/ProductCrInput.cs +++ b/extend/Tnb.Extend.Entitys/Dto/Product/ProductCrInput.cs @@ -87,17 +87,17 @@ public class ProductCrInput /// /// 让利金额. /// - public decimal partPrice { get; set; } + public decimal? partPrice { get; set; } /// /// 优惠金额. /// - public decimal reducedPrice { get; set; } + public decimal? reducedPrice { get; set; } /// /// 折后金额. /// - public decimal discountPrice { get; set; } + public decimal? discountPrice { get; set; } /// /// 备注. diff --git a/extend/Tnb.Extend.Entitys/Dto/Product/ProductInfoOutput.cs b/extend/Tnb.Extend.Entitys/Dto/Product/ProductInfoOutput.cs index 8cf39190..1976c821 100644 --- a/extend/Tnb.Extend.Entitys/Dto/Product/ProductInfoOutput.cs +++ b/extend/Tnb.Extend.Entitys/Dto/Product/ProductInfoOutput.cs @@ -92,17 +92,17 @@ public class ProductInfoOutput /// /// 让利金额. /// - public decimal partPrice { get; set; } + public decimal? partPrice { get; set; } /// /// 优惠金额. /// - public decimal reducedPrice { get; set; } + public decimal? reducedPrice { get; set; } /// /// 折后金额. /// - public decimal discountPrice { get; set; } + public decimal? discountPrice { get; set; } /// /// 备注. diff --git a/extend/Tnb.Extend.Entitys/Dto/Product/ProductListOutput.cs b/extend/Tnb.Extend.Entitys/Dto/Product/ProductListOutput.cs index dc56c981..0dc6fa52 100644 --- a/extend/Tnb.Extend.Entitys/Dto/Product/ProductListOutput.cs +++ b/extend/Tnb.Extend.Entitys/Dto/Product/ProductListOutput.cs @@ -67,4 +67,9 @@ public class ProductListOutput /// 联系人. /// public string contactName { get; set; } + + /// + /// 子表数据. + /// + public List productEntryList { get; set; } } \ No newline at end of file diff --git a/extend/Tnb.Extend.Entitys/Dto/Customer/CustomerListOutput.cs b/extend/Tnb.Extend.Entitys/Dto/ProductCustomer/ProductCustomerListOutput.cs similarity index 95% rename from extend/Tnb.Extend.Entitys/Dto/Customer/CustomerListOutput.cs rename to extend/Tnb.Extend.Entitys/Dto/ProductCustomer/ProductCustomerListOutput.cs index cfff8590..21aa8fdc 100644 --- a/extend/Tnb.Extend.Entitys/Dto/Customer/CustomerListOutput.cs +++ b/extend/Tnb.Extend.Entitys/Dto/ProductCustomer/ProductCustomerListOutput.cs @@ -7,7 +7,7 @@ namespace JNPF.Extend.Entitys.Dto.Customer; /// 客户信息. /// [SuppressSniffer] -public class CustomerListOutput +public class ProductCustomerListOutput { /// /// 主键. diff --git a/extend/Tnb.Extend.Entitys/Entity/BigDataEntity.cs b/extend/Tnb.Extend.Entitys/Entity/BigDataEntity.cs index 5be87cd3..7b29de88 100644 --- a/extend/Tnb.Extend.Entitys/Entity/BigDataEntity.cs +++ b/extend/Tnb.Extend.Entitys/Entity/BigDataEntity.cs @@ -1,4 +1,5 @@ using JNPF.Common.Contracts; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using SqlSugar; namespace JNPF.Extend.Entitys; diff --git a/extend/Tnb.Extend.Entitys/Entity/DocumentEntity.cs b/extend/Tnb.Extend.Entitys/Entity/DocumentEntity.cs index e3fb9113..f187c65d 100644 --- a/extend/Tnb.Extend.Entitys/Entity/DocumentEntity.cs +++ b/extend/Tnb.Extend.Entitys/Entity/DocumentEntity.cs @@ -78,4 +78,10 @@ public class DocumentEntity : CLDEntityBase /// [SugarColumn(ColumnName = "F_SORTCODE")] public long? SortCode { get; set; } + + /// + /// 下载地址. + /// + [SugarColumn(ColumnName = "F_UPLOADERURL")] + public string? UploaderUrl { get; set; } } diff --git a/extend/Tnb.Extend.Entitys/Entity/CustomerEntity.cs b/extend/Tnb.Extend.Entitys/Entity/ProductCustomerEntity.cs similarity index 96% rename from extend/Tnb.Extend.Entitys/Entity/CustomerEntity.cs rename to extend/Tnb.Extend.Entitys/Entity/ProductCustomerEntity.cs index c7bee238..76bc96bd 100644 --- a/extend/Tnb.Extend.Entitys/Entity/CustomerEntity.cs +++ b/extend/Tnb.Extend.Entitys/Entity/ProductCustomerEntity.cs @@ -7,7 +7,7 @@ namespace JNPF.Extend.Entitys.Entity; /// 客户信息. /// [SugarTable("ext_customer", TableDescription = "客户信息")] -public class CustomerEntity : CLEntityBase +public class ProductCustomerEntity : CLEntityBase { /// /// 编码. diff --git a/extend/Tnb.Extend.Entitys/Entity/ProductEntity.cs b/extend/Tnb.Extend.Entitys/Entity/ProductEntity.cs index a0c4ccfa..00144cd5 100644 --- a/extend/Tnb.Extend.Entitys/Entity/ProductEntity.cs +++ b/extend/Tnb.Extend.Entitys/Entity/ProductEntity.cs @@ -159,19 +159,19 @@ public class ProductEntity : EntityBase /// 让利金额. /// [SugarColumn(ColumnName = "F_PartPrice")] - public decimal PartPrice { get; set; } + public decimal? PartPrice { get; set; } /// /// 优惠金额. /// [SugarColumn(ColumnName = "F_ReducedPrice")] - public decimal ReducedPrice { get; set; } + public decimal? ReducedPrice { get; set; } /// /// 折后金额. /// [SugarColumn(ColumnName = "F_DiscountPrice")] - public decimal DiscountPrice { get; set; } + public decimal? DiscountPrice { get; set; } /// /// 备注. diff --git a/extend/Tnb.Extend.Entitys/Entity/ProductgoodsEntity.cs b/extend/Tnb.Extend.Entitys/Entity/ProductgoodsEntity.cs index 9765623a..3e587ce7 100644 --- a/extend/Tnb.Extend.Entitys/Entity/ProductgoodsEntity.cs +++ b/extend/Tnb.Extend.Entitys/Entity/ProductgoodsEntity.cs @@ -9,7 +9,7 @@ namespace JNPF.Extend.Entitys; /// [SugarTable("ext_productgoods")] [Tenant(ClaimConst.TENANTID)] -public class ProductgoodsEntity +public class ProductGoodsEntity { /// /// 主键. diff --git a/extend/Tnb.Extend/DocumentService.cs b/extend/Tnb.Extend/DocumentService.cs index 185a6e43..b04bedd2 100644 --- a/extend/Tnb.Extend/DocumentService.cs +++ b/extend/Tnb.Extend/DocumentService.cs @@ -84,6 +84,12 @@ public class DocumentService : IDynamicApiController, ITransient .WhereIF(input.keyword.IsNotEmptyOrNull(), t => t.FullName.Contains(input.keyword)) .OrderBy(x => x.SortCode).OrderBy(x => x.CreatorTime, OrderByType.Desc) .OrderByIF(!string.IsNullOrEmpty(input.keyword), t => t.LastModifyTime, OrderByType.Desc).ToListAsync()).Adapt>(); + string[]? typeList = new string[] { "doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf", "jpg", "jpeg", "gif", "png", "bmp" }; + foreach (var item in data) + { + string? type = item.fullName.Split('.').LastOrDefault(); + item.isPreview = typeList.Contains(type) ? "1" : null; + } return new { list = data }; } @@ -248,6 +254,7 @@ public class DocumentService : IDynamicApiController, ITransient entity.FilePath = Path.Combine(_filePath, input.file.FileName); entity.FileSize = input.file.Length.ToString(); entity.DeleteMark = 0; + entity.UploaderUrl = string.Format("/api/file/Image/document/{0}", entity.FilePath); var isOk = await _repository.AsSugarClient().Insertable(entity).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); if (isOk < 1) throw Oops.Oh(ErrorCode.D8001); @@ -261,11 +268,12 @@ public class DocumentService : IDynamicApiController, ITransient [HttpPost("merge")] public async Task merge([FromForm] ChunkModel input) { - if (await _repository.IsAnyAsync(x => x.FullName == input.fileName && x.Type == 1 && x.DeleteMark != 1)) + if (await _repository.IsAnyAsync(x =>x.CreatorUserId==_userManager.UserId && x.FullName == input.fileName && x.Type == 1 && x.DeleteMark != 1)) { - string directoryPath = Path.Combine(App.GetConfig("JNPF_App", true).SystemPath, "TemporaryFile", input.identifier); - FileHelper.DeleteDirectory(directoryPath); - throw Oops.Oh(ErrorCode.D8002); + //string directoryPath = Path.Combine(App.GetConfig("JNPF_App", true).SystemPath, "TemporaryFile", input.identifier); + //FileHelper.DeleteDirectory(directoryPath); + //throw Oops.Oh(ErrorCode.D8002); + input.fileName = string.Format("{0}-{1}", DateTime.Now.ParseToUnixTime(), input.fileName); } input.isUpdateName = false; input.type = "document"; @@ -276,10 +284,11 @@ public class DocumentService : IDynamicApiController, ITransient entity.Type = 1; entity.FullName = input.fileName; entity.ParentId = input.parentId; - entity.FileExtension = Path.GetExtension(input.fileName).Replace(".", string.Empty); + entity.FileExtension = input.extension; entity.FilePath = output.name; entity.FileSize = input.fileSize; entity.DeleteMark = 0; + entity.UploaderUrl = string.Format("/api/file/Image/document/{0}", entity.FilePath); var isOk = await _repository.AsSugarClient().Insertable(entity).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); if (isOk < 1) throw Oops.Oh(ErrorCode.D8001); @@ -299,8 +308,7 @@ public class DocumentService : IDynamicApiController, ITransient throw Oops.Oh(ErrorCode.D8000); var fileName = _userManager.UserId + "|" + entity.FilePath + "|document"; _cacheManager.Set(entity.FilePath, string.Empty); - return new - { + return new { name = entity.FullName, url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(fileName, "JNPF") }; diff --git a/extend/Tnb.Extend/EmailService.cs b/extend/Tnb.Extend/EmailService.cs index 270505a2..bc67f23d 100644 --- a/extend/Tnb.Extend/EmailService.cs +++ b/extend/Tnb.Extend/EmailService.cs @@ -233,7 +233,7 @@ public class EmailService : IDynamicApiController, ITransient var mailAccount = mailConfig.Adapt(); if (MailUtil.CheckConnected(mailAccount)) { - new List(); + new List(); var startTime = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd") + " 00:00"); var endTime = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd") + " 23:59"); var receiveCount = await _repository.AsSugarClient().Queryable().CountAsync(x => x.MAccount == mailConfig.Account && SqlFunc.Between(x.CreatorTime, startTime, endTime)); @@ -331,7 +331,7 @@ public class EmailService : IDynamicApiController, ITransient var mailFilePath = FileVariable.EmailFilePath; foreach (MailFileParameterInfo mailFile in attachmentList) { - FileHelper.MoveFile(Path.Combine(temporaryFile , mailFile.fileId), Path.Combine(mailFilePath , mailFile.fileId)); + FileHelper.MoveFile(Path.Combine(temporaryFile, mailFile.fileId), Path.Combine(mailFilePath, mailFile.fileId)); mailFile.fileName = mailFile.name; } //发送邮件 @@ -342,7 +342,7 @@ public class EmailService : IDynamicApiController, ITransient mailModel.Subject = entity.Subject; mailModel.BodyText = HttpUtility.HtmlDecode(entity.BodyText); mailModel.Attachment = attachmentList; - MailUtil.Send(new MailParameterInfo { AccountName = mailConfig.SenderName, Account = mailConfig.Account, Password = mailConfig.Password, SMTPHost = mailConfig.SMTPHost, SMTPPort = mailConfig.SMTPPort.ParseToInt() }, mailModel); + MailUtil.Send(new MailParameterInfo { AccountName = mailConfig.SenderName, Account = mailConfig.Account, Password = mailConfig.Password, SMTPHost = mailConfig.SMTPHost, SMTPPort = mailConfig.SMTPPort.ParseToInt(), Ssl = mailConfig.Ssl == 1 }, mailModel); if (isOk < 1) throw Oops.Oh(ErrorCode.COM1008); } @@ -396,10 +396,10 @@ public class EmailService : IDynamicApiController, ITransient [HttpPost("Download")] public async Task Download(AnnexModel fileModel) { - var filePath = Path.Combine(FileVariable.EmailFilePath , fileModel.FileId); + var filePath = Path.Combine(FileVariable.EmailFilePath, fileModel.FileId); if (await _fileManager.ExistsFile(filePath)) { - _fileManager.DownloadFileByType(filePath, fileModel.FileName); + _fileManager.DownloadFileByType(filePath, fileModel.FileName); } } diff --git a/extend/Tnb.Extend/EmployeeService.cs b/extend/Tnb.Extend/EmployeeService.cs index a5f64f22..fa4ac24e 100644 --- a/extend/Tnb.Extend/EmployeeService.cs +++ b/extend/Tnb.Extend/EmployeeService.cs @@ -5,6 +5,7 @@ using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; using JNPF.Common.Helper; +using JNPF.Common.Manager; using JNPF.Common.Models.NPOI; using JNPF.Common.Security; using JNPF.DataEncryption; @@ -34,12 +35,14 @@ public class EmployeeService : IDynamicApiController, ITransient private readonly ISqlSugarRepository _repository; private readonly IFileManager _fileManager; private readonly IUserManager _userManager; + private readonly ICacheManager _cacheManager; - public EmployeeService(ISqlSugarRepository repository, IFileManager fileManager, IUserManager userManager) + public EmployeeService(ISqlSugarRepository repository, IFileManager fileManager, IUserManager userManager,ICacheManager cacheManager) { _repository = repository; _fileManager = fileManager; _userManager = userManager; + _cacheManager = cacheManager; } #region GET @@ -114,6 +117,7 @@ public class EmployeeService : IDynamicApiController, ITransient //得到数据 var sr = await _fileManager.GetFileStream(savePath); var excelData = ExcelImportHelper.ToDataTable(savePath, sr); + excelData.Rows.RemoveAt(0); foreach (var item in excelData.Columns) { excelData.Columns[item.ToString()].ColumnName = GetFiledEncode(item.ToString()); @@ -200,6 +204,7 @@ public class EmployeeService : IDynamicApiController, ITransient var addPath = Path.Combine(FileVariable.TemporaryFilePath, excelconfig.FileName); var stream = ExcelExportHelper.ExportMemoryStream(dataList, excelconfig); await _fileManager.UploadFileByType(stream, FileVariable.TemporaryFilePath, excelconfig.FileName); + _cacheManager.Set(excelconfig.FileName, string.Empty); return new { name = excelconfig.FileName, url = "/api/file/Download?encryption=" + DESCEncryption.Encrypt(_userManager.UserId + "|" + excelconfig.FileName + "|" + addPath, "JNPF") }; } @@ -214,6 +219,7 @@ public class EmployeeService : IDynamicApiController, ITransient var _fileName = DateTime.Now.ToString("yyyyMMdd") + "_" + SnowflakeIdHelper.NextId() + Path.GetExtension(file.FileName); var stream = file.OpenReadStream(); await _fileManager.UploadFileByType(stream, _filePath, _fileName); + _cacheManager.Set(_fileName, string.Empty); return new { name = _fileName, url = string.Format("/api/File/Image/{0}/{1}", string.Empty, _fileName) }; } @@ -267,6 +273,7 @@ public class EmployeeService : IDynamicApiController, ITransient { var stream = await _fileManager.GetFileStream(filePath); await _fileManager.UploadFileByType(stream, FileVariable.TemporaryFilePath, "职员信息.xlsx"); + _cacheManager.Set("职员信息.xlsx", string.Empty); } return new { name = "职员信息.xlsx", url = "/api/file/Download?encryption=" + DESCEncryption.Encrypt(_userManager.UserId + "|职员信息.xlsx", "JNPF") }; } diff --git a/extend/Tnb.Extend/OrderService.cs b/extend/Tnb.Extend/OrderService.cs index 25117549..a99b328c 100644 --- a/extend/Tnb.Extend/OrderService.cs +++ b/extend/Tnb.Extend/OrderService.cs @@ -44,14 +44,12 @@ public class OrderService : IDynamicApiController, ITransient ISqlSugarRepository repository, IUserManager userManager, IUsersService usersService, - ICacheManager cacheManager, - IFileManager fileManager) + ICacheManager cacheManager) { _repository = repository; _userManager = userManager; _usersService = usersService; _cacheManager = cacheManager; - _fileManager = fileManager; } #region GET @@ -141,6 +139,7 @@ public class OrderService : IDynamicApiController, ITransient [HttpGet("{id}")] public async Task GetInfo(string id) { + if ("0".Equals(id)) return null; var data = (await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null)).Adapt(); if (data.IsNullOrEmpty()) return null; data.collectionPlanList = (await _repository.AsSugarClient().Queryable().Where(x => x.OrderId == id).ToListAsync()).Adapt>(); diff --git a/extend/Tnb.Extend/ProductClassifyService.cs b/extend/Tnb.Extend/ProductClassifyService.cs index ce8eba2b..6b77a037 100644 --- a/extend/Tnb.Extend/ProductClassifyService.cs +++ b/extend/Tnb.Extend/ProductClassifyService.cs @@ -30,10 +30,10 @@ public class ProductClassifyService : IDynamicApiController, ITransient private readonly IUserManager _userManager; public ProductClassifyService( - ISqlSugarRepository extProductRepository, + ISqlSugarRepository repository, IUserManager userManager) { - _repository = extProductRepository; + _repository = repository; _userManager = userManager; } diff --git a/extend/Tnb.Extend/ProductCustomerService.cs b/extend/Tnb.Extend/ProductCustomerService.cs new file mode 100644 index 00000000..4198f04c --- /dev/null +++ b/extend/Tnb.Extend/ProductCustomerService.cs @@ -0,0 +1,65 @@ +using JNPF.Common.Core.Manager; +using JNPF.Common.Filter; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using JNPF.DynamicApiController; +using JNPF.DependencyInjection; +using JNPF.Common.Extension; +using JNPF.Extend.Entitys.Entity; +using JNPF.Extend.Entitys.Dto.Customer; + +namespace JNPF.Extend; + +/// +/// 客户信息. +/// +[ApiDescriptionSettings(Tag = "Extend", Name = "Customer", Order = 600)] +[Route("api/extend/saleOrder/[controller]")] +public class ProductCustomerService : IDynamicApiController, ITransient +{ + /// + /// 服务基础仓储. + /// + private readonly ISqlSugarRepository _repository; + + /// + /// 用户管理. + /// + private readonly IUserManager _userManager; + + public ProductCustomerService( + ISqlSugarRepository repository, + IUserManager userManager) + { + _repository = repository; + _userManager = userManager; + } + + #region GET + + /// + /// 客户列表. + /// + /// + [HttpGet("")] + public async Task GetList([FromQuery] PageInputBase input) + { + var data = await _repository.AsQueryable() + .Where(it => it.Deletemark == null) + .WhereIF(input.keyword.IsNotEmptyOrNull(), x => x.Name.Contains(input.keyword)) + .Select(x => new ProductCustomerListOutput + { + id = x.Id, + code = x.Code, + name = x.Name, + customerName = x.Customername, + address = x.Address, + contactTel = x.ContactTel + }) + .ToListAsync(); + + return new { list = data }; + } + + #endregion +} \ No newline at end of file diff --git a/extend/Tnb.Extend/ProductGoodsService.cs b/extend/Tnb.Extend/ProductGoodsService.cs new file mode 100644 index 00000000..73de5aaf --- /dev/null +++ b/extend/Tnb.Extend/ProductGoodsService.cs @@ -0,0 +1,87 @@ +using JNPF.Common.Core.Manager; +using JNPF.Common.Extension; +using JNPF.Common.Filter; +using JNPF.DependencyInjection; +using JNPF.DynamicApiController; +using JNPF.Extend.Entitys; +using JNPF.Extend.Entitys.Dto.ProductGoods; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; + +namespace JNPF.Extend; + +/// +/// 选择产品. +/// +[ApiDescriptionSettings(Tag = "Extend", Name = "Goods", Order = 600)] +[Route("api/extend/saleOrder/[controller]")] +public class ProductGoodsService : IDynamicApiController, ITransient +{ + /// + /// 服务基础仓储. + /// + private readonly ISqlSugarRepository _repository; + + /// + /// 用户管理. + /// + private readonly IUserManager _userManager; + + public ProductGoodsService( + ISqlSugarRepository repository, + IUserManager userManager) + { + _repository = repository; + _userManager = userManager; + } + + #region GET + + /// + /// 产品列表. + /// + /// + [HttpGet("")] + public async Task GetList([FromQuery] ProductGoodsListQueryInput input) + { + var data = await _repository.AsQueryable() + .Where(it => it.DeleteMark == null) + .WhereIF(!string.IsNullOrEmpty(input.classifyId), it => it.ClassifyId.Equals(input.classifyId)) + .WhereIF(!string.IsNullOrEmpty(input.code), it => it.Code.Contains(input.code)) + .WhereIF(!string.IsNullOrEmpty(input.fullName), it => it.FullName.Contains(input.fullName)) + .Select(it => new ProductGoodsListOutput + { + id = it.Id, + code = it.Code, + fullName = it.FullName, + qty = it.Qty, + }).MergeTable().OrderByIF(string.IsNullOrEmpty(input.sidx), it => it.id).OrderByIF(!string.IsNullOrEmpty(input.sidx), input.sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize); + return PageResult.SqlSugarPageResult(data); + } + + /// + /// 商品编码. + /// + /// + [HttpGet("Selector")] + public async Task GetSelectorList([FromQuery] PageInputBase input) + { + var data = await _repository.AsQueryable() + .Where(it => it.DeleteMark == null) + .WhereIF(input.keyword.IsNotEmptyOrNull(), x => x.Code.Contains(input.keyword)) + .Select(it => new ProductGoodsListOutput + { + id = it.Id, + classifyId = it.ClassifyId, + code = it.Code, + fullName = it.FullName, + qty = it.Qty, + type = it.Type, + amount = it.Amount, + money = it.Money, + }).ToListAsync(); + return new { list = data }; + } + + #endregion +} \ No newline at end of file diff --git a/extend/Tnb.Extend/ProductService.cs b/extend/Tnb.Extend/ProductService.cs index 505f07e9..41324786 100644 --- a/extend/Tnb.Extend/ProductService.cs +++ b/extend/Tnb.Extend/ProductService.cs @@ -43,11 +43,11 @@ public class ProductService : IDynamicApiController, ITransient /// 初始化一个类型的新实例. /// public ProductService( - ISqlSugarRepository extProductRepository, + ISqlSugarRepository repository, IBillRullService billRullService, IUserManager userManager) { - _repository = extProductRepository; + _repository = repository; _billRullService = billRullService; _userManager = userManager; } @@ -74,7 +74,8 @@ public class ProductService : IDynamicApiController, ITransient Price = it.Price, Amount = it.Amount, Description = it.Description - }).ToList()).Where(a => a.Id.Equals(id) && a.DeleteMark == null) + }).ToList()) + .Where(it => it.Id.Equals(id) && it.DeleteMark == null) .ToListAsync(it => new ProductInfoOutput { id = it.Id, @@ -100,6 +101,52 @@ public class ProductService : IDynamicApiController, ITransient }))?.FirstOrDefault(); } + /// + /// 获取全订单示例. + /// + /// 请求参数. + /// + [HttpGet("Goods")] + public async Task GetAllProductEntryList([FromQuery] ProductListQueryInput input) + { + var data = await _repository.AsQueryable() + .Includes(x => x.productEntryList.Where(it => it.DeleteMark == null).Select(it => new ProductEntryEntity + { + ProductCode = it.ProductCode, + ProductName = it.ProductName, + ProductSpecification = it.ProductSpecification, + Qty = it.Qty, + Type = it.Type, + Money = it.Money, + Price = it.Price, + Amount = it.Amount, + Description = it.Description, + Activity = it.Activity + }).ToList()) + .Where(it => it.DeleteMark == null) + .WhereIF(!string.IsNullOrEmpty(input.code), it => it.Code.Contains(input.code)) + .WhereIF(!string.IsNullOrEmpty(input.customerName), it => it.CustomerName.Contains(input.customerName)) + .OrderByIF(string.IsNullOrEmpty(input.sidx), it => it.Id) + .OrderByIF(!string.IsNullOrEmpty(input.sidx), input.sidx + " " + input.sort) + .ToPagedListAsync(input.currentPage, input.pageSize, it => new ProductListOutput + { + id = it.Id, + code = it.Code, + customerName = it.CustomerName, + business = it.Business, + address = it.Address, + contactTel = it.ContactTel, + salesmanName = it.SalesmanName, + auditState = it.AuditState, + goodsState = it.GoodsState, + closeState = it.CloseState, + closeDate = it.CloseDate, + contactName = it.ContactName, + productEntryList = it.productEntryList.Adapt>() + }); + return PageResult.SqlSugarPageResult(data); + } + /// /// 获取订单示例列表. /// @@ -119,6 +166,7 @@ public class ProductService : IDynamicApiController, ITransient .WhereIF(!string.IsNullOrEmpty(input.contactTel), it => it.ContactTel.Contains(input.contactTel)) .WhereIF(!string.IsNullOrEmpty(input.auditState), it => it.AuditState.Equals(input.auditState)) .WhereIF(!string.IsNullOrEmpty(input.closeState), it => it.CloseState.Equals(input.closeState)) + .OrderByIF(string.IsNullOrEmpty(input.sidx), it => it.Id).OrderByIF(!string.IsNullOrEmpty(input.sidx), input.sidx + " " + input.sort) .Select(it => new ProductListOutput { id = it.Id, @@ -133,7 +181,7 @@ public class ProductService : IDynamicApiController, ITransient closeState = it.CloseState, closeDate = it.CloseDate, contactName = it.ContactName - }).MergeTable().OrderByIF(string.IsNullOrEmpty(input.sidx), it => it.id).OrderByIF(!string.IsNullOrEmpty(input.sidx), input.sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize); + }).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(data); } diff --git a/message/Tnb.Message.Entitys/Dto/Message/MessageListOutput.cs b/message/Tnb.Message.Entitys/Dto/Message/MessageListOutput.cs index 8afa66bd..be8c57d9 100644 --- a/message/Tnb.Message.Entitys/Dto/Message/MessageListOutput.cs +++ b/message/Tnb.Message.Entitys/Dto/Message/MessageListOutput.cs @@ -37,4 +37,5 @@ public class MessageListOutput /// 是否已读(0-未读,1-已读). /// public int? isRead { get; set; } + public int? flowType { get; set; } } \ No newline at end of file diff --git a/message/Tnb.Message.Entitys/Entity/MessageEntity.cs b/message/Tnb.Message.Entitys/Entity/MessageEntity.cs index 1339a6c9..ab55cc10 100644 --- a/message/Tnb.Message.Entitys/Entity/MessageEntity.cs +++ b/message/Tnb.Message.Entitys/Entity/MessageEntity.cs @@ -65,4 +65,6 @@ public class MessageEntity : CLDEntityBase /// [SugarColumn(ColumnName = "F_FILES")] public string Files { get; set; } + [SugarColumn(ColumnName = "F_FLOWTYPE")] + public int? FlowType { get; set; } } \ No newline at end of file diff --git a/message/Tnb.Message.Interfaces/IMessageService.cs b/message/Tnb.Message.Interfaces/IMessageService.cs index abb788ee..d9b18ce4 100644 --- a/message/Tnb.Message.Interfaces/IMessageService.cs +++ b/message/Tnb.Message.Interfaces/IMessageService.cs @@ -15,5 +15,5 @@ public interface IMessageService /// /// /// - Task SentMessage(List toUserIds, string title, string bodyText = null, Dictionary bodyDic = null); + Task SentMessage(List toUserIds, string title, string bodyText = null, Dictionary bodyDic = null, int type = 2, string flowType = "1"); } \ No newline at end of file diff --git a/message/Tnb.Message.Interfaces/ISendMessageService.cs b/message/Tnb.Message.Interfaces/ISendMessageService.cs index 439531b6..ceccaaf7 100644 --- a/message/Tnb.Message.Interfaces/ISendMessageService.cs +++ b/message/Tnb.Message.Interfaces/ISendMessageService.cs @@ -6,5 +6,7 @@ public interface ISendMessageService { Task SendMessage(MessageSendModel messageSendModel, Dictionary bodyDic); - Task SendMessageDefult(string enCode, List toUser, string taskName, Dictionary bodyDic); + Task SendMessageDefult(string enCode, List toUser, string creatorUser, string flowName, Dictionary bodyDic); + Task SendMessageDelegate(string delegateType, string ToUserId, string flowName); + Task SendMessageSystem(string enCode); } \ No newline at end of file diff --git a/message/Tnb.Message/Service/MessageAccountService.cs b/message/Tnb.Message/Service/MessageAccountService.cs index c799ff82..af1cd157 100644 --- a/message/Tnb.Message/Service/MessageAccountService.cs +++ b/message/Tnb.Message/Service/MessageAccountService.cs @@ -95,7 +95,7 @@ public class MessageAccountService : IDynamicApiController, ITransient [HttpPost("")] public async Task Create([FromBody] MessageAccountListOutput input) { - if (await _repository.IsAnyAsync(x => (x.EnCode == input.enCode) && x.DeleteMark == null)) + if (await _repository.IsAnyAsync(x => (x.EnCode == input.enCode) && x.Type == input.type && x.DeleteMark == null)) throw Oops.Oh(ErrorCode.COM1004); var entity = input.Adapt(); var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); @@ -112,7 +112,7 @@ public class MessageAccountService : IDynamicApiController, ITransient [HttpPut("{id}")] public async Task Update(string id, [FromBody] MessageAccountListOutput input) { - if (await _repository.IsAnyAsync(x => x.Id != id && (x.EnCode == input.enCode) && x.DeleteMark == null)) + if (await _repository.IsAnyAsync(x => x.Id != id && (x.EnCode == input.enCode) && x.Type == input.type && x.DeleteMark == null)) throw Oops.Oh(ErrorCode.COM1004); if ((await _repository.AsSugarClient().Queryable().AnyAsync(x => x.AccountConfigId == id && x.DeleteMark == null)) && input.enabledMark == 0) throw Oops.Oh(ErrorCode.D7013); @@ -153,6 +153,8 @@ public class MessageAccountService : IDynamicApiController, ITransient entity.FullName = string.Format("{0}副本{1}", entity.FullName, random); entity.EnCode = string.Format("{0}{1}", entity.EnCode, random); entity.EnabledMark = 0; + entity.LastModifyTime = null; + entity.LastModifyUserId = null; if (entity.Type == "7") { entity.AppKey = string.Format("{0}{1}", entity.AppKey, random); diff --git a/message/Tnb.Message/Service/MessageService.cs b/message/Tnb.Message/Service/MessageService.cs index a9df9431..3e634ac4 100644 --- a/message/Tnb.Message/Service/MessageService.cs +++ b/message/Tnb.Message/Service/MessageService.cs @@ -119,7 +119,8 @@ public class MessageService : IMessageService, IDynamicApiController, ITransient releaseUser = SqlFunc.MergeString(c.RealName, "/", c.Account), title = a.Title, type = a.Type, - isRead = b.IsRead + isRead = b.IsRead, + flowType=a.FlowType }).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } @@ -297,7 +298,7 @@ public class MessageService : IMessageService, IDynamicApiController, ITransient { try { - _repository.AsSugarClient().Insertable(receiveEntityList).ExecuteCommandAsync(); + _repository.AsSugarClient().Insertable(receiveEntityList).ExecuteCommand(); return _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteCommand(); } @@ -317,7 +318,7 @@ public class MessageService : IMessageService, IDynamicApiController, ITransient { try { - _repository.AsSugarClient().Insertable(receiveEntityList).ExecuteCommandAsync(); + _repository.AsSugarClient().Insertable(receiveEntityList).ExecuteCommand(); return _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommand(); } catch (Exception) @@ -405,7 +406,7 @@ public class MessageService : IMessageService, IDynamicApiController, ITransient /// 标题. /// 内容. [NonAction] - public async Task SentMessage(List toUserIds, string title, string bodyText = null, Dictionary bodyDic = null) + public async Task SentMessage(List toUserIds, string title, string bodyText = null, Dictionary bodyDic = null, int type = 2, string flowType = "1") { try { @@ -413,9 +414,10 @@ public class MessageService : IMessageService, IDynamicApiController, ITransient entity.Id = SnowflakeIdHelper.NextId(); entity.Title = title; entity.BodyText = bodyText; - entity.Type = 2; + entity.Type = type; entity.LastModifyTime = DateTime.Now; entity.LastModifyUserId = _userManager.UserId; + entity.FlowType = flowType.ParseToInt(); List receiveEntityList = toUserIds .Select(x => new MessageReceiveEntity() { @@ -432,7 +434,7 @@ public class MessageService : IMessageService, IDynamicApiController, ITransient { var userId = item.Replace("-delegate", string.Empty); // 消息推送 - 指定用户 - await _imHandler.SendMessageToUserAsync(string.Format("{0}-{1}", _userManager.TenantId, item), new { method = "messagePush", messageType = 2, userId = _userManager.UserId, toUserId = toUserIds, title = entity.Title, unreadNoticeCount = 1, id = entity.Id }.ToJsonString()); + await _imHandler.SendMessageToUserAsync(string.Format("{0}-{1}", _userManager.TenantId, userId), new { method = "messagePush", messageType = 2, userId = _userManager.UserId, toUserId = toUserIds, title = entity.Title, unreadNoticeCount = 1, id = entity.Id }.ToJsonString()); } } } diff --git a/message/Tnb.Message/Service/MessageTemplateService.cs b/message/Tnb.Message/Service/MessageTemplateService.cs index 3a3201b1..14df414f 100644 --- a/message/Tnb.Message/Service/MessageTemplateService.cs +++ b/message/Tnb.Message/Service/MessageTemplateService.cs @@ -194,6 +194,8 @@ public class MessageTemplateService : IDynamicApiController, ITransient entity.Id = SnowflakeIdHelper.NextId(); entity.EnabledMark = 0; entity.TemplateType = "0"; + entity.LastModifyTime = null; + entity.LastModifyUserId = null; if (entity.FullName.Length >= 50 || entity.EnCode.Length >= 50) throw Oops.Oh(ErrorCode.COM1009); var templateParamList = await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == id && x.DeleteMark == null).ToListAsync(); diff --git a/message/Tnb.Message/Service/SendMessageService.cs b/message/Tnb.Message/Service/SendMessageService.cs index d0c81d80..e934651a 100644 --- a/message/Tnb.Message/Service/SendMessageService.cs +++ b/message/Tnb.Message/Service/SendMessageService.cs @@ -106,7 +106,7 @@ public class SendMessageService : ISendMessageService, IDynamicApiController, IT { fullName = b.FullName, type = a.MessageType, - }).ToListAsync(); + }).Distinct().ToListAsync(); } return PageResult.SqlSugarPageResult(list); } @@ -115,10 +115,8 @@ public class SendMessageService : ISendMessageService, IDynamicApiController, IT public async Task GetSendList([FromQuery] MessageTemplateQuery input) { var list = await _repository.AsSugarClient().Queryable() - .Where(a => a.DeleteMark == null) + .Where(a => a.DeleteMark == null && a.EnabledMark == 1 && a.TemplateType == "0") .WhereIF(input.messageSource.IsNotEmptyOrNull(), a => a.MessageSource == input.messageSource) - .WhereIF(input.templateType.IsNotEmptyOrNull(), a => a.TemplateType == input.templateType) - .WhereIF(input.enabledMark.IsNotEmptyOrNull(), a => a.EnabledMark == input.enabledMark) .WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) .OrderBy(a => a.SortCode) .OrderBy(a => a.CreatorTime, OrderByType.Desc) @@ -251,6 +249,10 @@ public class SendMessageService : ISendMessageService, IDynamicApiController, IT entity.FullName = string.Format("{0}副本{1}", entity.FullName, random); entity.EnCode = string.Format("{0}{1}", entity.EnCode, random); entity.Id = SnowflakeIdHelper.NextId(); + entity.EnabledMark = 0; + entity.TemplateType = "0"; + entity.LastModifyTime = null; + entity.LastModifyUserId = null; if (entity.FullName.Length >= 50 || entity.EnCode.Length >= 50) throw Oops.Oh(ErrorCode.COM1009); var sendTemplateList = await _repository.AsSugarClient().Queryable().Where(x => x.SendConfigId == id && x.DeleteMark == null).ToListAsync(); @@ -460,11 +462,11 @@ public class SendMessageService : ISendMessageService, IDynamicApiController, IT return errorList.Any() ? string.Join(",", errorList) : string.Empty; } - public async Task SendMessageDefult(string enCode,List toUser, string taskName, Dictionary bodyDic) + public async Task SendMessageDefult(string enCode, List toUser,string creatorUser, string flowName, Dictionary bodyDic) { var msgTemplateEntity= await _repository.AsSugarClient().Queryable().FirstAsync(x => x.EnCode == enCode && x.TemplateType=="1" && x.DeleteMark == null); - msgTemplateEntity.Title= msgTemplateEntity.Title.Replace("@流程发起人@流程名称", taskName); - msgTemplateEntity.Content = msgTemplateEntity.Content.Replace("@流程发起人@流程名称", taskName); + msgTemplateEntity.Title = msgTemplateEntity.Title.Replace("@流程发起人", creatorUser).Replace("@流程名称", flowName); + msgTemplateEntity.Content = msgTemplateEntity.Content.Replace("@流程发起人", creatorUser).Replace("@流程名称", flowName); await _messageService.SentMessage(toUser, msgTemplateEntity.Title, msgTemplateEntity.Content, bodyDic); #region 消息监控 foreach (var item in toUser) @@ -482,6 +484,21 @@ public class SendMessageService : ISendMessageService, IDynamicApiController, IT } #endregion } + public async Task SendMessageDelegate(string delegateType, string ToUserId, string flowName) + { + var title = string.Format("{0}已{1}您的{2}流程!", _userManager.User.RealName, delegateType, flowName); + var parameter = new { type = "1" }; + var bodyDic = new Dictionary(); + bodyDic.Add(ToUserId, parameter); + await _messageService.SentMessage(new List() { ToUserId }, title, null, bodyDic, 2, "2"); + } + public async Task SendMessageSystem(string enCode) + { + var msgTemplateEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.EnCode == enCode && x.TemplateType == "1" && x.DeleteMark == null); + var bodyDic = new Dictionary(); + bodyDic.Add(_userManager.UserId, msgTemplateEntity.Content); + await _messageService.SentMessage(new List() { _userManager.UserId }, msgTemplateEntity.Title, msgTemplateEntity.Content, bodyDic, 3); + } #endregion #region PrivateMethod @@ -680,9 +697,13 @@ public class SendMessageService : ISendMessageService, IDynamicApiController, IT if (text.IsNotEmptyOrNull()) { // 默认站内信 - if (paramDic.ContainsKey("@taskFullName")) + if (paramDic.ContainsKey("@flowFullName")) { - text = text.Replace("@流程发起人@流程名称", paramDic["@taskFullName"]); + text = text.Replace("@流程名称", paramDic["@flowFullName"]); + } + if (paramDic.ContainsKey("@launchUserName")) + { + text = text.Replace("@流程发起人", paramDic["@launchUserName"]); } foreach (var item in paramDic.Keys) { diff --git a/message/Tnb.Message/Service/ShortLinkService.cs b/message/Tnb.Message/Service/ShortLinkService.cs index 4b364574..5e5cba1f 100644 --- a/message/Tnb.Message/Service/ShortLinkService.cs +++ b/message/Tnb.Message/Service/ShortLinkService.cs @@ -8,6 +8,7 @@ using JNPF.Common.Security; using JNPF.DataEncryption; using JNPF.DependencyInjection; using JNPF.DynamicApiController; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using JNPF.FriendlyException; using JNPF.Logging.Attributes; using JNPF.Message.Entitys.Entity; @@ -92,9 +93,15 @@ public class ShortLinkService : IShortLinkService, IDynamicApiController, ITrans options = JNPFTenantExtensions.GetLinkToCustom(tenantId, result.data.linkList); } } - + if (!"default".Equals(tenantId) && _tenant.MultiTenancyType.Equals("COLUMN")) + { + _sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == tenantId); + } + else + { _sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options)); _sqlSugarClient.ChangeDatabase(tenantId); + } } var entity = await _sqlSugarClient.Queryable().SingleAsync(x => x.ShortLink == shortLink && x.DeleteMark == null); diff --git a/system/Tnb.OAuth/Dto/LoginInput.cs b/system/Tnb.OAuth/Dto/LoginInput.cs index c89be0eb..45c3dcea 100644 --- a/system/Tnb.OAuth/Dto/LoginInput.cs +++ b/system/Tnb.OAuth/Dto/LoginInput.cs @@ -53,4 +53,9 @@ public class LoginInput /// 未绑定 成功登录后 自动绑定 缓存 Key. /// public string jnpf_ticket { get; set; } + + /// + /// 单点登录票据. + /// + public string online_ticket { get; set; } } \ No newline at end of file diff --git a/system/Tnb.OAuth/OAuthService.cs b/system/Tnb.OAuth/OAuthService.cs index 10de81ef..f494dee3 100644 --- a/system/Tnb.OAuth/OAuthService.cs +++ b/system/Tnb.OAuth/OAuthService.cs @@ -35,6 +35,12 @@ using JNPF.Systems.Entitys.Model.Permission.SocialsUser; using JNPF.Systems.Interfaces.Permission; using JNPF.Extras.CollectiveOAuth.Models; using JNPF.Common.Models; +using JNPF.Common.Options; +using Microsoft.CodeAnalysis; +using JNPF.Common.Core.Handlers; +using JNPF.Message.Interfaces.Message; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; +using Aop.Api.Domain; namespace JNPF.OAuth; @@ -45,6 +51,11 @@ namespace JNPF.OAuth; [Route("api/[controller]")] public class OAuthService : IDynamicApiController, ITransient { + /// + /// 配置文档. + /// + private readonly OauthOptions _oauthOptions = App.GetConfig("OAuth", true); + /// /// 用户仓储. /// @@ -125,6 +136,10 @@ public class OAuthService : IDynamicApiController, ITransient /// private SqlSugarScope _sqlSugarClient; + private readonly ISendMessageService _sendMessageService; + + private readonly IMHandler _imHandler; + /// /// 初始化一个类型的新实例. /// @@ -138,13 +153,15 @@ public class OAuthService : IDynamicApiController, ITransient IModuleFormService formService, ISysConfigService sysConfigService, ISocialsUserService socialsUserService, + ISendMessageService sendMessageService, IOptions connectionOptions, IOptions tenantOptions, ISqlSugarClient sqlSugarClient, IHttpContextAccessor httpContextAccessor, ICacheManager cacheManager, IUserManager userManager, - IEventPublisher eventPublisher) + IEventPublisher eventPublisher, + IMHandler imHandler) { _captchaHandler = captchaHandler; _userRepository = userRepository; @@ -155,6 +172,7 @@ public class OAuthService : IDynamicApiController, ITransient _formService = formService; _sysConfigService = sysConfigService; _socialsUserService = socialsUserService; + _sendMessageService = sendMessageService; _connectionStrings = connectionOptions.Value; _tenant = tenantOptions.Value; _sqlSugarClient = (SqlSugarScope)sqlSugarClient; @@ -162,6 +180,7 @@ public class OAuthService : IDynamicApiController, ITransient _cacheManager = cacheManager; _userManager = userManager; _eventPublisher = eventPublisher; + _imHandler = imHandler; } #region Get @@ -290,12 +309,15 @@ public class OAuthService : IDynamicApiController, ITransient if ((loginOutput.userInfo.systemIds.Any() && !loginOutput.userInfo.systemIds.Any(x => x.id.Equals(loginOutput.userInfo.systemId))) || loginOutput.userInfo.systemId.IsNullOrEmpty()) { - var defaultItem = loginOutput.userInfo.systemIds.Find(x => x.enCode.Equals("mainSystem")); - if (defaultItem == null) defaultItem = loginOutput.userInfo.systemIds.FirstOrDefault(); - loginOutput.userInfo.systemId = defaultItem.id; - defaultItem.currentSystem = true; - await _userRepository.AsUpdateable().SetColumns(x => x.SystemId == loginOutput.userInfo.systemId).Where(x => x.Id.Equals(userId)).ExecuteCommandAsync(); - loginOutput.menuList = await _moduleService.GetUserTreeModuleList(type); + if (loginOutput.userInfo.systemIds.Any()) + { + var defaultItem = loginOutput.userInfo.systemIds.Find(x => x.enCode.Equals("mainSystem")); + if (defaultItem == null) defaultItem = loginOutput.userInfo.systemIds.FirstOrDefault(); + loginOutput.userInfo.systemId = defaultItem.id; + defaultItem.currentSystem = true; + await _userRepository.AsUpdateable().SetColumns(x => x.SystemId == loginOutput.userInfo.systemId).Where(x => x.Id.Equals(userId)).ExecuteCommandAsync(); + loginOutput.menuList = await _moduleService.GetUserTreeModuleList(type); + } } if (!loginOutput.userInfo.systemIds.Any()) loginOutput.menuList.Clear(); @@ -357,24 +379,26 @@ public class OAuthService : IDynamicApiController, ITransient /// /// [HttpGet("Logout")] - public async Task Logout() + public async Task Logout([FromQuery] string ticket) { + var tenantId = _userManager.TenantId ?? "default"; + var userId = _userManager.UserId ?? "admim"; var httpContext = _httpContextAccessor.HttpContext; httpContext.SignoutToSwagger(); - // 清除IM中的webSocket, modified by PhilPan 改为在IMHandle中处理 - //var list = await GetOnlineUserList(); - //if (list != null) - //{ - // var onlineUser = list.Find(it => it.tenantId == _userManager.TenantId && it.userId == _userManager.UserId); - // if (onlineUser != null) - // { - // list.RemoveAll((x) => x.connectionId == onlineUser.connectionId); - // await SetOnlineUserList(list); - // } - //} + // 清除IM中的webSocket + var list = await GetOnlineUserList(tenantId); + if (list != null) + { + var onlineUser = list.Find(it => it.tenantId == tenantId && it.userId == userId); + if (onlineUser != null) + { + list.RemoveAll((x) => x.connectionId == onlineUser.connectionId); + await SetOnlineUserList(list, tenantId); + } + } - await DelUserInfo(); + await DelUserInfo(tenantId, userId); } #endregion @@ -431,9 +455,15 @@ public class OAuthService : IDynamicApiController, ITransient options = JNPFTenantExtensions.GetLinkToCustom(tenantId, result.data.linkList); } } - - _sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options)); - _sqlSugarClient.ChangeDatabase(tenantId); + if (!"default".Equals(tenantId) && _tenant.MultiTenancyType.Equals("COLUMN")) + { + _sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == tenantId); + } + else + { + _sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options)); + _sqlSugarClient.ChangeDatabase(tenantId); + } } else { @@ -563,9 +593,13 @@ public class OAuthService : IDynamicApiController, ITransient { ClaimConst.CLAINMADMINISTRATOR, userAnyPwd.IsAdministrator }, { ClaimConst.TENANTID, options.ConfigId }, { ClaimConst.CONNECTIONCONFIG, options}, - { ClaimConst.SINGLELOGIN, (int)sysConfig.singleLogin } + { ClaimConst.SINGLELOGIN, (int)sysConfig.singleLogin }, + { ClaimConst.OnlineTicket, input.online_ticket } }, tokenTimeout); + // 单点登录标识缓存 + if (_oauthOptions.Enabled) _cacheManager.Set("OnlineTicket_" + input.online_ticket, options.ConfigId); + // 设置Swagger自动登录 _httpContextAccessor.HttpContext.SigninToSwagger(accessToken); @@ -635,8 +669,7 @@ public class OAuthService : IDynamicApiController, ITransient } } - return new - { + return new { theme = user.Theme == null ? "classic" : user.Theme, token = string.Format("Bearer {0}", accessToken) }; @@ -676,6 +709,63 @@ public class OAuthService : IDynamicApiController, ITransient await _userRepository.AsUpdateable(userInfo).ExecuteCommandAsync(); return new { code = 200, msg = "注销成功" }; } + + /// + /// 单点登录退出. + /// + /// + [HttpPost("Logout/auth2")] + [AllowAnonymous] + public async Task OnlineLogout() + { + var ticket = _httpContextAccessor.HttpContext.Request.Form["ticket"]; + var tenantId = await _cacheManager.GetAsync("OnlineTicket_" + ticket); + if (ticket.IsNotEmptyOrNull()) + { + await _cacheManager.DelAsync("OnlineTicket_" + ticket); + var userId = _userManager.GetAdminUserId(); + var userOnlineList = new List(); + userOnlineList = await GetOnlineUserList(tenantId); + var userOnline = userOnlineList.Find(x => x.onlineTicket.Equals(ticket)); + if (userOnline != null) + { + userId = userOnline.userId; + await _imHandler.SendMessageAsync(userOnline.connectionId, new { method = "logout", msg = "此账号已在其他地方登陆" }.ToJsonString()); + } + + // 清除IM中的webSocket + if (userOnlineList != null) + { + var onlineUser = userOnlineList.Find(it => it.tenantId == tenantId && it.userId == userId); + if (onlineUser != null) + { + userOnlineList.RemoveAll((x) => x.connectionId == onlineUser.connectionId); + await SetOnlineUserList(userOnlineList, tenantId); + } + } + + await DelUserInfo(tenantId, userId); + } + } + + /// + /// 密码过期提醒. + /// + /// + [HttpPost("updatePasswordMessage")] + public async Task PwdMessage() + { + var sysConfigInfo = await _sysConfigService.GetInfo(); + // 密码修改时间. + var changePasswordDate = _userManager.User.ChangePasswordDate.IsNullOrEmpty() ? _userManager.User.CreatorTime : _userManager.User.ChangePasswordDate; + // 提醒时间 + var remindDate = changePasswordDate.ParseToDateTime().AddDays(sysConfigInfo.updateCycle - sysConfigInfo.updateInAdvance); + if (sysConfigInfo.passwordIsUpdatedRegularly == 1 && remindDate < DateTime.Now) + { + await _sendMessageService.SendMessageSystem("XTXXTX001"); + } + } + #endregion #region PrivateMethod @@ -740,9 +830,9 @@ public class OAuthService : IDynamicApiController, ITransient /// 获取在线用户列表. /// /// - private async Task> GetOnlineUserList() + private async Task> GetOnlineUserList(string tenantId) { - string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, _userManager.ConnectionConfig.ConfigId); + string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, tenantId); return await _cacheManager.GetAsync>(cacheKey); } @@ -751,18 +841,18 @@ public class OAuthService : IDynamicApiController, ITransient /// /// 在线用户列表. /// - private async Task SetOnlineUserList(List onlineList) + private async Task SetOnlineUserList(List onlineList, string tenantId) { - string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, _userManager.ConnectionConfig.ConfigId); + string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, tenantId); return await _cacheManager.SetAsync(cacheKey, onlineList); } /// /// 删除用户登录信息缓存. /// - private async Task DelUserInfo() + private async Task DelUserInfo(string tenantId, string userId) { - string cacheKey = string.Format("{0}{1}_{2}", CommonConst.CACHEKEYUSER, _userManager.ConnectionConfig.ConfigId, _userManager.UserId); + string cacheKey = string.Format("{0}:{1}:{2}", tenantId, CommonConst.CACHEKEYUSER, userId); return await _cacheManager.DelAsync(cacheKey); } @@ -1109,15 +1199,25 @@ public class OAuthService : IDynamicApiController, ITransient { var loginConfigModel = new SocialsLoginConfigModel(); - // 追加第三方登录配置 - var loginList = _socialsUserService.GetLoginList(CommonConst.PARAMS_JNPF_TICKET.ToUpper()); - if (loginList == null) return loginConfigModel; - if (loginList.Any()) + if (_oauthOptions.Enabled) { - loginConfigModel.socialsList = loginList.ToObject>(); - loginConfigModel.redirect = false; + var url = _oauthOptions.LoginPath + "/" + _oauthOptions.DefaultSSO; + loginConfigModel.redirect = true; + loginConfigModel.url = url; loginConfigModel.ticketParams = CommonConst.PARAMS_JNPF_TICKET; } + else + { + // 追加第三方登录配置 + var loginList = _socialsUserService.GetLoginList(CommonConst.PARAMS_JNPF_TICKET.ToUpper()); + if (loginList == null) return loginConfigModel; + if (loginList.Any()) + { + loginConfigModel.socialsList = loginList.ToObject>(); + loginConfigModel.redirect = false; + loginConfigModel.ticketParams = CommonConst.PARAMS_JNPF_TICKET; + } + } return loginConfigModel; } @@ -1132,10 +1232,10 @@ public class OAuthService : IDynamicApiController, ITransient public dynamic GetTicket() { SocialsLoginTicketModel ticketModel = new SocialsLoginTicketModel(); - var curDate = DateTime.Now.AddMinutes(5); // 默认过期5分钟. + var curDate = DateTime.Now.AddMinutes(_oauthOptions.TicketTimeout); // 默认过期5分钟. ticketModel.ticketTimeout = curDate.ParseToUnixTime(); - var key = "SocialsLogin_" + Yitter.IdGenerator.YitIdHelper.NextId().ToString(); - _cacheManager.Set(key, ticketModel.ToJsonString(), TimeSpan.FromMinutes(5)); + var key = "SocialsLogin_" + SnowflakeIdHelper.NextId(); + _cacheManager.Set(key, ticketModel.ToJsonString(), TimeSpan.FromMinutes(_oauthOptions.TicketTimeout)); return key; } @@ -1158,4 +1258,264 @@ public class OAuthService : IDynamicApiController, ITransient } #endregion + + #region 单点登录. + + /// + /// 单点登录接口. + /// + /// + /// + [HttpGet("Login/{type}")] + [AllowAnonymous] + [IgnoreLog] + [NonUnify] + public async Task LoginByType(string type, [FromQuery] Dictionary input) + { + #region Cas + //if (type.ToLower().Equals("cas")) + //{ + // var ticket = input.ContainsKey(CommonConst.PARAMS_JNPF_TICKET) ? input[CommonConst.PARAMS_JNPF_TICKET].ToString() : string.Empty; + // var ticketModel = _cacheManager.Get(ticket); + // if (ticketModel == null) return "登录票据已失效"; + + // var casTicket = input.ContainsKey(CommonConst.CAS_Ticket) ? input[CommonConst.CAS_Ticket].ToString() : string.Empty; + // if (casTicket.IsNotEmptyOrNull()) + // { + + // } + // else + // { + // var loginUrl = _oauthOptions.SSO.Cas.ServerLoginUrl; + // //http://sso.maxkey.top:8527/sign/authz/cas/?service=http://sa-oauth-client.demo.maxkey.top:8002 + + // loginUrl = Extras.CollectiveOAuth.Utils.UrlBuilder.fromBaseUrl(loginUrl) + // .queryParam("service", _oauthOptions.LoginPath + "/cas") + // .queryParam(CommonConst.PARAMS_JNPF_TICKET, ticket) + // .build(); + // _httpContextAccessor.HttpContext.Response.Redirect(loginUrl); + // } + //} + #endregion + + if (type.ToLower().Equals("auth2")) + { + var ticket = string.Empty; + if (input.ContainsKey(CommonConst.PARAMS_JNPF_TICKET) && input[CommonConst.PARAMS_JNPF_TICKET].IsNotEmptyOrNull()) + { + ticket = input[CommonConst.PARAMS_JNPF_TICKET]; + var ticketModel = _cacheManager.Get(ticket); + if (ticketModel == null) return "登录票据已失效"; + } + + var code = input.ContainsKey(CommonConst.Code) ? input[CommonConst.Code] : string.Empty; + + // 接受CODE 进行登录 + if (code.IsNotEmptyOrNull()) + { + try + { + await loginByCode(code, ticket); + } + catch (Exception e) + { + // 更新登录结果 + return e.Message; + } + } + else + { + redirectLogin(ticket); + } + } + + return null; + } + + /// + /// 跳转单点登录页面. + /// + protected void redirectLogin(string ticket) + { + var loginUrl = _oauthOptions.SSO.Auth2.AuthorizeUrl; + var tmpAuthCallbackUrl = _oauthOptions.LoginPath + "/auth2"; + //http://sso.maxkey.top:8527/sign/authz/oauth/v20/authorize?response_type=code&client_id=745057899234983936&redirect_uri=http://sa-oauth-client.demo.maxkey.top:8002/&scope=all + + if (ticket.IsNotEmptyOrNull()) + { + tmpAuthCallbackUrl = Extras.CollectiveOAuth.Utils.UrlBuilder.fromBaseUrl(tmpAuthCallbackUrl) + .queryParam(CommonConst.PARAMS_JNPF_TICKET, ticket) + .build(); + } + + loginUrl = Extras.CollectiveOAuth.Utils.UrlBuilder.fromBaseUrl(loginUrl) + .queryParam("response_type", CommonConst.Code) + .queryParam("client_id", _oauthOptions.SSO.Auth2.ClientId) + .queryParam("scope", "read") + .queryParam("redirect_uri", tmpAuthCallbackUrl) + .build(); + + _httpContextAccessor.HttpContext.Response.Redirect(loginUrl); + } + + /// + /// Oauth2登录. + /// + /// + /// + protected async Task loginByCode(string code, string ticket) + { + var token = await getAccessToken(code); + var remoteUserInfo = await getRemoteInfo(token); + //var userId = remoteUserInfo.getOrDefault("accounts.username", remoteUserInfo["username"]).ToString(); + var userId = remoteUserInfo.ContainsKey("accounts.username") ? remoteUserInfo["accounts.username"].ToString() : remoteUserInfo["username"].ToString(); + var userAccount = string.Empty; + if (_tenant.MultiTenancy) + { + var instId = remoteUserInfo["institution"].ToString(); + userAccount = instId + "@" + userId; + } + else + { + userAccount = userId; + } + + // 登录账号 + var loginInput = await GetUserInfoByUserAccount(userAccount); + loginInput.online_ticket = remoteUserInfo["online_ticket"].ToString(); + var loginRes = await Login(loginInput); + + var jnpfTicket = _cacheManager.Get(ticket); + if (jnpfTicket.IsNotEmptyOrNull()) + { + // 修改 缓存 状态 + jnpfTicket.status = (int)SocialsLoginTicketStatus.Success; + jnpfTicket.value = loginRes.token; + _cacheManager.Set(ticket, jnpfTicket.ToJsonString(), TimeSpan.FromMinutes(_oauthOptions.TicketTimeout)); + } + else + { + var url = string.Format("{0}?token={1}&theme={2}", _oauthOptions.SucessFrontUrl, loginRes.token, loginRes.theme); + _httpContextAccessor.HttpContext.Response.Redirect(url); + } + } + + /// + /// 获取OAUTH2 AccessToken. + /// + /// + /// + private async Task getAccessToken(string code) + { + var reqUrl = _oauthOptions.SSO.Auth2.AccessTokenUrl + .AddUrlQuery(string.Format("grant_type={0}", "authorization_code")) + .AddUrlQuery(string.Format("client_id={0}", _oauthOptions.SSO.Auth2.ClientId)) + .AddUrlQuery(string.Format("client_secret={0}", _oauthOptions.SSO.Auth2.ClientSecret)) + .AddUrlQuery(string.Format("redirect_uri={0}", _oauthOptions.LoginPath + "/auth2")) + .AddUrlQuery(string.Format("code={0}", code)); + + var response = await reqUrl.GetAsStringAsync(); + Dictionary result = null; + try + { + result = response.ToObject>(); + } + catch (Exception e) + { + // log.error("解析Auth2 access_token失败", e); + } + + if (result == null || !result.ContainsKey("access_token")) + { + throw new Exception("Auth2: 获取access_token失败"); + } + + var access_token = result["access_token"].ToString(); + + // log.debug("Auth2 Token: {}", access_token); + return access_token; + } + + /// + /// 获取用户信息. + /// + /// + /// + private async Task> getRemoteInfo(string access_token) + { + var reqUrl = _oauthOptions.SSO.Auth2.UserInfoUrl + .AddUrlQuery(string.Format("access_token={0}", access_token)); + var response = await reqUrl.GetAsStringAsync(); + + Dictionary result = null; + try + { + // log.debug("Auth2 User: {}", response); + result = response.ToObject>(); + } + catch (Exception e) + { + // log.error("解析Auth2 用户信息失败", e); + } + + if (result == null || !result.ContainsKey("username")) + { + // log.error(response); + throw new Exception("Auth2: 获取远程用户信息失败"); + } + + return result; + } + + private async Task GetUserInfoByUserAccount(string account) + { + ConnectionConfigOptions options = JNPFTenantExtensions.GetLinkToOrdinary(_connectionStrings.ConfigId, _connectionStrings.DBName); + UserAgent userAgent = new UserAgent(App.HttpContext); + if (_tenant.MultiTenancy) + { + // 分割账号 + var tenantAccount = account.Split('@'); + var tenantId = tenantAccount.FirstOrDefault(); + if (tenantAccount.Length == 1) + account = "admin"; + else + account = tenantAccount[1]; + + var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, tenantId); + var response = await interFace.GetAsStringAsync(); + var result = response.ToObject>(); + if (result.code != 200) + { + throw Oops.Oh(result.msg); + } + else if (result.data.dotnet == null && result.data.linkList == null) + { + throw Oops.Oh(ErrorCode.D1025); + } + else + { + if (result.data.linkList == null || result.data.linkList?.Count == 0) + { + options = JNPFTenantExtensions.GetLinkToOrdinary(tenantId, result.data.dotnet); + } + else if (result.data.dotnet == null) + { + options = JNPFTenantExtensions.GetLinkToCustom(tenantId, result.data.linkList); + } + } + + _sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options)); + _sqlSugarClient.ChangeDatabase(tenantId); + } + + var userEntity = _sqlSugarClient.Queryable().Single(u => u.Account == account && u.DeleteMark == null); + return new LoginInput() + { + account = userEntity.Account, + password = userEntity.Password, + isSocialsLoginCallBack = true + }; + } + + #endregion } \ No newline at end of file diff --git a/system/Tnb.OAuth/Tnb.OAuth.csproj b/system/Tnb.OAuth/Tnb.OAuth.csproj index 1640baae..af2ae6c7 100644 --- a/system/Tnb.OAuth/Tnb.OAuth.csproj +++ b/system/Tnb.OAuth/Tnb.OAuth.csproj @@ -11,6 +11,7 @@ + diff --git a/system/Tnb.Systems.Entitys/Dto/Permission/User/GetDefaultCurrentValueInput.cs b/system/Tnb.Systems.Entitys/Dto/Permission/User/GetDefaultCurrentValueInput.cs new file mode 100644 index 00000000..85c0a9d6 --- /dev/null +++ b/system/Tnb.Systems.Entitys/Dto/Permission/User/GetDefaultCurrentValueInput.cs @@ -0,0 +1,41 @@ +using System.Text.Json.Serialization; +using JNPF.DependencyInjection; + +namespace JNPF.Systems.Entitys.Dto.User; + +/// +/// 当前用户默认值信息输出. +/// +[SuppressSniffer] +public class GetDefaultCurrentValueInput +{ + /// + /// 部门Ids. + /// + public List DepartIds { get; set; } + + /// + /// 用户Ids. + /// + public List UserIds { get; set; } + + /// + /// 角色Ids. + /// + public List RoleIds { get; set; } + + /// + /// 岗位Ids. + /// + public List PositionIds { get; set; } + + /// + /// 分组Ids. + /// + public List GroupIds { get; set; } + + /// + /// . + /// + public string Keyword { get; set; } +} \ No newline at end of file diff --git a/system/Tnb.Systems.Entitys/Dto/System/CommonWords/CommonWordsInput.cs b/system/Tnb.Systems.Entitys/Dto/System/CommonWords/CommonWordsInput.cs new file mode 100644 index 00000000..65e810fe --- /dev/null +++ b/system/Tnb.Systems.Entitys/Dto/System/CommonWords/CommonWordsInput.cs @@ -0,0 +1,40 @@ +namespace JNPF.Systems.Entitys.Dto.System.CommonWords +{ + public class CommonWordsInput + { + /// + /// 自然主键. + /// + public string id { get; set; } + + /// + /// 应用id. + /// + public List systemIds { get; set; } = new List(); + + /// + /// 应用名称. + /// + public List systemNames { get; set; } = new List(); + + /// + /// 常用语. + /// + public string commonWordsText { get; set; } + + /// + /// 常用语类型(0:系统,1:个人). + /// + public int commonWordsType { get; set; } + + /// + /// 排序. + /// + public long sortCode { get; set; } + + /// + /// 有效标志. + /// + public int? enabledMark { get; set; } + } +} diff --git a/system/Tnb.Systems.Entitys/Dto/System/CommonWords/CommonWordsOutput.cs b/system/Tnb.Systems.Entitys/Dto/System/CommonWords/CommonWordsOutput.cs new file mode 100644 index 00000000..68b3b857 --- /dev/null +++ b/system/Tnb.Systems.Entitys/Dto/System/CommonWords/CommonWordsOutput.cs @@ -0,0 +1,39 @@ +namespace JNPF.Systems.Entitys.Dto.System.CommonWords; + +public class CommonWordsOutput +{ + /// + /// 自然主键. + /// + public string id { get; set; } + + /// + /// 应用id. + /// + public string systemId { get; set; } + + /// + /// 应用名称. + /// + public string systemNames { get; set; } + + /// + /// 常用语. + /// + public string commonWordsText { get; set; } + + /// + /// 常用语类型(0:系统,1:个人). + /// + public int commonWordsType { get; set; } + + /// + /// 排序. + /// + public long sortCode { get; set; } + + /// + /// 有效标志. + /// + public int? enabledMark { get; set; } +} diff --git a/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevCrInput.cs b/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevCrInput.cs index 5a4dfc3c..ce7d9725 100644 --- a/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevCrInput.cs +++ b/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevCrInput.cs @@ -62,4 +62,9 @@ public class PrintDevCrInput /// 打印模板. /// public string printTemplate { get; set; } + + /// + /// 纸张参数. + /// + public string pageParam { get; set; } } \ No newline at end of file diff --git a/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevInfoOutput.cs b/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevInfoOutput.cs index 4aa37d1a..253381df 100644 --- a/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevInfoOutput.cs +++ b/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevInfoOutput.cs @@ -67,4 +67,9 @@ public class PrintDevInfoOutput /// 打印模板. /// public string printTemplate { get; set; } + + /// + /// 纸张参数. + /// + public string pageParam { get; set; } } \ No newline at end of file diff --git a/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevSqlDataQuery.cs b/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevSqlDataQuery.cs index e963a7c7..dfa39350 100644 --- a/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevSqlDataQuery.cs +++ b/system/Tnb.Systems.Entitys/Dto/System/PrintDev/PrintDevSqlDataQuery.cs @@ -17,4 +17,9 @@ public class PrintDevSqlDataQuery /// 参数. /// public string formId { get; set; } + + /// + /// 模板id. + /// + public List ids { get; set; } } \ No newline at end of file diff --git a/system/Tnb.Systems.Entitys/Dto/System/PrintLog/PrintLogOutuut.cs b/system/Tnb.Systems.Entitys/Dto/System/PrintLog/PrintLogOutuut.cs new file mode 100644 index 00000000..dc0bb802 --- /dev/null +++ b/system/Tnb.Systems.Entitys/Dto/System/PrintLog/PrintLogOutuut.cs @@ -0,0 +1,34 @@ +namespace JNPF.Systems.Entitys.Dto.System.PrintLog; + +public class PrintLogOutuut +{ + /// + /// id. + /// + public string id { get; set; } + + /// + /// 打印人. + /// + public string printMan { get; set; } + + /// + /// 打印时间. + /// + public DateTime? printTime { get; set; } + + /// + /// 打印条数. + /// + public int? printNum { get; set; } + + /// + /// 打印功能名称. + /// + public string printTitle { get; set; } + + /// + /// 打印模板id. + /// + public string printId { get; set; } +} diff --git a/system/Tnb.Systems.Entitys/Dto/System/PrintLog/PrintLogQuery.cs b/system/Tnb.Systems.Entitys/Dto/System/PrintLog/PrintLogQuery.cs new file mode 100644 index 00000000..7c6fd5ac --- /dev/null +++ b/system/Tnb.Systems.Entitys/Dto/System/PrintLog/PrintLogQuery.cs @@ -0,0 +1,16 @@ +using JNPF.Common.Filter; + +namespace JNPF.Systems.Entitys.Dto.System.PrintLog; + +public class PrintLogQuery : PageInputBase +{ + /// + /// 开始时间. + /// + public long? startTime { get; set; } + + /// + /// 结束时间. + /// + public long? endTime { get; set; } +} diff --git a/system/Tnb.Systems.Entitys/Dto/System/SysConfig/SysConfigOutput.cs b/system/Tnb.Systems.Entitys/Dto/System/SysConfig/SysConfigOutput.cs index 277f0394..f9499516 100644 --- a/system/Tnb.Systems.Entitys/Dto/System/SysConfig/SysConfigOutput.cs +++ b/system/Tnb.Systems.Entitys/Dto/System/SysConfig/SysConfigOutput.cs @@ -346,4 +346,71 @@ public class SysConfigOutput /// 链接点击几次后失效. /// public int unClickNum { get; set; } + + #region 密码策略 + /// + /// 密码定期更新开关. + /// + public int passwordIsUpdatedRegularly { get; set; } + + /// + /// 更新周期. + /// + public int updateCycle { get; set; } + + /// + /// 提前N天提醒更新. + /// + public int updateInAdvance { get; set; } + + /// + /// 密码强度限制开关. + /// + public int passwordStrengthLimit { get; set; } + + /// + /// 最小长度开关. + /// + public int passwordLengthMin { get; set; } + + /// + /// 密码最小长度限制. + /// + public int passwordLengthMinNumber { get; set; } + + /// + /// 是否包含数字. + /// + public int containsNumbers { get; set; } + + /// + /// 是否包含小写字母. + /// + public int includeLowercaseLetters { get; set; } + + /// + /// 是否包含大写字母. + /// + public int includeUppercaseLetters { get; set; } + + /// + /// 是否包含字符. + /// + public int containsCharacters { get; set; } + + /// + /// 是否禁用旧密码开关. + /// + public int disableOldPassword { get; set; } + + /// + /// 禁用旧密码个数. + /// + public int disableTheNumberOfOldPasswords { get; set; } + + /// + /// 初始密码强制修改开关. + /// + public int mandatoryModificationOfInitialPassword { get; set; } + #endregion } \ No newline at end of file diff --git a/system/Tnb.Systems.Entitys/Dto/System/System/SystemQuery.cs b/system/Tnb.Systems.Entitys/Dto/System/System/SystemQuery.cs new file mode 100644 index 00000000..c5764e12 --- /dev/null +++ b/system/Tnb.Systems.Entitys/Dto/System/System/SystemQuery.cs @@ -0,0 +1,11 @@ +using JNPF.Common.Filter; + +namespace JNPF.Systems.Entitys.Dto.System.System; + +public class SystemQuery : KeywordInput +{ + /// + /// 开启 1 0 禁用. + /// + public string enableMark { get; set; } +} diff --git a/system/Tnb.Systems.Entitys/Entity/Permission/UserOldPasswordEntity.cs b/system/Tnb.Systems.Entitys/Entity/Permission/UserOldPasswordEntity.cs new file mode 100644 index 00000000..bf474a97 --- /dev/null +++ b/system/Tnb.Systems.Entitys/Entity/Permission/UserOldPasswordEntity.cs @@ -0,0 +1,47 @@ +using JNPF.Common.Contracts; +using SqlSugar; + +namespace JNPF.Systems.Entitys.Entity.Permission; + +/// +/// 用户旧密码记录表. +/// +[SugarTable("BASE_USER_OLD_PASSWORD")] +public class UserOldPasswordEntity : EntityBase +{ + /// + /// 用户ID. + /// + [SugarColumn(ColumnName = "F_USERID")] + public string UserId { get; set; } + + /// + /// 用户ID. + /// + [SugarColumn(ColumnName = "F_Account")] + public string Account { get; set; } + + /// + /// 账户. + /// + [SugarColumn(ColumnName = "F_OldPassword")] + public string OldPassword { get; set; } + + /// + /// 秘钥. + /// + [SugarColumn(ColumnName = "F_Secretkey")] + public string Secretkey { get; set; } + + /// + /// 创建时间. + /// + [SugarColumn(ColumnName = "F_CreatorTime")] + public DateTime CreatorTime { get; set; } + + /// + /// 租户ID. + /// + [SugarColumn(ColumnName = "F_TenantId")] + public string TenantId { get; set; } +} diff --git a/system/Tnb.Systems.Entitys/Entity/System/CommonWordsEntity.cs b/system/Tnb.Systems.Entitys/Entity/System/CommonWordsEntity.cs new file mode 100644 index 00000000..c5b9bbf1 --- /dev/null +++ b/system/Tnb.Systems.Entitys/Entity/System/CommonWordsEntity.cs @@ -0,0 +1,45 @@ +using JNPF.Common.Contracts; +using SqlSugar; + +namespace JNPF.Systems.Entitys.Entity.System; + +/// +/// 常用语 +/// 版 本:V3.2 +/// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) +/// 作 者:JNPF开发平台组 +/// 日 期:2021-06-01. +/// +[SugarTable("BASE_COMMONWORDS")] +public class CommonWordsEntity : CLDEntityBase +{ + /// + /// 应用id. + /// + [SugarColumn(ColumnName = "F_SYSTEMIDS")] + public string SystemIds { get; set; } + + /// + /// 应用名称. + /// + [SugarColumn(ColumnName = "F_SYSTEMNAMES")] + public string SystemNames { get; set; } + + /// + /// 常用语. + /// + [SugarColumn(ColumnName = "F_COMMONWORDSTEXT")] + public string CommonWordsText { get; set; } + + /// + /// 常用语类型(0:系统,1:个人). + /// + [SugarColumn(ColumnName = "F_COMMONWORDSTYPE")] + public int CommonWordsType { get; set; } + + /// + /// 排序. + /// + [SugarColumn(ColumnName = "F_SORTCODE")] + public long SortCode { get; set; } +} diff --git a/system/Tnb.Systems.Entitys/Entity/System/PrintDevEntity.cs b/system/Tnb.Systems.Entitys/Entity/System/PrintDevEntity.cs index 932d71d7..e08e062d 100644 --- a/system/Tnb.Systems.Entitys/Entity/System/PrintDevEntity.cs +++ b/system/Tnb.Systems.Entitys/Entity/System/PrintDevEntity.cs @@ -73,4 +73,6 @@ public class PrintDevEntity : CLDEntityBase /// [SugarColumn(ColumnName = "F_PRINTTEMPLATE")] public string PrintTemplate { get; set; } + [SugarColumn(ColumnName = "F_PAGEPARAM")] + public string PageParam { get; set; } } \ No newline at end of file diff --git a/system/Tnb.Systems.Entitys/Entity/System/PrintLogEntity.cs b/system/Tnb.Systems.Entitys/Entity/System/PrintLogEntity.cs new file mode 100644 index 00000000..d309b5af --- /dev/null +++ b/system/Tnb.Systems.Entitys/Entity/System/PrintLogEntity.cs @@ -0,0 +1,47 @@ +using JNPF.Common.Const; +using JNPF.Common.Contracts; +using SqlSugar; + +namespace JNPF.Systems.Entitys.Entity.System; + +/// +/// 打印模板日志 +/// 版 本:V3.2 +/// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) +/// 作 者:JNPF开发平台组 +/// 日 期:2021-06-01. +/// +[SugarTable("BASE_PRINT_LOG")] +[Tenant(ClaimConst.TENANTID)] +public class PrintLogEntity : EntityBase +{ + /// + /// 打印人. + /// + [SugarColumn(ColumnName = "F_PrintMan")] + public string PrintMan { get; set; } + + /// + /// 打印时间. + /// + [SugarColumn(ColumnName = "F_PrintTime")] + public DateTime? PrintTime { get; set; } + + /// + /// 打印条数. + /// + [SugarColumn(ColumnName = "F_PrintNum")] + public int? PrintNum { get; set; } + + /// + /// 打印功能名称. + /// + [SugarColumn(ColumnName = "F_PrintTitle")] + public string PrintTitle { get; set; } + + /// + /// 打印模板id. + /// + [SugarColumn(ColumnName = "F_PrintId")] + public string PrintId { get; set; } +} diff --git a/system/Tnb.Systems.Entitys/Model/Permission/User/SSOUserInfoModel.cs b/system/Tnb.Systems.Entitys/Model/Permission/User/SSOUserInfoModel.cs new file mode 100644 index 00000000..4bb35de7 --- /dev/null +++ b/system/Tnb.Systems.Entitys/Model/Permission/User/SSOUserInfoModel.cs @@ -0,0 +1,201 @@ +namespace JNPF.Systems.Entitys.Model.Permission.User; + +public class UserInfo +{ + private static readonly long serialVersionUID = 6402443942083382236L; + + public static readonly string CLASS_TYPE = "UserInfo"; + + public static readonly string DEFAULT_PASSWORD_SUFFIX = "MaxKey@888"; + + string sessionId { get; set; } + + public string id { get; set; } + public string username { get; set; } + public string password { get; set; } + public string decipherable { get; set; } + public string sharedSecret { get; set; } + public string sharedCounter { get; set; } + /** + * "Employee", "Supplier","Dealer","Contractor",Partner,Customer "Intern", + * "Temp", "External", and "Unknown" . + */ + public string userType { get; set; } + + public string userState { get; set; } + + public string windowsAccount { get; set; } + + // for user name + public string displayName { get; set; } + public string nickName { get; set; } + public string nameZhSpell { get; set; } + public string nameZhShortSpell { get; set; } + public string givenName { get; set; } + public string middleName { get; set; } + public string familyName { get; set; } + public string honorificPrefix { get; set; } + public string honorificSuffix { get; set; } + public string formattedName { get; set; } + + public int married { get; set; } + public int gender { get; set; } + public string birthDate { get; set; } + public byte[] picture { get; set; } + public string pictureBase64 { get; set; } + public string pictureId { get; set; } + public int idType { get; set; } + public string idCardNo { get; set; } + public string webSite { get; set; } + public string startWorkDate { get; set; } + + // for security + public int authnType { get; set; } + public string email { get; set; } + + public int emailVerified { get; set; } + public string mobile { get; set; } + + public int mobileVerified { get; set; } + + public string passwordQuestion { get; set; } + + public string passwordAnswer { get; set; } + // for apps login public + public int appLoginAuthnType { get; set; } + public string appLoginPassword { get; set; } + public string protectedApps { get; set; } + public Dictionary protectedAppsMap { get; set; } + + public string passwordLastSetTime { get; set; } + public int badPasswordCount { get; set; } + public string badPasswordTime { get; set; } + public string unLockTime { get; set; } + public int isLocked { get; set; } + public string lastLoginTime { get; set; } + public string lastLoginIp { get; set; } + public string lastLogoffTime { get; set; } + public int passwordSetType { get; set; } + public int loginCount { get; set; } + public string regionHistory { get; set; } + public string passwordHistory { get; set; } + + public string locale { get; set; } + public string timeZone { get; set; } + public string preferredLanguage { get; set; } + + // for work + public string workCountry { get; set; } + public string workRegion { get; set; }// province + public string workLocality { get; set; }// city + public string workStreetAddress { get; set; } + public string workAddressFormatted { get; set; } + public string workEmail { get; set; } + public string workPhoneNumber { get; set; } + public string workPostalCode { get; set; } + public string workFax { get; set; } + + public string workOfficeName { get; set; } + // for home + public string homeCountry { get; set; } + public string homeRegion { get; set; }// province + public string homeLocality { get; set; }// city + public string homeStreetAddress { get; set; } + public string homeAddressFormatted { get; set; } + public string homeEmail { get; set; } + public string homePhoneNumber { get; set; } + public string homePostalCode { get; set; } + public string homeFax { get; set; } + // for company + public string employeeNumber { get; set; } + public string costCenter { get; set; } + public string organization { get; set; } + public string division { get; set; } + public string departmentId { get; set; } + public string department { get; set; } + public string jobTitle { get; set; } + public string jobLevel { get; set; } + public string managerId { get; set; } + public string manager { get; set; } + public string assistantId { get; set; } + public string assistant { get; set; } + public string entryDate { get; set; } + public string quitDate { get; set; } + + // for social contact + public string defineIm { get; set; } + public int weixinFollow { get; set; } + + public string theme { get; set; } + /* + * for extended Attribute from userType extraAttribute for database + * extraAttributeName & extraAttributeValue for page submit + */ + public string extraAttribute { get; set; } + public string extraAttributeName { get; set; } + public string extraAttributeValue { get; set; } + public Dictionary extraAttributeMap { get; set; } + + public int online { get; set; } + + public string ldapDn { get; set; } + + public int gridList { get; set; } + + public string createdBy { get; set; } + public string createdDate { get; set; } + public string modifiedBy { get; set; } + public string modifiedDate { get; set; } + public int status { get; set; } + string description { get; set; } + + /// + /// 租户Id. + /// + public string instId { get; set; } + + private string instName; + + string syncId { get; set; } + + string syncName { get; set; } + + string originId { get; set; } + + string originId2 { get; set; } + + string gradingUserId { get; set; } + + public override string ToString() + { + return "UserInfo{" + + "id='" + id + '\'' + + ", username='" + username + '\'' + + '}'; + } +} + +public class MqMessage +{ + public string id { get; set; } + public string topic { get; set; } + public string actionType { get; set; } + public string sendTime { get; set; } + public object content { get; set; } + public UserInfo userInfo { get; set; } + + public MqMessage() + { + } + + public MqMessage(string id, string topic, string actionType, string sendTime, object content, UserInfo userInfo) + { + this.id = id; + this.topic = topic; + this.actionType = actionType; + this.sendTime = sendTime; + this.content = content; + this.userInfo = userInfo; + } +} + diff --git a/system/Tnb.Systems.Interfaces/Permission/IUsersService.cs b/system/Tnb.Systems.Interfaces/Permission/IUsersService.cs index bf333805..a352eb73 100644 --- a/system/Tnb.Systems.Interfaces/Permission/IUsersService.cs +++ b/system/Tnb.Systems.Interfaces/Permission/IUsersService.cs @@ -86,4 +86,5 @@ public interface IUsersService /// select 选择字段表达式. /// Task> GetUserListByExp(Expression> expression, Expression> select); + Task Receive(string message); } \ No newline at end of file diff --git a/system/Tnb.Systems/Common/FileService.cs b/system/Tnb.Systems/Common/FileService.cs index 3cfdb77d..cb62fdfa 100644 --- a/system/Tnb.Systems/Common/FileService.cs +++ b/system/Tnb.Systems/Common/FileService.cs @@ -1,4 +1,5 @@ -using System.Security.Cryptography; +using System.IO.Compression; +using System.Security.Cryptography; using System.Text; using System.Web; using JNPF.Common.Captcha.General; @@ -80,7 +81,7 @@ public class FileService : IFileService, IDynamicApiController, ITransient /// /// [HttpGet("Uploader/Preview")] - public async Task Preview(string fileName) + public async Task Preview(string fileName, string fileDownloadUrl) { string[]? typeList = new string[] { "doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf", "jpg", "jpeg", "gif", "png", "bmp" }; string? type = fileName.Split('.').LastOrDefault(); @@ -92,7 +93,7 @@ public class FileService : IFileService, IDynamicApiController, ITransient switch (_appOptions.PreviewType) { case PreviewType.kkfile: - previewUrl = KKFileUploaderPreview(fileName); + previewUrl = KKFileUploaderPreview(fileName, fileDownloadUrl); break; case PreviewType.yozo: previewUrl = await YoZoUploaderPreview(fileName, 5, 1); @@ -154,10 +155,15 @@ public class FileService : IFileService, IDynamicApiController, ITransient /// 下载. /// /// + /// [HttpGet("down/{fileName}")] - public async Task FileDown(string fileName) + public async Task FileDown(string fileName, [FromQuery] string type) { string? systemFilePath = Path.Combine(FileVariable.SystemFilePath, fileName); + if (type.IsNotEmptyOrNull()) + { + systemFilePath = Path.Combine(_fileManager.GetPathByType(type), fileName); + } var fileStreamResult = await _fileManager.DownloadFileByType(systemFilePath, fileName); byte[] bytes = new byte[fileStreamResult.FileStream.Length]; @@ -190,6 +196,39 @@ public class FileService : IFileService, IDynamicApiController, ITransient return new { name = fileName, url = string.Format("/api/file/Download?encryption={0}", encryptStr) }; } + /// + /// 全部下载. + /// + /// 图片类型. + /// 文件名称. + /// + [HttpPost("PackDownload/{type}")] + public async Task DownloadAll(string type, [FromBody] List input) + { + var fileName = RandomExtensions.NextLetterAndNumberString(new Random(), 7); + //临时目录 + string directoryPath = Path.Combine(App.GetConfig("JNPF_App", true).SystemPath, "TemporaryFile", fileName); + Directory.CreateDirectory(directoryPath); + foreach (var item in input) + { + string filePath = Path.Combine(GetPathByType(type), item.fileId.Replace("@", ".")); + await _fileManager.CopyFile(filePath, Path.Combine(directoryPath, item.fileName)); + } + // 压缩文件 + string downloadPath = directoryPath + ".zip"; + + // 判断是否存在同名称文件 + if (File.Exists(downloadPath)) + File.Delete(downloadPath); + + ZipFile.CreateFromDirectory(directoryPath, downloadPath); + if (!App.Configuration["OSS:Provider"].Equals("Invalid")) + await UploadFileByType(downloadPath, "SystemPath", string.Format("文件{0}.zip", fileName)); + var downloadFileName = string.Format("{0}|{1}.zip|TemporaryFile", _userManager.UserId, fileName); + _cacheManager.Set(fileName + ".zip", string.Empty); + return new { downloadName = string.Format("文件{0}.zip", fileName), downloadVo = new { name = fileName, url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(downloadFileName, "JNPF") } }; + } + /// /// 下载文件链接. /// @@ -268,16 +307,17 @@ public class FileService : IFileService, IDynamicApiController, ITransient [HttpPost("Uploader/{type}")] [AllowAnonymous] [IgnoreLog] - public async Task Uploader(string type, IFormFile file) + public async Task Uploader(string type, [FromForm] ChunkModel input) { - string? fileType = Path.GetExtension(file.FileName).Replace(".", string.Empty); + string? fileType = Path.GetExtension(input.file.FileName).Replace(".", string.Empty); if (!AllowFileType(fileType, type)) throw Oops.Oh(ErrorCode.D1800); - string filePath = GetPathByType(type); - string fileName = string.Format("{0}{1}{2}", DateTime.Now.ToString("yyyyMMdd"), RandomExtensions.NextLetterAndNumberString(new Random(), 5), Path.GetExtension(file.FileName)); - var stream = file.OpenReadStream(); - await _fileManager.UploadFileByType(stream, filePath, fileName); - return new { name = fileName, url = string.Format("/api/File/Image/{0}/{1}", type, fileName), fileSize = file.Length, fileExtension = fileType }; + string saveFileName = string.Format("{0}{1}{2}", DateTime.Now.ToString("yyyyMMdd"), RandomExtensions.NextLetterAndNumberString(new Random(), 5), Path.GetExtension(input.file.FileName)); + var stream = input.file.OpenReadStream(); + input.type = type; + _fileManager.GetChunkModel(input, saveFileName); + await _fileManager.UploadFileByType(stream, input.folder, saveFileName); + return new FileControlsModel { name = input.fileName, url = string.Format("/api/File/Image/{0}/{1}", type, input.fileName), fileExtension = fileType, fileSize = input.file.Length, fileName = input.fileName }; } /// @@ -364,12 +404,18 @@ public class FileService : IFileService, IDynamicApiController, ITransient /// KKFile 文件预览. /// /// 文件名称. + /// 文件地址. /// - public string KKFileUploaderPreview(string fileName) + public string KKFileUploaderPreview(string fileName, string fileDownloadUrl) { var domain = App.Configuration["JNPF_APP:Domain"]; var filePath = (domain + "/api/File/down/" + fileName).ToBase64String(); - + if (fileDownloadUrl.IsNotEmptyOrNull()) + { + var list = fileDownloadUrl.Split('/'); + var type = list.Length > 4 ? list[4] : string.Empty; + filePath = string.Format("{0}{1}{2}?type={3}", domain, "/api/File/down/", fileName, type).ToBase64String(); + } var kkFileDoMain = App.Configuration["JNPF_APP:KKFileDomain"]; var kkurl = kkFileDoMain + "/onlinePreview?url="; diff --git a/system/Tnb.Systems/Permission/AuthorizeService.cs b/system/Tnb.Systems/Permission/AuthorizeService.cs index da29fb93..a680dfc6 100644 --- a/system/Tnb.Systems/Permission/AuthorizeService.cs +++ b/system/Tnb.Systems/Permission/AuthorizeService.cs @@ -1,4 +1,5 @@ -using JNPF.Common.Const; +using Aop.Api.Domain; +using JNPF.Common.Const; using JNPF.Common.Core.Handlers; using JNPF.Common.Core.Manager; using JNPF.Common.Enums; @@ -453,7 +454,7 @@ public class AuthorizeService : IAuthorizeService, IDynamicApiController, ITrans _authorizeRepository.AsSugarClient().Ado.RollbackTran(); } - if(input.objectId.Any()) await ForcedOffline(input.objectId); // 编辑角色权限退出角色的登录用户 + if (input.objectId.Any() && !input.itemType.Equals("portal")) await ForcedOffline(input.objectId); // 编辑角色权限退出角色的登录用户 } /// @@ -1083,7 +1084,7 @@ public class AuthorizeService : IAuthorizeService, IDynamicApiController, ITrans /// private async Task DelUserInfo(string tenantId, string userId) { - var cacheKey = string.Format("{0}{1}_{2}", CommonConst.CACHEKEYUSER, tenantId, userId); + var cacheKey = string.Format("{0}:{1}:{2}", tenantId, CommonConst.CACHEKEYUSER, userId); return await _cacheManager.DelAsync(cacheKey); } diff --git a/system/Tnb.Systems/Permission/DepartmentService.cs b/system/Tnb.Systems/Permission/DepartmentService.cs index 3dc97348..0e74df6e 100644 --- a/system/Tnb.Systems/Permission/DepartmentService.cs +++ b/system/Tnb.Systems/Permission/DepartmentService.cs @@ -172,13 +172,16 @@ public class DepartmentService : IDepartmentService, IDynamicApiController, ITra var pItems = treeList.Select(x => x.organizeIds.FirstOrDefault()).Distinct().ToList(); pItems.ForEach(item => { - var addItem = orgTree.Find(x => x.Id.Equals(item)).Adapt(); - if (addItem.type != null && addItem.type.Equals("company")) addItem.icon = "icon-ym icon-ym-tree-organization3"; - addItem.fullName = orgTree.FirstOrDefault(x => x.Id.Equals(addItem.id))?.Description; - addItem.organize = addItem.fullName; - addItem.organizeIds = addItem.organizeIdTree.Split(",").ToList(); - addItem.disabled = true; - if (!treeList.Any(x => x.id.Equals(addItem.id))) treeList.Add(addItem); + if (treeList.Select(x => x.id).Contains(item)) + { + var addItem = orgTree.Find(x => x.Id.Equals(item)).Adapt(); + if (addItem.type != null && addItem.type.Equals("company")) addItem.icon = "icon-ym icon-ym-tree-organization3"; + addItem.fullName = orgTree.FirstOrDefault(x => x.Id.Equals(addItem.id))?.Description; + addItem.organize = addItem.fullName; + addItem.organizeIds = addItem.organizeIdTree.Split(",").ToList(); + addItem.disabled = true; + if (!treeList.Any(x => x.id.Equals(addItem.id))) treeList.Add(addItem); + } }); } diff --git a/system/Tnb.Systems/Permission/OrganizeAdministratorService.cs b/system/Tnb.Systems/Permission/OrganizeAdministratorService.cs index e8e913b9..111711c9 100644 --- a/system/Tnb.Systems/Permission/OrganizeAdministratorService.cs +++ b/system/Tnb.Systems/Permission/OrganizeAdministratorService.cs @@ -1,4 +1,5 @@ -using JNPF.Common.Core.Manager; +using JNPF.Common.Contracts; +using JNPF.Common.Core.Manager; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; @@ -86,10 +87,10 @@ public class OrganizeAdministratorService : IOrganizeAdministratorService, IDyna var userIdList = await _repository.AsSugarClient().Queryable().Where(x => x.ObjectType.Equals("Organize") && orgIds.Contains(x.ObjectId)).Select(x => x.UserId).ToListAsync(); var organizeAdmin = await _repository.AsSugarClient().Queryable().Where(x => !SqlFunc.ToString(x.UserId).Equals(_userManager.UserId)) .WhereIF(!_userManager.IsAdministrator, x => orgIds.Contains(x.OrganizeId) && userIdList.Contains(x.UserId)) - .Select(x => x.UserId).ToListAsync(); + .Select(x => new { x.UserId, x.CreatorTime }).ToListAsync(); var data = await _repository.AsSugarClient().Queryable() - .Where(x => organizeAdmin.Contains(x.Id) && x.DeleteMark == null) + .Where(x => organizeAdmin.Select(xx => xx.UserId).Contains(x.Id) && x.DeleteMark == null) .WhereIF(input.keyword.IsNotEmptyOrNull(), x => x.Account.Contains(input.keyword) || x.RealName.Contains(input.keyword)) .Select(x => new OrganizeAdministratorListOutput() { @@ -109,6 +110,7 @@ public class OrganizeAdministratorService : IOrganizeAdministratorService, IDyna // 获取用户组织集合 List? roleOrgList = orgUserIdAll.Where(x => x.UserId == item.id).Select(x => x.ObjectId).ToList(); item.organizeId = string.Join(" , ", orgTreeNameList.Where(x => roleOrgList.Contains(x.Id)).Select(x => x.Description)); + item.creatorTime = organizeAdmin.Find(x => x.UserId.Equals(item.id)).CreatorTime; } return PageResult.SqlSugarPageResult(data); diff --git a/system/Tnb.Systems/Permission/OrganizeService.cs b/system/Tnb.Systems/Permission/OrganizeService.cs index 190a515c..fd02a5a2 100644 --- a/system/Tnb.Systems/Permission/OrganizeService.cs +++ b/system/Tnb.Systems/Permission/OrganizeService.cs @@ -11,6 +11,7 @@ using JNPF.JsonSerialization; using JNPF.LinqBuilder; using JNPF.Systems.Entitys.Dto.Organize; using JNPF.Systems.Entitys.Dto.SysConfig; +using JNPF.Systems.Entitys.Dto.User; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.Permission; @@ -215,13 +216,16 @@ public class OrganizeService : IOrganizeService, IDynamicApiController, ITransie var pItems = treeList.Select(x => x.organizeIds.FirstOrDefault()).Distinct().ToList(); pItems.ForEach(item => { - var addItem = orgTree.Find(x => x.Id.Equals(item)).Adapt(); - if (addItem.type != null && addItem.type.Equals("company")) addItem.icon = "icon-ym icon-ym-tree-organization3"; - addItem.fullName = orgTree.FirstOrDefault(x => x.Id.Equals(addItem.id))?.Description; - addItem.organize = addItem.fullName; - addItem.organizeIds = addItem.organizeIdTree.Split(",").ToList(); - addItem.disabled = true; - if (!treeList.Any(x => x.id.Equals(addItem.id))) treeList.Add(addItem); + if (treeList.Select(x => x.id).Contains(item)) + { + var addItem = orgTree.Find(x => x.Id.Equals(item)).Adapt(); + if (addItem.type != null && addItem.type.Equals("company")) addItem.icon = "icon-ym icon-ym-tree-organization3"; + addItem.fullName = orgTree.FirstOrDefault(x => x.Id.Equals(addItem.id))?.Description; + addItem.organize = addItem.fullName; + addItem.organizeIds = addItem.organizeIdTree.Split(",").ToList(); + addItem.disabled = true; + if (!treeList.Any(x => x.id.Equals(addItem.id))) treeList.Add(addItem); + } }); } @@ -282,6 +286,23 @@ public class OrganizeService : IOrganizeService, IDynamicApiController, ITransie #region POST + /// + /// 根据组织Id List 获取当前所属组织(部门). + /// + /// + [HttpPost("getDefaultCurrentValueDepartmentId")] + public async Task GetDefaultCurrentValueDepartmentId([FromBody] GetDefaultCurrentValueInput input) + { + var depId = _repository.AsSugarClient().Queryable().Where(x => x.Id.Equals(_userManager.UserId)).Select(x => x.OrganizeId).First(); + + if (input.DepartIds == null || !input.DepartIds.Any()) return new { departmentId = depId }; + var userRelationList = _repository.AsSugarClient().Queryable().Where(x => input.DepartIds.Contains(x.ObjectId)) + .Select(x => x.UserId).ToList(); + + if (userRelationList.Contains(_userManager.UserId)) return new { userId = depId }; + else return new { departmentId = string.Empty }; + } + /// /// 通过部门id获取部门列表. /// @@ -295,19 +316,19 @@ public class OrganizeService : IOrganizeService, IDynamicApiController, ITransie queryWhere = queryWhere.And(x => x.DeleteMark == null); List? data = await _repository.AsQueryable().Where(queryWhere) .WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)).Select(a => new OrganizeListOutput - { - id = a.Id, - organizeIdTree = a.OrganizeIdTree, - type = a.Category, - parentId = a.ParentId, - lastFullName = a.FullName, - fullName = a.FullName, - enabledMark = a.EnabledMark, - creatorTime = a.CreatorTime, - icon = a.Category.Equals("company") ? "icon-ym icon-ym-tree-organization3" : "icon-ym icon-ym-tree-department1", - sortCode = a.SortCode, - isLeaf = true - }).ToListAsync(); + { + id = a.Id, + organizeIdTree = a.OrganizeIdTree, + type = a.Category, + parentId = a.ParentId, + lastFullName = a.FullName, + fullName = a.FullName, + enabledMark = a.EnabledMark, + creatorTime = a.CreatorTime, + icon = a.Category.Equals("company") ? "icon-ym icon-ym-tree-organization3" : "icon-ym icon-ym-tree-department1", + sortCode = a.SortCode, + isLeaf = true + }).ToListAsync(); // 获取所有组织 List? allOrgList = GetOrgListTreeName(); @@ -398,7 +419,7 @@ public class OrganizeService : IOrganizeService, IDynamicApiController, ITransie }); }); - if (adminlist.Any()) await _repository.AsSugarClient().Insertable(adminlist).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + if(adminlist.Any()) await _repository.AsSugarClient().Insertable(adminlist).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); #endregion #region 第三方同步 diff --git a/system/Tnb.Systems/Permission/PositionService.cs b/system/Tnb.Systems/Permission/PositionService.cs index dd19b31a..9bb961ca 100644 --- a/system/Tnb.Systems/Permission/PositionService.cs +++ b/system/Tnb.Systems/Permission/PositionService.cs @@ -124,78 +124,29 @@ public class PositionService : IPositionService, IDynamicApiController, ITransie childOrgIds.AddRange(_repository.AsSugarClient().Queryable().ToChildList(x => x.ParentId, input.organizeId).Select(x => x.Id).ToList()); childOrgIds = childOrgIds.Distinct().ToList(); } - var strChildOrgIds = string.Join(",", childOrgIds); + var data = await _repository.AsSugarClient().Queryable( + (a, b, c) => new JoinQueryInfos(JoinType.Left, b.Id == a.OrganizeId, JoinType.Left, a.Type == c.EnCode && c.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e")) - SqlSugarPagedList? data = new SqlSugarPagedList(); - if (childOrgIds.Any()) - { - // 拼接查询 - List>? listQuery = new List>(); - foreach (string item in childOrgIds) + // 组织机构 + .WhereIF(childOrgIds.Any(), a => childOrgIds.Contains(a.OrganizeId)) + .WhereIF(!_userManager.IsAdministrator, a => dataScope.Contains(a.OrganizeId)) + + // 关键字(名称、编码) + .WhereIF(!input.keyword.IsNullOrEmpty(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) + .Where(a => a.DeleteMark == null).OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc).OrderBy(a => a.LastModifyTime, OrderByType.Desc) + .Select((a, b, c) => new PositionListOutput { - var quer = _repository.AsQueryable() - - // 组织机构 - .Where(a => item.Equals(a.OrganizeId)) - .WhereIF(!_userManager.IsAdministrator, a => dataScope.Contains(a.OrganizeId)) - .WhereIF(!input.keyword.IsNullOrEmpty(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) - .Select(a => new PositionListOutput - { - id = a.Id, - fullName = a.FullName, - enCode = a.EnCode, - type = SqlFunc.Subqueryable().Where(d => d.EnCode.Equals(a.Type) && d.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e").Select(d => d.FullName), - department = SqlFunc.Subqueryable().Where(o => o.Id.Equals(a.OrganizeId)).Select(o => o.FullName), - organizeId = SqlFunc.Subqueryable().Where(o => o.Id.Equals(a.OrganizeId)).Select(o => o.OrganizeIdTree), - enabledMark = a.EnabledMark, - creatorTime = a.CreatorTime, - description = a.Description, - sortCode = a.SortCode - }); - listQuery.Add(quer); - } - - data = await _repository.AsSugarClient().UnionAll(listQuery) - .Select(a => new PositionListOutput - { - id = a.id, - fullName = a.fullName, - enCode = a.enCode, - type = a.type, - department = a.department, - organizeId = a.organizeId, - enabledMark = a.enabledMark, - creatorTime = a.creatorTime, - description = a.description, - sortCode = a.sortCode - }).ToPagedListAsync(input.currentPage, input.pageSize); - } - else - { - data = await _repository.AsSugarClient().Queryable( - (a, b, c) => new JoinQueryInfos(JoinType.Left, b.Id == a.OrganizeId, JoinType.Left, a.Type == c.EnCode && c.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e")) - - // 组织机构 - .WhereIF(childOrgIds.Any(), a => childOrgIds.Contains(a.OrganizeId)) - .WhereIF(!_userManager.IsAdministrator, a => dataScope.Contains(a.OrganizeId)) - - // 关键字(名称、编码) - .WhereIF(!input.keyword.IsNullOrEmpty(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) - .Where(a => a.DeleteMark == null).OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc).OrderBy(a => a.LastModifyTime, OrderByType.Desc) - .Select((a, b, c) => new PositionListOutput - { - id = a.Id, - fullName = a.FullName, - enCode = a.EnCode, - type = c.FullName, - department = b.FullName, - organizeId = b.OrganizeIdTree, - enabledMark = a.EnabledMark, - creatorTime = a.CreatorTime, - description = a.Description, - sortCode = a.SortCode - }).ToPagedListAsync(input.currentPage, input.pageSize); - } + id = a.Id, + fullName = a.FullName, + enCode = a.EnCode, + type = c.FullName, + department = b.FullName, + organizeId = b.OrganizeIdTree, + enabledMark = a.EnabledMark, + creatorTime = a.CreatorTime, + description = a.Description, + sortCode = a.SortCode + }).ToPagedListAsync(input.currentPage, input.pageSize); // 处理组织树 名称 List? orgList = _organizeService.GetOrgListTreeName(); diff --git a/system/Tnb.Systems/Permission/RoleService.cs b/system/Tnb.Systems/Permission/RoleService.cs index bbac5217..65dcd4de 100644 --- a/system/Tnb.Systems/Permission/RoleService.cs +++ b/system/Tnb.Systems/Permission/RoleService.cs @@ -102,62 +102,42 @@ public class RoleService : IRoleService, IDynamicApiController, ITransient SqlSugarPagedList? data = new SqlSugarPagedList(); if (childOrgIds.Any()) { - // 拼接查询 - List>? listQuery = new List>(); - foreach (string item in childOrgIds) - { - var quer = _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.ObjectId)) - .Where((a, b) => item == a.OrganizeId) - .WhereIF(!pageInput.keyword.IsNullOrEmpty(), (a, b) => b.FullName.Contains(pageInput.keyword) || b.EnCode.Contains(pageInput.keyword)) - .WhereIF(!_userManager.IsAdministrator, a => dataScope.Contains(a.ObjectId)) - .Where((a, b) => b.DeleteMark == null) + data = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.ObjectId)) + .Where((a, b) => childOrgIds.Contains(b.OrganizeId)).Where((a, b) => a.DeleteMark == null) + .WhereIF(!pageInput.keyword.IsNullOrEmpty(), (a, b) => a.FullName.Contains(pageInput.keyword) || a.EnCode.Contains(pageInput.keyword)) + .WhereIF(!_userManager.IsAdministrator, (a, b) => dataScope.Contains(b.OrganizeId)) + .GroupBy((a, b) => new { a.Id, a.Type, a.GlobalMark, a.EnCode, a.FullName, a.EnabledMark, a.CreatorTime, a.SortCode }) .Select((a, b) => new RoleListOutput { - id = b.Id, - parentId = b.Type, - type = SqlFunc.IIF(b.GlobalMark == 1, "全局", "组织"), - enCode = b.EnCode, - fullName = b.FullName, - enabledMark = b.EnabledMark, - creatorTime = b.CreatorTime, - sortCode = b.SortCode - }); - listQuery.Add(quer); - } - var sql = _repository.AsSugarClient().UnionAll(listQuery).Where(a => !SqlFunc.IsNullOrEmpty(a.id)).ToSqlString(); - data = await _repository.AsSugarClient().UnionAll(listQuery).Where(a => !SqlFunc.IsNullOrEmpty(a.id)) - .GroupBy(a => new { a.id, a.parentId, a.type, a.creatorTime, a.enCode, a.fullName, a.sortCode, a.enabledMark }) - .Select(a => new RoleListOutput - { - id = a.id, - parentId = a.parentId, - type = a.type, - creatorTime = a.creatorTime, - enCode = a.enCode, - fullName = a.fullName, - sortCode = a.sortCode - }).ToPagedListAsync(input.currentPage, input.pageSize); + id = a.Id, + parentId = a.Type, + type = SqlFunc.IIF(a.GlobalMark == 1, "全局", "组织"), + enCode = a.EnCode, + fullName = a.FullName, + enabledMark = a.EnabledMark, + creatorTime = a.CreatorTime, + sortCode = a.SortCode + }).MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); } else { - data = await _repository.AsSugarClient().Queryable() - .WhereIF(input.organizeId == "0", a => a.GlobalMark == 1) - .WhereIF(!_userManager.IsAdministrator, a => a.GlobalMark == 0) - .WhereIF(!_userManager.IsAdministrator, a => a.GlobalMark == 1) - .WhereIF(!string.IsNullOrEmpty(input.keyword), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) - .Where(a => a.DeleteMark == null) - .Select((a) => new RoleListOutput - { - id = a.Id, - parentId = a.Type, - type = SqlFunc.IIF(a.GlobalMark == 1, "全局", "组织"), - enCode = a.EnCode, - fullName = a.FullName, - description = a.Description, - enabledMark = a.EnabledMark, - creatorTime = a.CreatorTime, - sortCode = a.SortCode - }).MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); + data = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.ObjectId)) + .Where((a, b) => a.DeleteMark == null) + .WhereIF(input.organizeId == "0", (a, b) => a.GlobalMark == 1) + .WhereIF(!pageInput.keyword.IsNullOrEmpty(), (a, b) => a.FullName.Contains(pageInput.keyword) || a.EnCode.Contains(pageInput.keyword)) + .WhereIF(!_userManager.IsAdministrator && input.organizeId != "0", (a, b) => dataScope.Contains(b.OrganizeId)) + .GroupBy((a, b) => new { a.Id, a.Type, a.GlobalMark, a.EnCode, a.FullName, a.EnabledMark, a.CreatorTime, a.SortCode }) + .Select((a, b) => new RoleListOutput + { + id = a.Id, + parentId = a.Type, + type = SqlFunc.IIF(a.GlobalMark == 1, "全局", "组织"), + enCode = a.EnCode, + fullName = a.FullName, + enabledMark = a.EnabledMark, + creatorTime = a.CreatorTime, + sortCode = a.SortCode + }).MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); } #region 处理 多组织 @@ -169,11 +149,8 @@ public class RoleService : IRoleService, IDynamicApiController, ITransient // 获取组织集合 var organizeList = orgUserIdAll.Where(x => x.ObjectId == item.id).Select(x => x.OrganizeId).ToList(); item.organizeInfo = string.Join(" ; ", orgTreeNameList.Where(x => organizeList.Contains(x.Id)).Select(x => x.Description)); - item.sortCode = 999; - if (organizeList.Contains(input.organizeId)) item.sortCode = 0; } - data.list = data.list.OrderBy(x => x.sortCode).ToList(); #endregion return PageResult.SqlSugarPageResult(data); diff --git a/system/Tnb.Systems/Permission/SocialsUserService.cs b/system/Tnb.Systems/Permission/SocialsUserService.cs index 5241c19c..2c0df364 100644 --- a/system/Tnb.Systems/Permission/SocialsUserService.cs +++ b/system/Tnb.Systems/Permission/SocialsUserService.cs @@ -354,7 +354,7 @@ public class SocialsUserService : ISocialsUserService, IDynamicApiController, IT return new WeChatOpenAuthRequest(clientConfig, authStateCache); case DefaultAuthSourceEnum.WECHAT_ENTERPRISE: - //return new WeChatEnterpriseAuthRequest(clientConfig, authStateCache); + //return new WeChatEnterpriseAuthRequest(clientConfig, authStateCache); case DefaultAuthSourceEnum.WECHAT_ENTERPRISE_SCAN: clientConfig.redirectUri = HttpUtility.UrlEncode(clientConfig.redirectUri); @@ -554,4 +554,5 @@ public class SocialsUserService : ISocialsUserService, IDynamicApiController, IT var socialName = resData.username.IsNullOrWhiteSpace() ? resData.nickname : resData.username; return await GetUserInfo(model.source, uuid, socialName); } + } \ No newline at end of file diff --git a/system/Tnb.Systems/Permission/UsersCurrentService.cs b/system/Tnb.Systems/Permission/UsersCurrentService.cs index 6caad7e8..09535467 100644 --- a/system/Tnb.Systems/Permission/UsersCurrentService.cs +++ b/system/Tnb.Systems/Permission/UsersCurrentService.cs @@ -17,6 +17,7 @@ using JNPF.Systems.Entitys.Model.UsersCurrent; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.Permission; +using JNPF.Systems.Interfaces.System; using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; @@ -50,11 +51,21 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, /// private readonly ICacheManager _cacheManager; + /// + /// 系统配置. + /// + private readonly ISysConfigService _sysConfigService; + /// /// 用户管理. /// private readonly IUserManager _userManager; + /// + /// 操作权限服务. + /// + private readonly OnlineUserService _onlineUserService; + /// /// 初始化一个类型的新实例. /// @@ -63,12 +74,16 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, IAuthorizeService authorizeService, IOrganizeService organizeService, ICacheManager cacheManager, + ISysConfigService sysConfigService, + OnlineUserService onlineUserService, IUserManager userManager) { _repository = userRepository; _authorizeService = authorizeService; _organizeService = organizeService; _cacheManager = cacheManager; + _sysConfigService = sysConfigService; + _onlineUserService = onlineUserService; _userManager = userManager; } @@ -126,7 +141,7 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, position = string.Empty, positionId = a.PositionId, organizeId = a.OrganizeId, - manager = SqlFunc.Subqueryable().Where(x => x.Id.Equals(a.Id)).Select(x => SqlFunc.MergeString(x.RealName, "/", x.Account)), + manager = SqlFunc.Subqueryable().Where(x => x.Id.Equals(a.ManagerId)).Select(x => SqlFunc.MergeString(x.RealName, "/", x.Account)), roleId = string.Empty, roleIds = a.RoleId, creatorTime = a.CreatorTime, @@ -305,6 +320,7 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, if (MD5Encryption.Encrypt(input.oldPassword + user.Secretkey) != user.Password.ToLower()) throw Oops.Oh(ErrorCode.D5007); string? imageCode = await GetCode(input.timestamp); + await PwdStrategy(input); if (!input.code.ToLower().Equals(imageCode.ToLower())) { throw Oops.Oh(ErrorCode.D5015); @@ -312,15 +328,14 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, else { await DelCode(input.timestamp); - await DelUserInfo(string.Format("{0}_{1}", _userManager.TenantId, user.Id)); + await DelUserInfo(_userManager.TenantId, user.Id); + await _onlineUserService.ForcedOffline(user.Id); } - user.Password = MD5Encryption.Encrypt(input.password + user.Secretkey); user.ChangePasswordDate = DateTime.Now; user.LastModifyTime = DateTime.Now; user.LastModifyUserId = _userManager.UserId; - int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new - { + int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new { it.Password, it.ChangePasswordDate, it.LastModifyUserId, @@ -341,8 +356,7 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, userInfo.IsAdministrator = Convert.ToInt32(_userManager.IsAdministrator); userInfo.LastModifyTime = DateTime.Now; userInfo.LastModifyUserId = _userManager.UserId; - int isOk = await _repository.AsUpdateable(userInfo).UpdateColumns(it => new - { + int isOk = await _repository.AsUpdateable(userInfo).UpdateColumns(it => new { it.RealName, it.Signature, it.Gender, @@ -376,8 +390,7 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, user.Theme = input.theme; user.LastModifyTime = DateTime.Now; user.LastModifyUserId = _userManager.UserId; - int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new - { + int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new { it.Theme, it.LastModifyUserId, it.LastModifyTime @@ -396,8 +409,7 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, user.Language = input.language; user.LastModifyTime = DateTime.Now; user.LastModifyUserId = _userManager.UserId; - int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new - { + int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new { it.Language, it.LastModifyUserId, it.LastModifyTime @@ -416,8 +428,7 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, user.HeadIcon = name; user.LastModifyTime = DateTime.Now; user.LastModifyUserId = _userManager.UserId; - int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new - { + int isOk = await _repository.AsUpdateable(user).UpdateColumns(it => new { it.HeadIcon, it.LastModifyUserId, it.LastModifyTime @@ -468,8 +479,17 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, if (input.menuType.Equals(1)) { // 系统下没有菜单不允许切换. - if (!await _repository.AsSugarClient().Queryable().AnyAsync(x => x.SystemId.Equals(input.majorId) && x.DeleteMark == null && x.Category.Equals("App"))) - throw Oops.Oh(ErrorCode.D4009); + var mList = await _repository.AsSugarClient().Queryable().Where(x => x.SystemId.Equals(input.majorId) && x.DeleteMark == null && x.Category.Equals("App")).Select(x => x.Id).ToListAsync(); + if (!mList.Any()) throw Oops.Oh(ErrorCode.D4009); + + List? roleList = await _userManager.GetUserOrgRoleIds(userInfo.RoleId, userInfo.OrganizeId); + + // 非管理员 没有任何权限 切换失败 + if (!_userManager.IsAdministrator && !_repository.AsSugarClient().Queryable() + .Where(x => x.ObjectType == "Role" && x.ItemType == "module" && roleList.Contains(x.ObjectId)) + .Where(x => mList.Contains(x.ItemId)).Any()) + throw Oops.Oh(ErrorCode.D5023); + userInfo.SystemId = input.majorId; } else @@ -501,8 +521,7 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, userInfo.LastModifyTime = DateTime.Now; userInfo.LastModifyUserId = _userManager.UserId; - int isOk = await _repository.AsUpdateable(userInfo).UpdateColumns(it => new - { + int isOk = await _repository.AsUpdateable(userInfo).UpdateColumns(it => new { it.OrganizeId, it.PositionId, it.LastModifyUserId, @@ -709,14 +728,48 @@ public class UsersCurrentService : IUsersCurrentService, IDynamicApiController, /// /// 删除用户登录信息缓存. /// + /// 租户ID. /// 用户ID. /// - private Task DelUserInfo(string userId) + private Task DelUserInfo(string tenantId, string userId) { - string? cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYUSER, userId); + string? cacheKey = string.Format("{0}:{1}:{2}", tenantId, CommonConst.CACHEKEYUSER, userId); _cacheManager.DelAsync(cacheKey); return Task.FromResult(true); } + /// + /// 密码策略验证. + /// + /// + private async Task PwdStrategy(UsersCurrentActionsModifyPasswordInput input) + { + // 系统配置信息 + var sysInfo = await _sysConfigService.GetInfo(); + // 禁用旧密码 + if (sysInfo.disableOldPassword == 1 && sysInfo.disableTheNumberOfOldPasswords > 0) + { + var oldPwdList = _repository.AsSugarClient().Queryable().Where(x => x.UserId == _userManager.UserId).OrderByDescending(o => o.CreatorTime).Take(sysInfo.disableTheNumberOfOldPasswords).ToList(); + if (oldPwdList.Any()) + { + foreach (var item in oldPwdList) + { + if (MD5Encryption.Encrypt(input.password + item.Secretkey) == item.OldPassword.ToLower()) + throw Oops.Oh(ErrorCode.D5026); + } + } + } + + // 保存旧密码数据 + var oldPwdEntity = new UserOldPasswordEntity(); + oldPwdEntity.Id = SnowflakeIdHelper.NextId(); + oldPwdEntity.UserId = _userManager.UserId; + oldPwdEntity.Account = _userManager.Account; + oldPwdEntity.OldPassword = MD5Encryption.Encrypt(input.password + _userManager.User.Secretkey); + oldPwdEntity.Secretkey = _userManager.User.Secretkey; + oldPwdEntity.CreatorTime = DateTime.Now; + oldPwdEntity.TenantId = _userManager.TenantId; + _repository.AsSugarClient().Insertable(oldPwdEntity).ExecuteCommand(); + } #endregion } \ No newline at end of file diff --git a/system/Tnb.Systems/Permission/UsersService.cs b/system/Tnb.Systems/Permission/UsersService.cs index d355ef61..18cf74b8 100644 --- a/system/Tnb.Systems/Permission/UsersService.cs +++ b/system/Tnb.Systems/Permission/UsersService.cs @@ -1,7 +1,9 @@ -using JNPF.Common.Configuration; +using Aop.Api.Domain; +using JNPF.Common.Configuration; using JNPF.Common.Const; using JNPF.Common.Core.Manager; using JNPF.Common.Core.Manager.Files; +using JNPF.Common.Dtos.OAuth; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; @@ -9,27 +11,42 @@ using JNPF.Common.Helper; using JNPF.Common.Manager; using JNPF.Common.Models.NPOI; using JNPF.Common.Models.User; +using JNPF.Common.Options; using JNPF.Common.Security; using JNPF.DatabaseAccessor; using JNPF.DataEncryption; using JNPF.DependencyInjection; using JNPF.DynamicApiController; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using JNPF.FriendlyException; +using JNPF.RemoteRequest.Extensions; using JNPF.Systems.Entitys.Dto.Organize; using JNPF.Systems.Entitys.Dto.Role; using JNPF.Systems.Entitys.Dto.SysConfig; using JNPF.Systems.Entitys.Dto.User; using JNPF.Systems.Entitys.Dto.UserRelation; using JNPF.Systems.Entitys.Enum; +using JNPF.Systems.Entitys.Model.Permission.User; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.Permission; using JNPF.Systems.Interfaces.System; using Mapster; +using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.CodeAnalysis; +using Microsoft.Extensions.Options; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using Org.BouncyCastle.Ocsp; +using Qiniu.Util; +using Senparc.NeuChar.App.AppStore; using SqlSugar; +using System; using System.Linq.Expressions; +using System.Security.Principal; +using System.Text.Json.Nodes; namespace JNPF.Systems; @@ -40,6 +57,11 @@ namespace JNPF.Systems; [Route("api/permission/[controller]")] public class UsersService : IUsersService, IDynamicApiController, ITransient { + /// + /// 配置文档. + /// + private readonly OauthOptions _oauthOptions = App.GetConfig("OAuth", true); + /// /// 服务基础仓储. /// @@ -80,6 +102,16 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient /// private readonly IUserManager _userManager; + /// + /// SqlSugarClient客户端. + /// + private SqlSugarScope _sqlSugarClient; + + /// + /// 多租户配置选项. + /// + private readonly TenantOptions _tenant; + /// /// 初始化一个类型的新实例. /// @@ -91,6 +123,8 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient ISynThirdInfoService synThirdInfoService, ICacheManager cacheManager, IFileManager fileService, + ISqlSugarClient sqlSugarClient, + IOptions tenantOptions, IUserManager userManager) { _repository = userRepository; @@ -101,6 +135,8 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient _cacheManager = cacheManager; _synThirdInfoService = synThirdInfoService; _fileManager = fileService; + _tenant = tenantOptions.Value; + _sqlSugarClient = (SqlSugarScope)sqlSugarClient; } #region GET @@ -140,70 +176,26 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient ErrorStrategy configLockType = (ErrorStrategy)Enum.Parse(typeof(ErrorStrategy), config?.Value); SqlSugarPagedList? data = new SqlSugarPagedList(); - if (childOrgIds.Any()) - { - // 拼接查询 - List>? listQuery = new List>(); - foreach (string item in childOrgIds) - { - var quer = _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.UserId)) - .Where((a, b) => item == a.ObjectId) - .WhereIF(!pageInput.keyword.IsNullOrEmpty(), (a, b) => b.Account.Contains(pageInput.keyword) || b.RealName.Contains(pageInput.keyword)) - .WhereIF(!_userManager.IsAdministrator, a => dataScope.Contains(a.ObjectId)) - .Where((a, b) => b.DeleteMark == null && !b.Id.Equals("admin")) - .Select((a, b) => new UserListOutput - { - id = b.Id, - account = b.Account, - realName = b.RealName, - headIcon = b.HeadIcon, - creatorTime = b.CreatorTime, - gender = b.Gender, - mobilePhone = b.MobilePhone, - sortCode = b.SortCode, - unLockTime = b.UnLockTime, - enabledMark = b.EnabledMark - }); - listQuery.Add(quer); - } - data = await _repository.AsSugarClient().UnionAll(listQuery) - .GroupBy(a => new { a.id, a.account, a.realName, a.creatorTime, a.gender, a.mobilePhone, a.sortCode, a.enabledMark, a.unLockTime }) - .Select(a => new UserListOutput - { - id = a.id, - account = a.account, - realName = a.realName, - creatorTime = a.creatorTime, - gender = a.gender, - mobilePhone = a.mobilePhone, - sortCode = a.sortCode, - enabledMark = SqlFunc.IIF(configLockType == ErrorStrategy.Delay && a.enabledMark == 2 && a.unLockTime < DateTime.Now, 1, a.enabledMark) - }).ToPagedListAsync(input.currentPage, input.pageSize); - var userHeadIcon = await _repository.AsQueryable().Where(x => data.list.Select(xx => xx.id).Contains(x.Id)).Select(x => new { Id = x.Id, headIcon = x.HeadIcon }).ToListAsync(); - foreach (var item in data.list) item.headIcon = "/api/File/Image/userAvatar/" + userHeadIcon.Find(x => x.Id.Equals(item.id)).headIcon; - } - else - { - data = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.UserId)) - .Where((a, b) => b.DeleteMark == null && !b.Id.Equals("admin")) - .WhereIF(!pageInput.keyword.IsNullOrEmpty(), (a, b) => b.Account.Contains(pageInput.keyword) || b.RealName.Contains(pageInput.keyword)) - .WhereIF(!_userManager.IsAdministrator, (a, b) => dataScope.Contains(a.ObjectId)) - .OrderBy((a, b) => b.SortCode).OrderBy((a, b) => b.CreatorTime, OrderByType.Desc).OrderBy((a, b) => b.LastModifyTime, OrderByType.Desc) - .GroupBy((a, b) => new { b.Id, b.Account, b.RealName, b.CreatorTime, b.LastModifyTime, b.Gender, b.MobilePhone, b.SortCode, b.EnabledMark, b.UnLockTime }) - .Select((a, b) => new UserListOutput - { - id = b.Id, - account = b.Account, - realName = b.RealName, - headIcon = SqlFunc.Subqueryable().Where(e => e.Id == b.Id).Select(u => SqlFunc.MergeString("/api/File/Image/userAvatar/", u.HeadIcon)), - creatorTime = b.CreatorTime, - gender = b.Gender, - mobilePhone = b.MobilePhone, - sortCode = b.SortCode, - enabledMark = SqlFunc.IIF(configLockType == ErrorStrategy.Delay && b.EnabledMark == 2 && b.UnLockTime < DateTime.Now, 1, b.EnabledMark) - }).ToPagedListAsync(input.currentPage, input.pageSize); - } + data = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.UserId)) + .Where((a, b) => b.DeleteMark == null && !b.Account.Equals("admin")) + .WhereIF(childOrgIds.Any(), (a, b) => childOrgIds.Contains(a.ObjectId)) + .WhereIF(!pageInput.keyword.IsNullOrEmpty(), (a, b) => b.Account.Contains(pageInput.keyword) || b.RealName.Contains(pageInput.keyword)) + .WhereIF(!_userManager.IsAdministrator, (a, b) => dataScope.Contains(a.ObjectId)) + .OrderBy((a, b) => b.SortCode).OrderBy((a, b) => b.CreatorTime, OrderByType.Desc).OrderBy((a, b) => b.LastModifyTime, OrderByType.Desc) + .GroupBy((a, b) => new { b.Id, b.Account, b.RealName, b.CreatorTime, b.LastModifyTime, b.Gender, b.MobilePhone, b.SortCode, b.EnabledMark, b.UnLockTime }) + .Select((a, b) => new UserListOutput + { + id = b.Id, + account = b.Account, + realName = b.RealName, + headIcon = SqlFunc.Subqueryable().Where(e => e.Id == b.Id).Select(u => SqlFunc.MergeString("/api/File/Image/userAvatar/", u.HeadIcon)), + creatorTime = b.CreatorTime, + gender = b.Gender, + mobilePhone = b.MobilePhone, + sortCode = b.SortCode, + enabledMark = SqlFunc.IIF(configLockType == ErrorStrategy.Delay && b.EnabledMark == 2 && b.UnLockTime < DateTime.Now, 1, b.EnabledMark) + }).ToPagedListAsync(input.currentPage, input.pageSize); #region 处理 用户 多组织 @@ -214,11 +206,8 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient // 获取用户组织集合 item.organizeList = orgUserIdAll.Where(x => x.UserId == item.id).Select(x => x.ObjectId).ToList(); item.organize = string.Join(" ; ", orgTreeNameList.Where(x => item.organizeList.Contains(x.Id)).Select(x => x.Description)); - item.sortCode = 999; - if (item.organizeList.Contains(input.organizeId)) item.sortCode = 0; } - data.list = data.list.OrderBy(x => x.sortCode).ToList(); #endregion return PageResult.SqlSugarPageResult(data); @@ -323,8 +312,7 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient .Where((a, b) => b.ObjectType == "Organize" && orgList.Contains(b.ObjectId)).Where((a, b) => a.EnabledMark == 1 && a.DeleteMark == null) .Where((a, b) => a.RealName.Contains(input.keyword) || a.Account.Contains(input.keyword)) .GroupBy((a, b) => new { a.Id, a.RealName, a.Account, a.EnabledMark }) - .Select((a, b) => new - { + .Select((a, b) => new { id = a.Id, fullName = SqlFunc.MergeString(a.RealName, "/", a.Account), enabledMark = a.EnabledMark, @@ -369,8 +357,7 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient var res = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.UserId == a.Id)) .Where((a, b) => b.ObjectType == "Organize" && b.ObjectId == input.organizeId).Where((a, b) => a.EnabledMark == 1 && a.DeleteMark == null) .GroupBy((a, b) => new { a.Id, a.RealName, a.Account, a.EnabledMark }) - .Select((a, b) => new - { + .Select((a, b) => new { id = a.Id, fullName = SqlFunc.MergeString(a.RealName, "/", a.Account), enabledMark = a.EnabledMark, @@ -527,6 +514,24 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient #region POST + /// + /// 根据用户Id List 获取当前用户Id. + /// + /// + [HttpPost("getDefaultCurrentValueUserId")] + public async Task GetDefaultCurrentValueUserId([FromBody] GetDefaultCurrentValueInput input) + { + if ((input.UserIds == null || !input.UserIds.Any()) && (input.DepartIds == null || !input.DepartIds.Any()) && (input.PositionIds == null || !input.PositionIds.Any()) + && (input.RoleIds == null || !input.RoleIds.Any()) && (input.GroupIds == null || !input.GroupIds.Any())) return new { userId = _userManager.UserId }; + + var userRelationList = _repository.AsSugarClient().Queryable().Select(x => new UserRelationEntity() { UserId = x.UserId, ObjectId = x.ObjectId }).ToList(); + var userIdList = userRelationList.Where(x => input.UserIds.Contains(x.UserId) || input.DepartIds.Contains(x.ObjectId) + || input.PositionIds.Contains(x.ObjectId) || input.RoleIds.Contains(x.ObjectId) || input.GroupIds.Contains(x.ObjectId)).Select(x => x.UserId).ToList(); + + if (userIdList.Contains(_userManager.UserId)) return new { userId = _userManager.UserId }; + else return new { userId = string.Empty }; + } + /// /// 获取. /// @@ -534,16 +539,14 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient [HttpPost("GetUserList")] public async Task GetUserList([FromBody] UserRelationInput input) { - var data = await _repository.AsSugarClient().Queryable((u, org) => new JoinQueryInfos(JoinType.Inner, u.OrganizeId == org.Id)) - .Where((u, org) => u.EnabledMark > 0 && u.DeleteMark == null) - .Where((u, org) => input.userId.Contains(u.Id)) - .Select((u, org) => new OrganizeMemberListOutput() + var data = await _repository.AsQueryable().Where(it => it.EnabledMark > 0 && it.DeleteMark == null) + .Where(it => input.userId.Contains(it.Id)) + .Select(it => new OrganizeMemberListOutput() { - id = u.Id, - fullName = SqlFunc.MergeString(u.RealName, "/", u.Account), - headIcon = SqlFunc.MergeString("/api/File/Image/userAvatar/", u.HeadIcon), - enabledMark = u.EnabledMark, - type = org.FullName, + id = it.Id, + fullName = SqlFunc.MergeString(it.RealName, "/", it.Account), + headIcon = SqlFunc.MergeString("/api/File/Image/userAvatar/", it.HeadIcon), + enabledMark = it.EnabledMark, }).ToListAsync(); data = data.OrderBy(x => input.userId.IndexOf(x.id)).ToList(); @@ -561,6 +564,7 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient var oids = userList.Where(x => x.UserId.Equals(item.id)).Select(x => x.ObjectId).ToList(); var oTree = orgList.Where(x => oids.Contains(x.Id)).Select(x => x.Description).ToList(); item.organize = string.Join(",", oTree); + //item.type = org.fullName; }); } @@ -804,15 +808,12 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient if (input.roleIds != null) input.departIds.AddRange(input.roleIds); if (input.groupIds != null) input.departIds.AddRange(input.groupIds); if (!input.departIds.Any()) return PageResult.SqlSugarPageResult(data); - data = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.UserId)) + var ids = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.UserId)) .Where((a, b) => b.DeleteMark == null) .WhereIF(input.departIds.Any() || input.userIds.Any(), (a, b) => input.departIds.Contains(a.ObjectId) || input.userIds.Contains(b.Id)) .WhereIF(input.pagination.keyword.IsNotEmptyOrNull(), (a, b) => b.Account.Contains(input.pagination.keyword) || b.RealName.Contains(input.pagination.keyword)) - .Select((a, b) => new UserListOutput() - { - id = b.Id - }).Distinct().ToPagedListAsync(input.pagination.currentPage, input.pagination.pageSize); - data = await _repository.AsQueryable().Where(x => data.list.Select(xx => xx.id).Contains(x.Id)).Select(x => new UserListOutput() + .Select((a, b) => b.Id).Distinct().ToListAsync(); + data = await _repository.AsQueryable().Where(x => ids.Contains(x.Id)).Select(x => new UserListOutput() { id = x.Id, organizeId = x.OrganizeId, @@ -821,8 +822,7 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient headIcon = SqlFunc.MergeString("/api/File/Image/userAvatar/", x.HeadIcon), gender = x.Gender, mobilePhone = x.MobilePhone - }).ToPagedListAsync(1, input.pagination.pageSize); - + }).ToPagedListAsync(input.pagination.currentPage, input.pagination.pageSize); if (data.list.Any()) { var orgList = _organizeService.GetOrgListTreeName(); @@ -1075,6 +1075,9 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient } #endregion + + // 单点登录同步 + await syncUserInfo(entity, "create", _userManager.TenantId); } catch (Exception) { @@ -1130,6 +1133,9 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient } #endregion + + // 单点登录同步 + await syncUserInfo(entity, "delete", _userManager.TenantId); } /// @@ -1142,6 +1148,7 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient public async Task Update(string id, [FromBody] UserUpInput input) { UserEntity? oldUserEntity = await _repository.GetFirstAsync(it => it.Id == id); + input.roleId = input.roleId == null ? string.Empty : input.roleId; // 超级管理员 只有 admin 账号才有变更权限 if (_userManager.UserId != oldUserEntity.Id && oldUserEntity.IsAdministrator == 1 && _userManager.Account != "admin") @@ -1233,8 +1240,7 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient try { // 更新用户记录 - int newEntity = await _repository.AsUpdateable(entity).UpdateColumns(it => new - { + int newEntity = await _repository.AsUpdateable(entity).UpdateColumns(it => new { it.Account, it.RealName, it.QuickQuery, @@ -1315,6 +1321,9 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient } #endregion + + // 单点登录同步 + await syncUserInfo(entity, "update", _userManager.TenantId); } /// @@ -1372,7 +1381,9 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient if (!(isOk > 0)) throw Oops.Oh(ErrorCode.D5005); - // 强制将用户提掉线 + // 单点登录同步 + entity.Password = input.userPassword; + await syncUserInfo(entity, "modifyPassword", _userManager.TenantId); } /// @@ -1794,6 +1805,8 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient #endregion + #region PrivateMethod + /// /// 获取集合中的组织 树,根据上级ID. /// @@ -2256,5 +2269,244 @@ public class UsersService : IUsersService, IDynamicApiController, ITransient return output; } + #endregion + #region 单点登录 数据同步 + + /// + /// 同步数据导maxkey. + /// + /// + /// + /// + public async Task syncUserInfo(UserEntity userEntity, string method, string tenantId) + { + try + { + if (_oauthOptions.Enabled) + { + var userName = string.Format("{0}:{1}", _oauthOptions.Pull.UserName, _oauthOptions.Pull.Password).ToBase64String(); + + // http调用结果 + HttpResponse execute = null; + var map = parse(userEntity); + tenantId = tenantId != null && tenantId.Length > 0 ? tenantId : "1"; + if (tenantId.Equals("default")) tenantId = "1"; + map.Add("instId", tenantId); + + // 得到userId + // String username = userEntity.get("id") != null && userEntity.get("id").toString().length() > 0 ? userEntity.get("id").toString() : null; + + Dictionary jsonObject = null; + var resString = string.Empty; + var headers = new Dictionary(); + headers.Add("Authorization", _oauthOptions.Pull.CredentialType + " " + userName); + + if (method.Equals("create")) + { + resString = await (_oauthOptions.Pull.CreateRestAddress + "?appId=" + _oauthOptions.Pull.UserName).SetHeaders(headers).SetBody(map).PostAsStringAsync(); + } + else if (method.Equals("update")) + { + resString = await (_oauthOptions.Pull.ReplaceRestAddress + "?appId=" + _oauthOptions.Pull.UserName).SetHeaders(headers).SetBody(map).PutAsStringAsync(); + } + else if (method.Equals("delete")) + { + resString = await (_oauthOptions.Pull.DeleteRestAddress + "?appId=" + _oauthOptions.Pull.UserName).SetHeaders(headers).SetBody(map).DeleteAsStringAsync(); + } + else if (method.Equals("modifyPassword")) + { + resString = await (_oauthOptions.Pull.ChangePasswordRestAddress + "?appId=" + _oauthOptions.Pull.UserName).SetHeaders(headers).SetBody(map).PostAsStringAsync(); + } + + // else if (method.Equals("modifyPassword")) { + // jsonObject = HttpUtil.httpRequest(_oauthOptions.Pull.getGetRestAddress() + username + // , "GET" + // , null, _oauthOptions.Pull.getCredentialType() + " " + _oauthOptions.Pull.getUserName() + "Og==" + _oauthOptions.Pull.getPassword() + // , null); + // } + } + } + catch (Exception e) + { + + } + } + + private Dictionary parse(UserEntity userEntity) + { + var map = new Dictionary(); + + // map.Add("id", userEntity.get("id")); + map.Add("username", userEntity.Account); + map.Add("password", userEntity.Password); + map.Add("mobile", userEntity.MobilePhone); + map.Add("email", userEntity.Email); + map.Add("gender", (int)userEntity.Gender == 1 ? 2 : 1); + map.Add("createdBy", userEntity.CreatorUserId); + map.Add("createdDate", userEntity.CreatorTime); + map.Add("modifiedBy", userEntity.LastModifyUserId); + map.Add("modifiedDate", userEntity.LastModifyTime); + map.Add("displayName", userEntity.RealName); + + // map.Add("managerId", userEntity.get("managerId")); + // map.Add("departmentId", userEntity.get("organizeId")); + map.Add("loginCount", userEntity.LogSuccessCount); + map.Add("badPasswordCount", userEntity.LogErrorCount); + map.Add("lastLoginIp", userEntity.LastLogIP); + map.Add("lastLoginTime", userEntity.LastLogTime); + map.Add("status", userEntity.EnabledMark != null ? (userEntity.EnabledMark == 1 ? 1 : 4) : 4); + return map; + } + + /// + /// 根据单点服务端消息 同步用户信息到数据库. + /// + /// + [NonAction] + public async Task Receive(string message) + { + bool isSuccess; + var map = new Dictionary(); + try + { + var mqMessage = message.ToObject(); + + // 转成用户实体类 + var userInfo = mqMessage.content.ToObject(); + var userEntity = new UserEntity(); + userEntity.Id = userInfo.id; + userEntity.Account = userInfo.username; + userEntity.MobilePhone = userInfo.mobile; + userEntity.Email = userInfo.email; + userEntity.Gender = userInfo.gender; + userEntity.CreatorTime = userInfo.createdDate.IsNullOrWhiteSpace() ? null : userInfo.createdDate?.ParseToLong().TimeStampToDateTime(); + userEntity.CreatorUserId = userInfo.createdBy; + userEntity.LastModifyUserId = userInfo.modifiedBy; + userEntity.LastModifyTime = userInfo.modifiedDate.IsNullOrWhiteSpace() ? null : userInfo.modifiedDate?.ParseToLong().TimeStampToDateTime(); + userEntity.RealName = userInfo.displayName; + userEntity.LogSuccessCount = userInfo.loginCount; + userEntity.LogErrorCount = userInfo.badPasswordCount; + userEntity.LastLogIP = userInfo.lastLoginIp; + userEntity.LastLogTime = userInfo.lastLoginTime.IsNullOrWhiteSpace() ? null : userInfo.lastLoginTime?.ParseToLong().TimeStampToDateTime(); + userEntity.EnabledMark = userInfo.status == 1 ? 1 : 0; + userEntity.HeadIcon = "001.png"; + + if (_tenant.MultiTenancy) + { + ConnectionConfigOptions options = new ConnectionConfigOptions(); + var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, userInfo.instId); + var response = interFace.GetAsStringAsync().Result; + var result = response.ToObject>(); + if (result.code != 200) + { + throw Oops.Oh(result.msg); + } + else if (result.data.dotnet == null && result.data.linkList == null) + { + throw Oops.Oh(ErrorCode.D1025); + } + else + { + if (result.data.linkList == null || result.data.linkList?.Count == 0) + { + options = JNPFTenantExtensions.GetLinkToOrdinary(userInfo.instId, result.data.dotnet); + } + else if (result.data.dotnet == null) + { + options = JNPFTenantExtensions.GetLinkToCustom(userInfo.instId, result.data.linkList); + } + } + if (!"default".Equals(userInfo.instId) && _tenant.MultiTenancyType.Equals("COLUMN")) + { + _sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == userInfo.instId); + } + else + { + _sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options)); + _sqlSugarClient.ChangeDatabase(userInfo.instId); + } + } + + isSuccess = await process(userEntity, mqMessage.actionType, userInfo.instId); + } + catch (Exception e) + { + // _logger.error("同步用户失败", e); + isSuccess = false; + } + + if (!isSuccess) + { + // _logger.info("消息消费失败:" + message); + } + else + { + // _logger.debug("同步用户信息, {}", JSONObject.toJSONString(map)); + } + + return isSuccess; + } + + /// + /// 保存到数据库处理逻辑. + /// + /// + /// + /// + private async Task process(UserEntity entity, string actionType, string instId) + { + if (actionType.Equals("CREATE_ACTION")) + { + if (_sqlSugarClient.Queryable().Any(x => x.Account.Equals(entity.Account) && x.DeleteMark == null)) return true; + entity.Secretkey = Guid.NewGuid().ToString(); + entity.Password = MD5Encryption.Encrypt(MD5Encryption.Encrypt(CommonConst.DEFAULTPASSWORD) + entity.Secretkey); + + UserRelationEntity? entityRelation = new UserRelationEntity(); + entityRelation.Id = SnowflakeIdHelper.NextId(); + entityRelation.ObjectType = "Organize"; + entityRelation.ObjectId = _sqlSugarClient.Queryable().First(x => x.ParentId.Equals("-1")).Id; + entityRelation.SortCode = 0; + entityRelation.UserId = entity.Id; + entityRelation.CreatorTime = DateTime.Now; + entityRelation.CreatorUserId = entity.CreatorUserId; + _sqlSugarClient.Insertable(entityRelation).ExecuteCommand(); // 批量新增用户关系 + + // 新增用户记录 + return await _sqlSugarClient.Insertable(entity).CallEntityMethod(m => m.Create()).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync() > 0; + } + else if (actionType.Equals("UPDATE_ACTION")) + { + var oldEntity = await _sqlSugarClient.Queryable().FirstAsync(x => x.Account.Equals(entity.Account) && x.DeleteMark == null); + entity.Id = oldEntity.Id; + return await _sqlSugarClient.Updateable(entity).CallEntityMethod(m => m.LastModify()).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync() > 0; + } + else if (actionType.Equals("DELETE_ACTION")) + { + var oldEntity = await _sqlSugarClient.Queryable().FirstAsync(x => x.Account.Equals(entity.Account) && x.DeleteMark == null); + oldEntity.EnabledMark = 0; + + // 同步删除用户 只能 该状态为 : 禁用 + return await _sqlSugarClient.Updateable(oldEntity).CallEntityMethod(m => m.LastModify()).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync() > 0; + + } + else if (actionType.Equals("PASSWORD_ACTION")) + { + return await _sqlSugarClient.Updateable().SetColumns(it => new UserEntity() + { + Password = entity.Password, + ChangePasswordDate = SqlFunc.GetDate(), + LastModifyUserId = _userManager.UserId, + LastModifyTime = SqlFunc.GetDate() + }).Where(it => it.Id == entity.Id).ExecuteCommandAsync() > 0; + } + else + { + //_logger.info("Other Action , will sikp it ..."); + } + + return true; + } + + #endregion } \ No newline at end of file diff --git a/system/Tnb.Systems/System/CommonWordsService.cs b/system/Tnb.Systems/System/CommonWordsService.cs new file mode 100644 index 00000000..89844499 --- /dev/null +++ b/system/Tnb.Systems/System/CommonWordsService.cs @@ -0,0 +1,184 @@ +using JNPF.Common.Core.Manager; +using JNPF.Common.Enums; +using JNPF.Common.Extension; +using JNPF.Common.Filter; +using JNPF.DependencyInjection; +using JNPF.DynamicApiController; +using JNPF.FriendlyException; +using JNPF.Systems.Entitys.Dto.System.CommonWords; +using JNPF.Systems.Entitys.Entity.System; +using JNPF.Systems.Entitys.System; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; + +namespace JNPF.Systems.System; + +/// +/// 常用语. +/// +[ApiDescriptionSettings(Tag = "System", Name = "CommonWords", Order = 200)] +[Route("api/system/[controller]")] +public class CommonWordsService : IDynamicApiController, ITransient +{ + private readonly ISqlSugarRepository _repository; + private readonly IUserManager _userManager; + + /// + /// 初始化一个类型的新实例. + /// + public CommonWordsService( + ISqlSugarRepository repository, + IUserManager userManager) + { + _repository = repository; + _userManager = userManager; + } + + #region Get + + /// + /// 列表. + /// + /// 参数. + /// + [HttpGet("")] + public async Task GetList([FromQuery] PageInputBase input) + { + var list = await _repository.AsSugarClient().Queryable() + .Where(a => a.CommonWordsType == 0 && a.DeleteMark == null) + .WhereIF(input.keyword.IsNotEmptyOrNull(), a => SqlFunc.ToString(a.SystemNames).Contains(input.keyword) || SqlFunc.ToString(a.CommonWordsText).Contains(input.keyword)) + .OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc) + .Select(a => new CommonWordsOutput() + { + id = a.Id, + systemNames = SqlFunc.ToString(a.SystemNames), + commonWordsText = SqlFunc.ToString(a.CommonWordsText), + sortCode = a.SortCode, + enabledMark = a.EnabledMark, + }).ToPagedListAsync(input.currentPage, input.pageSize); + return PageResult.SqlSugarPageResult(list); + } + + /// + /// 获取信息. + /// + /// 主键id. + /// + [HttpGet("{id}")] + public async Task GetInfo(string id) + { + var data = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); + var output = new CommonWordsInput(); + if (data.IsNotEmptyOrNull()) + { + output.id = data.Id; + output.commonWordsText = data.CommonWordsText; + output.sortCode = data.SortCode; + output.enabledMark = data.EnabledMark; + output.commonWordsType = data.CommonWordsType; + foreach (var item in data.SystemIds.Split(",")) + { + var systemEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == item && x.EnabledMark == 1 && x.DeleteMark == null); + if (systemEntity.IsNotEmptyOrNull()) + { + output.systemIds.Add(systemEntity.Id); + output.systemNames.Add(systemEntity.FullName); + } + } + } + return output; + } + + /// + /// 下拉列表. + /// + /// + [HttpGet("Selector")] + public async Task GetSelector() + { + var list = await _repository.AsSugarClient().Queryable() + .Where(a => (a.CommonWordsType == 0 || a.CreatorUserId == _userManager.UserId) && a.SystemIds.Contains(_userManager.User.SystemId) && a.EnabledMark == 1 && a.DeleteMark == null) + .OrderBy(a => a.CommonWordsType, OrderByType.Desc).OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc) + .Select(a => new CommonWordsOutput() + { + id = a.Id, + systemNames = SqlFunc.ToString(a.SystemNames), + commonWordsText = SqlFunc.ToString(a.CommonWordsText), + sortCode = a.SortCode, + enabledMark = a.EnabledMark, + commonWordsType = a.CommonWordsType, + }).ToListAsync(); + return new { list = list }; + } + #endregion + + #region Post + + /// + /// 新建. + /// + /// 实体对象. + /// + [HttpPost("")] + public async Task Create([FromBody] CommonWordsInput input) + { + var entity = input.Adapt(); + if (input.systemIds.Any()) + { + entity.SystemIds = string.Join(",", input.systemIds); + entity.SystemNames = string.Join(",", input.systemNames); + } + else + { + entity.SystemIds = _userManager.User.SystemId; + entity.SystemNames = _repository.AsSugarClient().Queryable().First(x => x.Id == _userManager.User.SystemId && x.DeleteMark == null).FullName; + } + var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); + if (isOk < 1) + throw Oops.Oh(ErrorCode.COM1000); + } + + /// + /// 修改. + /// + /// 主键值. + /// 实体对象. + /// + [HttpPut("{id}")] + public async Task Update(string id, [FromBody] CommonWordsInput input) + { + var entity = input.Adapt(); + if (input.systemIds.Any()) + { + entity.SystemIds = string.Join(",", input.systemIds); + entity.SystemNames = string.Join(",", input.systemNames); + } + else + { + entity.SystemIds = _userManager.User.SystemId; + entity.SystemNames = _repository.AsSugarClient().Queryable().First(x => x.Id == _userManager.User.SystemId && x.DeleteMark == null).FullName; + } + var isOk = await _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); + if (!isOk) + throw Oops.Oh(ErrorCode.COM1001); + } + + /// + /// 删除. + /// + /// 主键. + /// + [HttpDelete("{id}")] + public async Task Delete(string id) + { + var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); + if (entity == null) + throw Oops.Oh(ErrorCode.COM1005); + var isOk = await _repository.AsUpdateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandHasChangeAsync(); + if (!isOk) + throw Oops.Oh(ErrorCode.COM1002); + } + + #endregion +} diff --git a/system/Tnb.Systems/System/DataBaseService.cs b/system/Tnb.Systems/System/DataBaseService.cs index 62904074..35c1bb6d 100644 --- a/system/Tnb.Systems/System/DataBaseService.cs +++ b/system/Tnb.Systems/System/DataBaseService.cs @@ -1,11 +1,7 @@ -using System.ArrayExtensions; -using System.Collections; -using System.ComponentModel.DataAnnotations.Schema; +using System.Collections; using System.Data; using System.Text; -using System.Text.RegularExpressions; using JNPF.Common.Configuration; -using JNPF.Common.Contracts; using JNPF.Common.Core.Manager; using JNPF.Common.Core.Manager.Files; using JNPF.Common.Dtos.DataBase; @@ -26,8 +22,6 @@ using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using NPOI.SS.Formula.Functions; -using Org.BouncyCastle.Asn1.Cms; using SqlSugar; namespace JNPF.Systems; @@ -101,30 +95,41 @@ public class DataBaseService : IDynamicApiController, ITransient /// 过滤条件. /// [HttpGet("{id}/Tables")] - public async Task GetList(string id, [FromQuery] KeywordInput input) + public async Task GetList(string id, [FromQuery] PageInputBase input) { - var link = await _dbLinkService.GetInfo(id); - var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); - var tables = _dataBaseManager.GetDBTableList(tenantLink); - //tables = tables.Where((x, i) => tables.FindIndex(z => z.Name == x.Name) == i).ToList(); - //var output = tables.Adapt>(); - if (!string.IsNullOrEmpty(input.keyword)) + try { - var keyword = input.keyword.ToLower(); - tables = tables.FindAll(d => d.table.ToLower().Contains(keyword) || (d.tableName.IsNotEmptyOrNull() && d.tableName.ToLower().Contains(keyword))); + var link = await _dbLinkService.GetInfo(id); + var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); + var tables = _dataBaseManager.GetTableInfos(tenantLink); + tables = tables.Where((x, i) => tables.FindIndex(z => z.Name == x.Name) == i).ToList();//去重 + var output = tables.Adapt>(); + if (!string.IsNullOrEmpty(input.keyword)) + output = output.FindAll(d => d.table.ToLower().Contains(input.keyword.ToLower()) || (d.tableName.IsNotEmptyOrNull() && d.tableName.ToLower().Contains(input.keyword.ToLower()))); + return PageResult.SqlSugarPageResult(new SqlSugarPagedList() + { + list = output.OrderBy(x => x.table).Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).OrderBy(x => x.table).ToList(), + pagination = new Pagination() + { + CurrentPage = input.currentPage, + PageSize = input.pageSize, + Total = output.Count + } + }); } - if (tenantLink.DbType.ToLower().Equals("dm")) + catch (Exception ex) { - GetTableCount(tables, tenantLink); + return PageResult.SqlSugarPageResult(new SqlSugarPagedList() + { + list = new List(), + pagination = new Pagination() + { + CurrentPage = input.currentPage, + PageSize = input.pageSize, + Total = 0 + } + }); } - return new { list = tables.OrderBy(x => x.table).ToList() }; - //try - //{ - //} - //catch (Exception ex) - //{ - // return new { list = new List() }; - //} } /// @@ -186,8 +191,7 @@ public class DataBaseService : IDynamicApiController, ITransient if (string.IsNullOrEmpty(tableName)) return new PageResult(); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var output = _dataBaseManager.GetDataBaseTableInfo(tenantLink, tableName); - var data = _dataBaseManager.GetData(tenantLink, tableName); - output.hasTableData = data.Rows.Count > 0; + output.hasTableData = _dataBaseManager.IsAnyData(tenantLink, tableName); return output; } @@ -262,6 +266,8 @@ public class DataBaseService : IDynamicApiController, ITransient var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); if (_dataBaseManager.IsAnyTable(tenantLink, input.tableInfo.newTable)) throw Oops.Oh(ErrorCode.D1503); + if (input.tableInfo.newTable.Length >= 30) throw Oops.Oh(ErrorCode.D1514); + if (input.tableFieldList.Any(x => x.field.Length >= 30)) throw Oops.Oh(ErrorCode.D1515); var tableInfo = input.tableInfo.Adapt(); tableInfo.table = input.tableInfo.newTable; var tableFieldList = input.tableFieldList.Adapt>(); @@ -280,10 +286,12 @@ public class DataBaseService : IDynamicApiController, ITransient public async Task Update(string linkId, [FromBody] DatabaseTableUpInput input) { var link = await _dbLinkService.GetInfo(linkId); + if (input.tableInfo.newTable.Length >= 30) throw Oops.Oh(ErrorCode.D1514); + if (input.tableFieldList.Any(x => x.field.Length >= 30)) throw Oops.Oh(ErrorCode.D1515); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var oldFieldList = _dataBaseManager.GetFieldList(tenantLink, input.tableInfo.table).Adapt>(); oldFieldList = _dataBaseManager.ViewDataTypeConversion(oldFieldList, _dataBaseManager.ToDbType(tenantLink.DbType)); - var oldTableInfo = _dataBaseManager.GetDBTableList(tenantLink).Find(m => m.table == input.tableInfo.table).Adapt(); + var oldTableInfo = _dataBaseManager.GetTableInfos(tenantLink).Find(m => m.Name == input.tableInfo.table).Adapt(); var data = _dataBaseManager.GetData(tenantLink, input.tableInfo.table); if (data.Rows.Count > 0) throw Oops.Oh(ErrorCode.D1508); @@ -313,6 +321,7 @@ public class DataBaseService : IDynamicApiController, ITransient { try { + if (input.tableFieldList.Any(x => x.field.Length >= 30)) throw Oops.Oh(ErrorCode.D1515); var link = await _dbLinkService.GetInfo(linkId); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); _dataBaseManager.AddTableColumn(tenantLink, input.tableInfo.table, input.tableFieldList.Adapt>()); @@ -631,7 +640,7 @@ public class DataBaseService : IDynamicApiController, ITransient {"tool_", "Tnb.EquipMgr.Entities" }, {"qc_", "Tnb.QcMgr.Entities" }, }; - var allTables = sugar.DbMaintenance.GetTableInfoList().WhereIF(!string.IsNullOrEmpty(tbName), t=>t.Name == tbName); + var allTables = sugar.DbMaintenance.GetTableInfoList().WhereIF(!string.IsNullOrEmpty(tbName), t => t.Name == tbName); foreach (var tbl in allTables) { var prefix = tbl.Name.Split('_')[0] + "_"; diff --git a/system/Tnb.Systems/System/DataInterfaceService.cs b/system/Tnb.Systems/System/DataInterfaceService.cs index ab5b29ba..e8403e0d 100644 --- a/system/Tnb.Systems/System/DataInterfaceService.cs +++ b/system/Tnb.Systems/System/DataInterfaceService.cs @@ -21,6 +21,7 @@ using JNPF.Common.Security; using JNPF.DatabaseAccessor; using JNPF.DependencyInjection; using JNPF.DynamicApiController; +using JNPF.Extras.DatabaseAccessor.SqlSugar.Models; using JNPF.Extras.Thirdparty.JSEngine; using JNPF.FriendlyException; using JNPF.LinqBuilder; @@ -506,19 +507,65 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController ConnectionString = string.Format($"{App.Configuration["ConnectionStrings:DefaultConnection"]}", result.data.dotnet) }); } - - _sqlSugarClient.ChangeDatabase(tenantId); + if (!"default".Equals(tenantId) && KeyVariable.MultiTenancyType.Equals("COLUMN")) + { + _sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == tenantId); + } + else + { + _sqlSugarClient.ChangeDatabase(tenantId); + } } var interfaceOauthEntity = await _sqlSugarClient.Queryable().FirstAsync(x => x.AppId == appId && x.DeleteMark == null && x.EnabledMark == 1); if (interfaceOauthEntity == null) return null; var ymDate = DateTime.Now.ParseToUnixTime().ToString(); var authorization = GetVerifySignature(interfaceOauthEntity, intefaceId, ymDate); - return new - { + return new { YmDate = ymDate, Authorization = authorization, }; } + + /// + /// 复制. + /// + /// 主键值. + /// + [HttpPost("{id}/Actions/Copy")] + public async Task ActionsCopy(string id) + { + var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); + if (entity == null) + throw Oops.Oh(ErrorCode.COM1005); + var random = RandomExtensions.NextLetterAndNumberString(new Random(), 5).ToLower(); + 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; + var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); + if (isOk < 1) + throw Oops.Oh(ErrorCode.COM1000); + } + + /// + /// 预览接口字段. + /// + /// + /// + [HttpPost("{id}/Actions/GetFields")] + [UnitOfWork] + public async Task GetFields(string id, [FromBody] DataInterfacePreviewInput input) + { + try + { + return (await Preview(id, input)).ToObject>>().FirstOrDefault().Keys.ToList(); + } + catch (Exception e) + { + throw Oops.Oh(ErrorCode.COM1020); + } + } #endregion #region PublicMethod @@ -549,7 +596,7 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController /// 根据不同类型请求接口. /// /// - /// 0 : 分页 1 :详情 ,其他 原始. + /// 0 : 分页 1 :详情 2:数据视图 ,其他 原始. /// /// /// @@ -579,36 +626,61 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController }); } - _sqlSugarClient.ChangeDatabase(tenantId); + if (!"default".Equals(tenantId) && KeyVariable.MultiTenancyType.Equals("COLUMN")) + { + _sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == tenantId); + } + else + { + _sqlSugarClient.ChangeDatabase(tenantId); + } _configId = tenantId; _dbName = result.data.dotnet; } - var data = await _sqlSugarClient.Queryable().FirstAsync(x => x.Id == id && x.DeleteMark == null); + var data = await _sqlSugarClient.CopyNew().Queryable().FirstAsync(x => x.Id == id && x.DeleteMark == null); if (data == null) throw Oops.Oh(ErrorCode.COM1005); // 远端数据(sql过滤) if (input.IsNotEmptyOrNull()) { - var columnList = new List(); - if (input.keyword.IsNotEmptyOrNull()) - input.columnOptions.Split(",").ToList().ForEach(x => columnList.Add(string.Format("{0} like '%{1}%'", x, input.keyword))); - - if (columnList.Any() && !string.IsNullOrWhiteSpace(input.keyword)) - data.Query = string.Format("select * from ({0}) t where {1} ", data.Query.TrimEnd(';'), string.Join(" or ", columnList)); - else if (!string.IsNullOrWhiteSpace(input.relationField) && !string.IsNullOrWhiteSpace(input.keyword)) - data.Query = string.Format("select * from ({0}) t where {1} like '%{2}%' ", data.Query.TrimEnd(';'), input.relationField, input.keyword); - - if (!string.IsNullOrWhiteSpace(input.propsValue) && !string.IsNullOrWhiteSpace(input.id)) - data.Query = string.Format("select * from ({0}) t where {1} = '{2}' ", data.Query.TrimEnd(';'), input.propsValue, input.id); - if (!string.IsNullOrWhiteSpace(input.propsValue) && input.ids.Any()) - data.Query = string.Format("select * from ({0}) t where {1} in ('{2}') ", data.Query.TrimEnd(';'), input.propsValue, string.Join("','", input.ids)); - if (input.columnOptions.IsNotEmptyOrNull() && !string.IsNullOrWhiteSpace(input.keyword)) + if (type == 2 && !2.Equals(data.DataType) && (input.queryJson.IsNotEmptyOrNull() || input.sidx.IsNotEmptyOrNull())) { - var whereStr = new List(); - input.columnOptions.Split(",").ToList().ForEach(item => whereStr.Add(string.Format(" {0} like '%{1}%' ", item, input.keyword))); - data.Query = string.Format("select * from ({0}) t where {1} ", data.Query.TrimEnd(';'), string.Join(" or ", whereStr)); + if (input.queryJson.IsNotEmptyOrNull()) + { + var sqlFields = input.queryJson.ToObject>(); + var whereList = new List(); + foreach (var item in sqlFields) + { + if (item.Key.Contains("jnpf_searchType_equals_")) whereList.Add(string.Format("{0} = '{1}' ", item.Key.Replace("jnpf_searchType_equals_", string.Empty), item.Value)); + else whereList.Add(string.Format("{0} like '%{1}%' ", item.Key, item.Value)); + } + data.Query = string.Format("select * from ({0}) t where {1} ", data.Query.TrimEnd(';'), string.Join(" and ", whereList)); + } + if (input.sidx.IsNotEmptyOrNull()) data.Query = string.Format("{0} order by {1} {2}", data.Query.TrimEnd(';'), input.sidx, input.sort); + } + else + { + var columnList = new List(); + if (input.keyword.IsNotEmptyOrNull()) + input.columnOptions.Split(",").ToList().ForEach(x => columnList.Add(string.Format("{0} like '%{1}%'", x, input.keyword))); + + if (columnList.Any() && !string.IsNullOrWhiteSpace(input.keyword)) + data.Query = string.Format("select * from ({0}) t where {1} ", data.Query.TrimEnd(';'), string.Join(" or ", columnList)); + else if (!string.IsNullOrWhiteSpace(input.relationField) && !string.IsNullOrWhiteSpace(input.keyword)) + data.Query = string.Format("select * from ({0}) t where {1} like '%{2}%' ", data.Query.TrimEnd(';'), input.relationField, input.keyword); + + if (!string.IsNullOrWhiteSpace(input.propsValue) && !string.IsNullOrWhiteSpace(input.id)) + data.Query = string.Format("select * from ({0}) t where {1} = '{2}' ", data.Query.TrimEnd(';'), input.propsValue, input.id); + if (!string.IsNullOrWhiteSpace(input.propsValue) && input.ids.Any()) + data.Query = string.Format("select * from ({0}) t where {1} in ('{2}') ", data.Query.TrimEnd(';'), input.propsValue, string.Join("','", input.ids)); + if (input.columnOptions.IsNotEmptyOrNull() && !string.IsNullOrWhiteSpace(input.keyword)) + { + var whereStr = new List(); + input.columnOptions.Split(",").ToList().ForEach(item => whereStr.Add(string.Format(" {0} like '%{1}%' ", item, input.keyword))); + data.Query = string.Format("select * from ({0}) t where {1} ", data.Query.TrimEnd(';'), string.Join(" or ", whereStr)); + } } if (input.paramList.IsNotEmptyOrNull() && input.paramList.Count > 0) { @@ -625,12 +697,11 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController if (1.Equals(data.DataType)) { var resTable = await GetData(data); - if (type == 0) + if (type == 0 || type == 2) { // 分页 var dt = GetPageToDataTable(resTable, input.currentPage, input.pageSize); - output = new - { + output = new { pagination = new PageResult() { currentPage = input.currentPage, @@ -677,8 +748,7 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController // }); //} resList = resList.FindAll(x => x.Where(xx => xx.Value != null && xx.Value.Contains(input.keyword)).Any()); - output = new - { + output = new { pagination = new PageResult() { currentPage = input.currentPage, @@ -699,6 +769,47 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController return resList.FindAll(x => x.ContainsKey(input.propsValue) && x.Any(it => input.ids.Contains(it.Value))); } } + else if (type == 2) + { + if (input.queryJson.IsNotEmptyOrNull() || input.sidx.IsNotEmptyOrNull()) + { + if (input.queryJson.IsNotEmptyOrNull()) + { + var querList = input.queryJson.ToObject>(); + foreach (var item in querList) + { + if (item.Key.Contains("jnpf_searchType_equals_")) resList = resList.Where(x => x[item.Key.Replace("jnpf_searchType_equals_", "")].Equals(item.Value)).ToList(); + else resList = resList.Where(x => x[item.Key].Contains(item.Value)).ToList(); + } + } + if (input.sidx.IsNotEmptyOrNull()) + { + if (input.sort.Equals("desc")) resList = resList.OrderBy(x => x[input.sidx]).ToList(); + else resList = resList.OrderByDescending(x => x[input.sidx]).ToList(); + } + output = new { + pagination = new PageResult() + { + currentPage = input.currentPage, + pageSize = input.pageSize, + total = resList.Count + }, + list = resList.Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).ToList(), + }; + } + else + { + output = new { + pagination = new PageResult() + { + currentPage = input.currentPage, + pageSize = input.pageSize, + total = resList.Count + }, + list = resList.Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).ToList(), + }; + } + } else { output = result; @@ -800,12 +911,12 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController } else { - dataProcessingResults = resList.ToJsonString(); + dataProcessingResults = resList; } break; // 静态数据 case 2: - dataProcessingResults = resList.ToJsonString(); + dataProcessingResults = resList; break; } if (!dataProcessingResults.IsNullOrEmpty()) @@ -868,11 +979,11 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController var link = new DbLinkEntity(); if (!_sqlSugarClient.AsTenant().IsAnyConnection(_configId)) { - link = await _sqlSugarClient.Queryable().FirstAsync(x => x.Id == dbLinkId && x.DeleteMark == null); + link = await _sqlSugarClient.CopyNew().Queryable().FirstAsync(x => x.Id == dbLinkId && x.DeleteMark == null); } else { - link = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == dbLinkId && x.DeleteMark == null); + link = await _repository.AsSugarClient().CopyNew().Queryable().FirstAsync(x => x.Id == dbLinkId && x.DeleteMark == null); } var tenantLink = link ?? await GetTenantDbLink(); @@ -880,7 +991,7 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController sql = await GetSqlParameter(sql, parameter); if (reqMethod.Equals("3")) { - return _dataBaseManager.GetInterFaceData(tenantLink, sql, parameter.ToArray()); + return _dataBaseManager.GetInterFaceDataCopyNew(tenantLink, sql, parameter.ToArray()); } else { @@ -914,16 +1025,23 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController dicHerader[key.field] = key.defaultValue; } - switch (entity?.RequestMethod) + try { - case "6": - result = (await entity.Path.SetHeaders(dicHerader).SetQueries(dic).GetAsStringAsync()).ToObject(); - break; - case "7": - result = (await entity.Path.SetHeaders(dicHerader).SetBody(dic).PostAsStringAsync()).ToObject(); - break; + switch (entity.RequestMethod) + { + case "6": + result = (await entity.Path.SetHeaders(dicHerader).SetQueries(dic).GetAsStringAsync()).ToObject(); + break; + case "7": + result = (await entity.Path.SetHeaders(dicHerader).SetBody(dic).PostAsStringAsync()).ToObject(); + break; + } } - return result.ContainsKey("data") ? result["data"].ToObject() : result; + catch (Exception e) + { + throw Oops.Oh(ErrorCode.COM1018); + } + return result.ContainsKey("data") && result["data"].IsNotEmptyOrNull() ? result["data"].ToObject() : result; } /// @@ -1158,7 +1276,14 @@ public class DataInterfaceService : IDataInterfaceService, IDynamicApiController }); } - _sqlSugarClient.ChangeDatabase(tenantId); + if (!"default".Equals(tenantId) && KeyVariable.MultiTenancyType.Equals("COLUMN")) + { + _sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == tenantId); + } + else + { + _sqlSugarClient.ChangeDatabase(tenantId); + } _configId = tenantId; _dbName = result.data.dotnet; } diff --git a/system/Tnb.Systems/System/DbLinkService.cs b/system/Tnb.Systems/System/DbLinkService.cs index 6a337e44..3ead4d4b 100644 --- a/system/Tnb.Systems/System/DbLinkService.cs +++ b/system/Tnb.Systems/System/DbLinkService.cs @@ -13,7 +13,6 @@ using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.System; using Mapster; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Caching.Memory; using SqlSugar; namespace JNPF.Systems; @@ -43,21 +42,17 @@ public class DbLinkService : IDbLinkService, IDynamicApiController, ITransient /// private readonly IDataBaseManager _dataBaseManager; - private readonly IMemoryCache _memCache; - /// /// 初始化一个类型的新实例. /// public DbLinkService( ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService, - IDataBaseManager dataBaseManager, - IMemoryCache memCache) + IDataBaseManager dataBaseManager) { _repository = repository; _dictionaryDataService = dictionaryDataService; _dataBaseManager = dataBaseManager; - _memCache = memCache; } #region GET @@ -318,7 +313,7 @@ public class DbLinkService : IDbLinkService, IDynamicApiController, ITransient [NonAction] public async Task GetInfo(string id) { - return await _repository.AsSugarClient().CopyNew().Queryable().FirstAsync(m => m.Id == id && m.DeleteMark == null); + return await _repository.GetFirstAsync(m => m.Id == id && m.DeleteMark == null); } #endregion } \ No newline at end of file diff --git a/system/Tnb.Systems/System/InterfaceOauthService.cs b/system/Tnb.Systems/System/InterfaceOauthService.cs index 52c9ec54..97525968 100644 --- a/system/Tnb.Systems/System/InterfaceOauthService.cs +++ b/system/Tnb.Systems/System/InterfaceOauthService.cs @@ -16,220 +16,221 @@ using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; -namespace JNPF.Systems.System +namespace JNPF.Systems.System; + +/// +/// 接口认证 +/// 版 本:V3.2 +/// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) + /// 日 期:2021-06-01. +/// +[ApiDescriptionSettings(Tag = "System", Name = "InterfaceOauth", Order = 202)] +[Route("api/system/[controller]")] +public class InterfaceOauthService : IDynamicApiController, ITransient { /// - /// 接口认证 - /// 版 本:V3.2 - /// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) - /// 日 期:2021-06-01. + /// 服务基本仓储. /// - [ApiDescriptionSettings(Tag = "System", Name = "InterfaceOauth", Order = 202)] - [Route("api/system/[controller]")] - public class InterfaceOauthService : IDynamicApiController, ITransient + private readonly ISqlSugarRepository _repository; + + /// + /// 用户管理. + /// + private readonly IUserManager _userManager; + + /// + /// 初始化一个类型的新实例. + /// + public InterfaceOauthService( + ISqlSugarRepository repository, + IUserManager userManager) { - /// - /// 服务基本仓储. - /// - private readonly ISqlSugarRepository _repository; + _repository = repository; + _userManager = userManager; + } - /// - /// 用户管理. - /// - private readonly IUserManager _userManager; + #region Get - /// - /// 初始化一个类型的新实例. - /// - public InterfaceOauthService( - ISqlSugarRepository repository, - IUserManager userManager) + /// + /// 信息. + /// + /// 请求参数. + /// + [HttpGet("{id}")] + public async Task GetInfo(string id) + { + var info = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); + var output = info.Adapt(); + if (info.IsNotEmptyOrNull() && info.DataInterfaceIds.IsNotEmptyOrNull()) { - _repository = repository; - _userManager = userManager; - } - - #region Get - - /// - /// 信息. - /// - /// 请求参数. - /// - [HttpGet("{id}")] - public async Task GetInfo(string id) - { - var info = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); - var output = info.Adapt(); - if (info.IsNotEmptyOrNull() && info.DataInterfaceIds.IsNotEmptyOrNull()) - { - var ids = info.DataInterfaceIds.Split(","); - output.list = await _repository.AsSugarClient().Queryable() - .Where(a => ids.Contains(a.Id)) - .Select(a => new DataInterfaceListOutput - { - id = a.Id, - fullName = a.FullName, - enCode = a.EnCode, - path = a.Path, - requestParameters = a.RequestParameters, - dataType = a.DataType, - requestMethod = SqlFunc.IF(a.RequestMethod.Equals("1")).Return("新增").ElseIF(a.RequestMethod.Equals("2")).Return("修改") - .ElseIF(a.RequestMethod.Equals("3")).Return("查询").ElseIF(a.RequestMethod.Equals("4")).Return("删除") - .ElseIF(a.RequestMethod.Equals("5")).Return("存储过程").ElseIF(a.RequestMethod.Equals("6")).Return("Get") - .End("Post") - }).ToListAsync(); - } - return output; - } - - /// - /// 列表. - /// - [HttpGet("")] - public async Task GetList([FromQuery] PageInputBase input) - { - var list = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.CreatorUserId)) - .Where(a => a.DeleteMark == null) - .WhereIF(!string.IsNullOrEmpty(input.keyword), a => a.AppId.Contains(input.keyword) || a.AppName.Contains(input.keyword)) - .OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc) - .Select((a, b) => new InterfaceOauthListOutput - { - id = a.Id, - lastModifyTime = a.LastModifyTime, - enabledMark = a.EnabledMark, - creatorUser = SqlFunc.MergeString(b.RealName, "/", b.Account), - appId = a.AppId, - appName = a.AppName, - usefulLife = a.UsefulLife, - sortCode = a.SortCode, - creatorTime = a.CreatorTime - }).ToPagedListAsync(input.currentPage, input.pageSize); - return PageResult.SqlSugarPageResult(list); - } - - /// - /// 获取秘钥. - /// - /// - [HttpGet("getAppSecret")] - public async Task GetAppSecret() - { - return Guid.NewGuid().ToString().Replace("-", string.Empty); - } - - /// - /// 日志. - /// - /// - /// - /// - [HttpGet("dataInterfaceLog/{id}")] - public async Task GetList(string id, [FromQuery] DataInterfaceLogListQuery input) - { - var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); - var whereLambda = LinqExpression.And(); - if (!input.startTime.IsNullOrEmpty() && !input.endTime.IsNullOrEmpty()) - { - var startTime = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 00:00:00}", input.startTime?.TimeStampToDateTime())); - var endTime = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 23:59:59}", input.endTime?.TimeStampToDateTime())); - whereLambda = whereLambda.And(a => SqlFunc.Between(a.invokTime, startTime, endTime)); - } - var list = await _repository.AsSugarClient().Queryable((a, b, c) => - new JoinQueryInfos(JoinType.Left, b.Id == a.UserId, JoinType.Left, a.InvokId == c.Id)) - .Where(a => a.OauthAppId == entity.AppId) - .WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.UserId.Contains(input.keyword) || a.InvokIp.Contains(input.keyword)) - .Select((a, b, c) => new DataInterfaceLogListOutput + var ids = info.DataInterfaceIds.Split(","); + output.list = await _repository.AsSugarClient().Queryable() + .Where(a => ids.Contains(a.Id)) + .Select(a => new DataInterfaceListOutput { id = a.Id, - fullName = c.FullName, - enCode = c.EnCode, - invokDevice = a.InvokDevice, - invokIp = a.InvokIp, - userId = SqlFunc.MergeString(b.RealName, "/", b.Account), - invokTime = a.InvokTime, - invokType = a.InvokType, - invokWasteTime = a.InvokWasteTime - }).MergeTable().Where(whereLambda).OrderBy(a => a.invokTime).ToPagedListAsync(input.currentPage, input.pageSize); - return PageResult.SqlSugarPageResult(list); + fullName = a.FullName, + enCode = a.EnCode, + path = a.Path, + requestParameters = a.RequestParameters, + dataType = a.DataType, + requestMethod = SqlFunc.IF(a.RequestMethod.Equals("1")).Return("新增").ElseIF(a.RequestMethod.Equals("2")).Return("修改") + .ElseIF(a.RequestMethod.Equals("3")).Return("查询").ElseIF(a.RequestMethod.Equals("4")).Return("删除") + .ElseIF(a.RequestMethod.Equals("5")).Return("存储过程").ElseIF(a.RequestMethod.Equals("6")).Return("Get") + .End("Post") + }).ToListAsync(); } - #endregion - - #region Post - - /// - /// 新增. - /// - /// 请求参数. - /// - [HttpPost("")] - public async Task Create_Api([FromBody] InterfaceOauthInput input) - { - if (await _repository.IsAnyAsync(x => (x.AppId == input.appId || x.AppName == input.appName) && x.DeleteMark == null)) - throw Oops.Oh(ErrorCode.D3001); - var entity = input.Adapt(); - if (input.usefulLife.IsNullOrEmpty() || input.usefulLife == "0") - { - entity.UsefulLife = null; - } - var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); - if (isOk < 1) - throw Oops.Oh(ErrorCode.COM1000); - } - - /// - /// 删除. - /// - /// 请求参数. - /// - [HttpDelete("{id}")] - public async Task Delete(string id) - { - var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); - if (entity == null) - throw Oops.Oh(ErrorCode.COM1005); - var isOk = await _repository.AsUpdateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandHasChangeAsync(); - if (!isOk) - throw Oops.Oh(ErrorCode.COM1002); - } - - /// - /// 修改. - /// - /// id. - /// 请求参数. - /// - [HttpPut("{id}")] - public async Task Update(string id, [FromBody] InterfaceOauthInput input) - { - if (await _repository.IsAnyAsync(x => x.Id != id && (x.AppId == input.appId || x.AppName == input.appName) && x.DeleteMark == null)) - throw Oops.Oh(ErrorCode.COM1004); - var entity = input.Adapt(); - var isOk = await _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); - if (input.usefulLife.IsNullOrEmpty() || input.usefulLife == "0") - { - await _repository.AsUpdateable().SetColumns(it => new InterfaceOauthEntity() - { - UsefulLife = null - }).Where(it => it.Id.Equals(id)).ExecuteCommandHasChangeAsync(); - } - if (!isOk) - throw Oops.Oh(ErrorCode.COM1001); - } - - /// - /// 授权接口. - /// - /// 请求参数. - /// - [HttpPost("saveInterfaceList")] - public async Task SaveInterFaceList([FromBody] InterfaceOauthSaveInput input) - { - var isOk = await _repository.AsSugarClient().Updateable() - .SetColumns(it => it.DataInterfaceIds == input.dataInterfaceIds).Where(x => x.Id == input.interfaceIdentId).ExecuteCommandHasChangeAsync(); - if (!isOk) - throw Oops.Oh(ErrorCode.COM1002); - } - #endregion + return output; } + + /// + /// 列表. + /// + [HttpGet("")] + public async Task GetList([FromQuery] PageInputBase input) + { + var list = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.CreatorUserId)) + .Where(a => a.DeleteMark == null) + .WhereIF(!string.IsNullOrEmpty(input.keyword), a => a.AppId.Contains(input.keyword) || a.AppName.Contains(input.keyword)) + .OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc) + .Select((a, b) => new InterfaceOauthListOutput + { + id = a.Id, + lastModifyTime = a.LastModifyTime, + enabledMark = a.EnabledMark, + creatorUser = SqlFunc.MergeString(b.RealName, "/", b.Account), + appId = a.AppId, + appName = a.AppName, + usefulLife = a.UsefulLife, + sortCode = a.SortCode, + creatorTime = a.CreatorTime + }).ToPagedListAsync(input.currentPage, input.pageSize); + return PageResult.SqlSugarPageResult(list); + } + + /// + /// 获取秘钥. + /// + /// + [HttpGet("getAppSecret")] + public async Task GetAppSecret() + { + return Guid.NewGuid().ToString().Replace("-", string.Empty); + } + + /// + /// 日志. + /// + /// + /// + /// + [HttpGet("dataInterfaceLog/{id}")] + public async Task GetList(string id, [FromQuery] DataInterfaceLogListQuery input) + { + var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); + var whereLambda = LinqExpression.And(); + if (!input.startTime.IsNullOrEmpty() && !input.endTime.IsNullOrEmpty()) + { + var startTime = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 00:00:00}", input.startTime?.TimeStampToDateTime())); + var endTime = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 23:59:59}", input.endTime?.TimeStampToDateTime())); + whereLambda = whereLambda.And(a => SqlFunc.Between(a.invokTime, startTime, endTime)); + } + var list = await _repository.AsSugarClient().Queryable((a, b, c) => + new JoinQueryInfos(JoinType.Left, b.Id == a.UserId, JoinType.Left, a.InvokId == c.Id)) + .Where(a => a.OauthAppId == entity.AppId) + .WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.UserId.Contains(input.keyword) || a.InvokIp.Contains(input.keyword)) + .Select((a, b, c) => new DataInterfaceLogListOutput + { + id = a.Id, + fullName = c.FullName, + enCode = c.EnCode, + invokDevice = a.InvokDevice, + invokIp = a.InvokIp, + userId = SqlFunc.MergeString(b.RealName, "/", b.Account), + invokTime = a.InvokTime, + invokType = a.InvokType, + invokWasteTime = a.InvokWasteTime + }).MergeTable().Where(whereLambda).OrderBy(a => a.invokTime).ToPagedListAsync(input.currentPage, input.pageSize); + return PageResult.SqlSugarPageResult(list); + } + + #endregion + + #region Post + + /// + /// 新增. + /// + /// 请求参数. + /// + [HttpPost("")] + public async Task Create_Api([FromBody] InterfaceOauthInput input) + { + if (await _repository.IsAnyAsync(x => (x.AppId == input.appId || x.AppName == input.appName) && x.DeleteMark == null)) + throw Oops.Oh(ErrorCode.D3001); + var entity = input.Adapt(); + if (input.usefulLife.IsNullOrEmpty() || input.usefulLife == "0") + { + entity.UsefulLife = null; + } + var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); + if (isOk < 1) + throw Oops.Oh(ErrorCode.COM1000); + } + + /// + /// 删除. + /// + /// 请求参数. + /// + [HttpDelete("{id}")] + public async Task Delete(string id) + { + var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); + if (entity == null) + throw Oops.Oh(ErrorCode.COM1005); + var isOk = await _repository.AsUpdateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandHasChangeAsync(); + if (!isOk) + throw Oops.Oh(ErrorCode.COM1002); + } + + /// + /// 修改. + /// + /// id. + /// 请求参数. + /// + [HttpPut("{id}")] + public async Task Update(string id, [FromBody] InterfaceOauthInput input) + { + if (await _repository.IsAnyAsync(x => x.Id != id && (x.AppId == input.appId || x.AppName == input.appName) && x.DeleteMark == null)) + throw Oops.Oh(ErrorCode.COM1004); + var entity = input.Adapt(); + var isOk = await _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); + if (input.usefulLife.IsNullOrEmpty() || input.usefulLife == "0") + { + await _repository.AsUpdateable().SetColumns(it => new InterfaceOauthEntity() + { + UsefulLife = null + }).Where(it => it.Id.Equals(id)).ExecuteCommandHasChangeAsync(); + } + if (!isOk) + throw Oops.Oh(ErrorCode.COM1001); + } + + /// + /// 授权接口. + /// + /// 请求参数. + /// + [HttpPost("saveInterfaceList")] + public async Task SaveInterFaceList([FromBody] InterfaceOauthSaveInput input) + { + var isOk = await _repository.AsSugarClient().Updateable() + .SetColumns(it => it.DataInterfaceIds == input.dataInterfaceIds).Where(x => x.Id == input.interfaceIdentId).ExecuteCommandHasChangeAsync(); + if (!isOk) + throw Oops.Oh(ErrorCode.COM1002); + } + + #endregion } diff --git a/system/Tnb.Systems/System/MessageTemplateService.cs b/system/Tnb.Systems/System/MessageTemplateService.cs index 7ff4fc30..0bd8ffea 100644 --- a/system/Tnb.Systems/System/MessageTemplateService.cs +++ b/system/Tnb.Systems/System/MessageTemplateService.cs @@ -375,7 +375,8 @@ public class MessageTemplateService : IMessageTemplateService, IDynamicApiContro Account = sysconfig.emailAccount, Password = sysconfig.emailPassword, SMTPHost = sysconfig.emailSmtpHost, - SMTPPort = sysconfig.emailSmtpPort.ParseToInt() + SMTPPort = sysconfig.emailSmtpPort.ParseToInt(), + Ssl = sysconfig.emailSsl, }, mailModel); } diff --git a/system/Tnb.Systems/System/ModuleColumnService.cs b/system/Tnb.Systems/System/ModuleColumnService.cs index 1ff7de3e..27d2a174 100644 --- a/system/Tnb.Systems/System/ModuleColumnService.cs +++ b/system/Tnb.Systems/System/ModuleColumnService.cs @@ -1,4 +1,5 @@ -using JNPF.Common.Core.Manager; +using JNPF.Common.Const; +using JNPF.Common.Core.Manager; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; @@ -120,7 +121,7 @@ public class ModuleColumnService : IModuleColumnService, IDynamicApiController, var visualDevId = moduleEntity.PropertyJson.ToObject()["moduleId"].ToString(); var visualDevEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == visualDevId && x.DeleteMark == null); var defaultColumnList = visualDevEntity.ColumnData.ToObject().defaultColumnList; - var uelessList = new List() { "PsdInput", "colorPicker", "rate", "slider", "divider", "uploadImg", "uploadFz", "editor", "JNPFText", "relationFormAttr", "popupAttr", "groupTitle" }; + var uelessList = new List() { "PsdInput", JnpfKeyConst.COLORPICKER, JnpfKeyConst.RATE, JnpfKeyConst.SLIDER, JnpfKeyConst.DIVIDER, JnpfKeyConst.UPLOADIMG, JnpfKeyConst.UPLOADFZ, JnpfKeyConst.EDITOR, JnpfKeyConst.JNPFTEXT, JnpfKeyConst.RELATIONFORMATTR, JnpfKeyConst.POPUPATTR, JnpfKeyConst.GROUPTITLE }; return defaultColumnList?.Where(x => !uelessList.Contains(x.jnpfKey)).Select(x => new { field = x.prop, fieldName = x.label }).ToList(); } #endregion diff --git a/system/Tnb.Systems/System/ModuleDataAuthorizeService.cs b/system/Tnb.Systems/System/ModuleDataAuthorizeService.cs index 345fd5fc..05a0deba 100644 --- a/system/Tnb.Systems/System/ModuleDataAuthorizeService.cs +++ b/system/Tnb.Systems/System/ModuleDataAuthorizeService.cs @@ -73,7 +73,7 @@ public class ModuleDataAuthorizeService : IModuleDataAuthorizeService, IDynamicA type = a.Type, conditionSymbol = a.ConditionSymbol, conditionText = a.ConditionText, - conditionSymbolName = a.ConditionSymbol.Replace("Equal", "等于").Replace("Included", "包含").Replace("GreaterThan", "大于").Replace("LessThan", "小于").Replace("Not", "不").Replace("Or", ""), + conditionSymbolName = SqlFunc.ToString(a.ConditionSymbol).Replace("Equal", "等于").Replace("Included", "包含").Replace("GreaterThan", "大于").Replace("LessThan", "小于").Replace("Not", "不").Replace("Or", ""), bindTable = a.BindTable, fieldRule = a.FieldRule, enCode = SqlFunc.IF(b.Type == 2 && a.FieldRule == 1 && !SqlFunc.IsNullOrEmpty(a.BindTable)).Return(a.EnCode.Replace("jnpf_" + a.BindTable + "_jnpf_", "")) diff --git a/system/Tnb.Systems/System/OnlineUserService.cs b/system/Tnb.Systems/System/OnlineUserService.cs index bd1e9c17..7f99e4dd 100644 --- a/system/Tnb.Systems/System/OnlineUserService.cs +++ b/system/Tnb.Systems/System/OnlineUserService.cs @@ -142,7 +142,7 @@ public class OnlineUserService : IDynamicApiController, ITransient /// public async Task DelUserInfo(string tenantId, string userId) { - var cacheKey = string.Format("{0}{1}_{2}", CommonConst.CACHEKEYUSER, tenantId, userId); + var cacheKey = string.Format("{0}:{1}:{2}", tenantId, CommonConst.CACHEKEYUSER, userId); return await _cacheManager.DelAsync(cacheKey); } } \ No newline at end of file diff --git a/system/Tnb.Systems/System/PrintDevService.cs b/system/Tnb.Systems/System/PrintDevService.cs index 80f2ac36..9af13070 100644 --- a/system/Tnb.Systems/System/PrintDevService.cs +++ b/system/Tnb.Systems/System/PrintDevService.cs @@ -209,7 +209,7 @@ public class PrintDevService : IDynamicApiController, ITransient var fieldModel = new PrintDevFieldModel() { - id = index == 0 ? "headTable" : "childrenDataTable" + (index-1), + id = index == 0 ? "headTable" : "childrenDataTable" + (index - 1), parentId = "struct", fullName = index == 0 ? "主表" : "子表" + (index - 1), }; @@ -228,51 +228,37 @@ public class PrintDevService : IDynamicApiController, ITransient [HttpGet("Data")] public async Task GetData([FromQuery] PrintDevSqlDataQuery input) { - var output = new PrintDevDataOutput(); - var entity = await GetInfo(input.id); - if (entity == null) - throw Oops.Oh(ErrorCode.COM1005); - var link = await _dbLinkService.GetInfo(entity.DbLinkId); - var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); - var parameter = new List() - { - new SugarParameter("@formId", input.formId) - }; - var sqlList = entity.SqlTemplate.ToList(); - var dataTable = _dataBaseManager.GetInterFaceData(tenantLink, sqlList.FirstOrDefault().sql, parameter.ToArray()); - var dic = DateConver(DataTableToDicList(dataTable)).FirstOrDefault(); - for (int i = 1; i < sqlList.Count; i++) - { - if (sqlList[i].sql.IsNullOrEmpty()) - throw Oops.Oh(ErrorCode.COM1005); - var childDataTable = _dataBaseManager.GetInterFaceData(tenantLink, sqlList[i].sql, parameter.ToArray()); - if (childDataTable.Rows.Count > 0) - dic.Add("childrenDataTable" + (i - 1), DateConver(DataTableToDicList(childDataTable))); - } - - output.printData = dic; - output.printTemplate = entity.PrintTemplate; - output.operatorRecordList = await _repository.AsSugarClient().Queryable() - .Where(a => a.TaskId == input.formId) - .Select(a => new PrintDevDataModel() - { - id = a.Id, - handleId = a.HandleId, - handleOpinion = a.HandleOpinion, - handleStatus = a.HandleStatus, - nodeCode = a.NodeCode, - handleTime = a.HandleTime, - nodeName = a.NodeName, - signImg = a.SignImg, - taskId = a.TaskId, - operatorId = SqlFunc.Subqueryable().Where(u => u.Id == a.OperatorId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), - userName = SqlFunc.Subqueryable().Where(u => u.Id == a.HandleId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), - status = a.Status, - taskNodeId = a.TaskNodeId, - taskOperatorId = a.TaskOperatorId, - }).ToListAsync(); + var output = await GetPrintDevDataOutput(input.id, input.formId); return output; } + + /// + /// 模板数据. + /// + /// + /// + [HttpGet("BatchData")] + public async Task GetBatchData([FromQuery] PrintDevSqlDataQuery input) + { + var output = new List(); + foreach (var formId in input.formId.Split(',')) + { + var data = await GetPrintDevDataOutput(input.id, formId); + output.Add(data); + } + return output; + } + + /// + /// 模板列表. + /// + /// + /// + [HttpPost("getListOptions")] + public async Task GetListOptions([FromBody] PrintDevSqlDataQuery input) + { + return _repository.GetList(x => input.ids.Contains(x.Id)).Select(x => new { id = x.Id, fullName = x.FullName }).ToList(); + } #endregion #region Post @@ -362,6 +348,8 @@ public class PrintDevService : IDynamicApiController, ITransient entity.FullName = entity.FullName + "副本" + random; entity.EnabledMark = 0; entity.EnCode += random; + entity.LastModifyTime = null; + entity.LastModifyUserId = null; if (entity.FullName.Length >= 50 || entity.EnCode.Length >= 50) throw Oops.Oh(ErrorCode.COM1009); var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); @@ -407,6 +395,60 @@ public class PrintDevService : IDynamicApiController, ITransient #region PrivateMethod + /// + /// 模板数据. + /// + /// + /// + /// + private async Task GetPrintDevDataOutput(string id, string formId) + { + var output = new PrintDevDataOutput(); + var entity = await GetInfo(id); + if (entity == null) + throw Oops.Oh(ErrorCode.D9010); + var link = await _dbLinkService.GetInfo(entity.DbLinkId); + var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); + var parameter = new List() + { + new SugarParameter("@formId", formId) + }; + var sqlList = entity.SqlTemplate.ToList(); + var dataTable = _dataBaseManager.GetInterFaceData(tenantLink, sqlList.FirstOrDefault().sql, parameter.ToArray()); + var dic = DateConver(DataTableToDicList(dataTable)).FirstOrDefault(); + for (int i = 1; i < sqlList.Count; i++) + { + if (sqlList[i].sql.IsNullOrEmpty()) + throw Oops.Oh(ErrorCode.COM1005); + var childDataTable = _dataBaseManager.GetInterFaceData(tenantLink, sqlList[i].sql, parameter.ToArray()); + if (childDataTable.Rows.Count > 0) + dic.Add("childrenDataTable" + (i - 1), DateConver(DataTableToDicList(childDataTable))); + } + + output.printData = dic; + output.printTemplate = entity.PrintTemplate; + output.operatorRecordList = await _repository.AsSugarClient().Queryable() + .Where(a => a.TaskId == formId) + .Select(a => new PrintDevDataModel() + { + id = a.Id, + handleId = a.HandleId, + handleOpinion = a.HandleOpinion, + handleStatus = a.HandleStatus, + nodeCode = a.NodeCode, + handleTime = a.HandleTime, + nodeName = a.NodeName, + signImg = a.SignImg, + taskId = a.TaskId, + operatorId = SqlFunc.Subqueryable().Where(u => u.Id == a.OperatorId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), + userName = SqlFunc.Subqueryable().Where(u => u.Id == a.HandleId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), + status = a.Status, + taskNodeId = a.TaskNodeId, + taskOperatorId = a.TaskOperatorId, + }).ToListAsync(); + return output; + } + /// /// 获取字段模型. /// diff --git a/system/Tnb.Systems/System/PrintLogService.cs b/system/Tnb.Systems/System/PrintLogService.cs new file mode 100644 index 00000000..4d038345 --- /dev/null +++ b/system/Tnb.Systems/System/PrintLogService.cs @@ -0,0 +1,105 @@ +using JNPF.Common.Core.Manager; +using JNPF.Common.Enums; +using JNPF.Common.Filter; +using JNPF.Common.Security; +using JNPF.DependencyInjection; +using JNPF.DynamicApiController; +using JNPF.FriendlyException; +using JNPF.LinqBuilder; +using JNPF.Systems.Entitys.Dto.System.PrintLog; +using JNPF.Systems.Entitys.Entity.System; +using JNPF.Systems.Entitys.Permission; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using JNPF.Common.Extension; + +namespace JNPF.Systems.System; + +/// +/// 打印模板日志 +/// 版 本:V3.2 +/// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) +/// 作 者:JNPF开发平台组 +/// 日 期:2021-06-01. +/// +[ApiDescriptionSettings(Tag = "System", Name = "PrintLog", Order = 200)] +[Route("api/system/[controller]")] +public class PrintLogService : IDynamicApiController, ITransient +{ + /// + /// 服务基础仓储. + /// + private readonly ISqlSugarRepository _repository; + + /// + /// 用户管理. + /// + private readonly IUserManager _userManager; + + /// + /// 初始化一个类型的新实例. + /// + public PrintLogService( + ISqlSugarRepository repository, + IUserManager userManager) + { + _repository = repository; + _userManager = userManager; + } + + #region Get + /// + /// 列表(分页). + /// + /// 请求参数. + /// + [HttpGet("{id}")] + public async Task GetList(string id, [FromQuery] PrintLogQuery input) + { + var whereLambda = LinqExpression.And(); + whereLambda = whereLambda.And(x => x.PrintId == id); + var start = new DateTime(); + var end = new DateTime(); + if (input.endTime != null && input.startTime != null) + { + start = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 00:00:00}", input.startTime?.TimeStampToDateTime())); + end = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 23:59:59}", input.endTime?.TimeStampToDateTime())); + whereLambda = whereLambda.And(x => SqlFunc.Between(x.PrintTime, start, end)); + } + if (!string.IsNullOrEmpty(input.keyword)) + whereLambda = whereLambda.And(m => m.PrintTitle.Contains(input.keyword)); + var list = await _repository.AsQueryable().Where(whereLambda).OrderBy(x => x.PrintTime, OrderByType.Desc) + .Select(a => new PrintLogOutuut + { + id = a.Id, + printId = a.PrintId, + printMan = SqlFunc.Subqueryable().Where(u => u.Id == a.PrintMan).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), + printNum = a.PrintNum, + printTime = a.PrintTime, + printTitle = a.PrintTitle + }) + .ToPagedListAsync(input.currentPage, input.pageSize); + return PageResult.SqlSugarPageResult(list); + } + #endregion + + #region Post + /// + /// 新增. + /// + /// 请求参数. + /// + [HttpPost("save")] + public async Task Delete([FromBody] PrintLogOutuut input) + { + var entity = input.Adapt(); + entity.Id= SnowflakeIdHelper.NextId(); + entity.PrintMan = _userManager.UserId; + entity.PrintTime = DateTime.Now; + var isOk = await _repository.AsInsertable(entity).ExecuteCommandAsync(); + if (isOk < 1) + throw Oops.Oh(ErrorCode.COM1000); + } + #endregion +} diff --git a/system/Tnb.Systems/System/SysCacheService.cs b/system/Tnb.Systems/System/SysCacheService.cs index 006003ce..ed324a61 100644 --- a/system/Tnb.Systems/System/SysCacheService.cs +++ b/system/Tnb.Systems/System/SysCacheService.cs @@ -178,7 +178,7 @@ public class SysCacheService : IDynamicApiController, ITransient /// private async Task DelUserInfo(string tenantId, string userId) { - var cacheKey = string.Format("{0}{1}_{2}", CommonConst.CACHEKEYUSER, tenantId, userId); + var cacheKey = string.Format("{0}:{1}:{2}", tenantId, CommonConst.CACHEKEYUSER, userId); return await _cacheManager.DelAsync(cacheKey); } } diff --git a/system/Tnb.Systems/System/SysConfigService.cs b/system/Tnb.Systems/System/SysConfigService.cs index ae1109a1..23c44693 100644 --- a/system/Tnb.Systems/System/SysConfigService.cs +++ b/system/Tnb.Systems/System/SysConfigService.cs @@ -176,7 +176,7 @@ public class SysConfigService : ISysConfigService, IDynamicApiController, ITrans [UnitOfWork] public async Task SetAdminList([FromBody] SetAdminInput input) { - await _repository.AsSugarClient().Updateable().SetColumns(x => x.IsAdministrator == 0).Where(x => x.IsAdministrator == 1 && !x.Id.Equals("admin")).ExecuteCommandAsync(); + await _repository.AsSugarClient().Updateable().SetColumns(x => x.IsAdministrator == 0).Where(x => x.IsAdministrator == 1 && !x.Account.Equals("admin")).ExecuteCommandAsync(); await _repository.AsSugarClient().Updateable().SetColumns(x => x.IsAdministrator == 1).Where(x => input.adminIds.Contains(x.Id)).ExecuteCommandAsync(); } diff --git a/system/Tnb.Systems/System/SystemService.cs b/system/Tnb.Systems/System/SystemService.cs index c81e0ca4..a7cb7e81 100644 --- a/system/Tnb.Systems/System/SystemService.cs +++ b/system/Tnb.Systems/System/SystemService.cs @@ -1,4 +1,5 @@ -using JNPF.Common.Const; +using Aop.Api.Domain; +using JNPF.Common.Const; using JNPF.Common.Core.Handlers; using JNPF.Common.Core.Manager; using JNPF.Common.Enums; @@ -70,7 +71,7 @@ public class SystemService : IDynamicApiController, ITransient /// 参数. /// [HttpGet("")] - public async Task GetList([FromQuery] KeywordInput input) + public async Task GetList([FromQuery] SystemQuery input) { var authorIds = await _repository.AsSugarClient().Queryable() .Where(x => x.ItemType.Equals("system") && x.ObjectType.Equals("Role") && _userManager.Roles.Contains(x.ObjectId)).Select(x => x.ItemId).ToListAsync(); @@ -81,6 +82,8 @@ public class SystemService : IDynamicApiController, ITransient whereLambda = whereLambda.And(x => authorIds.Contains(x.Id)); if (input.keyword.IsNotEmptyOrNull()) whereLambda = whereLambda.And(x => x.FullName.Contains(input.keyword) || x.EnCode.Contains(input.keyword)); + if (input.enableMark.IsNotEmptyOrNull()) + whereLambda = whereLambda.And(x => x.EnabledMark == SqlFunc.ToInt32(input.enableMark)); var output = (await _repository.AsQueryable().Where(whereLambda).OrderBy(a => a.SortCode).OrderByDescending(a => a.CreatorTime).ToListAsync()).Adapt>(); return new { list = output }; } @@ -215,7 +218,7 @@ public class SystemService : IDynamicApiController, ITransient allUserOnlineList.RemoveAll((x) => x.connectionId == item.connectionId); // 删除用户登录信息缓存. - var mCacheKey = string.Format("{0}{1}_{2}", CommonConst.CACHEKEYUSER, tenantId, item.userId); + var mCacheKey = string.Format("{0}:{1}:{2}", tenantId, CommonConst.CACHEKEYUSER, item.userId); await _cacheManager.DelAsync(mCacheKey); }); await _cacheManager.SetAsync(cacheKey, allUserOnlineList); diff --git a/taskschedule/Tnb.TaskScheduler.Entitys/Entity/JobDetails.cs b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/JobDetails.cs new file mode 100644 index 00000000..c3b127a0 --- /dev/null +++ b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/JobDetails.cs @@ -0,0 +1,81 @@ +using JNPF.TaskScheduler.Entitys.Enum; +using SqlSugar; + +namespace JNPF.TaskScheduler.Entitys; + +[SugarTable("JobDetails", "作业信息表")] +[Tenant("JNPF-Job")] +public class JobDetails +{ + /// + /// Id. + /// + [SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true, IsIdentity = true)] + public virtual long Id { get; set; } + + /// + /// 作业 Id. + /// + [SugarColumn(ColumnDescription = "作业Id")] + public virtual string JobId { get; set; } + + /// + /// 组名称. + /// + [SugarColumn(ColumnDescription = "组名称")] + public string? GroupName { get; set; } + + /// + /// 作业类型 FullName. + /// + [SugarColumn(ColumnDescription = "作业类型")] + public string? JobType { get; set; } + + /// + /// 程序集 Name. + /// + [SugarColumn(ColumnDescription = "程序集")] + public string? AssemblyName { get; set; } + + /// + /// 描述信息. + /// + [SugarColumn(ColumnDescription = "描述信息")] + public string? Description { get; set; } + + /// + /// 是否并行执行. + /// + [SugarColumn(ColumnDescription = "是否并行执行")] + public bool Concurrent { get; set; } = true; + + /// + /// 是否扫描特性触发器. + /// + [SugarColumn(ColumnDescription = "是否扫描特性触发器")] + public bool IncludeAnnotations { get; set; } = false; + + /// + /// 额外数据. + /// + [SugarColumn(ColumnDescription = "额外数据", ColumnDataType = "longtext,text,clob")] + public string? Properties { get; set; } = "{}"; + + /// + /// 更新时间. + /// + [SugarColumn(ColumnDescription = "更新时间")] + public DateTime? UpdatedTime { get; set; } + + /// + /// 作业创建类型. + /// + [SugarColumn(ColumnDescription = "作业创建类型")] + public RequestTypeEnum CreateType { get; set; } = RequestTypeEnum.BuiltIn; + + /// + /// 脚本代码. + /// + [SugarColumn(ColumnDescription = "脚本代码", ColumnDataType = StaticConfig.CodeFirst_BigString)] + public string? ScriptCode { get; set; } +} \ No newline at end of file diff --git a/taskschedule/Tnb.TaskScheduler.Entitys/Entity/JobTriggers.cs b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/JobTriggers.cs new file mode 100644 index 00000000..a1a7abcc --- /dev/null +++ b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/JobTriggers.cs @@ -0,0 +1,142 @@ +using JNPF.Schedule; +using SqlSugar; + +namespace JNPF.TaskScheduler.Entitys; + +[SugarTable("JobTriggers", "作业触发器表")] +[Tenant("JNPF-Job")] +public class JobTriggers +{ + /// + /// Id. + /// + [SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true, IsIdentity = true)] + public virtual long Id { get; set; } + + /// + /// 触发器 Id. + /// + [SugarColumn(ColumnDescription = "触发器Id")] + public virtual string TriggerId { get; set; } + + /// + /// 作业 Id. + /// + [SugarColumn(ColumnDescription = "作业Id")] + public virtual string JobId { get; set; } + + /// + /// 触发器类型 FullName. + /// + [SugarColumn(ColumnDescription = "触发器类型")] + public string? TriggerType { get; set; } + + /// + /// 程序集 Name. + /// + [SugarColumn(ColumnDescription = "程序集")] + public string? AssemblyName { get; set; } + + /// + /// 参数. + /// + [SugarColumn(ColumnDescription = "参数")] + public string? Args { get; set; } + + /// + /// 描述信息. + /// + [SugarColumn(ColumnDescription = "描述信息")] + public string? Description { get; set; } + + /// + /// 状态. + /// + [SugarColumn(ColumnDescription = "状态")] + public TriggerStatus Status { get; set; } = TriggerStatus.Ready; + + /// + /// 起始时间. + /// + [SugarColumn(ColumnDescription = "起始时间")] + public DateTime? StartTime { get; set; } + + /// + /// 结束时间. + /// + [SugarColumn(ColumnDescription = "结束时间")] + public DateTime? EndTime { get; set; } + + /// + /// 最近运行时间. + /// + [SugarColumn(ColumnDescription = "最近运行时间")] + public DateTime? LastRunTime { get; set; } + + /// + /// 下一次运行时间. + /// + [SugarColumn(ColumnDescription = "下一次运行时间")] + public DateTime? NextRunTime { get; set; } + + /// + /// 触发次数. + /// + [SugarColumn(ColumnDescription = "触发次数")] + public long NumberOfRuns { get; set; } + + /// + /// 最大触发次数(0:不限制,n:N次. + /// + [SugarColumn(ColumnDescription = "最大触发次数")] + public long MaxNumberOfRuns { get; set; } + + /// + /// 出错次数. + /// + [SugarColumn(ColumnDescription = "出错次数")] + public long NumberOfErrors { get; set; } + + /// + /// 最大出错次数(0:不限制,n:N次). + /// + [SugarColumn(ColumnDescription = "最大出错次数")] + public long MaxNumberOfErrors { get; set; } + + /// + /// 重试次数. + /// + [SugarColumn(ColumnDescription = "重试次数")] + public int NumRetries { get; set; } + + /// + /// 重试间隔时间(ms). + /// + [SugarColumn(ColumnDescription = "重试间隔时间(ms)")] + public int RetryTimeout { get; set; } = 1000; + + /// + /// 是否立即启动. + /// + [SugarColumn(ColumnDescription = "是否立即启动")] + public bool StartNow { get; set; } = true; + + /// + /// 是否启动时执行一次. + /// + [SugarColumn(ColumnDescription = "是否启动时执行一次")] + public bool RunOnStart { get; set; } = false; + + /// + /// 是否在启动时重置最大触发次数等于一次的作业. + /// + /// 解决因持久化数据已完成一次触发但启动时不再执行的问题 + [SugarColumn(ColumnDescription = "是否在启动时重置最大触发次数等于一次的作业")] + public bool ResetOnlyOnce { get; set; } = true; + + /// + /// 更新时间. + /// + [SugarColumn(ColumnDescription = "更新时间")] + public DateTime? UpdatedTime { get; set; } +} \ No newline at end of file diff --git a/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskEntity.cs b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskEntity.cs index 72337b30..acccd160 100644 --- a/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskEntity.cs +++ b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskEntity.cs @@ -2,7 +2,7 @@ using JNPF.Common.Contracts; using SqlSugar; -namespace JNPF.TaskScheduler.Entitys.Entity; +namespace JNPF.TaskScheduler.Entitys; /// /// 定时任务 @@ -11,7 +11,6 @@ namespace JNPF.TaskScheduler.Entitys.Entity; /// 日 期:2021-06-01 . /// [SugarTable("BASE_TIMETASK")] -[Tenant(ClaimConst.TENANTID)] public class TimeTaskEntity : CLDEntityBase { /// diff --git a/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskLogEntity.cs b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskLogEntity.cs index 1f8677c7..9f070550 100644 --- a/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskLogEntity.cs +++ b/taskschedule/Tnb.TaskScheduler.Entitys/Entity/TimeTaskLogEntity.cs @@ -2,7 +2,7 @@ using JNPF.Common.Contracts; using SqlSugar; -namespace JNPF.TaskScheduler.Entitys.Entity; +namespace JNPF.TaskScheduler.Entitys; /// /// 定时任务日志 diff --git a/taskschedule/Tnb.TaskScheduler.Entitys/Enum/RequestTypeEnum.cs b/taskschedule/Tnb.TaskScheduler.Entitys/Enum/RequestTypeEnum.cs index 5c5a79ec..1b9f1840 100644 --- a/taskschedule/Tnb.TaskScheduler.Entitys/Enum/RequestTypeEnum.cs +++ b/taskschedule/Tnb.TaskScheduler.Entitys/Enum/RequestTypeEnum.cs @@ -1,23 +1,27 @@ -namespace JNPF.TaskScheduler.Entitys.Enum +using System.ComponentModel; + +namespace JNPF.TaskScheduler.Entitys.Enum; + +/// +/// http请求类型. +/// +public enum RequestTypeEnum { /// - /// http请求类型. + /// 内置. /// - public enum RequestTypeEnum - { - /// - /// Api数据. - /// - Api = 1, + [Description("内置")] + BuiltIn = 0, - /// - /// SQL操作. - /// - Sql = 2, + /// + /// 脚本. + /// + [Description("脚本")] + Script = 1, - /// - /// 执行本地任务. - /// - Run = 3, - } + /// + /// HTTP请求. + /// + [Description("HTTP请求")] + Http = 2, } diff --git a/taskschedule/Tnb.TaskScheduler.Entitys/Mapper/Mapper.cs b/taskschedule/Tnb.TaskScheduler.Entitys/Mapper/Mapper.cs index 0ac2a846..4663f2e8 100644 --- a/taskschedule/Tnb.TaskScheduler.Entitys/Mapper/Mapper.cs +++ b/taskschedule/Tnb.TaskScheduler.Entitys/Mapper/Mapper.cs @@ -1,7 +1,7 @@ using JNPF.Common.Extension; using JNPF.Common.Security; +using JNPF.TaskScheduler.Entitys; using JNPF.TaskScheduler.Entitys.Dto.TaskScheduler; -using JNPF.TaskScheduler.Entitys.Entity; using JNPF.TaskScheduler.Entitys.Model; using Mapster; diff --git a/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeDemo.cs b/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeDemo.cs index 0ec14f7c..ff4c1f17 100644 --- a/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeDemo.cs +++ b/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeDemo.cs @@ -1,8 +1,5 @@ -using JNPF.Common.Security; -using JNPF.DependencyInjection; -using JNPF.Logging; +using JNPF.DependencyInjection; using JNPF.Systems.Entitys.Permission; -using JNPF.TaskScheduler.Entitys.Entity; using SqlSugar; namespace JNPF.TaskScheduler.Listener; @@ -12,55 +9,42 @@ namespace JNPF.TaskScheduler.Listener; /// public class SpareTimeDemo : ISpareTimeWorker { - /// - /// 3秒后出勤统计. - /// - /// 参数 - /// 次数 - [SpareTime("* * * * * ?", "生成雪花Id", ExecuteType = SpareTimeExecuteTypes.Serial)] - public void GenerateSnowId(SpareTimer timer, long count) - { - // 创建作用域 - Scoped.Create((factory, scope) => + /// + /// 3秒后出勤统计. + /// + /// 参数 + /// 次数 + [SpareTime("* * * * * ?", "执行Sql", ExecuteType = SpareTimeExecuteTypes.Serial)] + public void ExecSql(SpareTimer timer, long count) { - try - { - // 数据库操作 - var sqlSugarRepository = App.GetService>(scope.ServiceProvider); - List ls = new List(); - for (int i = 0; i < 50; i++) + // 创建作用域 + Scoped.Create((factory, scope) => { - ls.Add(new SnowIdEntity { Id = SnowflakeIdHelper.NextId() }); - Thread.Sleep(1); - } - sqlSugarRepository.InsertRange(ls); - } - catch (Exception ex) - { - Log.Error("GenerateSnowId错误:", ex); - } - }); - } + // 数据库操作 + var sqlSugarRepository = App.GetService>(scope.ServiceProvider); + sqlSugarRepository.DeleteById("226890444955452677"); + }); + } - /// - /// 3秒后出勤统计. - /// - /// 参数 - /// 次数 - [SpareTime("0 0/1 * * * ?", "执行Sql1", ExecuteType = SpareTimeExecuteTypes.Serial)] - public void ExecSql1(SpareTimer timer, long count) - { - // 创建作用域 - Scoped.Create((factory, scope) => + /// + /// 3秒后出勤统计. + /// + /// 参数 + /// 次数 + [SpareTime("0 0/1 * * * ?", "执行Sql1", ExecuteType = SpareTimeExecuteTypes.Serial)] + public void ExecSql1(SpareTimer timer, long count) { - var start = DateTime.Now; - Console.WriteLine(start.ToString("yyyy-MM-dd HH:mm:ss") + ":任务开始-----------"); - // 数据库操作 - var sqlSugarRepository = App.GetService>(scope.ServiceProvider); - sqlSugarRepository.DeleteById("226890444955452677"); - var end = DateTime.Now; - Console.WriteLine(end.ToString("yyyy-MM-dd HH:mm:ss") + ":任务结束-----------"); - Console.WriteLine($"SQL执行了:{count} 次,耗时:{(end - start).TotalMilliseconds}ms"); - }); - } + // 创建作用域 + Scoped.Create((factory, scope) => + { + var start = DateTime.Now; + Console.WriteLine(start.ToString("yyyy-MM-dd HH:mm:ss") + ":任务开始-----------"); + // 数据库操作 + var sqlSugarRepository = App.GetService>(scope.ServiceProvider); + sqlSugarRepository.DeleteById("226890444955452677"); + var end = DateTime.Now; + Console.WriteLine(end.ToString("yyyy-MM-dd HH:mm:ss") + ":任务结束-----------"); + Console.WriteLine($"SQL执行了:{count} 次,耗时:{(end - start).TotalMilliseconds}ms"); + }); + } } diff --git a/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeListener.cs b/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeListener.cs index 4cd08159..494e7e49 100644 --- a/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeListener.cs +++ b/taskschedule/Tnb.TaskScheduler/Listener/SpareTimeListener.cs @@ -4,8 +4,7 @@ using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.EventBus; using JNPF.EventHandler; -using JNPF.Systems.Entitys.System; -using Microsoft.Extensions.DependencyInjection; +using JNPF.TaskScheduler.Entitys; using SqlSugar; namespace JNPF.TaskScheduler.Listener; diff --git a/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs b/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs index 93739262..427d0056 100644 --- a/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs +++ b/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs @@ -12,12 +12,13 @@ using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; using JNPF.LinqBuilder; +using JNPF.Schedule; using JNPF.Systems.Interfaces.System; +using JNPF.TaskScheduler.Entitys; using JNPF.TaskScheduler.Entitys.Dto.TaskScheduler; -using JNPF.TaskScheduler.Entitys.Entity; -using JNPF.TaskScheduler.Entitys.Enum; using JNPF.TaskScheduler.Entitys.Model; using JNPF.TaskScheduler.Interfaces.TaskScheduler; +using JNPF.TimeCrontab; using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; @@ -38,6 +39,8 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie private readonly IDataInterfaceService _dataInterfaceService; private readonly IUserManager _userManager; private readonly ICacheManager _cacheManager; + //private readonly ISchedulerFactory _schedulerFactory; + private readonly IDataBaseManager _dataBaseManager; /// /// 初始化一个类型的新实例. @@ -46,12 +49,16 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie ISqlSugarRepository repository, IUserManager userManager, IDataInterfaceService dataInterfaceService, - ICacheManager cacheManager) + ICacheManager cacheManager, + //ISchedulerFactory schedulerFactory, + IDataBaseManager dataBaseManager) { _repository = repository; _userManager = userManager; _dataInterfaceService = dataInterfaceService; _cacheManager = cacheManager; + _dataBaseManager = dataBaseManager; + //_schedulerFactory = schedulerFactory; } #region Get @@ -124,6 +131,7 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie { return await GetTaskMethods(); } + #endregion #region Post @@ -131,7 +139,7 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie /// /// 新建. /// - /// 实体对象 + /// 实体对象. /// [HttpPost("")] public async Task Create([FromBody] TimeTaskCrInput input) @@ -147,10 +155,14 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie entity.ExecuteContent = comtentModel.ToJsonString(); entity.ExecuteCycleJson = comtentModel.cron; var result = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + // var job = _repository.AsTenant().GetConnection("JNPF-Job"); + // var jobDetail = new JobDetail() { }; + // job.Insertable() _ = result ?? throw Oops.Oh(ErrorCode.COM1000); // 添加到任务调度里 AddTimerJob(result); + //await AddJob(result); } /// @@ -271,7 +283,7 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie // 非多租户模式启动自启任务 if (!KeyVariable.MultiTenancy) { - _repository.AsQueryable().Where(x => x.DeleteMark == null && x.EnabledMark == 1).ToList().ForEach(AddTimerJob); + //_repository.AsQueryable().Where(x => x.DeleteMark == null && x.EnabledMark == 1).ToList().ForEach(AddTimerJob); } } @@ -324,12 +336,11 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie Action? action = null; ContentModel? comtentModel = input.ExecuteContent.ToObject(); input.ExecuteCycleJson = comtentModel.cron; - TaskMethodInfo? taskMethod = null; switch (input.ExecuteType) { case "3": // 查询符合条件的任务方法 - taskMethod = GetTaskMethods()?.Result.FirstOrDefault(m => m.id == comtentModel.localHostTaskId); + TaskMethodInfo? taskMethod = GetTaskMethods()?.Result.FirstOrDefault(m => m.id == comtentModel.localHostTaskId); if (taskMethod == null) break; // 创建任务对象 @@ -347,7 +358,8 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie } if (action == null) return; - //SpareTime.Do(comtentModel.cron, action, input.Id, comtentModel.ConnectionConfig.ToJsonString(), true, executeType: SpareTimeExecuteTypes.Parallel); + + // SpareTime.Do(comtentModel.cron, action, input.Id, comtentModel.ConnectionConfig.ToJsonString(), true, executeType: SpareTimeExecuteTypes.Parallel); var starTime = comtentModel.startTime?.TimeStampToDateTime(); var endTime = comtentModel.endTime?.TimeStampToDateTime(); var interval = 1; @@ -355,65 +367,86 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie { interval = (starTime.ParseToDateTime() - DateTime.Now).TotalMilliseconds.ParseToInt(); } - - if (taskMethod.StartNow) //modifyby zhoukeda 20230516 - { - SpareTime.DoOnce(interval, action, "Once_" + input.Id); - } - - Func nextHandle = null; - var isRun = comtentModel.endTime.IsNullOrEmpty() ? DateTime.Now >= starTime : DateTime.Now >= starTime && DateTime.Now < endTime; - if (isRun) - { - nextHandle = ()=>SpareTime.GetCronNextOccurrence(comtentModel.cron); - } - SpareTime.Do(nextHandle - , + SpareTime.DoOnce(interval, action, "Once_" + input.Id); + SpareTime.Do( + () => + { + var isRun = comtentModel.endTime.IsNullOrEmpty() ? DateTime.Now >= starTime : DateTime.Now >= starTime && DateTime.Now < endTime; + if (isRun) + { + return SpareTime.GetCronNextOccurrence(comtentModel.cron); + } + else + { + return null; + } + }, action, input.Id, comtentModel.ConnectionConfig.ToJsonString(), true, executeType: SpareTimeExecuteTypes.Parallel, cancelInNoneNextTime: false); } + private async Task AddJob(TimeTaskEntity input) + { + //ContentModel? comtentModel = input.ExecuteContent.ToObject(); + //var starTime = comtentModel.startTime?.TimeStampToDateTime(); + //var endTime = comtentModel.endTime?.TimeStampToDateTime(); + //var jobBuilder = JobBuilder.Create(async (context, stoppingToken) => + //{ + // Console.WriteLine(string.Format("{0}在执行任务,执行时间{1},触发时间:{1}", context.JobId, context.ExecutingTime, context.OccurrenceTime)); + // if (!input.ExecuteType.Equals("3")) + // { + // var msg = await PerformJob(input); + // } + //}); + //jobBuilder.SetJobId(input.Id); + //jobBuilder.SetGroupName(input.FullName); + //var triggerBuilder = TriggerBuilder.Create(input.ExecuteCycleJson, CronStringFormat.WithSeconds); + //triggerBuilder.SetStartTime(starTime); + //triggerBuilder.SetEndTime(endTime); + ////triggerBuilder.SetRunOnStart(true); + //_schedulerFactory.AddJob(jobBuilder, triggerBuilder); + } + /// /// 获取所有本地任务. /// /// private async Task> GetTaskMethods() { - // var taskMethods = await _cacheManager.GetAsync>(CommonConst.CACHEKEYTIMERJOB); - // if (taskMethods != null) return taskMethods; + //var taskMethods = await _cacheManager.GetAsync>(CommonConst.CACHEKEYTIMERJOB); + //if (taskMethods != null) return taskMethods; - List taskMethods = null; - - // 获取所有本地任务方法,必须有spareTimeAttribute特性 - taskMethods = App.EffectiveTypes - .Where(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISpareTimeWorker).IsAssignableFrom(u)) - .SelectMany(u => u.GetMethods(BindingFlags.Public | BindingFlags.Instance) - .Where(m => m.GetCustomAttributes(typeof(SpareTimeAttribute), false).ToString().Contains("SpareTime") && - m.GetParameters().Length == 2 && - m.GetParameters()[0].ParameterType == typeof(SpareTimer) && - m.GetParameters()[1].ParameterType == typeof(long) && m.ReturnType == typeof(void)) - .Select(m => - { - // 默认获取第一条任务特性 - var spareTimeAttribute = m.GetCustomAttribute(); - return new TaskMethodInfo - { - id = $"{m.DeclaringType.Name}/{m.Name}", - fullName = spareTimeAttribute.WorkerName, - RequestUrl = $"{m.DeclaringType.Name}/{m.Name}", - cron = spareTimeAttribute.CronExpression, - DoOnce = spareTimeAttribute.DoOnce, - ExecuteType = spareTimeAttribute.ExecuteType, - Interval = (int)spareTimeAttribute.Interval / 1000, - StartNow = spareTimeAttribute.StartNow, - RequestType = RequestTypeEnum.Run, - Remark = spareTimeAttribute.Description, - TimerType = string.IsNullOrEmpty(spareTimeAttribute.CronExpression) ? SpareTimeTypes.Interval : SpareTimeTypes.Cron, - MethodName = m.Name, - DeclaringType = m.DeclaringType - }; - })).ToList(); - await _cacheManager.SetAsync(CommonConst.CACHEKEYTIMERJOB, taskMethods); - return taskMethods; + //// 获取所有本地任务方法,必须有spareTimeAttribute特性 + //taskMethods = App.EffectiveTypes + // .Where(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISpareTimeWorker).IsAssignableFrom(u)) + // .SelectMany(u => u.GetMethods(BindingFlags.Public | BindingFlags.Instance) + // .Where(m => m.IsDefined(typeof(SpareTimeAttribute), false) && + // m.GetParameters().Length == 2 && + // m.GetParameters()[0].ParameterType == typeof(SpareTimer) && + // m.GetParameters()[1].ParameterType == typeof(long) && m.ReturnType == typeof(void)) + // .Select(m => + // { + // // 默认获取第一条任务特性 + // var spareTimeAttribute = m.GetCustomAttribute(); + // return new TaskMethodInfo + // { + // id = $"{m.DeclaringType.Name}/{m.Name}", + // fullName = spareTimeAttribute.WorkerName, + // RequestUrl = $"{m.DeclaringType.Name}/{m.Name}", + // cron = spareTimeAttribute.CronExpression, + // DoOnce = spareTimeAttribute.DoOnce, + // ExecuteType = spareTimeAttribute.ExecuteType, + // Interval = (int)spareTimeAttribute.Interval / 1000, + // StartNow = spareTimeAttribute.StartNow, + // RequestType = RequestTypeEnum.BuiltIn, + // Remark = spareTimeAttribute.Description, + // TimerType = string.IsNullOrEmpty(spareTimeAttribute.CronExpression) ? SpareTimeTypes.Interval : SpareTimeTypes.Cron, + // MethodName = m.Name, + // DeclaringType = m.DeclaringType + // }; + // })).ToList(); + //await _cacheManager.SetAsync(CommonConst.CACHEKEYTIMERJOB, taskMethods); + //return taskMethods; + return new List(); } #endregion diff --git a/taskschedule/Tnb.TaskScheduler/Tnb.TaskScheduler.csproj b/taskschedule/Tnb.TaskScheduler/Tnb.TaskScheduler.csproj index 85fb18db..6da949e5 100644 --- a/taskschedule/Tnb.TaskScheduler/Tnb.TaskScheduler.csproj +++ b/taskschedule/Tnb.TaskScheduler/Tnb.TaskScheduler.csproj @@ -16,8 +16,4 @@ - - - - \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/CodeGen/CodeGenWay.cs b/visualdev/Tnb.VisualDev.Engine/CodeGen/CodeGenWay.cs index ba30ffbf..f11085bb 100644 --- a/visualdev/Tnb.VisualDev.Engine/CodeGen/CodeGenWay.cs +++ b/visualdev/Tnb.VisualDev.Engine/CodeGen/CodeGenWay.cs @@ -32,7 +32,10 @@ public class CodeGenWay columnDesignModel ??= new ColumnDesignModel(); columnDesignModel.searchList = GetMultiEndQueryMerging(templateEntity, controls); columnDesignModel.columnList = GetMultiTerminalListDisplayAndConsolidation(templateEntity); - FormDataModel formDataModel = templateEntity.FormData.ToObject(); + FormDataModel formDataModel = templateEntity.FormData.ToObjectOld(); + + // 移除流程引擎ID + dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowid")); // 移除乐观锁 dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("version")); @@ -58,18 +61,18 @@ public class CodeGenWay IsConversion = false, IsSystemControl = false, IsAuxiliary = true, + IsControlParsing = false, IsUpdate = false, TableNo = tableNo, TableName = tableName, }); break; default: - switch (controls.Any(c => c.__vModel__.Equals(string.Format("jnpf_{0}_jnpf_{1}", tableName, field)))) + var childControl = string.Format("jnpf_{0}_jnpf_{1}", tableName, field); + switch (controls.Any(c => c.__vModel__.Equals(childControl))) { case true: - var childControl = string.Empty; - childControl = string.Format("jnpf_{0}_jnpf_{1}", tableName, field); - FieldsModel control = controls.Find(c => c.__vModel__.Equals(string.Format("jnpf_{0}_jnpf_{1}", tableName, field))); + FieldsModel control = controls.Find(c => c.__vModel__.Equals(childControl)); var isImportField = templateEntity.WebType == 1 ? false : columnDesignModel?.uploaderTemplateJson?.selectKey?.Any(it => it.Equals(childControl)); switch (control.__config__.jnpfKey) { @@ -86,7 +89,8 @@ public class CodeGenWay NetType = CodeGenHelper.ConvertDataType(column.dataType), PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, - QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, childControl), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, childControl), IsShow = control.isIndexShow, IsUnique = control.__config__.unique, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), @@ -95,8 +99,8 @@ public class CodeGenWay IsDateTime = CodeGenFieldJudgeHelper.IsSecondaryTableDateTime(control), ActiveTxt = control.activeTxt, InactiveTxt = control.inactiveTxt, - IsDetailConversion = CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, "", CodeGenFieldJudgeHelper.IsMultipleColumn(controls, string.Format("jnpf_{0}_jnpf_{1}", tableName, field))), - IsConversion = modelType == 1 ? CodeGenControlsAttributeHelper.JudgeContainsChildTableControlIsDataConversion(control.__config__.jnpfKey) : CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, "", CodeGenFieldJudgeHelper.IsMultipleColumn(controls, string.Format("jnpf_{0}_jnpf_{1}", tableName, field))), + IsDetailConversion = CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, "", CodeGenFieldJudgeHelper.IsMultipleColumn(controls, childControl)), + IsConversion = modelType == 1 ? CodeGenControlsAttributeHelper.JudgeContainsChildTableControlIsDataConversion(control.__config__.jnpfKey) : CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, "", CodeGenFieldJudgeHelper.IsMultipleColumn(controls, childControl)), IsSystemControl = true, IsUpdate = CodeGenControlsAttributeHelper.JudgeControlIsSystemControls(control.__config__.jnpfKey), IsAuxiliary = true, @@ -105,7 +109,9 @@ public class CodeGenWay FormatTableName = tableName.ParseToPascalCase(), ControlLabel = control.__config__.label, IsImportField = isImportField.ParseToBool(), + IsControlParsing = false, ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), + IsTreeParentField = childControl.Equals(columnDesignModel.parentField), }); break; default: @@ -118,10 +124,11 @@ public class CodeGenWay DataType = column.dataType, NetType = CodeGenHelper.ConvertDataType(column.dataType), PrimaryKey = column.primaryKey.ParseToBool(), - QueryWhether = CodeGenFieldJudgeHelper.IsColumnQueryWhether(searchList: columnDesignModel.searchList, string.Format("jnpf_{0}_jnpf_{1}", tableName, field)), - QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, string.Format("jnpf_{0}_jnpf_{1}", tableName, field)), - IsShow = CodeGenFieldJudgeHelper.IsShowColumn(columnDesignModel.columnList, string.Format("jnpf_{0}_jnpf_{1}", tableName, field)), - IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, string.Format("jnpf_{0}_jnpf_{1}", tableName, field)), + QueryWhether = CodeGenFieldJudgeHelper.IsColumnQueryWhether(searchList: columnDesignModel.searchList, childControl), + QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, childControl), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, childControl), + IsShow = CodeGenFieldJudgeHelper.IsShowColumn(columnDesignModel.columnList, childControl), + IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, childControl), IsUnique = control.__config__.unique, jnpfKey = control.__config__.jnpfKey, Rule = control.__config__.rule, @@ -136,8 +143,8 @@ public class CodeGenWay Value = CodeGenControlsAttributeHelper.GetControlsValue(control.__config__.jnpfKey, dataType, control), Children = CodeGenControlsAttributeHelper.GetControlsChildren(control.__config__.jnpfKey, dataType, control), Separator = control.separator, - IsDetailConversion = CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, dataType, CodeGenFieldJudgeHelper.IsMultipleColumn(controls, string.Format("jnpf_{0}_jnpf_{1}", tableName, field))), - IsConversion = modelType == 1 ? CodeGenControlsAttributeHelper.JudgeContainsChildTableControlIsDataConversion(control.__config__.jnpfKey) : CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, "", CodeGenFieldJudgeHelper.IsMultipleColumn(controls, string.Format("jnpf_{0}_jnpf_{1}", tableName, field))), + IsDetailConversion = CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, dataType, CodeGenFieldJudgeHelper.IsMultipleColumn(controls, childControl)), + IsConversion = modelType == 1 ? CodeGenControlsAttributeHelper.JudgeContainsChildTableControlIsDataConversion(control.__config__.jnpfKey) : CodeGenControlsAttributeHelper.JudgeControlIsDataConversion(control.__config__.jnpfKey, "", CodeGenFieldJudgeHelper.IsMultipleColumn(controls, childControl)), IsSystemControl = false, IsUpdate = CodeGenControlsAttributeHelper.JudgeControlIsSystemControls(control.__config__.jnpfKey), IsAuxiliary = true, @@ -147,7 +154,9 @@ public class CodeGenWay ControlLabel = control.__config__.label, IsImportField = isImportField.ParseToBool(), ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), + IsControlParsing = CodeGenFieldJudgeHelper.IsControlParsing(control), ShowField = control.relational, + IsTreeParentField = childControl.Equals(columnDesignModel.parentField), }); break; } @@ -168,6 +177,7 @@ public class CodeGenWay IsAuxiliary = true, IsUpdate = false, TableNo = tableNo, + IsControlParsing = false, }); break; } @@ -187,6 +197,9 @@ public class CodeGenWay // 是否对象映射 bool isMapper = CodeGenFieldJudgeHelper.IsChildTableMapper(tableColumnList); + // 是否查询条件多选 + bool isSearchMultiple = tableColumnList.Any(it => it.QueryMultiple); + return new CodeGenConfigModel() { NameSpace = formDataModel.areasName, @@ -204,6 +217,7 @@ public class CodeGenWay PrimaryKeyPolicy = formDataModel.primaryKeyPolicy, IsImportData = tableColumnList.Any(it => it.IsImportField.Equals(true)), EnableFlow = templateEntity.EnableFlow == 1 ? true : false, + IsSearchMultiple = isSearchMultiple, }; } @@ -224,7 +238,10 @@ public class CodeGenWay columnDesignModel ??= new ColumnDesignModel(); columnDesignModel.searchList = GetMultiEndQueryMerging(templateEntity, controls); columnDesignModel.columnList = GetMultiTerminalListDisplayAndConsolidation(templateEntity); - FormDataModel formDataModel = templateEntity.FormData.ToObject(); + FormDataModel formDataModel = templateEntity.FormData.ToObjectOld(); + + // 移除流程引擎ID + dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowid")); // 移除乐观锁 dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("version")); @@ -247,6 +264,7 @@ public class CodeGenWay DataType = column.dataType, NetType = CodeGenHelper.ConvertDataType(column.dataType), PrimaryKey = true, + IsControlParsing = false, }); break; default: @@ -267,6 +285,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, string.Format("{0}-{1}", controlId, field)), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, string.Format("{0}-{1}", controlId, field)), IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), IsUnique = control.__config__.unique, jnpfKey = control.__config__.jnpfKey, @@ -290,6 +309,7 @@ public class CodeGenWay IsImportField = isImportField.ParseToBool(), ChildControlKey = controlId, ShowField = control.relational, + IsControlParsing = CodeGenFieldJudgeHelper.IsControlParsing(control), }); break; case false: @@ -302,6 +322,7 @@ public class CodeGenWay NetType = CodeGenHelper.ConvertDataType(column.dataType), ForeignKeyField = true, IsImportField = false, + IsControlParsing = false, }); break; } @@ -322,6 +343,9 @@ public class CodeGenWay bool isShowSubTableField = tableColumnList.Any(it => it.IsShow.Equals(true)); + // 是否查询条件多选 + bool isSearchMultiple = tableColumnList.Any(it => it.QueryMultiple); + return new CodeGenConfigModel() { NameSpace = formDataModel.areasName, @@ -337,6 +361,7 @@ public class CodeGenWay PrimaryKeyPolicy = formDataModel.primaryKeyPolicy, IsImportData = tableColumnList.Any(it => it.IsImportField.Equals(true)), IsShowSubTableField = isShowSubTableField, + IsSearchMultiple = isSearchMultiple, }; } @@ -355,7 +380,7 @@ public class CodeGenWay columnDesignModel ??= new ColumnDesignModel(); columnDesignModel.searchList = GetMultiEndQueryMerging(templateEntity, controls); columnDesignModel.columnList = GetMultiTerminalListDisplayAndConsolidation(templateEntity); - FormDataModel formDataModel = templateEntity.FormData.ToObject(); + FormDataModel formDataModel = templateEntity.FormData.ToObjectOld(); // 移除乐观锁 dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("version")); @@ -363,6 +388,9 @@ public class CodeGenWay // 移除真实流程ID dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowtaskid")); + // 移除流程引擎ID + dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowid")); + var table = templateEntity.Tables.ToObject>(); var tableColumnList = new List(); @@ -409,6 +437,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsUnique = control.__config__.unique, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), @@ -424,6 +453,7 @@ public class CodeGenWay ControlLabel = control.__config__.label, IsImportField = isImportField == null ? false : (bool)isImportField, ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), + IsTreeParentField = childControl.Equals(columnDesignModel.parentField), }); break; default: @@ -438,6 +468,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), IsUnique = control.__config__.unique, @@ -462,6 +493,7 @@ public class CodeGenWay IsImportField = isImportField == null ? false : (bool)isImportField, ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), ShowField = control.relational, + IsTreeParentField = childControl.Equals(columnDesignModel.parentField), }); break; } @@ -479,6 +511,7 @@ public class CodeGenWay IsSystemControl = false, ForeignKeyField = true, IsUpdate = false, + IsControlParsing = false, }); break; } @@ -507,7 +540,7 @@ public class CodeGenWay columnDesignModel ??= new ColumnDesignModel(); columnDesignModel.searchList = GetMultiEndQueryMerging(templateEntity, controls); columnDesignModel.columnList = GetMultiTerminalListDisplayAndConsolidation(templateEntity); - FormDataModel formDataModel = templateEntity.FormData.ToObject(); + FormDataModel formDataModel = templateEntity.FormData.ToObjectOld(); // 移除乐观锁 dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("version")); @@ -515,6 +548,9 @@ public class CodeGenWay // 移除真实流程ID dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowtaskid")); + // 移除流程引擎ID + dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowid")); + var tableColumnList = new List(); foreach (DbTableFieldModel? column in dbTableFields) { @@ -558,6 +594,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsUnique = control.__config__.unique, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), @@ -575,6 +612,7 @@ public class CodeGenWay ControlLabel = control.__config__.label, IsImportField = isImportField.ParseToBool(), ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), + IsTreeParentField = field.Equals(columnDesignModel.parentField), }); break; default: @@ -589,6 +627,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), IsUnique = control.__config__.unique, @@ -614,6 +653,7 @@ public class CodeGenWay ControlLabel = control.__config__.label, IsImportField = isImportField.ParseToBool(), ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), + IsTreeParentField = field.Equals(columnDesignModel.parentField), }); break; } @@ -631,6 +671,7 @@ public class CodeGenWay IsSystemControl = false, IsAuxiliary = false, IsUpdate = false, + IsControlParsing = false, }); break; } @@ -665,7 +706,7 @@ public class CodeGenWay columnDesignModel ??= new ColumnDesignModel(); columnDesignModel.searchList = GetMultiEndQueryMerging(templateEntity, controls); columnDesignModel.columnList = GetMultiTerminalListDisplayAndConsolidation(templateEntity); - FormDataModel formDataModel = templateEntity.FormData.ToObject(); + FormDataModel formDataModel = templateEntity.FormData.ToObjectOld(); // 移除乐观锁 dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("version")); @@ -673,6 +714,9 @@ public class CodeGenWay // 移除真实流程ID dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowtaskid")); + // 移除流程引擎ID + dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowid")); + var tableColumnList = new List(); foreach (DbTableFieldModel? column in dbTableFields) @@ -714,6 +758,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsUnique = control.__config__.unique, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), @@ -731,6 +776,7 @@ public class CodeGenWay ControlLabel = control.__config__.label, IsImportField = columnDesignModel?.uploaderTemplateJson?.selectKey?.Any(it => it.Equals(field)) == null ? false : (bool)columnDesignModel?.uploaderTemplateJson?.selectKey?.Any(it => it.Equals(field)), ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), + IsTreeParentField = field.Equals(columnDesignModel.parentField), }); break; default: @@ -745,6 +791,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), IsUnique = control.__config__.unique, @@ -771,6 +818,7 @@ public class CodeGenWay IsImportField = columnDesignModel?.uploaderTemplateJson?.selectKey?.Any(it => it.Equals(field)) == null ? false : (bool)columnDesignModel?.uploaderTemplateJson?.selectKey?.Any(it => it.Equals(field)), ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), ShowField = control.relational, + IsTreeParentField = field.Equals(columnDesignModel.parentField), }); break; } @@ -815,7 +863,7 @@ public class CodeGenWay columnDesignModel ??= new ColumnDesignModel(); columnDesignModel.searchList = GetMultiEndQueryMerging(templateEntity, controls); columnDesignModel.columnList = GetMultiTerminalListDisplayAndConsolidation(templateEntity); - FormDataModel formDataModel = templateEntity.FormData.ToObject(); + FormDataModel formDataModel = templateEntity.FormData.ToObjectOld(); var tableColumnList = new List(); // 移除乐观锁 @@ -824,6 +872,9 @@ public class CodeGenWay // 移除真实流程ID dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowtaskid")); + // 移除流程引擎ID + dbTableFields.RemoveAll(it => it.field.ReplaceRegex("^f_", string.Empty).ToLower().Equals("flowid")); + foreach (DbTableFieldModel? column in dbTableFields) { var field = column.field.ReplaceRegex("^f_", string.Empty).ParseToPascalCase().ToLowerCase(); @@ -866,6 +917,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsUnique = control.__config__.unique, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), @@ -881,6 +933,7 @@ public class CodeGenWay ControlLabel = control.__config__.label, IsImportField = isImportField.ParseToBool(), ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), + IsTreeParentField = field.Equals(columnDesignModel.parentField), }); break; default: @@ -895,6 +948,7 @@ public class CodeGenWay PrimaryKey = column.primaryKey.ParseToBool(), QueryWhether = control.isQueryField, QueryType = CodeGenFieldJudgeHelper.ColumnQueryType(searchList: columnDesignModel.searchList, field), + QueryMultiple = CodeGenFieldJudgeHelper.ColumnQueryMultiple(searchList: columnDesignModel.searchList, field), IsShow = control.isIndexShow, IsMultiple = CodeGenFieldJudgeHelper.IsMultipleColumn(controls, field), IsUnique = control.__config__.unique, @@ -919,6 +973,7 @@ public class CodeGenWay IsImportField = isImportField.ParseToBool(), ImportConfig = CodeGenControlsAttributeHelper.GetImportConfig(control, column.field, tableName), ShowField = control.relational, + IsTreeParentField = field.Equals(columnDesignModel.parentField), }); break; } @@ -995,13 +1050,14 @@ public class CodeGenWay controls = CodeGenUnifiedHandlerHelper.LinkageChainJudgment(controls, columnDesignModel); Dictionary> listQueryControls = CodeGenQueryControlClassificationHelper.ListQueryControl(logic); - Dictionary> listColumnControlsType = CodeGenQueryControlClassificationHelper.ListColumnControls(); // 表单脚本设计 - var formScriptDesign = CodeGenFormControlDesignHelper.FormScriptDesign("SingleTable", controls, tableColumns, columnDesignModel?.columnList); + List? formScriptDesign = CodeGenFormControlDesignHelper.FormScriptDesign("SingleTable", controls, tableColumns, columnDesignModel?.columnList); // 整个表单控件 - var formControlList = CodeGenFormControlDesignHelper.FormControlDesign(formDataModel.fields, controls, formDataModel.gutter, formDataModel.labelWidth, columnDesignModel?.columnList, columnDesignModel.type, logic, true); + List? formControlList = CodeGenFormControlDesignHelper.FormControlDesign(formDataModel.fields, controls, formDataModel.gutter, formDataModel.labelWidth, columnDesignModel?.columnList, columnDesignModel.type, logic, true); + + var formRealControl = CodeGenFormControlDesignHelper.FormRealControl(controls); // 列表控件Option var indnxControlOption = CodeGenFormControlDesignHelper.FormControlProps(formDataModel.fields, controls, columnDesignModel, logic, true); @@ -1069,6 +1125,7 @@ public class CodeGenWay Type = column.type, ShowAllLevels = column.showalllevels ? "true" : "false", Level = column.level, + IsMultiple = item.searchMultiple, SelectType = column.selectType != null ? column.selectType.Equals("custom") ? string.Format("selectType='{0}' ", column.selectType) : string.Format("selectType='all' ") : string.Empty, AbleDepIds = column.selectType != null && column.selectType == "custom" ? string.Format(":ableDepIds='{0}_AbleDepIds' ", childControl.Length >= 2 ? string.Format("{0}_{1}", childControl[0], column.__vModel__) : item.__vModel__) : string.Empty, AblePosIds = column.selectType != null && column.selectType == "custom" && (column.__config__.jnpfKey.Equals(JnpfKeyConst.USERSELECT) || column.__config__.jnpfKey.Equals(JnpfKeyConst.POSSELECT)) ? string.Format(":ablePosIds='{0}_AblePosIds' ", childControl.Length >= 2 ? string.Format("{0}_{1}", childControl[0], column.__vModel__) : item.__vModel__) : string.Empty, @@ -1086,7 +1143,7 @@ public class CodeGenWay { Type = columnDesignModel.btnsList.IndexOf(item) == 0 ? "primary" : "text", Icon = item.icon, - Method = GetCodeGenIndexButtonHelper.IndexTopButton(item.value), + Method = GetCodeGenIndexButtonHelper.IndexTopButton(item.value, templateEntity.EnableFlow == 1 ? true : false), Value = item.value, Label = item.label }); @@ -1114,8 +1171,6 @@ public class CodeGenWay { if (!ChildControlField.Any(it => it == item.__vModel__)) { - // 控件对应的控件类型 - var conversion = listColumnControlsType.Where(q => q.Value.Contains(item.jnpfKey)).FirstOrDefault(); var relationTable = item?.__config__?.relationTable; if (relationTable != null && !indexColumnDesign.Any(it => it.TableName == relationTable)) { @@ -1127,7 +1182,6 @@ public class CodeGenWay foreach (var child in childTableAll) { var columnControl = childTable.__config__.children.Find(it => it.__vModel__.Equals(child.__vModel__.Split('-')[1])); - conversion = listColumnControlsType.Where(q => q.Value.Contains(child.jnpfKey)).FirstOrDefault(); childTableColumnDesign.Add(new IndexColumnDesign() { TableName = child.__config__.tableName, @@ -1138,10 +1192,10 @@ public class CodeGenWay Label = columnControl.__config__.label, Width = child.width.ToString() == "0" ? "0" : string.Format("{0}", child.width), Align = child.align, - IsAutomatic = conversion.Key == null ? false : true, IsSort = child.sortable ? string.Format("sortable='custom' ") : string.Empty, IsChildTable = true, Format = child.format?.ToLower().Replace(":mm", ":MM"), + ModelId = child.modelId, }); ChildControlField.Add(string.Format("{0}", child.__vModel__)); } @@ -1154,7 +1208,6 @@ public class CodeGenWay jnpfKey = JnpfKeyConst.TABLE, IsChildTable = true, ChildTableDesigns = childTableColumnDesign, - IsAutomatic = childTableColumnDesign.Any(it => it.IsAutomatic), Fixed = string.Empty, }); } @@ -1172,10 +1225,9 @@ public class CodeGenWay Width = item.width == null ? string.Empty : string.Format("width='{0}' ", item.width), Fixed = columnDesignModel.childTableStyle == 1 ? (item.@fixed == "none" || item.@fixed == null ? string.Empty : string.Format("fixed='{0}' ", item.@fixed)) : string.Empty, Align = item.align, - Format = item.format?.ToLower().Replace(":mm", ":MM"), - IsAutomatic = conversion.Key == null ? false : true, IsSort = item.sortable ? string.Format("sortable='custom' ") : string.Empty, IsChildTable = false, + ModelId = item.modelId, }); } @@ -1188,7 +1240,11 @@ public class CodeGenWay break; } + var propertyJson = CodeGenFormControlDesignHelper.GetPropertyJson(formScriptDesign); + + var printIds = columnDesignModel.printIds != null ? string.Join(",", columnDesignModel.printIds) : null; var isBatchRemoveDel = indexTopButton.Any(it => it.Value == "batchRemove"); + var isBatchPrint = indexTopButton.Any(it => it.Value == "batchPrint"); var isUpload = indexTopButton.Any(it => it.Value == "upload"); var isDownload = indexTopButton.Any(it => it.Value == "download"); var isRemoveDel = indexColumnButtonDesign.Any(it => it.Value == "remove"); @@ -1199,24 +1255,40 @@ public class CodeGenWay var isAdd = indexTopButton.Any(it => it.Value == "add"); var isTreeRelation = !string.IsNullOrEmpty(columnDesignModel?.treeRelation); var isRelationForm = formControlList.Any(it => it.IsRelationForm); + var isTreeRelationMultiple = indexSearchFieldDesign.Any(it => it.Name.Equals(columnDesignModel?.treeRelation?.Replace("-", "_")) && it.IsMultiple); var isFixed = columnDesignModel.childTableStyle == 1 ? indexColumnDesign.Any(it => it.Fixed.Equals("fixed='left' ") && !it.Name.Equals(columnDesignModel.groupField)) : false; + var isChildrenRegular = formScriptDesign.Any(it => it.jnpfKey.Equals(JnpfKeyConst.TABLE) && it.RegList != null && it.RegList.Count > 0); + // 表单默认值控件列表 + var defaultFormControlList = new DefaultFormControlModel(); switch (logic) { case 4: columnDesignModel = templateEntity.ColumnData?.ToObject(); columnDesignModel ??= new ColumnDesignModel(); + defaultFormControlList = CodeGenFormControlDesignHelper.DefaultFormControlList(controls, columnDesignModel.searchList); break; case 5: ColumnDesignModel pcColumnDesignModel = templateEntity.ColumnData?.ToObject(); columnDesignModel = templateEntity.AppColumnData?.ToObject(); columnDesignModel ??= new ColumnDesignModel(); + defaultFormControlList = CodeGenFormControlDesignHelper.DefaultFormControlList(controls, columnDesignModel.searchList); // 移动端的分页遵循PC端 columnDesignModel.hasPage = templateEntity.WebType == 1 ? false : pcColumnDesignModel.hasPage; break; } + var isDefaultFormControl = defaultFormControlList.IsExistDate || defaultFormControlList.IsExistDepSelect || defaultFormControlList.IsExistComSelect || defaultFormControlList.IsExistUserSelect || defaultFormControlList.IsExistSubTable ? true : false; + + switch (columnDesignModel.type) + { + case 3: + case 5: + columnDesignModel.hasPage = false; + break; + } + switch (templateEntity.WebType) { case 1: @@ -1256,7 +1328,7 @@ public class CodeGenWay Sort = columnDesignModel.sort, HasPrintBtn = formDataModel.hasPrintBtn, PrintButtonText = formDataModel.printButtonText, - PrintId = formDataModel.printId, + PrintId = formDataModel.printId != null ? string.Join(",", formDataModel.printId) : null, IsChildDataTransfer = formScriptDesign.Any(it => it.IsDataTransfer.Equals(true)), IsChildTableQuery = indexSearchFieldDesign.Any(it => it.IsChildQuery.Equals(true)), IsChildTableShow = indexColumnDesign.Any(it => it.IsChildTable.Equals(true)), @@ -1268,10 +1340,22 @@ public class CodeGenWay PrimaryKeyPolicy = formDataModel.primaryKeyPolicy, IsRelationForm = isRelationForm, ChildTableStyle = columnDesignModel.childTableStyle, + IsChildrenRegular = isChildrenRegular, + DefaultFormControlList = defaultFormControlList, + IsDefaultFormControl = isDefaultFormControl, + PropertyJson = propertyJson, + FormRealControl = formRealControl, }; + break; default: + var codeGenColumnData = new CodeGenColumnData + { + treeInterfaceId = columnDesignModel.treeInterfaceId, + treeTemplateJson = columnDesignModel.treeTemplateJson + }; return new FrontEndGenConfigModel() { + PrintIds = printIds, NameSpace = formDataModel.areasName, ClassName = formDataModel.className.FirstOrDefault(), FormRef = formDataModel.formRef, @@ -1293,6 +1377,7 @@ public class CodeGenWay TreePropsUrl = columnDesignModel?.treePropsUrl, TreePropsChildren = columnDesignModel?.treePropsChildren, TreePropsLabel = columnDesignModel?.treePropsLabel, + IsTreeRelationMultiple = isTreeRelationMultiple, IsExistQuery = templateEntity.Type == 3 ? false : (bool)columnDesignModel?.searchList?.Any(it => it.prop.Equals(columnDesignModel?.treeRelation)), PrimaryKey = tableColumns?.Find(it => it.PrimaryKey.Equals(true))?.LowerColumnName, FormList = formScriptDesign, @@ -1303,6 +1388,7 @@ public class CodeGenWay ColumnDesign = indexColumnDesign, OptionsList = indnxControlOption, IsBatchRemoveDel = isBatchRemoveDel, + IsBatchPrint = isBatchPrint, IsDownload = isDownload, IsRemoveDel = isRemoveDel, IsDetail = isDetail, @@ -1322,7 +1408,7 @@ public class CodeGenWay Sort = columnDesignModel.sort, HasPrintBtn = formDataModel.hasPrintBtn, PrintButtonText = formDataModel.printButtonText, - PrintId = formDataModel.printId, + PrintId = formDataModel.printId != null ? string.Join(",", formDataModel.printId) : null, IsChildDataTransfer = formScriptDesign.Any(it => it.IsDataTransfer.Equals(true)), IsChildTableQuery = indexSearchFieldDesign.Any(it => it.IsChildQuery.Equals(true)), IsChildTableShow = indexColumnDesign.Any(it => it.IsChildTable.Equals(true)), @@ -1337,7 +1423,18 @@ public class CodeGenWay IsRelationForm = isRelationForm, ChildTableStyle = columnDesignModel.childTableStyle, IsFixed = isFixed, + IsChildrenRegular = isChildrenRegular, + TreeSynType = columnDesignModel.treeSynType, + HasTreeQuery = columnDesignModel.hasTreeQuery, + ColumnData = codeGenColumnData, + SummaryField = columnDesignModel.summaryField, + ShowSummary = columnDesignModel.showSummary, + DefaultFormControlList = defaultFormControlList, + IsDefaultFormControl = isDefaultFormControl, + PropertyJson = propertyJson, + FormRealControl = formRealControl, }; + break; } } @@ -1401,6 +1498,18 @@ public class CodeGenWay // 是否批量删除 bool isBatchRemove = false; + // 是否查询条件多选 + bool isSearchMultiple = false; + + // 是否树形表格 + bool isTreeTable = false; + + // 树形表格-父级字段 + string parentField = string.Empty; + + // 树形表格-显示字段 + string treeShowField = string.Empty; + switch (templateEntity.WebType) { case 2: @@ -1408,6 +1517,18 @@ public class CodeGenWay defaultSidx = columnDesignModel.defaultSidx ?? tableColumnList.Find(t => t.PrimaryKey).ColumnName; isExport = columnDesignModel.btnsList.Any(it => it.value == "download"); isBatchRemove = columnDesignModel.btnsList.Any(it => it.value == "batchRemove"); + isSearchMultiple = tableColumnList.Any(it => it.QueryMultiple && !it.IsAuxiliary); + break; + } + + switch (columnDesignModel.type) + { + case 5: + isTreeTable = true; + parentField = string.Format("{0}_pid", columnDesignModel.parentField); + treeShowField = columnDesignModel.columnList.Find(it => it.__vModel__.ToLower() != columnDesignModel.parentField.ToLower()).__vModel__; + break; + default: break; } @@ -1424,8 +1545,18 @@ public class CodeGenWay bool isUpdate = tableColumnList.Any(it => it.IsUpdate); + bool isLogicalDelete = formDataModel.logicalDelete; + List function = new List(); + // 树形表格没有分页 + switch (columnDesignModel.type) + { + case 5: + columnDesignModel.hasPage = false; + break; + } + switch (templateEntity.Type) { case 3: @@ -1514,6 +1645,11 @@ public class CodeGenWay ImportDataType = columnDesignModel?.uploaderTemplateJson?.dataType, IsSystemControl = isSystemControl, IsUpdate = isUpdate, + IsSearchMultiple = isSearchMultiple, + IsTreeTable = isTreeTable, + ParentField = parentField, + TreeShowField = treeShowField, + IsLogicalDelete = isLogicalDelete, }; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Core/FormDataParsing.cs b/visualdev/Tnb.VisualDev.Engine/Core/FormDataParsing.cs index 634430a0..9b5d4270 100644 --- a/visualdev/Tnb.VisualDev.Engine/Core/FormDataParsing.cs +++ b/visualdev/Tnb.VisualDev.Engine/Core/FormDataParsing.cs @@ -1,5 +1,4 @@ -using System.Text.RegularExpressions; -using JNPF.Common.Const; +using JNPF.Common.Const; using JNPF.Common.Core.Manager; using JNPF.Common.Dtos; using JNPF.Common.Extension; @@ -22,7 +21,6 @@ using JNPF.VisualDev.Entitys.Dto.VisualDevModelData; using JNPF.VisualDev.Interfaces; using JNPF.WorkFlow.Entitys.Entity; using Mapster; -using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json.Linq; using SqlSugar; @@ -55,53 +53,44 @@ public class FormDataParsing : ITransient /// private readonly ICacheManager _cacheManager; - /// - /// 缓存管理. - /// - private readonly IMemoryCache _memCache; + /// + /// 服务基础仓储. + /// + private readonly ISqlSugarRepository _db; - /// - /// 服务基础仓储. - /// - //private readonly ISqlSugarRepository _db; - private readonly ISqlSugarClient _sugar; + /// + /// 构造. + /// + /// + /// + /// + /// + /// + public FormDataParsing( + IUserManager userManager, + ICacheManager cacheManager, + IDataBaseManager databaseService, + IDataInterfaceService dataInterfaceService, + ISqlSugarRepository context) + { + _userManager = userManager; + _cacheManager = cacheManager; + _databaseService = databaseService; + _dataInterfaceService = dataInterfaceService; + _db = context; + } + #endregion - /// - /// 构造. - /// - /// - /// - /// - /// - /// - public FormDataParsing( - IUserManager userManager, - ICacheManager cacheManager, - IDataBaseManager databaseService, - IDataInterfaceService dataInterfaceService, - ISqlSugarRepository context, - IMemoryCache memCache) - { - _userManager = userManager; - _cacheManager = cacheManager; - _databaseService = databaseService; - _dataInterfaceService = dataInterfaceService; - _sugar = context.AsSugarClient().CopyNew(); - //_db = context; - _memCache = memCache; - } - #endregion + #region 解析模板数据 - #region 解析模板数据 - - /// - /// 控制模板数据转换. - /// - /// 数据. - /// 数据模板. - /// 操作类型(List-列表值,create-创建值,update-更新值,detail-详情值,transition-过渡值,query-查询). - /// object. - public object TemplateControlsDataConversion(object data, FieldsModel fieldsModel, string? actionType = null) + /// + /// 控制模板数据转换. + /// + /// 数据. + /// 数据模板. + /// 操作类型(List-列表值,create-创建值,update-更新值,detail-详情值,transition-过渡值,query-查询). + /// object. + public object TemplateControlsDataConversion(object data, FieldsModel fieldsModel, string? actionType = null) { if (fieldsModel == null || data == null || data.Equals("[]") || data.ToString().Equals("[]") || string.IsNullOrEmpty(data.ToString())) return string.Empty; try @@ -117,11 +106,20 @@ public class FormDataParsing : ITransient if (fieldsModel.precision.IsNullOrEmpty()) fieldsModel.precision = 0; // 数字输入 if (data.ToString().Contains(".")) { - var len = data.ToString().Split('.').Last().Length; - if (fieldsModel.precision > len) fieldsModel.precision = len; - conversionData = data.ToString().Substring(0, data.ToString().IndexOf(".") + (int)fieldsModel.precision + 1);//modifyby zhoukeda 20230512 增加+1 - conversionData = data.ParseToDouble();//modifyby zhoukeda 20230512 + var dataList = data.ToString().Split('.'); + if (fieldsModel.precision == 0) + { + conversionData = dataList.First(); + } + else + { + if (fieldsModel.precision > dataList.Last().Length) fieldsModel.precision = dataList.Last().Length; + conversionData = dataList.First() + "." + dataList.Last().Substring(0, (int)fieldsModel.precision); + } + //conversionData = data.ToString().Substring(0, data.ToString().IndexOf(".") + (int)fieldsModel.precision + 1);//modifyby zhoukeda 20230512 增加+1 + //conversionData = data.ParseToDouble();//modifyby zhoukeda 20230512 } + else if (fieldsModel.precision > 0) conversionData = data.ToString() + ".".PadRight((int)fieldsModel.precision + 1, '0'); else conversionData = data; break; case JnpfKeyConst.JNPFAMOUNT: @@ -206,7 +204,10 @@ public class FormDataParsing : ITransient conversionData = string.Format("{0:yyyy-MM-dd HH:mm:ss}", data.ToString().TimeStampToDateTime()); break; case "create": - conversionData = string.Format("{0:yyyy-MM-dd HH:mm:ss}", data.ToString().TimeStampToDateTime()); + if (fieldsModel.format.ToLower().Equals("yyyy-mm-dd")) + conversionData = string.Format("{0:yyyy-MM-dd}", data.ToString().TimeStampToDateTime()); + else + conversionData = string.Format("{0:yyyy-MM-dd HH:mm:ss}", data.ToString().TimeStampToDateTime()); break; case "detail": conversionData = data; @@ -435,6 +436,11 @@ public class FormDataParsing : ITransient if (data.GetType().Name.ToLower().Equals("string")) conversionData = data; else if (data.ToString().Contains("[")) conversionData = data.ToJsonString(); else conversionData = data; + break; + case "List": + if (fieldsModel.multiple) conversionData = data.ToString().ToObject>(); + else conversionData = data; + break; default: if (fieldsModel.multiple) conversionData = data.ToString().ToObject>(); @@ -498,8 +504,9 @@ public class FormDataParsing : ITransient /// 插入的数据. /// 控件集合. /// 操作类型. + /// 是否外链. /// string. - public object InsertValueHandle(string dbType, List _tableList, string field, object data, List _fieldsModelList, string actionType = "create") + public object InsertValueHandle(string dbType, List _tableList, string field, object data, List _fieldsModelList, string actionType = "create", bool isShortLink = false) { // 根据KEY查找模板 FieldsModel? model = _fieldsModelList.Find(f => f.__vModel__ == field); @@ -514,7 +521,9 @@ public class FormDataParsing : ITransient var res = TemplateControlsDataConversion(data, model, actionType); if (actionType.Equals("create")) { - if (model.__config__.jnpfKey.Equals(JnpfKeyConst.CREATETIME) || model.__config__.jnpfKey.Equals(JnpfKeyConst.DATE)) + if (isShortLink && model.__config__.jnpfKey.Equals(JnpfKeyConst.CREATETIME)) + return null; + else if(model.__config__.jnpfKey.Equals(JnpfKeyConst.CREATETIME) || model.__config__.jnpfKey.Equals(JnpfKeyConst.DATE)) return res.ToString().ParseToDateTime(); else if (model.__config__.jnpfKey.Equals(JnpfKeyConst.NUMINPUT) || model.__config__.jnpfKey.Equals(JnpfKeyConst.SWITCH))//modify by zhoukeda 2023427 开关默认数字 return res; @@ -561,11 +570,23 @@ public class FormDataParsing : ITransient if (vModelType.DYNAMIC.GetDescription() == configModel.dataType) list = await GetDynamicList(model); if (vModelType.STATIC.GetDescription() == configModel.dataType) { - foreach (Dictionary? item in model.__slot__.options) + if (model.__slot__ != null && model.__slot__.options != null && model.__slot__.options.Any()) { - Dictionary option = new Dictionary(); - option.Add(item[model.__config__.props.value].ToString(), item[model.__config__.props.label].ToString()); - list.Add(option); + foreach (Dictionary? item in model.__slot__.options) + { + Dictionary option = new Dictionary(); + option.Add(item[model.__config__.props.value].ToString(), item[model.__config__.props.label].ToString()); + list.Add(option); + } + } + else if (model.options != null && model.options.Any()) + { + foreach (Dictionary? item in model.options.ToObject>>()) + { + Dictionary option = new Dictionary(); + option.Add(item[model.props.props.value].ToString(), item[model.props.props.label].ToString()); + list.Add(option); + } } } @@ -621,7 +642,7 @@ public class FormDataParsing : ITransient case JnpfKeyConst.POSSELECT: // 岗位 if (!GetCacheValues(fieldCacheKey, templateData)) { - List? positionEntityList = await _sugar.Queryable().Where(u => u.DeleteMark == null).ToListAsync(); + List? positionEntityList = await _db.AsSugarClient().Queryable().Where(u => u.DeleteMark == null).ToListAsync(); List> positionList = new List>(); foreach (PositionEntity? item in positionEntityList) { @@ -638,7 +659,7 @@ public class FormDataParsing : ITransient case JnpfKeyConst.GROUPSELECT: // 分组 if (!GetCacheValues(fieldCacheKey, templateData)) { - List? positionEntityList = await _sugar.Queryable().Where(u => u.DeleteMark == null).ToListAsync(); + List? positionEntityList = await _db.AsSugarClient().Queryable().Where(u => u.DeleteMark == null).ToListAsync(); List> positionList = new List>(); foreach (GroupEntity? item in positionEntityList) { @@ -655,7 +676,7 @@ public class FormDataParsing : ITransient case JnpfKeyConst.ROLESELECT: // 角色 if (!GetCacheValues(fieldCacheKey, templateData)) { - List? positionEntityList = await _sugar.Queryable().Where(u => u.DeleteMark == null).ToListAsync(); + List? positionEntityList = await _db.AsSugarClient().Queryable().Where(u => u.DeleteMark == null).ToListAsync(); List> positionList = new List>(); foreach (RoleEntity? item in positionEntityList) { @@ -689,7 +710,7 @@ public class FormDataParsing : ITransient } else { - List? addressEntityList = await _sugar.Queryable().Select(x => new ProvinceEntity { Id = x.Id, ParentId = x.ParentId, Type = x.Type, FullName = x.FullName }).ToListAsync(); + List? addressEntityList = await _db.AsSugarClient().Queryable().Select(x => new ProvinceEntity { Id = x.Id, ParentId = x.ParentId, Type = x.Type, FullName = x.FullName }).ToListAsync(); // 处理省市区树 addressEntityList.Where(x => x.Type == "1").ToList().ForEach(item => item.QuickQuery = item.FullName); @@ -731,7 +752,7 @@ public class FormDataParsing : ITransient } else { - List? addressEntityList = await _sugar.Queryable().Select(x => new ProvinceEntity { Id = x.Id, ParentId = x.ParentId, Type = x.Type, FullName = x.FullName }).ToListAsync(); + List? addressEntityList = await _db.AsSugarClient().Queryable().Select(x => new ProvinceEntity { Id = x.Id, ParentId = x.ParentId, Type = x.Type, FullName = x.FullName }).ToListAsync(); // 处理省市区树 addressEntityList.Where(x => x.Type == "1").ToList().ForEach(item => item.QuickQuery = item.FullName); @@ -787,7 +808,7 @@ public class FormDataParsing : ITransient } else { - List? userEntityList = await _sugar.Queryable().Where(x => x.DeleteMark == null).Select(x => new UserEntity() { Id = x.Id, RealName = x.RealName, Account = x.Account }).ToListAsync(); + List? userEntityList = await _db.AsSugarClient().Queryable().Where(x => x.DeleteMark == null).Select(x => new UserEntity() { Id = x.Id, RealName = x.RealName, Account = x.Account }).ToListAsync(); List> userList = new List>(); foreach (UserEntity? item in userEntityList) @@ -813,32 +834,32 @@ public class FormDataParsing : ITransient else { var addList = new List>(); - (await _sugar.Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.RealName, x.Account }).ToListAsync()).ForEach(item => + (await _db.AsSugarClient().Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.RealName, x.Account }).ToListAsync()).ForEach(item => { Dictionary user = new Dictionary(); user.Add(item.Id + "--user", item.RealName + "/" + item.Account); addList.Add(user); }); - (await _sugar.Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => + (await _db.AsSugarClient().Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => { Dictionary user = new Dictionary(); user.Add(item.Id + "--company", item.FullName); user.Add(item.Id + "--department", item.FullName); addList.Add(user); }); - (await _sugar.Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => + (await _db.AsSugarClient().Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => { Dictionary user = new Dictionary(); user.Add(item.Id + "--role", item.FullName); addList.Add(user); }); - (await _sugar.Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => + (await _db.AsSugarClient().Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => { Dictionary user = new Dictionary(); user.Add(item.Id + "--position", item.FullName); addList.Add(user); }); - (await _sugar.Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => + (await _db.AsSugarClient().Queryable().Where(x => x.DeleteMark == null).Select(x => new { x.Id, x.FullName }).ToListAsync()).ForEach(item => { Dictionary user = new Dictionary(); user.Add(item.Id + "--group", item.FullName); @@ -884,7 +905,7 @@ public class FormDataParsing : ITransient { if (!GetCacheValues(fieldCacheKey, templateData)) { - List? dep_organizeEntityList = await _sugar.Queryable().Where(d => d.EnabledMark == 1 && d.DeleteMark == null) + List? dep_organizeEntityList = await _db.AsSugarClient().Queryable().Where(d => d.EnabledMark == 1 && d.DeleteMark == null) .WhereIF(orgType.Equals(JnpfKeyConst.DEPSELECT), d => d.Category.Equals("department")).ToListAsync(); List> vlist = new List>(); @@ -954,7 +975,7 @@ public class FormDataParsing : ITransient parameter.Add(new SugarParameter("@currentChargeorganizationAndSuborganization", subsidiary)); } - DbLinkEntity? linkEntity = await _sugar.Queryable().Where(m => m.Id == dynamic.DBLinkId && m.DeleteMark == null).FirstAsync(); + DbLinkEntity? linkEntity = await _db.AsSugarClient().Queryable().Where(m => m.Id == dynamic.DBLinkId && m.DeleteMark == null).FirstAsync(); if (linkEntity == null) linkEntity = _databaseService.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); _dataInterfaceService.ReplaceParameterValue(dynamic, new Dictionary()); System.Data.DataTable? dt = _databaseService.GetInterFaceData(linkEntity, dynamic.Query, parameter.ToArray()); @@ -1064,7 +1085,7 @@ public class FormDataParsing : ITransient /// List. private async Task>> GetDictionaryList(string? dictionaryTypeId = null) { - List dictionaryDataEntityList = await _sugar.Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.DictionaryTypeId)) + List dictionaryDataEntityList = await _db.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.DictionaryTypeId)) .WhereIF(dictionaryTypeId.IsNotEmptyOrNull(), (a, b) => b.Id == dictionaryTypeId || b.EnCode == dictionaryTypeId).Where(a => a.DeleteMark == null).ToListAsync(); List> dictionaryDataList = new List>(); @@ -1141,7 +1162,7 @@ public class FormDataParsing : ITransient Dictionary dataMap = modelData.ToObject>(); // 数据库保存的F_Data // 序列化后时间戳转换处理 - List? timeList = formData.Where(x => x.__config__.jnpfKey == "createTime" || x.__config__.jnpfKey == "modifyTime").ToList(); + List? timeList = formData.Where(x => x.__config__.jnpfKey == JnpfKeyConst.CREATETIME || x.__config__.jnpfKey == JnpfKeyConst.MODIFYTIME).ToList(); if (timeList.Any()) { timeList.ForEach(item => @@ -1185,10 +1206,10 @@ public class FormDataParsing : ITransient break; case JnpfKeyConst.CREATEUSER: case JnpfKeyConst.MODIFYUSER: - dataMap[key] = await _sugar.Queryable().Where(x => x.Id == dataValue).Select(x => SqlFunc.MergeString(x.RealName, "/", x.Account)).FirstAsync(); + dataMap[key] = await _db.AsSugarClient().Queryable().Where(x => x.Id == dataValue).Select(x => SqlFunc.MergeString(x.RealName, "/", x.Account)).FirstAsync(); break; case JnpfKeyConst.CURRPOSITION: - dataMap[key] = (await _sugar.Queryable().FirstAsync(p => p.Id == dataMap[key].ToString()))?.FullName; + dataMap[key] = (await _db.AsSugarClient().Queryable().FirstAsync(p => p.Id == dataMap[key].ToString()))?.FullName; if (dataMap[key].IsNullOrEmpty()) dataMap[key] = " "; break; case JnpfKeyConst.CURRORGANIZE: @@ -1267,111 +1288,6 @@ public class FormDataParsing : ITransient #endregion - #region 无表的数据查询筛选 - - /// - /// 无表的数据筛选. - /// - /// 数据列表. - /// 查询条件值. - /// - /// - public List> GetNoTableFilteringData(List list, Dictionary keyJsonMap, List formData) - { - List> realList = new List>(); - foreach (var entity in list) - { - Dictionary query = keyJsonMap; - Dictionary realEntity = entity.Data.ToObject>(); - realEntity.Add("id", entity.Id); - if (query != null && query.Count != 0) - { - int m = 0; - int dicCount = query.Keys.Count; - string[] strKey = new string[dicCount]; - query.Keys.CopyTo(strKey, 0); - for (int i = 0; i < strKey.Length; i++) - { - var keyValue = keyJsonMap[strKey[i]]; - var queryEntity = realEntity.Where(e => e.Key == strKey[i]).FirstOrDefault(); - var model = formData.Where(f => f.__vModel__ == strKey[i]).FirstOrDefault(); - if (queryEntity.Value != null && !string.IsNullOrWhiteSpace(keyValue.ToString())) - { - var realValue = queryEntity.Value.ObjToString(); - var type = model.__config__.jnpfKey; - switch (type) - { - case JnpfKeyConst.TIME: - { - var queryTime = new List(); - keyValue.ToObject>().ForEach(item => { if (!string.IsNullOrWhiteSpace(item)) queryTime.Add(item.ParseToDateTime().ToLongTimeString()); }); - - if (Common.Extension.Extensions.IsInTimeRange(realValue.ParseToDateTime(), queryTime.First(), queryTime.Last(), 3)) m++; - } - break; - case JnpfKeyConst.DATE: - { - List queryTime = keyValue.ToObject>(); - int formatType = 0; - if (model.format == "yyyy-MM") formatType = 1; - else if (model.format == "yyyy") formatType = 2; - string value1 = string.Format("{0:yyyy-MM-dd}", queryTime.First().ParseToDateTime()); - string value2 = string.Format("{0:yyyy-MM-dd}", queryTime.Last().ParseToDateTime()); - if (Common.Extension.Extensions.IsInTimeRange(realValue.ParseToDateTime(), value1, value2, formatType)) m++; - } - break; - case JnpfKeyConst.CREATETIME: - case JnpfKeyConst.MODIFYTIME: - { - List dayTime1 = keyValue.ToObject>(); - string value1 = string.Format("{0:yyyy-MM-dd 00:00:00}", dayTime1.First().ParseToDateTime()); - string value2 = string.Format("{0:yyyy-MM-dd 23:59:59}", dayTime1.Last().ParseToDateTime()); - if (!string.IsNullOrEmpty(realValue) && Common.Extension.Extensions.IsInTimeRange(Convert.ToDateTime(realValue), value1, value2)) m++; - } - break; - case JnpfKeyConst.NUMINPUT: - case JnpfKeyConst.CALCULATE: - { - List numArray = keyValue.ToObject>(); - var numA = numArray.First().ParseToInt(); - var numB = numArray.Last() == null ? long.MaxValue : numArray.Last().ParseToInt(); - var numC = realValue.ParseToInt(); - if (numC >= numA && numC <= numB) m++; - } - break; - default: - if (realValue.IsNotEmptyOrNull() && keyValue != null) - { - string keyV = keyValue.ToString(); - - if (model.searchType == 2 && realValue.Contains(keyV)) m++; - else if (model.searchType == 1) - { - // 多选时为模糊查询 - if ((model.multiple || type == "checkbox") && realValue.Contains(keyV)) m++; - else if (realValue.Equals(keyV)) m++; - } - else if (realValue.Replace(" ", "").Contains(keyV.Replace(" ", ""))) m++; - } - - break; - } - } - - if (m == dicCount) realList.Add(realEntity); - } - } - else - { - realList.Add(realEntity); - } - } - - return realList; - } - - #endregion - #region 列表转换数据(Id 转 Name) /// @@ -1383,17 +1299,31 @@ public class FormDataParsing : ITransient /// /// 表单类型1-纯表单、2-普通表单、3-工作流表单. /// 数据主键. - /// 子表解析时调用 (控件联动可能需要主表的数据). + /// 是否外链. /// - public async Task>> GetKeyData( - List formData, + public async Task>> GetKeyData(List formData, List> list, ColumnDesignModel? columnDesign = null, string actionType = "List", int webType = 2, string primaryKey = "F_Id", - Dictionary? mainData = null) + bool isShortLink = false) { + if (isShortLink) + { + formData = formData.Where(x => x.__config__.jnpfKey == JnpfKeyConst.COMINPUT || x.__config__.jnpfKey == JnpfKeyConst.TEXTAREA + || (x.__config__.jnpfKey == JnpfKeyConst.NUMINPUT && x.__config__.jnpfKey == JnpfKeyConst.SWITCH) + || (x.__config__.jnpfKey == JnpfKeyConst.RADIO && x.__config__.dataType.Equals("static")) + || (x.__config__.jnpfKey == JnpfKeyConst.CHECKBOX && x.__config__.dataType.Equals("static")) + || (x.__config__.jnpfKey == JnpfKeyConst.SELECT && x.__config__.dataType.Equals("static")) + || (x.__config__.jnpfKey == JnpfKeyConst.CASCADER && x.__config__.dataType.Equals("static")) + || (x.__config__.jnpfKey == JnpfKeyConst.TREESELECT && x.__config__.dataType.Equals("static")) + || x.__config__.jnpfKey == JnpfKeyConst.DATE || x.__config__.jnpfKey == JnpfKeyConst.TIME || x.__config__.jnpfKey == JnpfKeyConst.COLORPICKER + || x.__config__.jnpfKey == JnpfKeyConst.RATE || x.__config__.jnpfKey == JnpfKeyConst.SLIDER || x.__config__.jnpfKey == JnpfKeyConst.EDITOR + || x.__config__.jnpfKey == JnpfKeyConst.LINK || x.__config__.jnpfKey == JnpfKeyConst.JNPFTEXT || x.__config__.jnpfKey == JnpfKeyConst.ALERT) + .Where(x => !x.__config__.jnpfKey.Equals(JnpfKeyConst.POPUPTABLESELECT)).ToList(); + } + // 获取控件缓存数据 Dictionary templateData = await GetVisualDevCaCheData(formData); @@ -1418,12 +1348,13 @@ public class FormDataParsing : ITransient List>? roleTemplateValue = new List>(); // 角色 Dictionary>>? templateValues = new Dictionary>>(); // 其他 - if (webType == 3) + if (webType == 3 && list.Any(x => x.ContainsKey(primaryKey))) { var ids = list.Select(x => x[primaryKey]).ToList(); - var flowTaskList = await _sugar.Queryable().Where(x => ids.Contains(x.Id)).Select(x => new FlowTaskEntity() { Id = x.Id, Status = x.Status }).ToListAsync(); + var flowTaskList = await _db.AsSugarClient().Queryable().Where(x => ids.Contains(x.Id)).Select(x => new FlowTaskEntity() { Id = x.Id, Status = x.Status }).ToListAsync(); list.ForEach(item => { + if (item.ContainsKey("F_FlowId")) item["flowId"] = item["F_FlowId"]; if (flowTaskList.Any(x => x.Id.Equals(item[primaryKey].ToString()))) { var flowTask = flowTaskList.Where(x => x.Id.Equals(item[primaryKey].ToString())).FirstOrDefault(); @@ -1442,7 +1373,6 @@ public class FormDataParsing : ITransient foreach (Dictionary? dataMap in list) { var oldDataMap = dataMap.Copy(); - if (mainData != null) oldDataMap.Add("JnpfKeyConst_MainData", mainData); if (dataMap.ContainsKey(primaryKey)) dataMap["id"] = dataMap[primaryKey].ToString(); // 主键 int dicCount = dataMap.Keys.Count; @@ -1455,7 +1385,6 @@ public class FormDataParsing : ITransient if (!(dataMap[strKey[i]] is null)) { FieldsModel? form = formData.Where(f => f.__vModel__ == strKey[i]).FirstOrDefault(); - if (form != null) { if (form.__vModel__.Contains(form.__config__.jnpfKey + "Field")) dataMap[strKey[i]] = TemplateControlsDataConversion(dataMap[strKey[i]], form); @@ -1707,30 +1636,18 @@ public class FormDataParsing : ITransient } break; case JnpfKeyConst.CURRDEPT: - dataMap[key] = await _memCache.GetOrCreateAsync($"organizeId_{dataValue}", async entry => - { - entry.SlidingExpiration = TimeSpan.FromSeconds(60); - return (await _sugar.Queryable().FirstAsync(x => x.Id == dataValue.ToString()))?.FullName; - }); + dataMap[key] = (await _db.AsSugarClient().Queryable().FirstAsync(x => x.Id == dataValue.ToString()))?.FullName; break; case JnpfKeyConst.MODIFYUSER: case JnpfKeyConst.CREATEUSER: - dataMap[key] = await _memCache.GetOrCreateAsync($"userId_{dataValue}", async entry => - { - entry.SlidingExpiration = TimeSpan.FromSeconds(60); - return await _sugar.Queryable().Where(x => x.Id == dataValue.ToString()).Select(x => SqlFunc.MergeString(x.RealName, "/", x.Account)).FirstAsync(); - }); + dataMap[key] = await _db.AsSugarClient().Queryable().Where(x => x.Id == dataValue.ToString()).Select(x => SqlFunc.MergeString(x.RealName, "/", x.Account)).FirstAsync(); break; case JnpfKeyConst.MODIFYTIME: case JnpfKeyConst.CREATETIME: - dataMap[key] = string.Format("{0:yyyy-MM-dd HH:mm:ss}", dataMap[key].ToString().ParseToDateTime()); + dataMap[key] = string.Format("{0:yyyy-MM-dd HH:mm}", dataMap[key].ToString().ParseToDateTime()); break; case JnpfKeyConst.CURRPOSITION: - dataMap[key] = await _memCache.GetOrCreateAsync($"positionId_{dataValue}", async entry => - { - entry.SlidingExpiration = TimeSpan.FromSeconds(60); - return (await _sugar.Queryable().FirstAsync(x => x.Id == dataValue.ToString()))?.FullName; - }); + dataMap[key] = (await _db.AsSugarClient().Queryable().FirstAsync(x => x.Id == dataValue.ToString()))?.FullName; break; case JnpfKeyConst.POPUPTABLESELECT: case JnpfKeyConst.POPUPSELECT: @@ -1883,7 +1800,7 @@ public class FormDataParsing : ITransient else { // 根据可视化功能ID获取该模板全部数据 - var relationFormModel = await _sugar.Queryable().FirstAsync(v => v.Id == model.modelId); + var relationFormModel = await _db.AsSugarClient().Queryable().FirstAsync(v => v.Id == model.modelId); var newFieLdsModelList = relationFormModel.FormData.ToObject().fields.FindAll(x => model.relationField.Equals(x.__vModel__)); VisualDevModelListQueryInput listQueryInput = new VisualDevModelListQueryInput { @@ -1892,27 +1809,21 @@ public class FormDataParsing : ITransient sort = columnDesign.sort, pageSize = 999999 }; - //Scoped.Create(async (_, scope) => - //{ - // var services = scope.ServiceProvider; - // var _runService = App.GetService(services); - // var res = await _runService.GetRelationFormList(relationFormModel, listQueryInput); - // _cacheManager.Set(redisName, res.list.ToList(), TimeSpan.FromMinutes(10)); // 缓存10分钟 - //}); + var cacheStr = _cacheManager.Get(redisName); + if (cacheStr.IsNotEmptyOrNull()) relationFormDataList = cacheStr.ToObject>>(); //modified by PhilPan - if (string.IsNullOrEmpty(cacheStr)) + else { - await Scoped.CreateAsync(async (_, scope) => + Scoped.Create((_, scope) => { var services = scope.ServiceProvider; var _runService = App.GetService(services); - var res = await _runService.GetRelationFormList(relationFormModel, listQueryInput); - _cacheManager.Set(redisName, res.list.ToList(), TimeSpan.FromMinutes(10)); // 缓存10分钟 - cacheStr = _cacheManager.Get(redisName); - }); + var res = _runService.GetRelationFormList(relationFormModel, listQueryInput).WaitAsync(TimeSpan.FromMinutes(2)).Result; + relationFormDataList = res.list.ToList(); + _cacheManager.Set(redisName, relationFormDataList, TimeSpan.FromMinutes(10)); // 缓存10分钟 + }); } - if (cacheStr.IsNotEmptyOrNull()) relationFormDataList = cacheStr.ToObject>>(); } var relationFormRealData = relationFormDataList.Where(it => it["id"].Equals(dataMap[key])).FirstOrDefault(); @@ -1990,36 +1901,16 @@ public class FormDataParsing : ITransient if (data.ToJsonString().Equals(mValue.ToJsonString()) && (form.__config__.templateJson != null && form.__config__.templateJson.Any())) { data.Clear(); - form.__config__.templateJson.ForEach(x => - { - if (x.relationField.ToLower().Contains("tablefield") && x.relationField.Contains("-")) - { - var rField = x.relationField.Split("-").Last(); - if (dataMap.ContainsKey(rField)) x.defaultValue = dataMap[rField] != null ? dataMap[rField]?.ToString() : x.defaultValue; - } - else - { - if (dataMap.ContainsKey(x.relationField)) - { - x.defaultValue = dataMap[x.relationField] != null ? dataMap[x.relationField]?.ToString() : x.defaultValue; - } - else if (dataMap.ContainsKey("JnpfKeyConst_MainData")) - { - var mainData = dataMap["JnpfKeyConst_MainData"].ToObject>(); - if (mainData.ContainsKey(x.relationField)) x.defaultValue = mainData[x.relationField] != null ? mainData[x.relationField]?.ToString() : x.defaultValue; - } - } - }); + form.__config__.templateJson.ForEach(x => x.defaultValue = (dataMap.ContainsKey(x.relationField) && dataMap[x.relationField] != null) ? dataMap[x.relationField]?.ToString() : x.defaultValue); _databaseService.ChangeDataBase(_databaseService.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName)); var res = _dataInterfaceService.GetResponseByType(form.__config__.propsUrl, 0, string.Empty, new Common.Dtos.VisualDev.VisualDevDataFieldDataListInput() { paramList = form.__config__.templateJson.Adapt>(), pageSize = 500, currentPage = 1 }).Result; - var resList = res.ToObject>>(); + var resList = res.ToObject>>(); if (resList != null && resList.list.Any()) { foreach (object? item in mValue) { var comData = resList.list.Where(a => a.ContainsValue(item.ToString())).FirstOrDefault(); - var props = form.__config__.props != null ? form.__config__.props.label : form.props.props.label; - if (comData != null) data.Add(comData[props].ToString()); + if (comData != null) data.Add(comData[form.__config__.props.label].ToString()); else data.Add(item.ToString()); } } @@ -2055,7 +1946,7 @@ public class FormDataParsing : ITransient /// public void GetBARAndQR(List fieldsModels, Dictionary _newDataMap, Dictionary _dataMap) { - fieldsModels.Where(x => x.__config__.jnpfKey == "barcode" || x.__config__.jnpfKey == "qrcode").Where(x => !string.IsNullOrWhiteSpace(x.relationField)).ToList().ForEach(item => + fieldsModels.Where(x => x.__config__.jnpfKey == JnpfKeyConst.BARCODE || x.__config__.jnpfKey == JnpfKeyConst.QRCODE).Where(x => !string.IsNullOrWhiteSpace(x.relationField)).ToList().ForEach(item => { if (!_newDataMap.ContainsKey(item.relationField + "_id") && _dataMap.ContainsKey(item.relationField)) _newDataMap.Add(item.relationField + "_id", _dataMap[item.relationField]); diff --git a/visualdev/Tnb.VisualDev.Engine/Core/TemplateAnalysis.cs b/visualdev/Tnb.VisualDev.Engine/Core/TemplateAnalysis.cs index 1f2c3309..cee51ec1 100644 --- a/visualdev/Tnb.VisualDev.Engine/Core/TemplateAnalysis.cs +++ b/visualdev/Tnb.VisualDev.Engine/Core/TemplateAnalysis.cs @@ -23,6 +23,7 @@ public static class TemplateAnalysis switch (config.jnpfKey) { case JnpfKeyConst.TABLE: + item.__config__.defaultCurrent = item.__config__.children.Any(it => it.__config__.defaultCurrent); template.Add(item); break; case JnpfKeyConst.ROW: diff --git a/visualdev/Tnb.VisualDev.Engine/Core/TemplateParsingBase.cs b/visualdev/Tnb.VisualDev.Engine/Core/TemplateParsingBase.cs index bfd708e4..4066560a 100644 --- a/visualdev/Tnb.VisualDev.Engine/Core/TemplateParsingBase.cs +++ b/visualdev/Tnb.VisualDev.Engine/Core/TemplateParsingBase.cs @@ -1,11 +1,10 @@ using JNPF.Common.Const; using JNPF.Common.Extension; -using JNPF.Common.Models; using JNPF.Common.Security; using JNPF.Systems.Entitys.System; using JNPF.VisualDev.Engine.Model; using JNPF.VisualDev.Entitys; -using Mapster; +using SqlSugar; namespace JNPF.VisualDev.Engine.Core; @@ -145,6 +144,16 @@ public class TemplateParsingBase /// public List selectKey { get; set; } + /// + /// PC数据过滤 . + /// + public List DataRuleListJson { get; set; } + + /// + /// App数据过滤 . + /// + public List AppDataRuleListJson { get; set; } + /// /// 模板解析帮助 构造 (功能表单). /// @@ -177,96 +186,75 @@ public class TemplateParsingBase visualDevEntity = entity; WebType = entity.WebType; if (entity.FlowId.IsNotEmptyOrNull() && entity.EnableFlow.Equals(1)) WebType = 3; - FormDataModel formModel = entity.FormData.ToObject(); - FormModel = formModel; // 表单Json模型 - IsHasTable = !string.IsNullOrEmpty(entity.Tables) && !"[]".Equals(entity.Tables); // 是否有表 - AllFieldsModel = GetInDataFieldsModel(formModel.fields.ToJsonString().ToObject>()); // 所有控件集合 - FieldsModelList = GetInDataFieldsModel(formModel.fields); // 已剔除布局控件集合 - MainTable = entity.Tables.ToList().Find(m => m.typeId.Equals("1")); // 主表 - MainTableName = MainTable?.table; // 主表名称 - AddChlidTableFeildsModel(); - // 处理旧控件 部分没有 tableName - FieldsModelList.Where(x => string.IsNullOrWhiteSpace(x.__config__.tableName)).ToList().ForEach(item => + // 数据视图 + if (entity.WebType.Equals(4)) { - if (item.__vModel__.Contains("_jnpf_")) item.__config__.tableName = item.__vModel__.ReplaceRegex(@"_jnpf_(\w+)", string.Empty).Replace("jnpf_", string.Empty); // 副表 - else item.__config__.tableName = MainTableName != null ? MainTableName : string.Empty; // 主表 - }); - AllTable = entity.Tables.ToObject>(); // 所有表 - AuxiliaryTableFieldsModelList = FieldsModelList.Where(x => x.__vModel__.Contains("_jnpf_")).ToList(); // 单控件副表集合 - ChildTableFieldsModelList = FieldsModelList.Where(x => x.__config__.jnpfKey == "table").ToList(); // 子表集合 - MainTableFieldsModelList = FieldsModelList.Except(AuxiliaryTableFieldsModelList).Except(ChildTableFieldsModelList).ToList(); // 主表控件集合 - SingleFormData = FieldsModelList.Where(x => x.__config__.jnpfKey != "table").ToList(); // 非子表集合 - GenerateFields = GetGenerateFields(); // 系统生成控件 - - MainTableFields = new Dictionary(); - AuxiliaryTableFields = new Dictionary(); - ChildTableFields = new Dictionary(); - AllTableFields = new Dictionary(); - MainTableFieldsModelList.Where(x => x.__vModel__.IsNotEmptyOrNull()).ToList().ForEach(x => - { - MainTableFields.Add(x.__vModel__, x.__config__.tableName + "." + x.__vModel__); - AllTableFields.Add(x.__vModel__, x.__config__.tableName + "." + x.__vModel__); - }); - AuxiliaryTableFieldsModelList.Where(x => x.__vModel__.IsNotEmptyOrNull()).ToList().ForEach(x => - { - AuxiliaryTableFields.Add(x.__vModel__, x.__vModel__.Replace("_jnpf_", ".").Replace("jnpf_", string.Empty)); - AllTableFields.Add(x.__vModel__, x.__vModel__.Replace("_jnpf_", ".").Replace("jnpf_", string.Empty)); - }); - ChildTableFieldsModelList.ForEach(item => - { - item.__config__.children.Where(x => x.__vModel__.IsNotEmptyOrNull()).ToList().ForEach(x => + FullName = entity.FullName; + IsHasTable = false; + InitColumnData(entity); + AllFieldsModel = new List(); + ColumnData.columnList.ForEach(item => { - ChildTableFields.Add(item.__vModel__ + "-" + x.__vModel__, item.__config__.tableName + "." + x.__vModel__); - AllTableFields.Add(item.__vModel__ + "-" + x.__vModel__, item.__config__.tableName + "." + x.__vModel__); + AllFieldsModel.Add(new FieldsModel() { __vModel__ = item.__vModel__, __config__ = new ConfigModel() { label = item.label, jnpfKey = item.jnpfKey } }); }); - }); - - if (!string.IsNullOrWhiteSpace(entity.ColumnData)) ColumnData = entity.ColumnData.ToObject(); // 列配置模型 - else ColumnData = new ColumnDesignModel(); - - if (!string.IsNullOrWhiteSpace(entity.AppColumnData)) AppColumnData = entity.AppColumnData.ToObject(); // 列配置模型 - else AppColumnData = new ColumnDesignModel(); - - if (AppColumnData.columnList != null && AppColumnData.columnList.Any()) - { AppColumnData.columnList.ForEach(item => { - var addColumn = ColumnData.columnList.Find(x => x.prop == item.prop); - if (addColumn == null) ColumnData.columnList.Add(item); + AllFieldsModel.Add(new FieldsModel() { __vModel__ = item.__vModel__, __config__ = new ConfigModel() { label = item.label, jnpfKey = item.jnpfKey } }); }); + AllFieldsModel = AllFieldsModel.DistinctBy(x => x.__vModel__).ToList(); + FieldsModelList = AllFieldsModel; + AuxiliaryTableFieldsModelList = AllFieldsModel; + MainTableFieldsModelList = AllFieldsModel; + SingleFormData = AllFieldsModel; } - - if (AppColumnData.searchList != null && AppColumnData.searchList.Any()) + else { - AppColumnData.searchList.ForEach(item => + FormDataModel formModel = entity.FormData.ToObjectOld(); + FormModel = formModel; // 表单Json模型 + IsHasTable = !string.IsNullOrEmpty(entity.Tables) && !"[]".Equals(entity.Tables); // 是否有表 + AllFieldsModel = GetInDataFieldsModel(formModel.fields.ToJsonString().ToObjectOld>()); // 所有控件集合 + FieldsModelList = GetInDataFieldsModel(formModel.fields); // 已剔除布局控件集合 + MainTable = entity.Tables.ToList().Find(m => m.typeId.Equals("1")); // 主表 + MainTableName = MainTable?.table; // 主表名称 + AddChlidTableFeildsModel(); + + // 处理旧控件 部分没有 tableName + FieldsModelList.Where(x => string.IsNullOrWhiteSpace(x.__config__.tableName)).ToList().ForEach(item => { - var addSearch = ColumnData.searchList.Find(x => x.__config__.jnpfKey == item.__config__.jnpfKey); - if (addSearch == null) ColumnData.searchList.Add(item); + if (item.__vModel__.Contains("_jnpf_")) item.__config__.tableName = item.__vModel__.ReplaceRegex(@"_jnpf_(\w+)", string.Empty).Replace("jnpf_", string.Empty); // 副表 + else item.__config__.tableName = MainTableName != null ? MainTableName : string.Empty; // 主表 }); - } + AllTable = entity.Tables.ToObject>(); // 所有表 + AuxiliaryTableFieldsModelList = FieldsModelList.Where(x => x.__vModel__.Contains("_jnpf_")).ToList(); // 单控件副表集合 + ChildTableFieldsModelList = FieldsModelList.Where(x => x.__config__.jnpfKey == JnpfKeyConst.TABLE).ToList(); // 子表集合 + MainTableFieldsModelList = FieldsModelList.Except(AuxiliaryTableFieldsModelList).Except(ChildTableFieldsModelList).ToList(); // 主表控件集合 + SingleFormData = FieldsModelList.Where(x => x.__config__.jnpfKey != JnpfKeyConst.TABLE).ToList(); // 非子表集合 + GenerateFields = GetGenerateFields(); // 系统生成控件 - if (ColumnData.searchList != null && ColumnData.searchList.Any()) - { - ColumnData.searchList.Where(x => x.__config__.jnpfKey == JnpfKeyConst.CASCADER).ToList().ForEach(item => + MainTableFields = new Dictionary(); + AuxiliaryTableFields = new Dictionary(); + ChildTableFields = new Dictionary(); + AllTableFields = new Dictionary(); + MainTableFieldsModelList.Where(x => x.__vModel__.IsNotEmptyOrNull()).ToList().ForEach(x => + { + MainTableFields.Add(x.__vModel__, x.__config__.tableName + "." + x.__vModel__); + AllTableFields.Add(x.__vModel__, x.__config__.tableName + "." + x.__vModel__); + }); + AuxiliaryTableFieldsModelList.Where(x => x.__vModel__.IsNotEmptyOrNull()).ToList().ForEach(x => + { + AuxiliaryTableFields.Add(x.__vModel__, x.__vModel__.Replace("_jnpf_", ".").Replace("jnpf_", string.Empty)); + AllTableFields.Add(x.__vModel__, x.__vModel__.Replace("_jnpf_", ".").Replace("jnpf_", string.Empty)); + }); + ChildTableFieldsModelList.ForEach(item => + { + item.__config__.children.Where(x => x.__vModel__.IsNotEmptyOrNull()).ToList().ForEach(x => { - var it = SingleFormData.FirstOrDefault(x => x.__vModel__ == item.__vModel__); - if (it != null) item.multiple = it.props.props.multiple; + ChildTableFields.Add(item.__vModel__ + "-" + x.__vModel__, item.__config__.tableName + "." + x.__vModel__); + AllTableFields.Add(item.__vModel__ + "-" + x.__vModel__, item.__config__.tableName + "." + x.__vModel__); }); - } - - FullName = entity.FullName; - - if (ColumnData.uploaderTemplateJson != null && ColumnData.uploaderTemplateJson.selectKey != null) - { - dataType = ColumnData.uploaderTemplateJson.dataType; - selectKey = new List(); - - // 列顺序 - AllFieldsModel.ForEach(item => - { - if (ColumnData.uploaderTemplateJson.selectKey.Any(x => x.Equals(item.__vModel__))) selectKey.Add(item.__vModel__); }); + InitColumnData(entity); } } @@ -312,9 +300,9 @@ public class TemplateParsingBase else item.__config__.tableName = MainTableName != null ? MainTableName : string.Empty; // 主表 }); AuxiliaryTableFieldsModelList = FieldsModelList.Where(x => x.__vModel__.Contains("_jnpf_")).ToList(); // 单控件副表集合 - ChildTableFieldsModelList = FieldsModelList.Where(x => x.__config__.jnpfKey == "table").ToList(); // 子表集合 + ChildTableFieldsModelList = FieldsModelList.Where(x => x.__config__.jnpfKey == JnpfKeyConst.TABLE).ToList(); // 子表集合 MainTableFieldsModelList = FieldsModelList.Except(AuxiliaryTableFieldsModelList).Except(ChildTableFieldsModelList).ToList(); // 主表控件集合 - SingleFormData = FieldsModelList.Where(x => x.__config__.jnpfKey != "table").ToList(); // 非子表集合 + SingleFormData = FieldsModelList.Where(x => x.__config__.jnpfKey != JnpfKeyConst.TABLE).ToList(); // 非子表集合 GenerateFields = GetGenerateFields(); // 系统生成控件 MainTableFields = new Dictionary(); @@ -356,7 +344,7 @@ public class TemplateParsingBase /// true 通过. public bool VerifyTemplate() { - if (FieldsModelList != null && FieldsModelList.Any(x => x.__config__.jnpfKey == "table")) + if (FieldsModelList != null && FieldsModelList.Any(x => x.__config__.jnpfKey == JnpfKeyConst.TABLE)) { foreach (FieldsModel? item in ChildTableFieldsModelList) { @@ -477,10 +465,10 @@ public class TemplateParsingBase } else { - FormDataModel formModel = formJson.ToObject(); + FormDataModel formModel = formJson.ToObjectOld(); FormModel = formModel; // 表单Json模型 - IsHasTable = !string.IsNullOrEmpty(tables) && !"[]".Equals(tables); // 是否有表 - AllFieldsModel = GetInDataFieldsModel(formModel.fields.ToJsonString().ToObject>()); // 所有控件集合 + IsHasTable = !string.IsNullOrEmpty(tables) && !"[]".Equals(tables) && tables.IsNullOrEmpty(); // 是否有表 + AllFieldsModel = GetInDataFieldsModel(formModel.fields.ToJsonString().ToObjectOld>()); // 所有控件集合 FieldsModelList = GetInDataFieldsModel(formModel.fields); // 已剔除布局控件集合 MainTable = tables.ToList().Find(m => m.typeId.Equals("1")); // 主表 MainTableName = MainTable?.table; // 主表名称 @@ -494,9 +482,9 @@ public class TemplateParsingBase }); AllTable = tables.ToObject>(); // 所有表 AuxiliaryTableFieldsModelList = FieldsModelList.Where(x => x.__vModel__.Contains("_jnpf_")).ToList(); // 单控件副表集合 - ChildTableFieldsModelList = FieldsModelList.Where(x => x.__config__.jnpfKey == "table").ToList(); // 子表集合 + ChildTableFieldsModelList = FieldsModelList.Where(x => x.__config__.jnpfKey == JnpfKeyConst.TABLE).ToList(); // 子表集合 MainTableFieldsModelList = FieldsModelList.Except(AuxiliaryTableFieldsModelList).Except(ChildTableFieldsModelList).ToList(); // 主表控件集合 - SingleFormData = FieldsModelList.Where(x => x.__config__.jnpfKey != "table").ToList(); // 非子表集合 + SingleFormData = FieldsModelList.Where(x => x.__config__.jnpfKey != JnpfKeyConst.TABLE).ToList(); // 非子表集合 GenerateFields = GetGenerateFields(); // 系统生成控件 MainTableFields = new Dictionary(); @@ -526,4 +514,233 @@ public class TemplateParsingBase AppColumnData = new ColumnDesignModel(); } } + + /// + /// 初始化列配置模型. + /// + private void InitColumnData(VisualDevEntity entity) + { + if (!string.IsNullOrWhiteSpace(entity.ColumnData)) ColumnData = entity.ColumnData.ToObject(); // 列配置模型 + else ColumnData = new ColumnDesignModel(); + + if (!string.IsNullOrWhiteSpace(entity.AppColumnData)) AppColumnData = entity.AppColumnData.ToObject(); // 列配置模型 + else AppColumnData = new ColumnDesignModel(); + + if (AppColumnData.columnList != null && AppColumnData.columnList.Any()) + { + AppColumnData.columnList.ForEach(item => + { + var addColumn = ColumnData.columnList.Find(x => x.prop == item.prop); + if (addColumn == null) ColumnData.columnList.Add(item); + }); + } + + if (AppColumnData.searchList != null && AppColumnData.searchList.Any()) + { + AppColumnData.searchList.ForEach(item => + { + var addSearch = ColumnData.searchList.Find(x => x.__config__.jnpfKey == item.__config__.jnpfKey); + if (addSearch == null) ColumnData.searchList.Add(item); + }); + } + + if (ColumnData.searchList != null && ColumnData.searchList.Any()) + { + ColumnData.searchList.Where(x => x.__config__.jnpfKey == JnpfKeyConst.CASCADER).ToList().ForEach(item => + { + var it = SingleFormData.FirstOrDefault(x => x.__vModel__ == item.__vModel__); + if (it != null) item.multiple = it.props.props.multiple; + }); + } + + FullName = entity.FullName; + + if (ColumnData.uploaderTemplateJson != null && ColumnData.uploaderTemplateJson.selectKey != null) + { + dataType = ColumnData.uploaderTemplateJson.dataType; + selectKey = new List(); + + // 列顺序 + AllFieldsModel.ForEach(item => + { + if (ColumnData.uploaderTemplateJson.selectKey.Any(x => x.Equals(item.__vModel__))) selectKey.Add(item.__vModel__); + }); + } + + // 数据过滤 + if (ColumnData.ruleList != null && ColumnData.ruleList.Any()) + { + DataRuleListJson = new List(); + var condTree = new ConditionalTree() { ConditionalList = new List>() }; + ColumnData.ruleList.ForEach(item => condTree.ConditionalList.Add(new KeyValuePair(WhereType.And, GetItemRule(item)))); + DataRuleListJson.Add(condTree); + } + + if (AppColumnData.ruleListApp != null && AppColumnData.ruleListApp.Any()) + { + AppDataRuleListJson = new List(); + var condTree = new ConditionalTree() { ConditionalList = new List>() }; + AppColumnData.ruleListApp.ForEach(item => condTree.ConditionalList.Add(new KeyValuePair(WhereType.And, GetItemRule(item)))); + AppDataRuleListJson.Add(condTree); + } + } + + private IConditionalModel GetItemRule(RuleFieldModel item) + { + var conditionalType = ConditionalType.Equal; + var between = new List(); + if (item.fieldValue.IsNotEmptyOrNull()) + { + if (item.symbol.Equals("between")) between = item.fieldValue.ToObject>(); + switch (item.jnpfKey) + { + case JnpfKeyConst.CREATETIME: + case JnpfKeyConst.MODIFYTIME: + case JnpfKeyConst.DATE: + { + if (item.symbol.Equals("between")) + { + var startTime = between.First().TimeStampToDateTime(); + var endTime = between.Last().TimeStampToDateTime(); + between[0] = startTime.ToString(); + between[1] = endTime.ToString(); + if (item.format == "yyyy-MM-dd") + { + between[0] = new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0, 0).ToString(); + between[1] = new DateTime(endTime.Year, endTime.Month, endTime.Day, 23, 59, 59, 999).ToString(); + } + } + else + { + if (item.format == "yyyy-MM-dd") + { + var value = item.fieldValue.ToString().TimeStampToDateTime(); + item.fieldValue = new DateTime(value.Year, value.Month, value.Day, 0, 0, 0, 0).ToString(); + } + else + { + item.fieldValue = item.fieldValue.IsNotEmptyOrNull() ? item.fieldValue.ToString().TimeStampToDateTime() : item.fieldValue; + } + } + } + break; + } + } + switch (item.symbol) + { + case ">=": + conditionalType = ConditionalType.GreaterThanOrEqual; + break; + case ">": + conditionalType = ConditionalType.GreaterThan; + break; + case "==": + conditionalType = ConditionalType.Equal; + break; + case "<=": + conditionalType = ConditionalType.LessThanOrEqual; + break; + case "<": + conditionalType = ConditionalType.LessThan; + break; + case "<>": + conditionalType = ConditionalType.NoEqual; + break; + case "like": + if (item.fieldValue != null && item.fieldValue.ToString().Contains("[")) item.fieldValue = item.fieldValue.ToString().Replace("[", string.Empty).Replace("]", string.Empty); + conditionalType = ConditionalType.Like; + break; + case "notLike": + if (item.fieldValue != null && item.fieldValue.ToString().Contains("[")) item.fieldValue = item.fieldValue.ToString().Replace("[", string.Empty).Replace("]", string.Empty); + conditionalType = ConditionalType.NoLike; + break; + case "in": + case "notIn": + if (item.fieldValue != null && item.fieldValue.ToString().Contains("[")) + { + var isListValue = false; + var itemField = AllFieldsModel.Find(x => x.__vModel__.Equals(item.__vModel__)); + if (itemField.multiple || item.jnpfKey.Equals(JnpfKeyConst.CHECKBOX) || item.jnpfKey.Equals(JnpfKeyConst.CASCADER) || item.jnpfKey.Equals(JnpfKeyConst.ADDRESS)) + isListValue = true; + var conditionalList = new ConditionalCollections() { ConditionalList = new List>() }; + var ids = new List(); + if (item.fieldValue.ToString().Replace("\r\n", "").Replace(" ", "").Contains("[[")) ids = item.fieldValue.ToObject>>().Select(x => x.Last()).ToList(); + else ids = item.fieldValue.ToObject>(); + + for (var i = 0; i < ids.Count; i++) + { + var it = ids[i]; + var whereType = WhereType.And; + if (item.symbol.Equals("in")) whereType = i.Equals(0) && item.logic.Equals("&&") ? WhereType.And : WhereType.Or; + else whereType = i.Equals(0) && item.logic.Equals("||") ? WhereType.Or : WhereType.And; + conditionalList.ConditionalList.Add(new KeyValuePair(whereType, new ConditionalModel + { + FieldName = item.field, + ConditionalType = item.symbol.Equals("in") ? ConditionalType.Like : ConditionalType.NoLike, + FieldValue = isListValue ? it.ToJsonString() : it + })); + } + + if (item.symbol.Equals("notIn")) + { + conditionalList.ConditionalList.Add(new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.IsNot, + FieldValue = null + })); + conditionalList.ConditionalList.Add(new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.IsNot, + FieldValue = string.Empty + })); + } + + return conditionalList; + } + conditionalType = item.symbol.Equals("in") ? ConditionalType.In : ConditionalType.NotIn; + break; + case "null": + conditionalType = (item.jnpfKey.Equals(JnpfKeyConst.CALCULATE) || item.jnpfKey.Equals(JnpfKeyConst.NUMINPUT)) ? ConditionalType.EqualNull : ConditionalType.IsNullOrEmpty; + break; + case "notNull": + conditionalType = ConditionalType.IsNot; + break; + case "between": + return new ConditionalCollections() + { + ConditionalList = new List>() + { + new KeyValuePair((item.logic.Equals("&&") ? WhereType.And : WhereType.Or), new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.GreaterThanOrEqual, + FieldValue = between.First(), + FieldValueConvertFunc = it => Convert.ToDateTime(it) + }), + new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.LessThanOrEqual, + FieldValue = between.Last(), + FieldValueConvertFunc = it => Convert.ToDateTime(it) + }) + } + }; + } + + return new ConditionalCollections() + { + ConditionalList = new List>() + { + new KeyValuePair((item.logic.Equals("&&") ? WhereType.And : WhereType.Or), new ConditionalModel + { + FieldName = item.field, + ConditionalType = conditionalType, + FieldValue = item.fieldValue == null ? null : item.fieldValue.ToString() + }) + } + }; + } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenConfigModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenConfigModel.cs index 0d53de8a..bad13a01 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenConfigModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenConfigModel.cs @@ -259,6 +259,11 @@ public class CodeGenConfigModel /// public bool IsSystemControl { get; set; } + /// + /// 是否查询条件多选. + /// + public bool IsSearchMultiple { get; set; } + /// /// 需解析的控件类型 JnpfKeyConst @@ 需解析的字段集合(以,隔开). /// @@ -268,4 +273,24 @@ public class CodeGenConfigModel /// 需解析的控件类型 JnpfKeyConst @@ 需解析的字段集合(以,隔开)详情页 (行内编辑的时候特殊处理). /// public List ParsJnpfKeyConstListDetails { get; set; } + + /// + /// 是否树形表格. + /// + public bool IsTreeTable { get; set; } + + /// + /// 树形表格-父级字段. + /// + public string ParentField { get; set; } + + /// + /// 树形表格-显示字段. + /// + public string TreeShowField { get; set; } + + /// + /// 是否开启逻辑删除. + /// + public bool IsLogicalDelete { get; set; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenExportPropertyJsonModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenExportPropertyJsonModel.cs new file mode 100644 index 00000000..9b7ec43d --- /dev/null +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenExportPropertyJsonModel.cs @@ -0,0 +1,20 @@ +namespace JNPF.VisualDev.Engine.Model.CodeGen; + +public class CodeGenExportPropertyJsonModel +{ + public string filedName { get; set; } + + public string jnpfKey { get; set; } + + public string filedId { get; set; } + + /// + /// 是否必填. + /// + public bool required { get; set; } + + /// + /// 是否多选. + /// + public bool multiple { get; set; } +} diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenFormRealControlModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenFormRealControlModel.cs new file mode 100644 index 00000000..b1d67202 --- /dev/null +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenFormRealControlModel.cs @@ -0,0 +1,15 @@ +namespace JNPF.VisualDev.Engine.Model.CodeGen; + +/// +/// 代码生成表单真实控件. +/// +public class CodeGenFormRealControlModel +{ + public string jnpfKey { get; set; } + + public string vModel { get; set; } + + public bool multiple { get; set; } + + public List children { get; set; } +} \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenTableRelationsModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenTableRelationsModel.cs index 682e5e18..218e320f 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenTableRelationsModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/CodeGenTableRelationsModel.cs @@ -142,4 +142,11 @@ public class CodeGenTableRelationsModel /// 是否更新. /// public bool IsUpdate { get; set; } + + public bool IsControlParsing { get; set; } + + /// + /// 是否查询条件多选. + /// + public bool IsSearchMultiple { get; set; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/DefaultFormControlModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/DefaultFormControlModel.cs new file mode 100644 index 00000000..00eef949 --- /dev/null +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/DefaultFormControlModel.cs @@ -0,0 +1,167 @@ +using JNPF.DependencyInjection; + +namespace JNPF.VisualDev.Engine.Model.CodeGen; + +/// +/// 表单默认值控件模型. +/// +[SuppressSniffer] +public class DefaultFormControlModel +{ + /// + /// 是否存在日期控件. + /// + public bool IsExistDate { get; set; } + + /// + /// 是否存在组织选择. + /// + public bool IsExistComSelect { get; set; } + + /// + /// 是否存在部门织选择. + /// + public bool IsExistDepSelect { get; set; } + + /// + /// 是否存在用户选择. + /// + public bool IsExistUserSelect { get; set; } + + /// + /// 是否存在子表. + /// + public bool IsExistSubTable { get; set; } + + /// + /// 日期选择字段. + /// + public List DateField { get; set; } + + /// + /// 子表名称. + /// + public string SubTableName { get; set; } + + /// + /// 组织选择控件列表. + /// + public List ComSelectList { get; set; } + + /// + /// 部门选择控件列表. + /// + public List DepSelectList { get; set; } + + /// + /// 用户选择控件列表. + /// + public List UserSelectList { get; set; } + + /// + /// 子表默认值. + /// + public List SubTabelDefault { get; set; } +} + +/// +/// 组织选择默认值. +/// +public class DefaultComSelectControl +{ + /// + /// 表单多选. + /// + public bool IsMultiple { get; set; } + + /// + /// 查询多选. + /// + public bool IsSearchMultiple { get; set; } + + public string Field { get; set; } +} + +/// +/// 部门选择默认值. +/// +public class DefaultDepSelectControl +{ + /// + /// 表单多选. + /// + public bool IsMultiple { get; set; } + + /// + /// 查询多选. + /// + public bool IsSearchMultiple { get; set; } + + /// + /// 可选范围 + /// custom-自定义,all-全部. + /// + public string selectType { get; set; } + + /// + /// 可选部门. + /// + public string ableDepIds { get; set; } + + /// + /// 字段名称. + /// + public string Field { get; set; } +} + +/// +/// 用户选择默认值. +/// +public class DefaultUserSelectControl +{ + /// + /// 表单多选. + /// + public bool IsMultiple { get; set; } + + /// + /// 查询多选. + /// + public bool IsSearchMultiple { get; set; } + + /// + /// 可选范围 + /// custom-自定义,all-全部. + /// + public string selectType { get; set; } + + /// + /// 可选部门. + /// + public string ableDepIds { get; set; } + + /// + /// 可选用户. + /// + public string ableUserIds { get; set; } + + /// + /// 可选岗位. + /// + public string ablePosIds { get; set; } + + /// + /// 可选角色. + /// + public string ableRoleIds { get; set; } + + /// + /// 可选分组. + /// + public string ableGroupIds { get; set; } + + /// + /// 字段名称. + /// + public string Field { get; set; } +} \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FormControlDesignModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FormControlDesignModel.cs index 532d9ce7..f1619bd7 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FormControlDesignModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FormControlDesignModel.cs @@ -648,4 +648,25 @@ public class FormControlDesignModel /// 是否关联表单. /// public bool IsRelationForm { get; set; } + + /// + /// 路径类型. + /// + public string PathType { get; set; } + + /// + /// 是否开启 分用户存储 + /// 0-关闭,1-开启. + /// + public string IsAccount { get; set; } + + /// + /// 文件夹名. + /// + public string Folder { get; set; } + + /// + /// 当前默认值. + /// + public bool DefaultCurrent { get; set; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FrontEndGenConfigModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FrontEndGenConfigModel.cs index 2ab18fca..e625f5ef 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FrontEndGenConfigModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/FrontEndGenConfigModel.cs @@ -50,7 +50,7 @@ public class FrontEndGenConfigModel /// /// 列表布局 - /// 1-普通列表,2-左侧树形+普通表格,3-分组表格,4-行内编辑. + /// 1-普通列表,2-左侧树形+普通表格,3-分组表格,4-行内编辑,5-树形表格. /// public int Type { get; set; } @@ -74,6 +74,11 @@ public class FrontEndGenConfigModel /// public string TreeDataSource { get; set; } + /// + /// 是否左侧树绑定字段查询条件多选. + /// + public bool IsTreeRelationMultiple { get; set; } + /// /// 树数据字典. /// @@ -159,6 +164,16 @@ public class FrontEndGenConfigModel /// public bool IsBatchRemoveDel { get; set; } + /// + /// 是否有批量打印. + /// + public bool IsBatchPrint { get; set; } + + /// + /// 批量打印IDS. + /// + public string PrintIds { get; set; } + /// /// 是否有导出. /// @@ -194,6 +209,11 @@ public class FrontEndGenConfigModel /// public bool IsUpload { get; set; } + /// + /// 是否开启控件默认值. + /// + public bool IsDefaultFormControl { get; set; } + /// /// 是否开启按钮权限. /// @@ -339,4 +359,63 @@ public class FrontEndGenConfigModel /// 是否冻结. /// public bool IsFixed { get; set; } + + /// + /// 是否存在子表正则. + /// + public bool IsChildrenRegular { get; set; } + + /// + /// 左侧树同步类型 + /// 0-同步,1-异步. + /// + public int TreeSynType { get; set; } + + /// + /// 是否开启左侧树查询. + /// + public bool HasTreeQuery { get; set; } + + /// + /// 左侧树异步接口. + /// + public CodeGenColumnData ColumnData { get; set; } + + /// + /// 是否开启合计. + /// + public bool ShowSummary { get; set; } + + /// + /// 列表合计字段. + /// + public List SummaryField { get; set; } + + /// + /// 表单控件默认值. + /// + public DefaultFormControlModel DefaultFormControlList { get; set; } + + /// + /// 流程引擎表单字段json. + /// + public string PropertyJson { get; set; } + + /// + /// 表单真实控件(剔除布局控件). + /// + public List FormRealControl { get; set; } +} + +public class CodeGenColumnData +{ + /// + /// 左侧树异步接口. + /// + public string treeInterfaceId { get; set; } + + /// + /// 左侧树模板JSON. + /// + public List treeTemplateJson { get; set; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexColumnDesign.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexColumnDesign.cs index 5e5b7b3a..b740a9f9 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexColumnDesign.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexColumnDesign.cs @@ -48,11 +48,6 @@ public class IndexColumnDesign /// public string Align { get; set; } - /// - /// 是否自动转换. - /// - public bool IsAutomatic { get; set; } - /// /// 时间格式化. /// @@ -77,4 +72,9 @@ public class IndexColumnDesign /// 子表配置. /// public List ChildTableDesigns { get; set; } + + /// + /// 关联表单模板ID. + /// + public string ModelId { get; set; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexSearchFieldDesignModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexSearchFieldDesignModel.cs index adde39ab..282cd9b2 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexSearchFieldDesignModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/IndexSearchFieldDesignModel.cs @@ -98,6 +98,11 @@ public class IndexSearchFieldDesignModel /// public bool IsCustomSelect => SelectType == "all" ? false : true; + /// + /// 是否多选. + /// + public bool IsMultiple { get; set; } + /// /// 可选部门. /// diff --git a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/TableColumnConfigModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/TableColumnConfigModel.cs index 270fa3bf..dfbd7bec 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/TableColumnConfigModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/CodeGen/TableColumnConfigModel.cs @@ -68,6 +68,11 @@ public class TableColumnConfigModel /// public int QueryType { get; set; } + /// + /// 是否查询多选. + /// + public bool QueryMultiple { get; set; } + /// /// 是否展示. /// @@ -188,6 +193,11 @@ public class TableColumnConfigModel /// public bool IsUpdate { get; set; } + /// + /// 控制解析. + /// + public bool IsControlParsing { get; set; } + #endregion #region 副表使用 @@ -253,4 +263,9 @@ public class TableColumnConfigModel /// 展示字段. /// public string ShowField { get; set; } + + /// + /// 是否树形父级字段. + /// + public bool IsTreeParentField { get; set; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Model/ColumnDesignModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/ColumnDesignModel.cs index f6a00be6..7e7cac57 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/ColumnDesignModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/ColumnDesignModel.cs @@ -8,11 +8,26 @@ namespace JNPF.VisualDev.Engine; [SuppressSniffer] public class ColumnDesignModel { + /// + /// 打印模板ID. + /// + public List printIds { get; set; } + /// /// 查询列表. /// public List searchList { get; set; } + /// + /// 数据过滤. + /// + public List ruleList { get; set; } + + /// + /// App数据过滤. + /// + public List ruleListApp { get; set; } + /// /// 显示列. /// @@ -35,7 +50,7 @@ public class ColumnDesignModel /// /// 列表布局 - /// 1-普通列表,2-左侧树形+普通表格,3-分组表格,4-编辑表格. + /// 1-普通列表,2-左侧树形+普通表格,3-分组表格,4-编辑表格,5-树形表格. /// public int type { get; set; } = 1; @@ -110,11 +125,37 @@ public class ColumnDesignModel /// public string treePropsLabel { get; set; } + /// + /// 左侧树同步类型 + /// 0-同步,1-异步. + /// + public int treeSynType { get; set; } + + /// + /// 是否开启左侧树查询. + /// + public bool hasTreeQuery { get; set; } + + /// + /// 左侧树异步接口. + /// + public string treeInterfaceId { get; set; } + + /// + /// 左侧树模板JSON. + /// + public List treeTemplateJson { get; set; } + /// /// 分组字段. /// public string groupField { get; set; } + /// + /// 树形表格 - 父级字段. + /// + public string parentField { get; set; } + /// /// 列表权限. /// @@ -150,6 +191,16 @@ public class ColumnDesignModel /// public List customBtnsList { get; set; } + /// + /// 是否合计. + /// + public bool showSummary { get; set; } + + /// + /// 列表合计字段. + /// + public List summaryField { get; set; } + /// /// 上传数据模板json. /// diff --git a/visualdev/Tnb.VisualDev.Engine/Model/ConfigModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/ConfigModel.cs index 556060e6..1bf4c4a7 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/ConfigModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/ConfigModel.cs @@ -83,6 +83,11 @@ public class ConfigModel /// public object defaultValue { get; set; } + /// + /// 当前默认值. + /// + public bool defaultCurrent { get; set; } + /// /// 远端数据接口. /// diff --git a/visualdev/Tnb.VisualDev.Engine/Model/FieldsModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/FieldsModel.cs index 856ff640..57b13dac 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/FieldsModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/FieldsModel.cs @@ -135,6 +135,11 @@ public class FieldsModel /// public bool multiple { get; set; } + /// + /// 是否多选查询. + /// + public bool searchMultiple { get; set; } + /// /// 配置选项. /// @@ -546,6 +551,22 @@ public class FieldsModel /// public List templateJson { get; set; } + /// + /// 路径类型. + /// + public string pathType { get; set; } + + /// + /// 是否开启 分用户存储 + /// 0-关闭,1-开启. + /// + public int isAccount { get; set; } = -1; + + /// + /// 文件夹名. + /// + public string folder { get; set; } + /// /// 后端自我创建字段、用于统一处理减少循环判断 /// 是否查询字段. diff --git a/visualdev/Tnb.VisualDev.Engine/Model/FormDataModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/FormDataModel.cs index 966a7775..7db2bd35 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/FormDataModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/FormDataModel.cs @@ -131,7 +131,7 @@ public class FormDataModel /// /// 打印模板ID. /// - public string printId { get; set; } + public List printId { get; set; } /// /// 表单样式. diff --git a/visualdev/Tnb.VisualDev.Engine/Model/IndexGridFieldModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/IndexGridFieldModel.cs index cfdc7458..bba29120 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/IndexGridFieldModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/IndexGridFieldModel.cs @@ -8,11 +8,10 @@ namespace JNPF.VisualDev.Engine; [SuppressSniffer] public class IndexGridFieldModel : IndexEachConfigBase { - //modified by PhilPan - ///// - ///// 对齐. - ///// - //public string align { get; set; } + /// + /// 对齐. + /// + public string align { get; set; } /// /// 固定. diff --git a/visualdev/Tnb.VisualDev.Engine/Model/IndexSearchFieldModel.cs b/visualdev/Tnb.VisualDev.Engine/Model/IndexSearchFieldModel.cs index ba618fc0..e5fd5eb2 100644 --- a/visualdev/Tnb.VisualDev.Engine/Model/IndexSearchFieldModel.cs +++ b/visualdev/Tnb.VisualDev.Engine/Model/IndexSearchFieldModel.cs @@ -14,9 +14,56 @@ public class IndexSearchFieldModel : IndexEachConfigBase /// public string value { get; set; } - //modified by PhilPan - ///// - ///// 查询类型. - ///// - //public int? searchType { get; set; } + /// + /// 查询类型. + /// + public int? searchType { get; set; } } + +/// +/// 数据过滤集合. +/// 数据过滤条件. +/// +public class RuleFieldModel : IndexEachConfigBase +{ + /// + /// 字段过滤值. + /// + public object fieldValue { get; set; } + + /// + /// 字段类型. + /// + public string fieldType { get; set; } + + /// + /// 字段值类型. + /// + public string fieldValueType { get; set; } + + /// + /// . + /// + public string fieldLabel { get; set; } + + /// + /// 逻辑名. + /// + public string logicName { get; set; } + + /// + /// 字段. + /// + public string field { get; set; } + + /// + /// 条件符号标识. + /// + public string symbol { get; set; } + + /// + /// 逻辑: 并且、或者. + /// + public string logic { get; set; } + +} \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenControlsAttributeHelper.cs b/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenControlsAttributeHelper.cs index 5b3c009e..876c77ac 100644 --- a/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenControlsAttributeHelper.cs +++ b/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenControlsAttributeHelper.cs @@ -1,7 +1,13 @@ -using JNPF.Common.Const; +using Aop.Api.Domain; +using JNPF.Common.Const; +using JNPF.Common.Extension; using JNPF.Common.Models; +using JNPF.Common.Models.Authorize; using JNPF.Common.Security; +using JNPF.VisualDev.Engine.Core; +using JNPF.VisualDev.Entitys; using JNPF.VisualDev.Entitys.Enum; +using SqlSugar; namespace JNPF.VisualDev.Engine.Security; @@ -261,6 +267,7 @@ public class CodeGenControlsAttributeHelper case JnpfKeyConst.COMSELECT: case JnpfKeyConst.ADDRESS: case JnpfKeyConst.SWITCH: + case JnpfKeyConst.DATE: tag = true; break; } @@ -467,7 +474,7 @@ public class CodeGenControlsAttributeHelper res[JnpfKeyConst.RELATIONFORM].Add(item.__vModel__); break; case JnpfKeyConst.TABLE: // 遍历 子表 控件 - var ctRes = GetParsJnpfKeyConstList(item.__config__.children, isInlineEditor); + var ctRes = GetParsJnpfKeyConstList(item.__config__.children, false); if (ctRes != null && ctRes.Any()) { foreach (var ct in ctRes) @@ -547,4 +554,254 @@ public class CodeGenControlsAttributeHelper return ret; } + + /// + /// 获取模板配置的数据过滤. + /// + /// + /// + /// + public static List GetDataRuleList(VisualDevEntity templateEntity, Model.CodeGen.CodeGenConfigModel codeGenConfigModel) + { + var ruleList = new List(); + var tInfo = new TemplateParsingBase(templateEntity); + + // 数据过滤 + if (tInfo.ColumnData.ruleList != null && tInfo.ColumnData.ruleList.Any()) tInfo.ColumnData.ruleList.ForEach(item => ruleList.Add(GetItemRule(item, tInfo, "pc", codeGenConfigModel, ref ruleList))); + if (tInfo.AppColumnData.ruleListApp != null && tInfo.AppColumnData.ruleListApp.Any()) tInfo.AppColumnData.ruleListApp.ForEach(item => ruleList.Add(GetItemRule(item, tInfo, "app", codeGenConfigModel, ref ruleList))); + + var res = new List(); + foreach (var userOriginItem in new List() { "pc", "app" }) + { + ruleList.Where(x => x.UserOrigin.Equals(userOriginItem)).Select(x => x.TableName).Distinct().ToList().ForEach(tName => + { + var first = ruleList.FirstOrDefault(x => x.UserOrigin.Equals(userOriginItem) && x.TableName.Equals(tName)); + var condList = ruleList.Where(x => x.UserOrigin.Equals(userOriginItem) && x.TableName.Equals(tName)).Select(x => x.conditionalModel.First()).ToList(); + var dataRuleListJson = new List(); + var condTree = new ConditionalTree() { ConditionalList = new List>() }; + condList.ForEach(cItem => condTree.ConditionalList.Add(new KeyValuePair(WhereType.And, cItem))); + res.Add(new CodeGenDataRuleModuleResourceModel() + { + FieldRule = first.TableName.Contains("@ChildFieldIsNull") ? -1 : first.FieldRule, + TableName = first.TableName.Replace("@ChildFieldIsNull", string.Empty), + UserOrigin = first.UserOrigin, + conditionalModelJson = new List() { condTree }.ToJsonString() + }); + }); + } + + return res; + } + + private static CodeGenDataRuleModuleResourceModel GetItemRule(RuleFieldModel item, TemplateParsingBase tInfo, string userOrigin, Model.CodeGen.CodeGenConfigModel codeGenConfigModel, ref List ruleList) + { + var result = new CodeGenDataRuleModuleResourceModel() { FieldRule = 0, TableName = tInfo.MainTableName.ToLower(), UserOrigin = userOrigin, conditionalModel = new List() }; + if (tInfo.AuxiliaryTableFields.ContainsKey(item.__vModel__)) + { + var tf = tInfo.AuxiliaryTableFields[item.__vModel__].Split('.'); + result.FieldRule = 1; + result.TableName = tf.FirstOrDefault().ToLower(); + item.field = tf.LastOrDefault(); + } + else if (tInfo.ChildTableFields.ContainsKey(item.__vModel__)) + { + var tf = tInfo.ChildTableFields[item.__vModel__].Split('.'); + result.FieldRule = 2; + result.TableName = tf.FirstOrDefault().ToLower(); + item.field = tf.LastOrDefault(); + + if (item.symbol.Equals("null")) + { + var mainTableRelationsQuery = result.Copy(); + mainTableRelationsQuery.TableName = mainTableRelationsQuery.TableName + "@ChildFieldIsNull"; + var ctPrimaryKey = codeGenConfigModel.TableRelations.Find(x => x.OriginalTableName.Equals(result.TableName)).ChilderColumnConfigList.Find(x => x.ColumnName.Equals(codeGenConfigModel.TableRelations.Find(x => x.OriginalTableName.Equals(result.TableName)).PrimaryKey)).OriginalColumnName; + var condTree = new ConditionalCollections() + { + ConditionalList = new List>() + { + new KeyValuePair(WhereType.Or, new ConditionalModel() { FieldName = ctPrimaryKey, ConditionalType = ConditionalType.NoEqual, FieldValue = "0", FieldValueConvertFunc = it => SqlSugar.UtilMethods.ChangeType2(it, typeof(string)) }) + } + }; + + mainTableRelationsQuery.conditionalModel = new List() { condTree }; + ruleList.Add(mainTableRelationsQuery); + } + } + + if (codeGenConfigModel.TableField.Any(x => x.LowerColumnName.Equals(item.field))) + { + var fieldList = codeGenConfigModel.TableField.Where(x => x.LowerColumnName.Equals(item.field)).ToList(); + if (fieldList.Any() && fieldList.Count.Equals(1)) item.field = fieldList.First().OriginalColumnName; + else item.field = fieldList.Find(x => x.TableName != null && x.TableName.Equals(item.__config__.tableName)).OriginalColumnName; + } + else if (codeGenConfigModel.TableRelations.Any(x => x.OriginalTableName.Equals(result.TableName))) + { + var tableRelations = codeGenConfigModel.TableRelations.Find(x => x.OriginalTableName.Equals(result.TableName) && x.ChilderColumnConfigList.Any(xx => xx.LowerColumnName.Equals(item.field))); + if (tableRelations != null) item.field = tableRelations.ChilderColumnConfigList.Find(x => x.LowerColumnName.Equals(item.field)).OriginalColumnName; + } + + var conditionalType = ConditionalType.Equal; + var between = new List(); + if (item.fieldValue.IsNotEmptyOrNull()) + { + if (item.symbol.Equals("between")) between = item.fieldValue.ToObject>(); + switch (item.jnpfKey) + { + case JnpfKeyConst.CREATETIME: + case JnpfKeyConst.MODIFYTIME: + case JnpfKeyConst.DATE: + { + if (item.symbol.Equals("between")) + { + var startTime = between.First().TimeStampToDateTime(); + var endTime = between.Last().TimeStampToDateTime(); + between[0] = startTime.ToString(); + between[1] = endTime.ToString(); + if (item.format == "yyyy-MM-dd") + { + between[0] = new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0, 0).ToString(); + between[1] = new DateTime(endTime.Year, endTime.Month, endTime.Day, 23, 59, 59, 999).ToString(); + } + } + else + { + DateTime dtDate; + if (DateTime.TryParse(item.fieldValue.ToString(), out dtDate)) item.fieldValue = item.fieldValue.ToString(); + else item.fieldValue = string.Format("{0:yyyy-MM-dd HH:mm:ss}", item.fieldValue.ToString().TimeStampToDateTime()); + if (item.format == "yyyy-MM-dd") + { + var value = item.fieldValue.ToString().ParseToDateTime(); + item.fieldValue = new DateTime(value.Year, value.Month, value.Day, 0, 0, 0, 0).ToString(); + } + else + { + item.fieldValue = item.fieldValue.IsNotEmptyOrNull() ? item.fieldValue.ToString() : item.fieldValue; + } + } + } + break; + } + } + switch (item.symbol) + { + case ">=": + conditionalType = ConditionalType.GreaterThanOrEqual; + break; + case ">": + conditionalType = ConditionalType.GreaterThan; + break; + case "==": + conditionalType = ConditionalType.Equal; + break; + case "<=": + conditionalType = ConditionalType.LessThanOrEqual; + break; + case "<": + conditionalType = ConditionalType.LessThan; + break; + case "<>": + conditionalType = ConditionalType.NoEqual; + break; + case "like": + if (item.fieldValue != null && item.fieldValue.ToString().Contains("[")) item.fieldValue = item.fieldValue.ToString().Replace("[", string.Empty).Replace("]", string.Empty); + conditionalType = ConditionalType.Like; + break; + case "notLike": + if (item.fieldValue != null && item.fieldValue.ToString().Contains("[")) item.fieldValue = item.fieldValue.ToString().Replace("[", string.Empty).Replace("]", string.Empty); + conditionalType = ConditionalType.NoLike; + break; + case "in": + case "notIn": + if (item.fieldValue != null && item.fieldValue.ToString().Contains("[")) + { + var isListValue = false; + var itemField = tInfo.AllFieldsModel.Find(x => x.__vModel__.Equals(item.__vModel__)); + if (itemField.multiple || item.jnpfKey.Equals(JnpfKeyConst.CHECKBOX) || item.jnpfKey.Equals(JnpfKeyConst.CASCADER) || item.jnpfKey.Equals(JnpfKeyConst.ADDRESS)) + isListValue = true; + var conditionalList = new ConditionalCollections() { ConditionalList = new List>() }; + var ids = new List(); + if (item.fieldValue.ToString().Replace("\r\n", "").Replace(" ", "").Contains("[[")) ids = item.fieldValue.ToObject>>().Select(x => x.Last()).ToList(); + else ids = item.fieldValue.ToObject>(); + for (var i = 0; i < ids.Count; i++) + { + var it = ids[i]; + var whereType = WhereType.And; + if (item.symbol.Equals("in")) whereType = i.Equals(0) && item.logic.Equals("&&") ? WhereType.And : WhereType.Or; + else whereType = i.Equals(0) && item.logic.Equals("||") ? WhereType.Or : WhereType.And; + conditionalList.ConditionalList.Add(new KeyValuePair(whereType, new ConditionalModel + { + FieldName = item.field, + ConditionalType = item.symbol.Equals("in") ? ConditionalType.Like : ConditionalType.NoLike, + FieldValue = isListValue ? it.ToJsonString() : it + })); + } + + if (item.symbol.Equals("notIn")) + { + conditionalList.ConditionalList.Add(new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.IsNot, + FieldValue = null + })); + conditionalList.ConditionalList.Add(new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.IsNot, + FieldValue = string.Empty + })); + } + + result.conditionalModel.Add(conditionalList); + return result; + } + conditionalType = item.symbol.Equals("in") ? ConditionalType.In : ConditionalType.NotIn; + break; + case "null": + conditionalType = (item.jnpfKey.Equals(JnpfKeyConst.CALCULATE) || item.jnpfKey.Equals(JnpfKeyConst.NUMINPUT)) ? ConditionalType.EqualNull : ConditionalType.IsNullOrEmpty; + break; + case "notNull": + conditionalType = ConditionalType.IsNot; + break; + case "between": + var condItem = new ConditionalCollections() + { + ConditionalList = new List>() + { + new KeyValuePair((item.logic.Equals("&&") ? WhereType.And : WhereType.Or), new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.GreaterThanOrEqual, + FieldValue = between.First(), + FieldValueConvertFunc = it => Convert.ToDateTime(it) + }), + new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = item.field, + ConditionalType = ConditionalType.LessThanOrEqual, + FieldValue = between.Last(), + FieldValueConvertFunc = it => Convert.ToDateTime(it) + }) + } + }; + + result.conditionalModel.Add(condItem); + return result; + } + + var resItem = new ConditionalCollections() + { + ConditionalList = new List>() + { + new KeyValuePair((item.logic.Equals("&&") ? WhereType.And : WhereType.Or), new ConditionalModel + { + FieldName = item.field, + ConditionalType = conditionalType, + FieldValue = item.fieldValue == null ? null : item.fieldValue.ToString() + }) + } + }; + result.conditionalModel.Add(resItem); + return result; + } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenFieldJudgeHelper.cs b/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenFieldJudgeHelper.cs index 4d37e250..4a15a106 100644 --- a/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenFieldJudgeHelper.cs +++ b/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/CodeGenFieldJudgeHelper.cs @@ -33,6 +33,18 @@ public class CodeGenFieldJudgeHelper return column?.searchType ?? 0; } + /// + /// 列表查询多选. + /// + /// 模板内查询列表. + /// 字段名称. + /// + public static bool ColumnQueryMultiple(List? searchList, string fieldName) + { + var column = searchList?.Find(s => s.prop == fieldName); + return (column?.searchMultiple).ParseToBool(); + } + /// /// 是否展示列. /// @@ -74,7 +86,7 @@ public class CodeGenFieldJudgeHelper /// /// 获取是否多选. /// - /// 模板内控件列表. + /// 模板内控件. /// 字段名称. /// public static bool IsMultipleColumn(FieldsModel column, string fieldName) @@ -96,6 +108,25 @@ public class CodeGenFieldJudgeHelper return isMultiple; } + /// + /// 控制解析. + /// + /// + /// + public static bool IsControlParsing(FieldsModel column) + { + bool isExist = false; + switch (column?.__config__.jnpfKey) + { + case JnpfKeyConst.RELATIONFORM: + case JnpfKeyConst.POPUPSELECT: + case JnpfKeyConst.USERSSELECT: + isExist = true; + break; + } + return isExist; + } + /// /// 是否datetime. /// diff --git a/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/GetCodeGenIndexButtonHelper.cs b/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/GetCodeGenIndexButtonHelper.cs index b6086ae2..bbef17b2 100644 --- a/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/GetCodeGenIndexButtonHelper.cs +++ b/visualdev/Tnb.VisualDev.Engine/Security/BackEnd/GetCodeGenIndexButtonHelper.cs @@ -28,18 +28,10 @@ public class GetCodeGenIndexButtonHelper method = string.Format("scope.row.rowEdit=true"); break; default: - switch (primaryKeyPolicy) + switch (isFlow) { - case 2: - switch (isFlow) - { - case true: - method = string.Format("addOrUpdateHandle(scope.row.flowTaskId)"); - break; - default: - method = string.Format("addOrUpdateHandle(scope.row.{0})", primaryKey); - break; - } + case true: + method = string.Format("updateHandle(scope.row)"); break; default: method = string.Format("addOrUpdateHandle(scope.row.{0})", primaryKey); @@ -61,23 +53,15 @@ public class GetCodeGenIndexButtonHelper switch (primaryKeyPolicy) { case 2: - method = string.Format("goDetail(scope.row.flowTaskId,scope.row.flowState)"); + method = string.Format("goDetail(scope.row.flowTaskId,scope.row.flowState, scope.row.flowId)"); break; default: - method = string.Format("goDetail(scope.row.{0},scope.row.flowState)", primaryKey); + method = string.Format("goDetail(scope.row.{0},scope.row.flowState, scope.row.flowId)", primaryKey); break; } break; default: - switch (primaryKeyPolicy) - { - case 2: - method = string.Format("addOrUpdateHandle(scope.row.flowTaskId,scope.row.flowState)"); - break; - default: - method = string.Format("addOrUpdateHandle(scope.row.{0},scope.row.flowState)", primaryKey); - break; - } + method = string.Format("detailHandle(scope.row)", primaryKey); break; } break; @@ -95,14 +79,24 @@ public class GetCodeGenIndexButtonHelper /// /// 代码生成单表Index列表头部按钮方法. /// + /// 按钮类型. + /// 是否工作流表单. /// - public static string IndexTopButton(string value) + public static string IndexTopButton(string value, bool isFlow) { var method = string.Empty; switch (value) { case "add": - method = "addOrUpdateHandle()"; + switch (isFlow) + { + case true: + method = "addHandle()"; + break; + default: + method = "addOrUpdateHandle()"; + break; + } break; case "download": method = "exportData()"; @@ -113,6 +107,9 @@ public class GetCodeGenIndexButtonHelper case "upload": method = "handelUpload()"; break; + case "batchPrint": + method = "printDialog()"; + break; } return method; diff --git a/visualdev/Tnb.VisualDev.Engine/Security/CodeGenTargetPathHelper.cs b/visualdev/Tnb.VisualDev.Engine/Security/CodeGenTargetPathHelper.cs index 9e4041b9..8e6d0f01 100644 --- a/visualdev/Tnb.VisualDev.Engine/Security/CodeGenTargetPathHelper.cs +++ b/visualdev/Tnb.VisualDev.Engine/Security/CodeGenTargetPathHelper.cs @@ -123,9 +123,10 @@ public class CodeGenTargetPathHelper { var frontendPath = Path.Combine(KeyVariable.SystemPath, "CodeGenerate", fileName, "Net"); var indexPath = Path.Combine(frontendPath, "html", "PC", tableName, "index.vue"); + var extraForm = Path.Combine(frontendPath, "html", "PC", tableName, "extraForm.vue"); var detailPath = Path.Combine(frontendPath, "html", "PC", tableName, "Detail.vue"); var formPath = Path.Combine(frontendPath, "html", "PC", tableName, "Form.vue"); - var exportJsonPath = Path.Combine(frontendPath, "fff", "ExportJson.fff"); + var exportJsonPath = Path.Combine(frontendPath, "fff", "flowForm.fff"); var columnJsonPath = Path.Combine(frontendPath, "html", "PC", tableName, "columnList.js"); var superQueryJsonPath = Path.Combine(frontendPath, "html", "PC", tableName, "superQueryJson.js"); var pathList = new List(); @@ -134,6 +135,7 @@ public class CodeGenTargetPathHelper switch (enableFlow) { case 0: + pathList.Add(extraForm); if (isDetail) pathList.Add(detailPath); break; @@ -165,6 +167,7 @@ public class CodeGenTargetPathHelper { case 0: pathList.Add(Path.Combine(templatePath, "editorIndex.vue.vm")); + pathList.Add(Path.Combine(templatePath, "extraForm.vue.vm")); if (isDetail) pathList.Add(Path.Combine(templatePath, "Detail.vue.vm")); break; @@ -278,7 +281,7 @@ public class CodeGenTargetPathHelper var frontendPath = Path.Combine(KeyVariable.SystemPath, "CodeGenerate", fileName, "Net"); var indexPath = Path.Combine(frontendPath, "html", "App", tableName, "index.vue"); var formPath = Path.Combine(frontendPath, "html", "App", tableName, "form.vue"); - var detailPath = Path.Combine(frontendPath, "html", "App", tableName, "Detail.vue"); + var detailPath = Path.Combine(frontendPath, "html", "App", tableName, "detail.vue"); var columnJsonPath = Path.Combine(frontendPath, "html", "App", tableName, "columnList.js"); var pathList = new List(); switch (webType) diff --git a/visualdev/Tnb.VisualDev.Engine/Security/CodeGenUnifiedHandlerHelper.cs b/visualdev/Tnb.VisualDev.Engine/Security/CodeGenUnifiedHandlerHelper.cs index 339462fc..61c61c81 100644 --- a/visualdev/Tnb.VisualDev.Engine/Security/CodeGenUnifiedHandlerHelper.cs +++ b/visualdev/Tnb.VisualDev.Engine/Security/CodeGenUnifiedHandlerHelper.cs @@ -17,7 +17,7 @@ public class CodeGenUnifiedHandlerHelper var template = new List(); // 循环表单内控件 - formDataModel.ForEach(item => + foreach (var item in formDataModel) { var config = item.__config__; switch (config.jnpfKey) @@ -67,7 +67,7 @@ public class CodeGenUnifiedHandlerHelper break; } - }); + } return template; } @@ -176,7 +176,7 @@ public class CodeGenUnifiedHandlerHelper // dataType = dynamic && templateJson属性有长度,则代表有远端联动 if (config.dataType == "dynamic" && config.templateJson?.Count() > 0) { - config.templateJson.FindAll(it => it.relationField.Any()).ForEach(items => + config.templateJson.FindAll(it => it.relationField != null && it.relationField.Any()).ForEach(items => { var fieldModel = NewFormDataModel.Where(it => it.__vModel__.Equals(items.relationField) && it.__config__.jnpfKey.Equals(items.jnpfKey)).FirstOrDefault(); fieldModel.IsLinked = true; @@ -199,7 +199,7 @@ public class CodeGenUnifiedHandlerHelper { var childrenFieldModel = childrenFormModel.Where(it => item.__vModel__.Equals(it.__vModel__) && it.__config__.jnpfKey.Equals(config.jnpfKey)).FirstOrDefault(); childrenFieldModel.IsLinkage = true; - config.templateJson.FindAll(it => it.relationField.Any()).ForEach(items => + config.templateJson.FindAll(it => it.relationField != null && it.relationField.Any()).ForEach(items => { var isTrigger = false; var fieldModel = childrenFormModel.Where(it => items.relationField.Equals(string.Format("{0}-{1}", tableControlsKey, it.__vModel__)) && it.__config__.jnpfKey.Equals(items.jnpfKey)).FirstOrDefault(); @@ -233,27 +233,30 @@ public class CodeGenUnifiedHandlerHelper case true: var mainFieldModel = NewFormDataModel.Where(it => item.__vModel__.Equals(it.__vModel__) && it.__config__.jnpfKey.Equals(config.jnpfKey)).FirstOrDefault(); mainFieldModel.IsLinkage = true; - item.templateJson?.FindAll(it => it.relationField.Any()).ForEach(items => + item.templateJson?.FindAll(it => it.relationField != null && it.relationField.Any()).ForEach(items => { var fieldModel = NewFormDataModel.Where(it => it.__vModel__.Equals(items.relationField) && it.__config__.jnpfKey.Equals(items.jnpfKey)).FirstOrDefault(); - fieldModel.IsLinked = true; - List linkageConfigs = new List + if (fieldModel != null) { - new LinkageConfig() + fieldModel.IsLinked = true; + List linkageConfigs = new List { - field = item.__vModel__, - fieldName = item.__vModel__.ToLowerCase(), - jnpfKey = config.jnpfKey, - IsMultiple = config.jnpfKey.Equals(JnpfKeyConst.CASCADER) ? item.props.props.multiple : config.jnpfKey.Equals(JnpfKeyConst.CHECKBOX) ? true : item.multiple, - } - }; - fieldModel.linkageReverseRelationship.AddRange(linkageConfigs); + new LinkageConfig() + { + field = item.__vModel__, + fieldName = item.__vModel__.ToLowerCase(), + jnpfKey = config.jnpfKey, + IsMultiple = config.jnpfKey.Equals(JnpfKeyConst.CASCADER) ? item.props.props.multiple : config.jnpfKey.Equals(JnpfKeyConst.CHECKBOX) ? true : item.multiple, + } + }; + fieldModel.linkageReverseRelationship.AddRange(linkageConfigs); + } }); break; default: var childrenFieldModel = childrenFormModel.Where(it => item.__vModel__.Equals(it.__vModel__) && it.__config__.jnpfKey.Equals(config.jnpfKey)).FirstOrDefault(); childrenFieldModel.IsLinkage = true; - item.templateJson?.FindAll(it => it.relationField.Any()).ForEach(items => + item.templateJson?.FindAll(it => it.relationField != null && it.relationField.Any()).ForEach(items => { var isTrigger = false; var fieldModel = childrenFormModel.Where(it => items.relationField.Equals(string.Format("{0}-{1}", tableControlsKey, it.__vModel__)) && it.__config__.jnpfKey.Equals(items.jnpfKey)).FirstOrDefault(); diff --git a/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenFormControlDesignHelper.cs b/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenFormControlDesignHelper.cs index 063281e0..f3628c5b 100644 --- a/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenFormControlDesignHelper.cs +++ b/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenFormControlDesignHelper.cs @@ -171,7 +171,11 @@ public class CodeGenFormControlDesignHelper UserRelationAttr = GetUserRelationAttr(children, realisticControls, logic), IsLinked = realisticControl.IsLinked, IsLinkage = realisticControl.IsLinkage, - IsRelationForm = childrenConfig.jnpfKey.Equals(JnpfKeyConst.RELATIONFORM) + IsRelationForm = childrenConfig.jnpfKey.Equals(JnpfKeyConst.RELATIONFORM), + PathType = !string.IsNullOrEmpty(children.pathType) ? string.Format("pathType=\"{0}\" ", children.pathType) : string.Empty, + IsAccount = children.isAccount != -1 ? string.Format(":isAccount=\"{0}\" ", children.isAccount) : string.Empty, + Folder = !string.IsNullOrEmpty(children.folder) ? string.Format("folder=\"{0}\" ", children.folder) : string.Empty, + DefaultCurrent = childrenConfig.defaultCurrent, }); } @@ -194,6 +198,7 @@ public class CodeGenFormControlDesignHelper required = childrenTableList.Any(it => it.required.Equals(true)), AddType = item.addType, IsRelationForm = childrenTableList.Any(it => it.IsRelationForm.Equals(true)), + DefaultCurrent = childrenTableList.Any(it => it.DefaultCurrent.Equals(true)), }); } @@ -496,7 +501,11 @@ public class CodeGenFormControlDesignHelper UserRelationAttr = GetUserRelationAttr(item, realisticControls, logic), IsLinked = realisticControl.IsLinked, IsLinkage = realisticControl.IsLinkage, - IsRelationForm = config.jnpfKey.Equals(JnpfKeyConst.RELATIONFORM) + IsRelationForm = config.jnpfKey.Equals(JnpfKeyConst.RELATIONFORM), + PathType = !string.IsNullOrEmpty(item.pathType) ? string.Format("pathType=\"{0}\" ", item.pathType) : string.Empty, + IsAccount = item.isAccount != -1 ? string.Format(":isAccount=\"{0}\" ", item.isAccount) : string.Empty, + Folder = !string.IsNullOrEmpty(item.folder) ? string.Format("folder=\"{0}\" ", item.folder) : string.Empty, + DefaultCurrent = config.defaultCurrent, }); } @@ -507,6 +516,112 @@ public class CodeGenFormControlDesignHelper return list; } + /// + /// 表单默认值控件列表. + /// + /// 组件列表. + /// 查询字段. + /// 是否主表. + /// + public static DefaultFormControlModel DefaultFormControlList(List fieldList, List searchField, string subTableName = null, bool isMain = true) + { + DefaultFormControlModel model = new DefaultFormControlModel(); + model.DateField = new List(); + model.ComSelectList = new List(); + model.DepSelectList = new List(); + model.UserSelectList = new List(); + model.SubTabelDefault = new List(); + + // 获取表单内存在默认值控件 + foreach (var item in fieldList) + { + var config = item.__config__; + var search = new IndexSearchFieldModel(); + switch (isMain && !config.jnpfKey.Equals(JnpfKeyConst.TABLE)) + { + case false: + search = searchField?.Find(it => it.__vModel__.Equals(string.Format("{0}-{1}", subTableName, item.__vModel__))); + break; + default: + search = searchField?.Find(it => it.__vModel__.Equals(string.Format("{0}", item.__vModel__))); + break; + } + + // 未作为查询条件 + if (search == null) + { + search = new IndexSearchFieldModel(); + search.searchMultiple = false; + } + switch (config.defaultCurrent) + { + case true: + switch (config.jnpfKey) + { + case JnpfKeyConst.TABLE: + model.SubTabelDefault.Add(DefaultFormControlList(item.__config__.children, searchField, item.__vModel__, false)); + break; + case JnpfKeyConst.DATE: + model.DateField.Add(item.__vModel__); + break; + case JnpfKeyConst.COMSELECT: + model.ComSelectList.Add(new DefaultComSelectControl() + { + IsMultiple = item.multiple, + IsSearchMultiple = search.searchMultiple, + Field = item.__vModel__ + }); + break; + case JnpfKeyConst.DEPSELECT: + model.DepSelectList.Add(new DefaultDepSelectControl() + { + IsMultiple = item.multiple, + selectType = item.selectType, + IsSearchMultiple = search.searchMultiple, + Field = item.__vModel__, + ableDepIds = item.ableDepIds.ToJsonString(), + }); + break; + case JnpfKeyConst.USERSELECT: + model.UserSelectList.Add(new DefaultUserSelectControl() + { + IsMultiple = item.multiple, + selectType = item.selectType, + IsSearchMultiple = search.searchMultiple, + Field = item.__vModel__, + ableDepIds = item.ableDepIds.ToJsonString(), + ableGroupIds = item.ableGroupIds.ToJsonString(), + ablePosIds = item.ablePosIds.ToJsonString(), + ableRoleIds = item.ableRoleIds.ToJsonString(), + ableUserIds = item.ableUserIds.ToJsonString(), + }); + break; + } + break; + } + } + + switch (isMain) + { + case false: + model.SubTableName = subTableName; + model.IsExistDate = model.DateField.Any(); + model.IsExistComSelect = model.ComSelectList.Any(); + model.IsExistDepSelect = model.DepSelectList.Any(); + model.IsExistUserSelect = model.UserSelectList.Any(); + break; + default: + model.IsExistDate = model.DateField.Any() || model.SubTabelDefault.Any(it => it.DateField.Any()); + model.IsExistComSelect = model.ComSelectList.Any() || model.SubTabelDefault.Any(it => it.ComSelectList.Any()); + model.IsExistDepSelect = model.DepSelectList.Any() || model.SubTabelDefault.Any(it => it.DepSelectList.Any()); + model.IsExistUserSelect = model.UserSelectList.Any() || model.SubTabelDefault.Any(it => it.UserSelectList.Any()); + model.IsExistSubTable = model.SubTabelDefault.Count > 0 ? true : false; + break; + } + + return model; + } + /// /// 表单控件选项配置. /// @@ -1071,6 +1186,40 @@ public class CodeGenFormControlDesignHelper return list; } + /// + /// 表单真实控件-剔除布局控件后. + /// + /// 组件列表 + /// + public static List FormRealControl(List fieldList) + { + var list = new List(); + foreach (var item in fieldList) + { + var config = item.__config__; + switch (config.jnpfKey) + { + case JnpfKeyConst.TABLE: + list.Add(new CodeGenFormRealControlModel + { + jnpfKey = config.jnpfKey, + vModel = item.__vModel__, + children = FormRealControl(config.children) + }); + break; + default: + list.Add(new CodeGenFormRealControlModel + { + jnpfKey = config.jnpfKey, + vModel = item.__vModel__, + multiple = config.jnpfKey == JnpfKeyConst.CASCADER ? item.props.props.multiple : item.multiple + }); + break; + } + } + return list; + } + /// /// 表单脚本设计. /// @@ -1179,6 +1328,12 @@ public class CodeGenFormControlDesignHelper break; } } + List childrenRegList = new List(); + + foreach (var reg in childrenFormScript.FindAll(it => it.RegList != null && it.RegList.Count > 0).Select(it => it.RegList)) + { + childrenRegList.AddRange(reg); + } formScript.Add(new FormScriptDesignModel() { @@ -1188,6 +1343,7 @@ public class CodeGenFormControlDesignHelper jnpfKey = config.jnpfKey, ChildrenList = childrenFormScript, Required = childrenFormScript.Any(it => it.Required.Equals(true)), + RegList = childrenRegList, ShowSummary = item.showSummary, SummaryField = item.summaryField.ToJsonString(), IsDataTransfer = item.addType == 1 ? true : false, @@ -1417,4 +1573,51 @@ public class CodeGenFormControlDesignHelper return res; } + /// + /// 表单json. + /// + /// + /// + public static string GetPropertyJson(List formScriptDesignModels) + { + List? list = new List(); + foreach (var item in formScriptDesignModels) + { + switch (item.jnpfKey) + { + case JnpfKeyConst.TABLE: + list.Add(new CodeGenExportPropertyJsonModel + { + filedName = item.Placeholder, + jnpfKey = item.jnpfKey, + filedId = item.OriginalName, + required = item.Required, + multiple = item.Multiple, + }); + foreach (var subtable in item.ChildrenList) + { + list.Add(new CodeGenExportPropertyJsonModel + { + filedName = string.Format("{0}-{1}", item.Placeholder, subtable.Placeholder), + jnpfKey = subtable.jnpfKey, + filedId = string.Format("{0}-{1}", item.OriginalName, subtable.LowerName), + required = subtable.Required, + multiple = subtable.Multiple, + }); + } + break; + default: + list.Add(new CodeGenExportPropertyJsonModel + { + filedName = item.Placeholder, + jnpfKey = item.jnpfKey, + filedId = item.LowerName, + required = item.Required, + multiple = item.Multiple, + }); + break; + } + } + return list.ToJsonString(); + } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenQueryControlClassificationHelper.cs b/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenQueryControlClassificationHelper.cs index bf5194d7..0259ef1a 100644 --- a/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenQueryControlClassificationHelper.cs +++ b/visualdev/Tnb.VisualDev.Engine/Security/FrontEnd/CodeGenQueryControlClassificationHelper.cs @@ -150,7 +150,7 @@ public class CodeGenQueryControlClassificationHelper var usersSelectList = new List(); usersSelectList.Add(JnpfKeyConst.USERSSELECT); - listQueryControl["usersSelectList"] = usersSelectList; + listQueryControl["usersSelect"] = usersSelectList; var treeSelectList = new List(); treeSelectList.Add(JnpfKeyConst.TREESELECT); @@ -159,6 +159,10 @@ public class CodeGenQueryControlClassificationHelper var addressList = new List(); addressList.Add(JnpfKeyConst.ADDRESS); listQueryControl["address"] = addressList; + + listQueryControl["groupSelect"] = new List() { JnpfKeyConst.GROUPSELECT }; + + listQueryControl["roleSelect"] = new List() { JnpfKeyConst.ROLESELECT }; } break; @@ -166,21 +170,4 @@ public class CodeGenQueryControlClassificationHelper return listQueryControl; } - - /// - /// 需要转换的列表列控件. - /// - /// - public static Dictionary> ListColumnControls() - { - Dictionary> listColumnControlsType = new Dictionary>(); - var columnList = new List(); - columnList.Add("date"); - columnList.Add("createTime"); - columnList.Add("modifyTime"); - - listColumnControlsType["columnList"] = columnList; - - return listColumnControlsType; - } } diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/Dashboard/FlowTodoCountInput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/Dashboard/FlowTodoCountInput.cs new file mode 100644 index 00000000..5a6467f4 --- /dev/null +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/Dashboard/FlowTodoCountInput.cs @@ -0,0 +1,22 @@ +namespace JNPF.VisualDev.Entitys.Dto.Dashboard; + +/// +/// 我的待办输出实体类. +/// +public class FlowTodoCountInput +{ + /// + /// 待我审核. + /// + public List toBeReviewedType { get; set; } + + /// + /// 已办事宜. + /// + public List flowDoneType { get; set; } + + /// + /// 抄送. + /// + public List flowCirculateType { get; set; } +} diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/Dashboard/FlowTodoCountOutput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/Dashboard/FlowTodoCountOutput.cs index 29baec04..ebece583 100644 --- a/visualdev/Tnb.VisualDev.Entitys/Dto/Dashboard/FlowTodoCountOutput.cs +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/Dashboard/FlowTodoCountOutput.cs @@ -19,4 +19,9 @@ public class FlowTodoCountOutput /// 已办事宜. /// public int flowDone { get; set; } + + /// + /// 抄送. + /// + public int flowCirculate { get; set; } } diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevCrInput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevCrInput.cs index 006608fc..e3f9e2c2 100644 --- a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevCrInput.cs +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevCrInput.cs @@ -89,4 +89,19 @@ public class VisualDevCrInput /// 是否启用流程. /// public int enableFlow { get; set; } + + /// + /// 接口id. + /// + public string interfaceId { get; set; } + + /// + /// 接口名称. + /// + public string interfaceName { get; set; } + + /// + /// 接口参数. + /// + public string interfaceParam { get; set; } } diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevInfoOutput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevInfoOutput.cs index 2cc19f69..fbd81e70 100644 --- a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevInfoOutput.cs +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevInfoOutput.cs @@ -99,4 +99,19 @@ public class VisualDevInfoOutput /// 是否启用流程. /// public int enableFlow { get; set; } + + /// + /// 接口id. + /// + public string interfaceId { get; set; } + + /// + /// 接口名称. + /// + public string interfaceName { get; set; } + + /// + /// 接口参数. + /// + public string interfaceParam { get; set; } } diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevListOutput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevListOutput.cs index 19abebc1..681848a2 100644 --- a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevListOutput.cs +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevListOutput.cs @@ -100,4 +100,24 @@ public class VisualDevListOutput : TreeModel /// 是否启用流程. /// public int enableFlow { get; set; } + + /// + /// 接口id. + /// + public string interfaceId { get; set; } + + /// + /// 接口名称. + /// + public string interfaceName { get; set; } + + /// + /// 接口参数. + /// + public string interfaceParam { get; set; } + + /// + /// 是否显示包名(java用,.net不显示). + /// + public bool hasPackage { get; set; } = false; } diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkInfoOutput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkInfoOutput.cs new file mode 100644 index 00000000..07b0a19e --- /dev/null +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkInfoOutput.cs @@ -0,0 +1,76 @@ +using JNPF.DependencyInjection; + +namespace JNPF.VisualDev.Entitys.Dto.VisualDev; + +/// +/// 功能信息输出. +/// +[SuppressSniffer] +public class VisualDevShortLinkInfoOutput +{ + public string id { get; set; } + + public string shortLink { get; set; } + + public int formUse { get; set; } = 0; + + public string formLink { get; set; } + + public int formPassUse { get; set; } = 0; + + public string formPassword { get; set; } + + public int columnUse { get; set; } = 0; + + public string columnLink { get; set; } + + public int columnPassUse { get; set; } = 0; + + public string columnPassword { get; set; } + + public string columnCondition { get; set; } + + public string columnText { get; set; } + + public string userId { get; set; } + + public string tenantId { get; set; } + + public int enabledMark { get; set; } + +} + +/// +/// 获取外链配置输出. +/// +public class VisualdevShortLinkConfigOutput +{ + public string id { get; set; } + public int formUse { get; set; } = 0; + public int formPassUse { get; set; } = 0; + public int columnUse { get; set; } = 0; + public int columnPassUse { get; set; } = 0; + public string columnCondition { get; set; } + public string columnText { get; set; } + public string userId { get; set; } + public string tenantId { get; set; } + public int enabledMark { get; set; } + public string formLink { get; set; } + public string columnLink { get; set; } +} + +/// +/// 获取外链配置输出. +/// +public class VisualdevShortLinkFormConfigOutput +{ + public string formData { get; set; } + public string columnData { get; set; } + public string appColumnData { get; set; } + public string webType { get; set; } + public string flowTemplateJson { get; set; } + public string flowEnCode { get; set; } + public string flowId { get; set; } + public string fullName { get; set; } + public int enableFlow { get; set; } +} \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkInput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkInput.cs new file mode 100644 index 00000000..024c0f6a --- /dev/null +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkInput.cs @@ -0,0 +1,18 @@ +using JNPF.DependencyInjection; + +namespace JNPF.VisualDev.Entitys.Dto.VisualDev; + +/// +/// 功能表单外联信息输入. +/// +[SuppressSniffer] +public class VisualDevShortLinkInput +{ + public string encryption { get; set; } + + public string tenantId { get; set; } + + public string modelId { get; set; } + + public string type { get; set; } +} diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkPwdInput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkPwdInput.cs new file mode 100644 index 00000000..32bb9e30 --- /dev/null +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualDevShortLinkPwdInput.cs @@ -0,0 +1,16 @@ +using JNPF.DependencyInjection; + +namespace JNPF.VisualDev.Entitys.Dto.VisualDev; + +/// +/// 在线表单外链密码验证 输入. +/// +[SuppressSniffer] +public class VisualDevShortLinkPwdInput +{ + public string id { get; set; } + + public int type { get; set; } + + public string password { get; set; } +} diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualdevShortLinkFormInput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualdevShortLinkFormInput.cs new file mode 100644 index 00000000..c345be7a --- /dev/null +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDev/VisualdevShortLinkFormInput.cs @@ -0,0 +1,24 @@ +using JNPF.DependencyInjection; + +namespace JNPF.VisualDev.Entitys.Dto.VisualDev; + +/// +/// 修改外链信息 输入. +/// +[SuppressSniffer] +public class VisualdevShortLinkFormInput +{ + public string id { get; set; } + public string shortLink { get; set; } + public int formUse { get; set; } + public string formLink { get; set; } + public int formPassUse { get; set; } + public string formPassword { get; set; } + public int columnUse { get; set; } + public string columnLink { get; set; } + public int columnPassUse { get; set; } + public string columnPassword { get; set; } + public string columnCondition { get; set; } + public string columnText { get; set; } + public int enabledMark { get; set; } +} diff --git a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDevModelData/VisualDevModelListQueryInput.cs b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDevModelData/VisualDevModelListQueryInput.cs index 5a5f52d8..5a28bb9a 100644 --- a/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDevModelData/VisualDevModelListQueryInput.cs +++ b/visualdev/Tnb.VisualDev.Entitys/Dto/VisualDevModelData/VisualDevModelListQueryInput.cs @@ -1,5 +1,4 @@ -using System.DirectoryServices.Protocols; -using JNPF.Common.Filter; +using JNPF.Common.Filter; namespace JNPF.VisualDev.Entitys.Dto.VisualDevModelData; @@ -8,12 +7,6 @@ namespace JNPF.VisualDev.Entitys.Dto.VisualDevModelData; /// public class VisualDevModelListQueryInput : PageInputBase { - //modified by PhilPan - ///// - ///// 菜单ID. - ///// - //public string menuId { get; set; } - /// /// 选择导出数据key. /// @@ -24,10 +17,16 @@ public class VisualDevModelListQueryInput : PageInputBase /// public string dataType { get; set; } = "0"; + /// + /// 数据过滤. + /// + public string dataRuleJson { get; set; } + /// /// 高级查询. /// public virtual string superQueryJson { get; set; } + // TODO 不能放在这里 /// /// 工位编码 /// diff --git a/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevEntity.cs b/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevEntity.cs index 7f203c25..a4ed0956 100644 --- a/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevEntity.cs +++ b/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevEntity.cs @@ -83,7 +83,7 @@ public class VisualDevEntity : CLDEntityBase public string FlowTemplateJson { get; set; } /// - /// 页面类型(1、纯表单,2、表单加列表). + /// 页面类型(1、纯表单,2、表单加列表,3、系统表单,4、数据视图). /// [SugarColumn(ColumnName = "F_WEBTYPE")] public int WebType { get; set; } = 2; @@ -105,4 +105,28 @@ public class VisualDevEntity : CLDEntityBase /// [SugarColumn(ColumnName = "F_ENABLEFLOW")] public int EnableFlow { get; set; } + + /// + /// 接口id. + /// + [SugarColumn(ColumnName = "F_INTERFACEID")] + public string InterfaceId { get; set; } + + /// + /// 接口名称. + /// + [SugarColumn(ColumnName = "F_INTERFACENAME")] + public string InterfaceName { get; set; } + + /// + /// 接口参数. + /// + [SugarColumn(ColumnName = "F_INTERFACEPARAM")] + public string InterfaceParam { get; set; } + + /// + /// 是否外链(虚拟字段). + /// + [SugarColumn(IsIgnore = true)] + public bool isShortLink { get; set; } = false; } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevReleaseEntity.cs b/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevReleaseEntity.cs index 82fd75bd..54c6b424 100644 --- a/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevReleaseEntity.cs +++ b/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevReleaseEntity.cs @@ -99,4 +99,22 @@ public class VisualDevReleaseEntity : CLDEntityBase /// [SugarColumn(ColumnName = "F_ENABLEFLOW")] public int EnableFlow { get; set; } + + /// + /// 接口id. + /// + [SugarColumn(ColumnName = "F_INTERFACEID")] + public string InterfaceId { get; set; } + + /// + /// 接口名称. + /// + [SugarColumn(ColumnName = "F_INTERFACENAME")] + public string InterfaceName { get; set; } + + /// + /// 接口参数. + /// + [SugarColumn(ColumnName = "F_INTERFACEPARAM")] + public string InterfaceParam { get; set; } } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevShortLinkEntity.cs b/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevShortLinkEntity.cs new file mode 100644 index 00000000..c4869e3b --- /dev/null +++ b/visualdev/Tnb.VisualDev.Entitys/Entity/VisualDevShortLinkEntity.cs @@ -0,0 +1,101 @@ +using JNPF.Common.Contracts; +using SqlSugar; + +namespace JNPF.VisualDev.Entitys; + +/// +/// 可视化开发功能实体. +/// +[SugarTable("BASE_VISUALDEV_SHORT_LINK")] +public class VisualDevShortLinkEntity : CLDEntityBase +{ + /// + /// 短链接. + /// + [SugarColumn(ColumnName = "F_SHORTLINK")] + public string ShortLink { get; set; } + + /// + /// 外链填单开关. + /// + [SugarColumn(ColumnName = "F_FormUse")] + public int FormUse { get; set; } + + /// + /// 外链填单. + /// + [SugarColumn(ColumnName = "F_FormLink")] + public string FormLink { get; set; } + + /// + /// 外链密码开关(1:开 , 0:关). + /// + [SugarColumn(ColumnName = "F_FormPassUse")] + public int FormPassUse { get; set; } + + /// + /// 外链填单密码. + /// + [SugarColumn(ColumnName = "F_FormPassword")] + public string FormPassword { get; set; } + + /// + /// 公开查询开关. + /// + [SugarColumn(ColumnName = "F_ColumnUse")] + public int ColumnUse { get; set; } + + /// + /// 公开查询. + /// + [SugarColumn(ColumnName = "F_ColumnLink")] + public string ColumnLink { get; set; } + + /// + /// 查询密码开关. + /// + [SugarColumn(ColumnName = "F_ColumnPassUse")] + public int ColumnPassUse { get; set; } + + /// + /// 公开查询密码. + /// + [SugarColumn(ColumnName = "F_ColumnPassword")] + public string ColumnPassword { get; set; } + + /// + /// 查询条件. + /// + [SugarColumn(ColumnName = "F_ColumnCondition")] + public string ColumnCondition { get; set; } + + /// + /// 显示内容. + /// + [SugarColumn(ColumnName = "F_ColumnText")] + public string ColumnText { get; set; } + + /// + /// PC端链接. + /// + [SugarColumn(ColumnName = "F_RealPcLink")] + public string RealPcLink { get; set; } + + /// + /// App端链接. + /// + [SugarColumn(ColumnName = "F_RealAppLink")] + public string RealAppLink { get; set; } + + /// + /// 用户id. + /// + [SugarColumn(ColumnName = "F_UserId")] + public string UserId { get; set; } + + /// + /// 租户id. + /// + [SugarColumn(ColumnName = "F_TenantId")] + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev.Interfaces/IRunService.cs b/visualdev/Tnb.VisualDev.Interfaces/IRunService.cs index 50773d67..5841a3e9 100644 --- a/visualdev/Tnb.VisualDev.Interfaces/IRunService.cs +++ b/visualdev/Tnb.VisualDev.Interfaces/IRunService.cs @@ -81,13 +81,6 @@ public interface IRunService /// Task>> GetRelationFormList(VisualDevEntity entity, VisualDevModelListQueryInput input, string actionType = "List"); - /// - /// 获取模型数据信息. - /// - /// - /// - Task GetInfo(string id); - /// /// 获取有表详情转换. /// @@ -102,7 +95,7 @@ public interface IRunService /// /// /// - /// modified by pf 2023-04-12 返回值不序列化 + /// modified by PhilPan 2023-04-12 返回值不序列化成字符串 Task?> GetHaveTableInfoDetails(string id, VisualDevEntity templateEntity, bool isFlowTask = false); /// @@ -127,9 +120,10 @@ public interface IRunService /// 表单模板. /// 表单数据json. /// 主键Id. + /// 流程引擎主键Id. /// 是否修改. /// - Task SaveFlowFormData(FlowFormEntity fEntity, string formData, string dataId, bool isUpdate = false); + Task SaveFlowFormData(FlowFormEntity fEntity, string formData, string dataId, string flowId, bool isUpdate = false); /// /// 获取流程表单数据解析详情. @@ -148,4 +142,14 @@ public interface IRunService /// 表单数据. /// 是否子流程. Task> SaveDataToDataByFId(string oldFId, string newFId, List> mapRule, Dictionary formData, bool isSubFlow = false); + + /// + /// 处理模板默认值 (针对流程表单). + /// 用户选择 , 部门选择. + /// + /// 表单json. + /// 关联表单. + /// 表单类型(1:系统表单 2:自定义表单). + /// + string GetVisualDevModelDataConfig(string propertyJson, string tableJson, int formType); } diff --git a/visualdev/Tnb.VisualDev.Interfaces/IVisualDevService.cs b/visualdev/Tnb.VisualDev.Interfaces/IVisualDevService.cs index 4c973623..40f97c42 100644 --- a/visualdev/Tnb.VisualDev.Interfaces/IVisualDevService.cs +++ b/visualdev/Tnb.VisualDev.Interfaces/IVisualDevService.cs @@ -44,11 +44,4 @@ public interface IVisualDevService /// Task NoTblToTable(VisualDevEntity vEntity, string mainTableName); - /// - /// 数据 转 插入Sql语句. - /// - /// 表名. - /// 数据包字符串. - /// - List DataToInsertSql(string tableName, string dataStr); } diff --git a/visualdev/Tnb.VisualDev/CodeGen/DataParsing/ControlParsing.cs b/visualdev/Tnb.VisualDev/CodeGen/DataParsing/ControlParsing.cs index e1be8234..3d5e91ba 100644 --- a/visualdev/Tnb.VisualDev/CodeGen/DataParsing/ControlParsing.cs +++ b/visualdev/Tnb.VisualDev/CodeGen/DataParsing/ControlParsing.cs @@ -77,12 +77,12 @@ public class ControlParsing : ITransient // 子表 if (item.Value != null && item.Key.ToLower().Contains("tablefield") && (item.Value is List> || item.Value.GetType().Name.Equals("JArray"))) { - var ctOldDatas = item.Value.ToObject>>(); + var ctOldDatas = item.Value.ToObject>>(CommonConst.options); ctOldDatas.ForEach(ctItems => { foreach (var ctItem in ctItems) { - if (vModelList.Contains(item.Key + "-" + ctItem.Key) && !vModels.ContainsKey(item.Key + "-" + ctItem.Key)) + if ((vModelList.Contains(item.Key + "-" + ctItem.Key) || vModelList.Contains(item.Key + "-" + ctItem.Key + "_name")) && !vModels.ContainsKey(item.Key + "-" + ctItem.Key)) vModels.Add(item.Key + "-" + ctItem.Key, jnpfKeyConst); } }); @@ -108,13 +108,13 @@ public class ControlParsing : ITransient foreach (var items in oldDatas) { - for(var i = 0; i < items.Count; i++) + for (var i = 0; i < items.Count; i++) { var item = items.ToList()[i]; if (vModels.Any(x => x.Key.Equals(item.Key)) && items[item.Key] != null) { - FieldsModel model = fields.Any(x=>x.__vModel__.Equals(item.Key)) ? fields.Find(x=> x.__vModel__.Equals(item.Key)) : (fields.Any(x => x.__vModel__.Equals(item.Key.Replace("_name", string.Empty))) ? fields.Find(x => x.__vModel__.Equals(item.Key.Replace("_name", string.Empty))) : new FieldsModel()); + FieldsModel model = fields.Any(x => x.__vModel__.Equals(item.Key)) ? fields.Find(x => x.__vModel__.Equals(item.Key)) : (fields.Any(x => x.__vModel__.Equals(item.Key.Replace("_name", string.Empty))) ? fields.Find(x => x.__vModel__.Equals(item.Key.Replace("_name", string.Empty))) : new FieldsModel()); model.separator = ","; var jnpfKey = vModels.FirstOrDefault(x => x.Key.Equals(item.Key)).Value; switch (jnpfKey) @@ -194,7 +194,7 @@ public class ControlParsing : ITransient if (specificData != null) { // 要用模板的 “显示字段 - relationField”来展示数据 - items[item.Key + "_id"] = items[item.Key]; + items[model.__vModel__ + "_id"] = items[item.Key]; items[item.Key] = specificData[model.relationField]; // 弹窗选择属性 @@ -208,7 +208,7 @@ public class ControlParsing : ITransient var vara = popupselectDataList.Where(a => a.ContainsValue(items[item.Key] == null ? model.interfaceId : items[item.Key].ToString())).FirstOrDefault(); if (vara != null) { - items[item.Key + "_id"] = items[item.Key]; + items[model.__vModel__ + "_id"] = items[item.Key]; items[item.Key] = vara[items[item.Key].ToString()]; // 弹窗选择属性 @@ -222,7 +222,7 @@ public class ControlParsing : ITransient var vara = popupselectDataList.Where(a => a.ContainsValue(items[item.Key] == null ? model.interfaceId : items[item.Key].ToString())).FirstOrDefault(); if (vara != null) { - items[item.Key + "_id"] = items[item.Key]; + items[model.__vModel__ + "_id"] = items[item.Key]; items[item.Key] = vara[items[item.Key].ToString()]; // 弹窗选择属性 @@ -257,11 +257,11 @@ public class ControlParsing : ITransient pageSize = 999999 }; - Scoped.Create(async (_, scope) => + Scoped.Create((_, scope) => { var services = scope.ServiceProvider; var _runService = App.GetService(services); - var res = await _runService.GetRelationFormList(relationFormModel, listQueryInput); + var res = _runService.GetRelationFormList(relationFormModel, listQueryInput).WaitAsync(TimeSpan.FromMinutes(2)).Result; _cacheManager.Set(redisName, res.list.ToList(), TimeSpan.FromMinutes(10)); // 缓存10分钟 }); var cacheStr = _cacheManager.Get(redisName); @@ -271,7 +271,7 @@ public class ControlParsing : ITransient var relationFormRealData = relationFormDataList.Where(it => it["id"].Equals(items[item.Key])).FirstOrDefault(); if (relationFormRealData != null && relationFormRealData.Count > 0) { - items[item.Key + "_id"] = relationFormRealData["id"]; + items[model.__vModel__ + "_id"] = relationFormRealData["id"]; items[item.Key] = relationFormRealData.ContainsKey(model.relationField) ? relationFormRealData[model.relationField] : string.Empty; // 关联表单属性 @@ -291,7 +291,7 @@ public class ControlParsing : ITransient // 子表 if (item.Value != null && item.Key.ToLower().Contains("tablefield") && (item.Value is List> || item.Value.GetType().Name.Equals("JArray"))) { - var ctList = item.Value.ToObject>>(); + var ctList = item.Value.ToObject>>(CommonConst.options); var ctVModels = new Dictionary(); foreach (var ctItem in vModels.Where(x => x.Key.Contains(item.Key)).ToList()) { @@ -349,71 +349,112 @@ public class ControlParsing : ITransient /// 获取用户组件查询条件组装. /// /// 字段名. - /// 查询值. - /// 是否多选. + /// 查询值. /// - public List GetUsersSelectQueryWhere(string key, string value, bool multiple) + public List GetUsersSelectQueryWhere(string key, string values) + { + if (values.IsNotEmptyOrNull()) return GetUsersSelectQueryWhere(key, new List() { values }); + else return new List(); + } + + /// + /// 获取用户组件查询条件组装. + /// + /// 字段名. + /// 查询值. + /// + public List GetUsersSelectQueryWhere(string key, string values, bool isMultiple = false) + { + return GetUsersSelectQueryWhere(key, values); + } + + /// + /// 获取用户组件查询条件组装. + /// + /// 字段名. + /// 查询值. + /// + public List GetUsersSelectQueryWhere(string key, List values) { var conModels = new List(); - if (value.IsNullOrEmpty()) return conModels; - if (multiple) + if (values.IsNullOrEmpty() || !values.Any()) return conModels; + var userIds = values.Select(x => x.Replace("--user", string.Empty)).ToList(); + var rIdList = _repository.AsSugarClient().Queryable().Where(x => userIds.Contains(x.UserId)).Select(x => new { x.ObjectId, x.ObjectType }).ToList(); + var objIdList = values; + rIdList.ForEach(x => { - var rIdList = _repository.AsSugarClient().Queryable().Where(x => x.UserId.Equals(value.Replace("--user", string.Empty))).Select(x => new { x.ObjectId, x.ObjectType }).ToList(); - var objIdList = new List() { value }; - rIdList.ForEach(x => + if (x.ObjectType.Equals("Organize")) { - if (x.ObjectType.Equals("Organize")) - { - objIdList.Add(x.ObjectId + "--company"); - objIdList.Add(x.ObjectId + "--department"); - } - else - { - objIdList.Add(x.ObjectId + "--" + x.ObjectType.ToLower()); - } - }); - - var whereList = new List>(); - for (var i = 0; i < objIdList.Count(); i++) - { - if (i == 0) - { - whereList.Add(new KeyValuePair(WhereType.And, new ConditionalModel - { - FieldName = key, - ConditionalType = ConditionalType.Like, - FieldValue = objIdList[i] - })); - } - else - { - whereList.Add(new KeyValuePair(WhereType.Or, new ConditionalModel - { - FieldName = key, - ConditionalType = ConditionalType.Like, - FieldValue = objIdList[i] - })); - } + objIdList.Add(x.ObjectId + "--company"); + objIdList.Add(x.ObjectId + "--department"); } - - conModels.Add(new ConditionalCollections() { ConditionalList = whereList }); - } - else - { - conModels.Add(new ConditionalCollections() + else { - ConditionalList = new List>() + objIdList.Add(x.ObjectId + "--" + x.ObjectType.ToLower()); + } + }); + + var whereList = new List>(); + for (var i = 0; i < objIdList.Count(); i++) + { + if (i == 0) + { + whereList.Add(new KeyValuePair(WhereType.And, new ConditionalModel { - new KeyValuePair(WhereType.And, new ConditionalModel - { - FieldName = key, - ConditionalType = ConditionalType.Equal, - FieldValue = value - }) - } - }); + FieldName = key, + ConditionalType = ConditionalType.Like, + FieldValue = objIdList[i] + })); + } + else + { + whereList.Add(new KeyValuePair(WhereType.Or, new ConditionalModel + { + FieldName = key, + ConditionalType = ConditionalType.Like, + FieldValue = objIdList[i] + })); + } } + whereList.Add(new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = key, + ConditionalType = ConditionalType.IsNot, + FieldValue = null + })); + whereList.Add(new KeyValuePair(WhereType.And, new ConditionalModel + { + FieldName = key, + ConditionalType = ConditionalType.IsNot, + FieldValue = string.Empty + })); + conModels.Add(new ConditionalCollections() { ConditionalList = whereList }); + return conModels; + } + + /// + /// 生成查询多选条件. + /// + /// 数据库列名称. + /// + /// + public List GenerateMultipleSelectionCriteriaForQuerying(string key, List? list) + { + var conModels = new List(); + var addItems = new List>(); + for (int i = 0; i < list?.Count; i++) + { + var add = new KeyValuePair(i == 0 ? WhereType.And : WhereType.Or, new ConditionalModel + { + FieldName = key, + ConditionalType = ConditionalType.Like, + FieldValue = list[i] + }); + addItems.Add(add); + } + if (addItems?.Count > 0) + conModels.Add(new ConditionalCollections() { ConditionalList = addItems }); return conModels; } diff --git a/visualdev/Tnb.VisualDev/CodeGenService.cs b/visualdev/Tnb.VisualDev/CodeGenService.cs index 9d9a205d..489d1922 100644 --- a/visualdev/Tnb.VisualDev/CodeGenService.cs +++ b/visualdev/Tnb.VisualDev/CodeGenService.cs @@ -21,6 +21,7 @@ using JNPF.VisualDev.Entitys; using JNPF.VisualDev.Entitys.Dto.CodeGen; using JNPF.VisualDev.Entitys.Enum; using Microsoft.AspNetCore.Mvc; +using NPOI.Util; using SqlSugar; using System.IO.Compression; using System.Text; @@ -124,7 +125,7 @@ public class CodeGenService : IDynamicApiController, ITransient var templateEntity = await _repository.GetFirstAsync(v => v.Id == id && v.DeleteMark == null); _ = templateEntity ?? throw Oops.Oh(ErrorCode.COM1005); _ = templateEntity.Tables ?? throw Oops.Oh(ErrorCode.D2100); - var model = templateEntity.FormData.ToObject(); + var model = templateEntity.FormData.ToObjectOld(); if (templateEntity.Type == 3) downloadCodeForm.module = "WorkFlow"; model.className = new List() { downloadCodeForm.className.ParseToPascalCase() }; @@ -186,7 +187,7 @@ public class CodeGenService : IDynamicApiController, ITransient var templateEntity = await _repository.GetFirstAsync(v => v.Id == id && v.DeleteMark == null); _ = templateEntity ?? throw Oops.Oh(ErrorCode.COM1005); _ = templateEntity.Tables ?? throw Oops.Oh(ErrorCode.D2100); - var model = templateEntity.FormData.ToObject(); + var model = templateEntity.FormData.ToObjectOld(); model.className = new List() { downloadCodeForm.className.ParseToPascalCase() }; model.areasName = downloadCodeForm.module; string fileName = SnowflakeIdHelper.NextId(); @@ -244,7 +245,7 @@ public class CodeGenService : IDynamicApiController, ITransient List? tableRelation = templateEntity.Tables.ToObject>(); // 表单数据 - var formDataModel = templateEntity.FormData.ToObject(); + var formDataModel = templateEntity.FormData.ToObjectOld(); // 列表属性 ColumnDesignModel? pcColumnDesignModel = templateEntity.ColumnData?.ToObject(); @@ -283,17 +284,42 @@ public class CodeGenService : IDynamicApiController, ITransient case 1: break; default: - if (pcColumnDesignModel.type == 2 && (pcColumnDesignModel.searchList.Count == 0 || pcColumnDesignModel.searchList.Any(it => !it.prop.Equals(pcColumnDesignModel.treeRelation)))) + if (pcColumnDesignModel.type == 2 && (pcColumnDesignModel.searchList.Count == 0 || !pcColumnDesignModel.searchList.Any(it => it.prop.Equals(pcColumnDesignModel.treeRelation)))) { - var search = controls.Find(x => x.__vModel__.Equals(pcColumnDesignModel.treeRelation)); - pcColumnDesignModel.searchList.Add(new IndexSearchFieldModel + var search = new FieldsModel(); + // 左侧树关联字段是否为子表字段 + switch (pcColumnDesignModel.treeRelation.StartsWith("tableField")) { - label = search.__config__.label, - prop = search.__vModel__, - jnpfKey = search.__config__.jnpfKey, - searchType = 1, - __vModel__ = search.__vModel__ - }); + case true: + foreach (var item in controls.FindAll(it => it.__config__.jnpfKey.Equals(JnpfKeyConst.TABLE))) + { + search = item.__config__.children.Find(x => x.__vModel__.Equals(pcColumnDesignModel.treeRelation.Replace(string.Format("{0}-", item.__vModel__), ""))); + if (search != null) + { + pcColumnDesignModel.searchList.Add(new IndexSearchFieldModel + { + label = search.__config__.label, + prop = string.Format("{0}-{1}", item.__vModel__, search.__vModel__), + jnpfKey = search.__config__.jnpfKey, + searchType = 1, + __vModel__ = string.Format("{0}-{1}", item.__vModel__, search.__vModel__), + }); + continue; + } + } + break; + default: + search = controls.Find(x => x.__vModel__.Equals(pcColumnDesignModel.treeRelation)); + pcColumnDesignModel.searchList.Add(new IndexSearchFieldModel + { + label = search.__config__.label, + prop = search.__vModel__, + jnpfKey = search.__config__.jnpfKey, + searchType = 1, + __vModel__ = search.__vModel__ + }); + break; + } } // 统一处理下表单内控件 @@ -352,9 +378,10 @@ public class CodeGenService : IDynamicApiController, ITransient // 默认主表开启自增子表也需要开启自增 if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) - { throw Oops.Oh(ErrorCode.D2109); - } + + if (formDataModel.logicalDelete && !fieldList.Any(it => it.field.ToLower().Equals("f_deletemark"))) + throw Oops.Oh(ErrorCode.D2110); // 后端生成 codeGenConfigModel = CodeGenWay.ChildTableBackEnd(item.table, item.className, fieldList, controls, templateEntity, controlId); @@ -366,8 +393,7 @@ public class CodeGenService : IDynamicApiController, ITransient for (int i = 0; i < templatePathList.Count; i++) { var tContent = File.ReadAllText(templatePathList[i]); - var tResult = _viewEngine.RunCompileFromCached(tContent, new - { + var tResult = _viewEngine.RunCompileFromCached(tContent, new { BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, NameSpace = formDataModel.areasName, @@ -412,6 +438,8 @@ public class CodeGenService : IDynamicApiController, ITransient IsConversion = codeGenConfigModel.TableField.Any(it => it.IsConversion.Equals(true)), IsDetailConversion = codeGenConfigModel.TableField.Any(it => it.IsDetailConversion.Equals(true)), IsImportData = codeGenConfigModel.TableField.Any(it => it.IsImportField.Equals(true)), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsControlParsing = codeGenConfigModel.TableField.Any(it => it.IsControlParsing), }); // 还原全部控件 @@ -427,20 +455,20 @@ public class CodeGenService : IDynamicApiController, ITransient // 开启乐观锁 if (formDataModel.concurrencyLock && !fieldList.Any(it => it.field.ToLower().Equals("f_version"))) - { throw Oops.Oh(ErrorCode.D2107); - } if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) - { throw Oops.Oh(ErrorCode.D2109); - } + + if (templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowid"))) + throw Oops.Oh(ErrorCode.D2105); // 列表带流程 或者 流程表单 自增ID if (formDataModel.primaryKeyPolicy == 2 && templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowtaskid"))) - { throw Oops.Oh(ErrorCode.D2108); - } + + if (formDataModel.logicalDelete && !fieldList.Any(it => it.field.ToLower().Equals("f_deletemark"))) + throw Oops.Oh(ErrorCode.D2110); // 后端生成 codeGenConfigModel = CodeGenWay.MainBeltBackEnd(item.table, fieldList, controls, templateEntity); @@ -448,21 +476,9 @@ public class CodeGenService : IDynamicApiController, ITransient codeGenConfigModel.BusName = item.tableName; codeGenConfigModel.TableRelations = tableRelationsList; codeGenConfigModel.IsChildConversion = tableRelationsList.Any(it => it.IsConversion); - switch (codeGenConfigModel.IndexDataType) + switch (templateEntity.WebType) { - case 4: - switch (templateEntity.Type) - { - case 3: - break; - default: - targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(item.className, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); - templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("2-MainBelt", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); - break; - } - - break; - default: + case 1: switch (templateEntity.Type) { case 3: @@ -474,7 +490,37 @@ public class CodeGenService : IDynamicApiController, ITransient templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("2-MainBelt", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); break; } + break; + case 2: + switch (codeGenConfigModel.IndexDataType) + { + case 4: + switch (templateEntity.Type) + { + case 3: + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(item.className, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("2-MainBelt", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } + break; + default: + switch (templateEntity.Type) + { + case 3: + targetPathList = CodeGenTargetPathHelper.BackendFlowTargetPathList(item.className, fileName, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendFlowTemplatePathList("2-MainBelt", codeGenConfigModel.IsMapper); + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(item.className, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("2-MainBelt", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } + + break; + } break; } @@ -482,8 +528,7 @@ public class CodeGenService : IDynamicApiController, ITransient for (int i = 0; i < templatePathList.Count; i++) { string tContent = File.ReadAllText(templatePathList[i]); - string tResult = _viewEngine.RunCompileFromCached(tContent, new - { + string tResult = _viewEngine.RunCompileFromCached(tContent, new { NameSpace = codeGenConfigModel.NameSpace, BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, @@ -538,6 +583,12 @@ public class CodeGenService : IDynamicApiController, ITransient ParsJnpfKeyConstList = codeGenConfigModel.ParsJnpfKeyConstList, ParsJnpfKeyConstListDetails = codeGenConfigModel.ParsJnpfKeyConstListDetails, ImportDataType = codeGenConfigModel.ImportDataType, + DataRuleJson = CodeGenControlsAttributeHelper.GetDataRuleList(templateEntity, codeGenConfigModel).ToJsonString().Replace("\"", "\\\"").Replace("\\\\\"", "\\\\\\\"").Replace("\\\\\\\\\"", "\\\\\\\\\\\\\""), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsTreeTable = codeGenConfigModel.IsTreeTable, + ParentField = codeGenConfigModel.ParentField, + TreeShowField = codeGenConfigModel.TreeShowField, + IsLogicalDelete = codeGenConfigModel.IsLogicalDelete, }); var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName; if (!Directory.Exists(dirPath)) @@ -552,12 +603,6 @@ public class CodeGenService : IDynamicApiController, ITransient } break; - - /* - * 使用导航查询一对一模式 - * 优点:语法糖简单 - * 缺点:子表的时间类型无法直接转换 - */ case GeneratePatterns.MainBeltVice: { var link = await _repository.AsSugarClient().Queryable().FirstAsync(m => m.Id == templateEntity.DbLinkId && m.DeleteMark == null); @@ -584,6 +629,9 @@ public class CodeGenService : IDynamicApiController, ITransient throw Oops.Oh(ErrorCode.D2109); } + if (formDataModel.logicalDelete && !fieldList.Any(it => it.field.ToLower().Equals("f_deletemark"))) + throw Oops.Oh(ErrorCode.D2110); + codeGenConfigModel = CodeGenWay.AuxiliaryTableBackEnd(item.table, fieldList, auxiliaryControls, templateEntity, tableNo, 0); codeGenConfigModel.BusName = item.tableName; codeGenConfigModel.ClassName = item.className; @@ -600,8 +648,7 @@ public class CodeGenService : IDynamicApiController, ITransient for (int i = 0; i < templatePathList.Count; i++) { var tContent = File.ReadAllText(templatePathList[i]); - var tResult = _viewEngine.RunCompileFromCached(tContent, new - { + var tResult = _viewEngine.RunCompileFromCached(tContent, new { BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, NameSpace = formDataModel.areasName, @@ -633,6 +680,7 @@ public class CodeGenService : IDynamicApiController, ITransient TableName = item.table.ParseToPascalCase(), PrimaryKey = codeGenConfigModel.TableField.Find(it => it.PrimaryKey).ColumnName, TableField = codeGenConfigModel.TableField.Find(it => it.ForeignKeyField).ColumnName, + ChilderColumnConfigList = codeGenConfigModel.TableField, OriginalTableField = codeGenConfigModel.TableField.Find(it => it.ForeignKeyField).OriginalColumnName, RelationField = item.relationField.ReplaceRegex("^f_", string.Empty).ParseToPascalCase(), OriginalRelationField = item.relationField, @@ -642,6 +690,8 @@ public class CodeGenService : IDynamicApiController, ITransient IsImportData = codeGenConfigModel.TableField.Any(it => it.IsImportField.Equals(true)), IsSystemControl = codeGenConfigModel.TableField.Any(it => it.IsSystemControl), IsUpdate = codeGenConfigModel.TableField.Any(it => it.IsUpdate), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsControlParsing = codeGenConfigModel.TableField.Any(it => it.IsControlParsing), }); auxiliaryTableColumnList.AddRange(codeGenConfigModel.TableField.FindAll(it => it.jnpfKey != null)); @@ -656,38 +706,27 @@ public class CodeGenService : IDynamicApiController, ITransient // 开启乐观锁 if (formDataModel.concurrencyLock && !fieldList.Any(it => it.field.ToLower().Equals("f_version"))) - { throw Oops.Oh(ErrorCode.D2107); - } if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) - { throw Oops.Oh(ErrorCode.D2109); - } + + if (templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowid"))) + throw Oops.Oh(ErrorCode.D2105); // 列表带流程 或者 流程表单 自增ID if (formDataModel.primaryKeyPolicy == 2 && templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowtaskid"))) - { throw Oops.Oh(ErrorCode.D2108); - } + + if (formDataModel.logicalDelete && !fieldList.Any(it => it.field.ToLower().Equals("f_deletemark"))) + throw Oops.Oh(ErrorCode.D2110); // 后端生成 codeGenConfigModel = CodeGenWay.MainBeltViceBackEnd(item.table, fieldList, auxiliaryTableColumnList, controls, templateEntity); - switch (codeGenConfigModel.IndexDataType) + switch (templateEntity.WebType) { - case 4: - switch (templateEntity.Type) - { - case 3: - break; - default: - targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(codeGenConfigModel.ClassName, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); - templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("4-MainBeltVice", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); - break; - } - break; - default: + case 1: switch (templateEntity.Type) { case 3: @@ -700,13 +739,41 @@ public class CodeGenService : IDynamicApiController, ITransient break; } break; + case 2: + switch (codeGenConfigModel.IndexDataType) + { + case 4: + switch (templateEntity.Type) + { + case 3: + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(codeGenConfigModel.ClassName, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("4-MainBeltVice", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } + break; + default: + switch (templateEntity.Type) + { + case 3: + targetPathList = CodeGenTargetPathHelper.BackendFlowTargetPathList(codeGenConfigModel.ClassName, fileName, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendFlowTemplatePathList("4-MainBeltVice", codeGenConfigModel.IsMapper); + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(codeGenConfigModel.ClassName, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("4-MainBeltVice", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } + break; + } + break; } for (var i = 0; i < templatePathList.Count; i++) { var tContent = File.ReadAllText(templatePathList[i]); - var tResult = _viewEngine.RunCompileFromCached(tContent, new - { + var tResult = _viewEngine.RunCompileFromCached(tContent, new { NameSpace = codeGenConfigModel.NameSpace, BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, @@ -759,6 +826,12 @@ public class CodeGenService : IDynamicApiController, ITransient ParsJnpfKeyConstList = codeGenConfigModel.ParsJnpfKeyConstList, ParsJnpfKeyConstListDetails = codeGenConfigModel.ParsJnpfKeyConstListDetails, ImportDataType = codeGenConfigModel.ImportDataType, + DataRuleJson = CodeGenControlsAttributeHelper.GetDataRuleList(templateEntity, codeGenConfigModel).ToJsonString().Replace("\"", "\\\"").Replace("\\\\\"", "\\\\\\\"").Replace("\\\\\\\\\"", "\\\\\\\\\\\\\""), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsTreeTable = codeGenConfigModel.IsTreeTable, + ParentField = codeGenConfigModel.ParentField, + TreeShowField = codeGenConfigModel.TreeShowField, + IsLogicalDelete = codeGenConfigModel.IsLogicalDelete, }); var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName; if (!Directory.Exists(dirPath)) @@ -816,9 +889,10 @@ public class CodeGenService : IDynamicApiController, ITransient // 默认主表开启自增子表也需要开启自增 if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) - { throw Oops.Oh(ErrorCode.D2109); - } + + if (formDataModel.logicalDelete && !fieldList.Any(it => it.field.ToLower().Equals("f_deletemark"))) + throw Oops.Oh(ErrorCode.D2110); // 后端生成 codeGenConfigModel = CodeGenWay.ChildTableBackEnd(item.table, item.className, fieldList, controls, templateEntity, controlId); @@ -830,8 +904,7 @@ public class CodeGenService : IDynamicApiController, ITransient for (int i = 0; i < templatePathList.Count; i++) { var tContent = File.ReadAllText(templatePathList[i]); - var tResult = _viewEngine.RunCompileFromCached(tContent, new - { + var tResult = _viewEngine.RunCompileFromCached(tContent, new { BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, NameSpace = formDataModel.areasName, @@ -876,6 +949,8 @@ public class CodeGenService : IDynamicApiController, ITransient IsConversion = codeGenConfigModel.TableField.Any(it => it.IsConversion.Equals(true)), IsDetailConversion = codeGenConfigModel.TableField.Any(it => it.IsDetailConversion.Equals(true)), IsImportData = codeGenConfigModel.TableField.Any(it => it.IsImportField.Equals(true)), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsControlParsing = codeGenConfigModel.TableField.Any(it => it.IsControlParsing), }); tableNo++; @@ -892,6 +967,10 @@ public class CodeGenService : IDynamicApiController, ITransient var auxiliaryControls = controls.FindAll(it => it.__config__.tableName == item.table); var fieldList = _databaseManager.GetFieldList(targetLink, item.table); + // 默认主表开启自增副表也需要开启自增 + if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) + throw Oops.Oh(ErrorCode.D2109); + codeGenConfigModel = CodeGenWay.AuxiliaryTableBackEnd(item.table, fieldList, auxiliaryControls, templateEntity, tableNo, 1); codeGenConfigModel.BusName = item.tableName; codeGenConfigModel.ClassName = item.className; @@ -901,18 +980,11 @@ public class CodeGenService : IDynamicApiController, ITransient codeGenConfigModel.TableField.ForEach(items => items.ClassName = item.className); - // 默认主表开启自增副表也需要开启自增 - if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) - { - throw Oops.Oh(ErrorCode.D2109); - } - // 生成副表相关文件 for (int i = 0; i < templatePathList.Count; i++) { var tContent = File.ReadAllText(templatePathList[i]); - var tResult = _viewEngine.RunCompileFromCached(tContent, new - { + var tResult = _viewEngine.RunCompileFromCached(tContent, new { BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, NameSpace = formDataModel.areasName, @@ -944,6 +1016,7 @@ public class CodeGenService : IDynamicApiController, ITransient TableName = item.table.ParseToPascalCase(), PrimaryKey = codeGenConfigModel.TableField.Find(it => it.PrimaryKey).ColumnName, TableField = codeGenConfigModel.TableField.Find(it => it.ForeignKeyField).ColumnName, + ChilderColumnConfigList = codeGenConfigModel.TableField, OriginalTableField = codeGenConfigModel.TableField.Find(it => it.ForeignKeyField).OriginalColumnName, RelationField = item.relationField.ReplaceRegex("^f_", string.Empty).ParseToPascalCase(), OriginalRelationField = item.relationField, @@ -953,6 +1026,8 @@ public class CodeGenService : IDynamicApiController, ITransient IsImportData = codeGenConfigModel.TableField.Any(it => it.IsImportField.Equals(true)), IsSystemControl = codeGenConfigModel.TableField.Any(it => it.IsSystemControl), IsUpdate = codeGenConfigModel.TableField.Any(it => it.IsUpdate), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsControlParsing = codeGenConfigModel.TableField.Any(it => it.IsControlParsing), }); auxiliaryTableColumnList.AddRange(codeGenConfigModel.TableField.FindAll(it => it.jnpfKey != null)); @@ -972,10 +1047,16 @@ public class CodeGenService : IDynamicApiController, ITransient if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) throw Oops.Oh(ErrorCode.D2109); + if (templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowid"))) + throw Oops.Oh(ErrorCode.D2105); + // 列表带流程 或者 流程表单 自增ID if (formDataModel.primaryKeyPolicy == 2 && templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowtaskid"))) throw Oops.Oh(ErrorCode.D2108); + if (formDataModel.logicalDelete && !fieldList.Any(it => it.field.ToLower().Equals("f_deletemark"))) + throw Oops.Oh(ErrorCode.D2110); + // 后端生成 codeGenConfigModel = CodeGenWay.PrimarySecondaryBackEnd(item.table, fieldList, auxiliaryTableColumnList, controls, templateEntity); @@ -983,21 +1064,10 @@ public class CodeGenService : IDynamicApiController, ITransient codeGenConfigModel.BusName = tableRelation.Find(it => it.relationTable.Equals("")).tableName; codeGenConfigModel.TableRelations = subTableRelationsList; codeGenConfigModel.IsChildConversion = subTableRelationsList.Any(it => it.IsConversion); - switch (codeGenConfigModel.IndexDataType) - { - case 4: - switch (templateEntity.Type) - { - case 3: - break; - default: - targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(item.className, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); - templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("5-PrimarySecondary", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); - break; - } - break; - default: + switch (templateEntity.WebType) + { + case 1: switch (templateEntity.Type) { case 3: @@ -1009,7 +1079,37 @@ public class CodeGenService : IDynamicApiController, ITransient templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("5-PrimarySecondary", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); break; } + break; + case 2: + switch (codeGenConfigModel.IndexDataType) + { + case 4: + switch (templateEntity.Type) + { + case 3: + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(item.className, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("5-PrimarySecondary", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } + break; + default: + switch (templateEntity.Type) + { + case 3: + targetPathList = CodeGenTargetPathHelper.BackendFlowTargetPathList(item.className, fileName, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendFlowTemplatePathList("5-PrimarySecondary", codeGenConfigModel.IsMapper); + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(item.className, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("5-PrimarySecondary", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } + + break; + } break; } @@ -1017,8 +1117,7 @@ public class CodeGenService : IDynamicApiController, ITransient for (int i = 0; i < templatePathList.Count; i++) { string tContent = File.ReadAllText(templatePathList[i]); - string tResult = _viewEngine.RunCompileFromCached(tContent, new - { + string tResult = _viewEngine.RunCompileFromCached(tContent, new { NameSpace = codeGenConfigModel.NameSpace, BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, @@ -1073,6 +1172,12 @@ public class CodeGenService : IDynamicApiController, ITransient ParsJnpfKeyConstList = codeGenConfigModel.ParsJnpfKeyConstList, ParsJnpfKeyConstListDetails = codeGenConfigModel.ParsJnpfKeyConstListDetails, ImportDataType = codeGenConfigModel.ImportDataType, + DataRuleJson = CodeGenControlsAttributeHelper.GetDataRuleList(templateEntity, codeGenConfigModel).ToJsonString().Replace("\"", "\\\"").Replace("\\\\\"", "\\\\\\\"").Replace("\\\\\\\\\"", "\\\\\\\\\\\\\""), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsTreeTable = codeGenConfigModel.IsTreeTable, + ParentField = codeGenConfigModel.ParentField, + TreeShowField = codeGenConfigModel.TreeShowField, + IsLogicalDelete = codeGenConfigModel.IsLogicalDelete, }); var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName; if (!Directory.Exists(dirPath)) @@ -1097,50 +1202,67 @@ public class CodeGenService : IDynamicApiController, ITransient // 开启乐观锁 if (formDataModel.concurrencyLock && !fieldList.Any(it => it.field.ToLower().Equals("f_version"))) - { throw Oops.Oh(ErrorCode.D2107); - } if (formDataModel.primaryKeyPolicy == 2 && !fieldList.Any(it => it.primaryKey && it.identity)) - { throw Oops.Oh(ErrorCode.D2109); - } + + if (templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowid"))) + throw Oops.Oh(ErrorCode.D2105); // 列表带流程 或者 流程表单 自增ID if (formDataModel.primaryKeyPolicy == 2 && templateEntity.EnableFlow == 1 && !fieldList.Any(it => it.field.ToLower().Equals("f_flowtaskid"))) - { throw Oops.Oh(ErrorCode.D2108); - } + + if (formDataModel.logicalDelete && !fieldList.Any(it => it.field.ToLower().Equals("f_deletemark"))) + throw Oops.Oh(ErrorCode.D2110); // 后端生成 codeGenConfigModel = CodeGenWay.SingleTableBackEnd(tableName, fieldList, controls, templateEntity); - switch (templateEntity.Type) + switch (templateEntity.WebType) { - case 3: - switch (codeGenConfigModel.IndexDataType) + case 1: + switch (templateEntity.Type) { - // 流程表单没有行内编辑 - case 4: - break; - default: + case 3: targetPathList = CodeGenTargetPathHelper.BackendFlowTargetPathList(codeGenConfigModel.ClassName, fileName, codeGenConfigModel.IsMapper); templatePathList = CodeGenTargetPathHelper.BackendFlowTemplatePathList("1-SingleTable", codeGenConfigModel.IsMapper); break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(codeGenConfigModel.ClassName, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("1-SingleTable", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; } - break; - case 4: - // 功能表单 - targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(codeGenConfigModel.ClassName, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + break; + case 2: switch (codeGenConfigModel.IndexDataType) { - // 流程表单没有行内编辑 case 4: - templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("1-SingleTable", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + switch (templateEntity.Type) + { + // 流程表单没有行内编辑 + case 3: + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(codeGenConfigModel.ClassName, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendInlineEditorTemplatePathList("1-SingleTable", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } break; default: - templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("1-SingleTable", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + switch (templateEntity.Type) + { + case 3: + targetPathList = CodeGenTargetPathHelper.BackendFlowTargetPathList(codeGenConfigModel.ClassName, fileName, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendFlowTemplatePathList("1-SingleTable", codeGenConfigModel.IsMapper); + break; + default: + targetPathList = CodeGenTargetPathHelper.BackendTargetPathList(codeGenConfigModel.ClassName, fileName, templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsInlineEditor, codeGenConfigModel.IsMapper); + templatePathList = CodeGenTargetPathHelper.BackendTemplatePathList("1-SingleTable", templateEntity.WebType, templateEntity.EnableFlow, codeGenConfigModel.IsMapper); + break; + } break; } break; @@ -1150,8 +1272,7 @@ public class CodeGenService : IDynamicApiController, ITransient for (var i = 0; i < templatePathList.Count; i++) { var tContent = File.ReadAllText(templatePathList[i]); - var tResult = _viewEngine.RunCompileFromCached(tContent, new - { + var tResult = _viewEngine.RunCompileFromCached(tContent, new { NameSpace = codeGenConfigModel.NameSpace, BusName = codeGenConfigModel.BusName, ClassName = codeGenConfigModel.ClassName, @@ -1201,6 +1322,12 @@ public class CodeGenService : IDynamicApiController, ITransient ParsJnpfKeyConstList = codeGenConfigModel.ParsJnpfKeyConstList, ParsJnpfKeyConstListDetails = codeGenConfigModel.ParsJnpfKeyConstListDetails, ImportDataType = codeGenConfigModel.ImportDataType, + DataRuleJson = CodeGenControlsAttributeHelper.GetDataRuleList(templateEntity, codeGenConfigModel).ToJsonString().Replace("\"", "\\\"").Replace("\\\\\"", "\\\\\\\"").Replace("\\\\\\\\\"", "\\\\\\\\\\\\\""), + IsSearchMultiple = codeGenConfigModel.IsSearchMultiple, + IsTreeTable = codeGenConfigModel.IsTreeTable, + ParentField = codeGenConfigModel.ParentField, + TreeShowField = codeGenConfigModel.TreeShowField, + IsLogicalDelete = codeGenConfigModel.IsLogicalDelete, }); var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName; if (!Directory.Exists(dirPath)) @@ -1366,7 +1493,7 @@ public class CodeGenService : IDynamicApiController, ITransient foreach (int logic in new List { 4, 5 }) { // 每次循环前重新定义表单数据 - formDataModel = templateEntity.FormData.ToObject(); + formDataModel = templateEntity.FormData.ToObjectOld(); frondEndGenConfig = CodeGenWay.SingleTableFrontEnd(logic, formDataModel, controls, tableColumns, templateEntity); @@ -1390,6 +1517,7 @@ public class CodeGenService : IDynamicApiController, ITransient { case 1: hasSuperQuery = false; + frondEndGenConfig.Type = 1; break; default: hasSuperQuery = columnDesignModel.hasSuperQuery; @@ -1430,8 +1558,7 @@ public class CodeGenService : IDynamicApiController, ITransient for (int i = 0; i < templatePathList.Count; i++) { string tContent = File.ReadAllText(templatePathList[i]); - var tResult = _viewEngine.RunCompileFromCached(tContent, new - { + var tResult = _viewEngine.RunCompileFromCached(tContent, new { NameSpace = frondEndGenConfig.NameSpace, ClassName = frondEndGenConfig.ClassName, FormRef = frondEndGenConfig.FormRef, @@ -1453,6 +1580,7 @@ public class CodeGenService : IDynamicApiController, ITransient TreePropsUrl = frondEndGenConfig.TreePropsUrl, TreePropsLabel = frondEndGenConfig.TreePropsLabel, TreePropsChildren = frondEndGenConfig.TreePropsChildren, + IsTreeRelationMultiple = frondEndGenConfig.IsTreeRelationMultiple, IsExistQuery = frondEndGenConfig.IsExistQuery, PrimaryKey = frondEndGenConfig.PrimaryKey, FormList = frondEndGenConfig.FormList, @@ -1463,6 +1591,8 @@ public class CodeGenService : IDynamicApiController, ITransient ColumnDesign = frondEndGenConfig.ColumnDesign, OptionsList = frondEndGenConfig.OptionsList, IsBatchRemoveDel = frondEndGenConfig.IsBatchRemoveDel, + IsBatchPrint = frondEndGenConfig.IsBatchPrint, + PrintIds = frondEndGenConfig.PrintIds, IsDownload = frondEndGenConfig.IsDownload, IsRemoveDel = frondEndGenConfig.IsRemoveDel, IsDetail = frondEndGenConfig.IsDetail, @@ -1478,7 +1608,7 @@ public class CodeGenService : IDynamicApiController, ITransient UseFormPermission = frondEndGenConfig.UseFormPermission, DefaultSidx = defaultSidx, WebType = templateEntity.Type == 3 ? templateEntity.Type : templateEntity.WebType, - HasPage = frondEndGenConfig.HasPage && !frondEndGenConfig.IndexDataType.Equals(3), + HasPage = frondEndGenConfig.HasPage, IsSummary = frondEndGenConfig.IsSummary, AddTitleName = frondEndGenConfig.TopButtonDesign?.Find(it => it.Value.Equals("add"))?.Label, EditTitleName = frondEndGenConfig.ColumnButtonDesign?.Find(it => it.Value.Equals("edit"))?.Label, @@ -1495,6 +1625,7 @@ public class CodeGenService : IDynamicApiController, ITransient Tables = templateEntity.Tables.ToJsonString(), DbLinkId = templateEntity.DbLinkId, MianTable = tableName, + PropertyJson = frondEndGenConfig.PropertyJson.ToJsonString(), CreatorTime = DateTime.Now.ParseToUnixTime(), CreatorUserId = _userManager.UserId, IsChildDataTransfer = frondEndGenConfig.IsChildDataTransfer, @@ -1509,12 +1640,21 @@ public class CodeGenService : IDynamicApiController, ITransient GroupShowField = frondEndGenConfig.GroupShowField, PrimaryKeyPolicy = frondEndGenConfig.PrimaryKeyPolicy, IsRelationForm = frondEndGenConfig.IsRelationForm, - ChildTableStyle = frondEndGenConfig.ChildTableStyle, + ChildTableStyle = controls.Any(it => it.__config__.jnpfKey.Equals(JnpfKeyConst.TABLE)) ? frondEndGenConfig.ChildTableStyle : 1, IsFixed = frondEndGenConfig.IsFixed, + IsChildrenRegular = frondEndGenConfig.IsChildrenRegular, + TreeSynType = frondEndGenConfig.TreeSynType, + HasTreeQuery = frondEndGenConfig.HasTreeQuery, + ColumnData = frondEndGenConfig.ColumnData.ToJsonString(), + SummaryField = frondEndGenConfig.SummaryField.ToJsonString(), + ShowSummary = frondEndGenConfig.ShowSummary, + DefaultFormControlList = frondEndGenConfig.DefaultFormControlList, + IsDefaultFormControl = frondEndGenConfig.IsDefaultFormControl, + FormRealControl = frondEndGenConfig.FormRealControl, }, builderAction: builder => { builder.AddUsing("JNPF.VisualDev.Engine.Model.CodeGen"); - builder.AddAssemblyReferenceByName("Tnb.VisualDev.Engine"); + builder.AddAssemblyReferenceByName("JNPF.VisualDev.Engine"); }); var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName; if (!Directory.Exists(dirPath)) diff --git a/visualdev/Tnb.VisualDev/RunService.cs b/visualdev/Tnb.VisualDev/RunService.cs index f794dc03..271c27fe 100644 --- a/visualdev/Tnb.VisualDev/RunService.cs +++ b/visualdev/Tnb.VisualDev/RunService.cs @@ -1,18 +1,20 @@ -using System.Text; +using System.Data; +using System.Text; using System.Text.RegularExpressions; using JNPF.Common.Const; using JNPF.Common.Core.Manager; +using JNPF.Common.Dtos; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; -using JNPF.Common.Manager; using JNPF.Common.Models.VisualDev; using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.FriendlyException; using JNPF.JsonSerialization; using JNPF.RemoteRequest.Extensions; +using JNPF.Systems.Entitys.Dto.Authorize; using JNPF.Systems.Entitys.Model.DataBase; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; @@ -25,6 +27,8 @@ using JNPF.VisualDev.Interfaces; using JNPF.WorkFlow.Entitys.Entity; using JNPF.WorkFlow.Interfaces.Repository; using Mapster; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; using SqlSugar; @@ -37,6 +41,13 @@ public class RunService : IRunService, ITransient { #region 构造 + private readonly IServiceScopeFactory _serviceScopeFactory; + + /// + /// 数据库配置选项. + /// + public ConnectionStringsOptions _connectionStrings; + /// /// 服务基础仓储. /// @@ -67,6 +78,11 @@ public class RunService : IRunService, ITransient /// private readonly IUserManager _userManager; + /// + /// 数据接口. + /// + private readonly IDataInterfaceService _dataInterfaceService; + /// /// 数据连接服务. /// @@ -77,6 +93,11 @@ public class RunService : IRunService, ITransient /// private readonly IFlowTaskRepository _flowTaskRepository; + /// + /// 多租户配置选项. + /// + private readonly TenantOptions _tenant; + /// /// 事务. /// @@ -86,22 +107,30 @@ public class RunService : IRunService, ITransient /// 构造. /// public RunService( + IOptions connectionOptions, + IServiceScopeFactory serviceScopeFactory, ISqlSugarRepository visualDevRepository, FormDataParsing formDataParsing, + IOptions tenantOptions, IUserManager userManager, IDbLinkService dbLinkService, IDataBaseManager databaseService, IFlowTaskRepository flowTaskRepository, + IDataInterfaceService dataInterfaceService, ISqlSugarClient context, IBillRullService billRuleService) { + _serviceScopeFactory = serviceScopeFactory; _visualDevRepository = visualDevRepository; + _dataInterfaceService = dataInterfaceService; _formDataParsing = formDataParsing; _userManager = userManager; + _tenant = tenantOptions.Value; _databaseService = databaseService; _dbLinkService = dbLinkService; _billRuleService = billRuleService; _flowTaskRepository = flowTaskRepository; + _connectionStrings = connectionOptions.Value; _db = context.AsTenant(); } #endregion @@ -119,6 +148,7 @@ public class RunService : IRunService, ITransient { PageResult>? realList = new PageResult>() { list = new List>() }; // 返回结果集 TemplateParsingBase templateInfo = new TemplateParsingBase(entity); // 解析模板控件 + if (entity.WebType.Equals(4)) return await GetDataViewResults(templateInfo, input); // 数据视图 // 处理查询 Dictionary queryJson = string.IsNullOrEmpty(input.queryJson) ? null : input.queryJson.ToObject>(); @@ -149,7 +179,9 @@ public class RunService : IRunService, ITransient LogicalDelete(templateInfo); // 处理软删除 primaryKey = GetPrimary(link, templateInfo.MainTableName); bool udp = _userManager.UserOrigin == "pc" ? templateInfo.ColumnData.useDataPermission : templateInfo.AppColumnData.useDataPermission; - var pvalue = await _userManager.GetCondition>(primaryKey, input.menuId, udp); + templateInfo.ColumnData = _userManager.UserOrigin == "pc" ? templateInfo.ColumnData : templateInfo.AppColumnData; + var pvalue = new List(); + if (_userManager.User != null || _userManager.UserId.IsNotEmptyOrNull()) pvalue = await _userManager.GetCondition>(primaryKey, input.menuId, udp); var pvalueJson = pvalue.ToJsonString(); foreach (var item in templateInfo.AllTableFields) { @@ -157,11 +189,15 @@ public class RunService : IRunService, ITransient pvalueJson.Replace(string.Format("\"FieldName\":\"{0}\",", item.Value), string.Format("\"FieldName\":\"{0}\",", item.Key)); } pvalue = _visualDevRepository.AsSugarClient().Utilities.JsonToConditionalModels(pvalueJson); + if (templateInfo.ColumnData.type.Equals(5)) pvalue.Clear(); // 树形表格 去掉数据权限. // 所有查询条件 + input.dataRuleJson = _userManager.UserOrigin == "pc" ? templateInfo.DataRuleListJson.ToJsonString() : templateInfo.AppDataRuleListJson.ToJsonString(); // 数据过滤 + var dataRuleWhere = new List(); var queryWhere = new List(); var superQueryWhere = new List(); - if (input.queryJson.IsNotEmptyOrNull()) queryWhere = GetQueryJson(input.queryJson, _userManager.UserOrigin == "pc" ? templateInfo.ColumnData : templateInfo.AppColumnData); + if (input.dataRuleJson.IsNotEmptyOrNull()) dataRuleWhere = _visualDevRepository.AsSugarClient().Utilities.JsonToConditionalModels(input.dataRuleJson); + if (input.queryJson.IsNotEmptyOrNull()) queryWhere = GetQueryJson(input.queryJson, templateInfo.ColumnData); if (input.superQueryJson.IsNotEmptyOrNull()) superQueryWhere = GetSuperQueryJson(input.superQueryJson); if (templateInfo.ColumnData.type == 4) await OptimisticLocking(link, templateInfo); // 开启行编辑 处理 开启并发锁定 @@ -172,17 +208,14 @@ public class RunService : IRunService, ITransient if (input.sidx.IsNotEmptyOrNull() && !templateInfo.ColumnData.columnList.Any(x => x.prop == input.sidx)) input.sidx = string.Empty; // 处理查询 - input.queryJson = GetQueryJson(input.queryJson, _userManager.UserOrigin == "pc" ? templateInfo.ColumnData : templateInfo.AppColumnData).ToJsonString(); + input.queryJson = GetQueryJson(input.queryJson, templateInfo.ColumnData).ToJsonString(); input.superQueryJson = GetSuperQueryJson(input.superQueryJson).ToJsonString(); - realList = _databaseService.GetInterFaceData(link, sql, input, templateInfo.ColumnData.Adapt(), new List(), tableFieldKeyValue); - - // 显示列有子表字段 - if ((templateInfo.ColumnData.type != 4 || _userManager.UserOrigin.Equals("app")) && templateInfo.ColumnData.columnList.Any(x => templateInfo.ChildTableFields.ContainsKey(x.__vModel__)) && realList.list.Any()) - realList = await GetListChildTable(templateInfo, primaryKey, queryWhere, superQueryWhere, realList, pvalue); + if (templateInfo.ColumnData.type != 4 && templateInfo.ColumnData.columnList.Any(x => templateInfo.ChildTableFields.ContainsKey(x.__vModel__)) && realList.list.Any()) + realList = await GetListChildTable(templateInfo, primaryKey, queryWhere, dataRuleWhere, superQueryWhere, realList, pvalue); // 处理 自增长ID 流程表单 自增长Id转成 流程Id if (entity.FlowId.IsNotEmptyOrNull() && entity.EnableFlow.Equals(1) && realList.list.Any()) @@ -208,10 +241,14 @@ public class RunService : IRunService, ITransient if (realList.list.Any()) { + // 树形表格 + if (templateInfo.ColumnData.type.Equals(5)) + realList.list.ForEach(item => item[templateInfo.ColumnData.parentField + "_pid"] = item[templateInfo.ColumnData.parentField]); + + // 数据解析 if (templateInfo.SingleFormData.Any(x => x.__config__.templateJson != null && x.__config__.templateJson.Any())) - realList.list = await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), realList.list, templateInfo.ColumnData, actionType, templateInfo.WebType, primaryKey); - else //modified by ly on 20230407 - realList.list = await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson == null || !x.__config__.templateJson.Any()).ToList(), realList.list, templateInfo.ColumnData, actionType, templateInfo.WebType, primaryKey); + realList.list = await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), realList.list, templateInfo.ColumnData, actionType, templateInfo.WebType, primaryKey, entity.isShortLink); + realList.list = await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson == null || !x.__config__.templateJson.Any()).ToList(), realList.list, templateInfo.ColumnData, actionType, templateInfo.WebType, primaryKey, entity.isShortLink); // 如果是无表数据并且排序字段不为空,再进行数据排序 if (!templateInfo.IsHasTable && input.sidx.IsNotEmptyOrNull()) @@ -254,6 +291,10 @@ public class RunService : IRunService, ITransient // 分组表格 if (templateInfo.ColumnData.type == 3 && _userManager.UserOrigin == "pc") realList.list = CodeGenHelper.GetGroupList(realList.list, templateInfo.ColumnData.groupField, templateInfo.ColumnData.columnList.Find(x => x.__vModel__.ToLower() != templateInfo.ColumnData.groupField.ToLower()).__vModel__); + + // 树形表格 + if (templateInfo.ColumnData.type.Equals(5)) + realList.list = CodeGenHelper.GetTreeList(realList.list, templateInfo.ColumnData.parentField + "_pid", templateInfo.ColumnData.columnList.Find(x => x.__vModel__.ToLower() != templateInfo.ColumnData.parentField.ToLower()).__vModel__); } else { @@ -271,7 +312,7 @@ public class RunService : IRunService, ITransient } // 增加前端回显字段 : key_name - if (templateInfo.ColumnData.type.Equals(4) && _userManager.UserOrigin.Equals("pc")) + if (!entity.isShortLink && templateInfo.ColumnData.type.Equals(4) && _userManager.UserOrigin.Equals("pc")) { var newList = new List>(); realList.list.ForEach(items => @@ -292,7 +333,11 @@ public class RunService : IRunService, ITransient } if (item.Key.Equals("flowState") || item.Key.Equals("flowState_name")) newItem.Add(item.Key, item.Value); if (item.Key.Equals("id") && !newItem.ContainsKey(item.Key)) newItem.Add(item.Key, item.Value); - if (templateInfo.AllFieldsModel.Any(x => x.__vModel__.Equals(item.Key) && x.__config__.jnpfKey.Equals(JnpfKeyConst.TIME))) newItem[item.Key] = items[item.Key]; + if (templateInfo.AllFieldsModel.Any(x => x.__vModel__.Equals(item.Key) && (x.__config__.jnpfKey.Equals(JnpfKeyConst.TIME) + || x.__config__.jnpfKey.Equals(JnpfKeyConst.CREATETIME) || x.__config__.jnpfKey.Equals(JnpfKeyConst.CREATEUSER) || x.__config__.jnpfKey.Equals(JnpfKeyConst.MODIFYTIME) + || x.__config__.jnpfKey.Equals(JnpfKeyConst.MODIFYUSER) || x.__config__.jnpfKey.Equals(JnpfKeyConst.CURRDEPT) || x.__config__.jnpfKey.Equals(JnpfKeyConst.CURRORGANIZE) + || x.__config__.jnpfKey.Equals(JnpfKeyConst.CURRPOSITION)))) + newItem[item.Key] = items[item.Key]; } newList.Add(newItem); @@ -314,6 +359,7 @@ public class RunService : IRunService, ITransient { PageResult>? realList = new PageResult>() { list = new List>() }; // 返回结果集 TemplateParsingBase? templateInfo = new TemplateParsingBase(entity); // 解析模板控件 + if (entity.WebType.Equals(4)) return await GetDataViewResults(templateInfo, input); // 数据视图 string? primaryKey = "F_Id"; // 列表主键 List? pvalue = new List(); // 关联表单调用 数据全部放开 @@ -346,7 +392,7 @@ public class RunService : IRunService, ITransient { if (templateInfo.SingleFormData.Any(x => x.__config__.templateJson != null && x.__config__.templateJson.Any())) realList.list = await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), realList.list, templateInfo.ColumnData, actionType, templateInfo.WebType, primaryKey); - realList.list = await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => !x.__config__.jnpfKey.Equals(JnpfKeyConst.RELATIONFORM) && x.__config__.templateJson == null).ToList(), realList.list, templateInfo.ColumnData, actionType, templateInfo.WebType.ParseToInt(), primaryKey); + realList.list = await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => !x.__config__.jnpfKey.Equals(JnpfKeyConst.RELATIONFORM) && (x.__config__.templateJson == null || !x.__config__.templateJson.Any())).ToList(), realList.list, templateInfo.ColumnData, actionType, templateInfo.WebType.ParseToInt(), primaryKey); if (input.queryJson.IsNotEmptyOrNull()) { @@ -400,16 +446,6 @@ public class RunService : IRunService, ITransient return realList; } - /// - /// 获取模型数据信息. - /// - /// - /// - public async Task GetInfo(string id) - { - return await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(m => m.Id == id); - } - /// /// 获取有表详情. /// @@ -425,8 +461,9 @@ public class RunService : IRunService, ITransient if (id.Equals("0") || id.IsNullOrWhiteSpace()) return new Dictionary(); id = GetPIdsByFlowIds(link, templateInfo, mainPrimary, new List() { id }).First().Value; Dictionary? tableFieldKeyValue = new Dictionary(); // 联表查询 表字段 别名 + tableFieldKeyValue[mainPrimary.ToUpper()] = mainPrimary; + if (templateInfo.WebType.Equals(3)) tableFieldKeyValue["F_FlowId".ToUpper()] = "F_FlowId"; var sql = GetInfoQuerySql(id, mainPrimary, templateInfo, ref tableFieldKeyValue); // 获取查询Sql - Dictionary? data = _databaseService.GetInterFaceData(link, sql).ToJsonString().ToObject>>().FirstOrDefault(); if (data == null) return null; @@ -460,7 +497,7 @@ public class RunService : IRunService, ITransient foreach (KeyValuePair value in item) { FieldsModel? child = model.__config__.children.Find(c => c.__vModel__ == value.Key); - if (child != null) dic.Add(value.Key, value.Value); + if (child != null || value.Key.Equals("id")) dic.Add(value.Key, value.Value); } newTables.Add(dic); @@ -478,7 +515,7 @@ public class RunService : IRunService, ITransient if (!newDataMap.ContainsKey("id")) newDataMap.Add("id", data[mainPrimary]); _formDataParsing.GetBARAndQR(templateInfo.FieldsModelList, newDataMap, dataMap); // 处理 条形码 、 二维码 控件 - + if (dataMap.ContainsKey("F_FlowId")) newDataMap["flowId"] = dataMap["F_FlowId"]; return await _formDataParsing.GetSystemComponentsData(templateInfo.FieldsModelList, newDataMap.ToJsonString()); } @@ -497,6 +534,8 @@ public class RunService : IRunService, ITransient string? mainPrimary = GetPrimary(link, templateInfo.MainTableName); id = GetPIdsByFlowIds(link, templateInfo, mainPrimary, new List() { id }).First().Value; Dictionary? tableFieldKeyValue = new Dictionary(); // 联表查询 表字段 别名 + tableFieldKeyValue[mainPrimary.ToUpper()] = mainPrimary; + if (templateInfo.WebType.Equals(3)) tableFieldKeyValue["F_FlowId".ToUpper()] = "F_FlowId"; var sql = GetInfoQuerySql(id, mainPrimary, templateInfo, ref tableFieldKeyValue); // 获取查询Sql Dictionary? data = _databaseService.GetInterFaceData(link, sql).ToJsonString().ToObject>>().ToObject>>().FirstOrDefault(); @@ -550,8 +589,8 @@ public class RunService : IRunService, ITransient { // 将关键字查询传输的id转换成名称 if (model.__config__.children.Any(x => x.__config__.templateJson != null && x.__config__.templateJson.Any())) - newDataMap[strKey[i]] = await _formDataParsing.GetKeyData(model.__config__.children.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), childModelData, templateInfo.ColumnData, "List", 2, "F_Id", dataMap); - newDataMap[strKey[i]] = await _formDataParsing.GetKeyData(model.__config__.children.Where(x => x.__config__.templateJson == null).ToList(), childModelData, templateInfo.ColumnData.ToObject()); + newDataMap[strKey[i]] = await _formDataParsing.GetKeyData(model.__config__.children.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), childModelData, templateInfo.ColumnData, "List", templateInfo.WebType, mainPrimary, templateEntity.isShortLink); + newDataMap[strKey[i]] = await _formDataParsing.GetKeyData(model.__config__.children.Where(x => x.__config__.templateJson == null || !x.__config__.templateJson.Any()).ToList(), childModelData, templateInfo.ColumnData.ToObject(), "List", templateInfo.WebType, mainPrimary, templateEntity.isShortLink); } } } @@ -561,8 +600,8 @@ public class RunService : IRunService, ITransient // 控件联动 var tempDataMap = new Dictionary(); if (templateInfo.SingleFormData.Any(x => x.__config__.templateJson != null && x.__config__.templateJson.Any())) - tempDataMap = (await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), listEntity, templateInfo.ColumnData)).FirstOrDefault(); - tempDataMap = (await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson == null).ToList(), listEntity, templateInfo.ColumnData)).FirstOrDefault(); + tempDataMap = (await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), listEntity, templateInfo.ColumnData, "List", templateInfo.WebType, mainPrimary, templateEntity.isShortLink)).FirstOrDefault(); + tempDataMap = (await _formDataParsing.GetKeyData(templateInfo.SingleFormData.Where(x => x.__config__.templateJson == null || !x.__config__.templateJson.Any()).ToList(), listEntity, templateInfo.ColumnData, "List", templateInfo.WebType, mainPrimary, templateEntity.isShortLink)).FirstOrDefault(); // 将关键字查询传输的id转换成名称 foreach (var entryMap in tempDataMap) @@ -648,7 +687,8 @@ public class RunService : IRunService, ITransient }); } - allDataMap = await GenerateFeilds(templateInfo.FieldsModelList.ToJsonString(), allDataMap, true); // 生成系统自动生成字段 + if (templateInfo.visualDevEntity != null && !templateInfo.visualDevEntity.isShortLink) + allDataMap = await GenerateFeilds(templateInfo.FieldsModelList.ToJsonString(), allDataMap, true); // 生成系统自动生成字段 DbLinkEntity link = templateInfo.DbLink; List? tableList = _databaseService.GetFieldList(link, templateInfo.MainTableName); // 获取主表 表结构 信息 @@ -668,12 +708,14 @@ public class RunService : IRunService, ITransient object? itemData = allDataMap[item.__vModel__]; if (item.__vModel__.IsNotEmptyOrNull() && itemData != null && !string.IsNullOrEmpty(itemData.ToString()) && itemData.ToString() != "[]") { - var value = _formDataParsing.InsertValueHandle(dbType, tableList, item.__vModel__, itemData, templateInfo.MainTableFieldsModelList); + var value = _formDataParsing.InsertValueHandle(dbType, tableList, item.__vModel__, itemData, templateInfo.MainTableFieldsModelList, "create", templateInfo.visualDevEntity != null ? templateInfo.visualDevEntity.isShortLink : false); tableField.Add(item.__vModel__, value); } } }); + if (_tenant.MultiTenancy && _databaseService.IsAnyColumn(templateInfo.DbLink, templateInfo.MainTableName, "f_tenantid")) tableField.Add("f_tenantid", _userManager.TenantId); // 多租户 + // 主键策略(雪花Id) if (templateInfo.FormModel.primaryKeyPolicy.Equals(1)) tableField.Add(mainPrimary?.field, mainId); @@ -688,11 +730,17 @@ public class RunService : IRunService, ITransient { if (!tableList.Any(x => SqlFunc.ToLower(x.field) == "f_flowtaskid")) { - List? pFieldList = new List() { new DbTableFieldModel() { field = "F_FlowTaskId", fieldName = "流程Id", dataType = "varchar", dataLength = "50", allowNull = 1 } }; + List? pFieldList = new List() { new DbTableFieldModel() { field = "F_FlowTaskId", fieldName = "流程任务Id", dataType = "varchar", dataLength = "50", allowNull = 1 } }; + _databaseService.AddTableColumn(link, templateInfo.MainTableName, pFieldList); + } + if (!tableList.Any(x => SqlFunc.ToLower(x.field) == "f_flowid")) + { + var pFieldList = new List() { new DbTableFieldModel() { field = "F_FlowId", fieldName = "流程引擎Id", dataType = "varchar", dataLength = "50", allowNull = 1 } }; _databaseService.AddTableColumn(link, templateInfo.MainTableName, pFieldList); } dictionarySql[templateInfo.MainTableName].First().Add("F_FlowTaskId", mainId); + dictionarySql[templateInfo.MainTableName].First().Add("F_FlowId", allDataMap["flowId"]); } // 自增长主键 需要返回的自增id @@ -735,7 +783,7 @@ public class RunService : IRunService, ITransient object? itemData = allDataMap.Where(x => x.Key == item).Count() > 0 ? allDataMap[item] : null; if (item.IsNotEmptyOrNull() && itemData != null && !string.IsNullOrEmpty(itemData.ToString()) && itemData.ToString() != "[]") { - var value = _formDataParsing.InsertValueHandle(dbType, tableList, item, allDataMap[item], templateInfo.FieldsModelList); + var value = _formDataParsing.InsertValueHandle(dbType, tableList, item, allDataMap[item], templateInfo.FieldsModelList, "create", templateInfo.visualDevEntity != null ? templateInfo.visualDevEntity.isShortLink : false); tableField.Add(item.ReplaceRegex(@"(\w+)_jnpf_", string.Empty), value); } }); @@ -762,31 +810,32 @@ public class RunService : IRunService, ITransient DbTableFieldModel? childPrimary = tableList.Find(t => t.primaryKey); foreach (Dictionary? data in model) { - if (data.Count > 0) + tableField = new Dictionary(); + + // 主键策略(雪花Id) + if (templateInfo.FormModel.primaryKeyPolicy.Equals(1)) tableField.Add(childPrimary.field, SnowflakeIdHelper.NextId()); + + // 外键 + tableField.Add(childTable.tableField, mainId); + + // 字段 + foreach (KeyValuePair child in data) { - tableField = new Dictionary(); - - // 主键策略(雪花Id) - if (templateInfo.FormModel.primaryKeyPolicy.Equals(1)) tableField.Add(childPrimary.field, SnowflakeIdHelper.NextId()); - - // 外键 - tableField.Add(childTable.tableField, mainId); - - // 字段 - foreach (KeyValuePair child in data) + if (child.Key.Equals("id") && child.Value.IsNotEmptyOrNull()) { - if (child.Key.IsNotEmptyOrNull() && child.Value != null && child.Value.ToString() != "[]" && child.Value.ToString() != string.Empty) - { - var value = _formDataParsing.InsertValueHandle(dbType, tableList, child.Key, child.Value, fieldsModel?.__config__.children); - tableField.Add(child.Key, value); - } + tableField[childPrimary.field] = child.Value; + } + else if (child.Key.IsNotEmptyOrNull() && child.Value.IsNotEmptyOrNull() && child.Value.ToString() != "[]") + { + var value = _formDataParsing.InsertValueHandle(dbType, tableList, child.Key, child.Value, fieldsModel?.__config__.children, "create", templateInfo.visualDevEntity != null ? templateInfo.visualDevEntity.isShortLink : false); + tableField.Add(child.Key, value); } - - if (dictionarySql.ContainsKey(fieldsModel.__config__.tableName)) - dictionarySql[fieldsModel.__config__.tableName].Add(tableField); - else - dictionarySql.Add(fieldsModel.__config__.tableName, new List>() { tableField }); } + + if (dictionarySql.ContainsKey(fieldsModel.__config__.tableName)) + dictionarySql[fieldsModel.__config__.tableName].Add(tableField); + else + dictionarySql.Add(fieldsModel.__config__.tableName, new List>() { tableField }); } } } @@ -814,8 +863,8 @@ public class RunService : IRunService, ITransient Dictionary newDataMap = new Dictionary(); foreach (var item in oldDataMap) { - var key = item.Key.Replace("_name", string.Empty); - if (!newDataMap.ContainsKey(key)) newDataMap.Add(key, oldDataMap[key]); + var key = item.Key.Substring(0, item.Key.LastIndexOf("_name") != -1 ? item.Key.LastIndexOf("_name") : item.Key.Length); + if (!newDataMap.ContainsKey(key) && oldDataMap.ContainsKey(key)) newDataMap.Add(key, oldDataMap[key]); } // modified by PhilPan 2023-04-12 提交和返回值不序列化 if (newDataMap.Any()) visualdevModelDataUpForm.data = newDataMap; @@ -857,7 +906,7 @@ public class RunService : IRunService, ITransient if (!templateInfo.VerifyTemplate()) throw Oops.Oh(ErrorCode.D1401); // 验证模板 // 处理系统控件(模板开启行编辑) - if (_userManager.UserOrigin?.Equals("pc") == true && templateInfo.ColumnData.type.Equals(4)) + if (templateInfo.ColumnData.type.Equals(4) && _userManager.UserOrigin.Equals("pc")) { // 处理显示列和提交的表单数据匹配(行编辑空数据 前端会过滤该控件) templateInfo.ColumnData.columnList.Where(x => !allDataMap.ContainsKey(x.prop) && x.__config__.visibility.Equals("pc")).ToList() @@ -930,27 +979,25 @@ public class RunService : IRunService, ITransient // 删除子表数据 if (templateInfo.AllTable.Any(x => x.typeId.Equals("0"))) { - templateInfo.AllTable.Where(x => x.typeId.Equals("0") && templateInfo.ChildTableFieldsModelList.Select(x => x.__config__.tableName).Contains(x.table)) - .ToList().ForEach(item => mainSql.Add(string.Format("delete from {0} where {1}='{2}';", item.table, item.tableField, id))); // 删除所有涉及子表数据 sql - // 拼接子表 sql foreach (string? item in allDataMap.Where(d => d.Key.ToLower().Contains("tablefield")).Select(d => d.Key).ToList()) { if (!templateInfo.AllFieldsModel.Any(x => x.__vModel__.Equals(item)) || !templateInfo.AllFieldsModel.Find(x => x.__vModel__.Equals(item)).__config__.jnpfKey.Equals(JnpfKeyConst.TABLE)) continue; // 查找到该控件数据 - object? objectData = allDataMap[item]; - List>? model = objectData.ToObject>>(); + List>? model = allDataMap[item].ToObject>>(); if (model != null && model.Count > 0) { // 利用key去找模板 FieldsModel? fieldsModel = templateInfo.FieldsModelList.Find(f => f.__vModel__ == item); ConfigModel? fieldsConfig = fieldsModel?.__config__; - StringBuilder childColumn = new StringBuilder(); + List? childColumn = new List(); List? childValues = new List(); + List? updateFieldSql = new List(); Engine.Model.TableModel? childTable = templateInfo.AllTable.Find(t => t.table == fieldsModel.__config__.tableName && t.table != templateInfo.MainTableName); if (childTable != null) { + if (!model.Any(x => x.ContainsKey("id"))) mainSql.Add(string.Format("delete from {0} where {1}='{2}';", childTable?.table, childTable.tableField, id)); tableList = new List(); tableList = _databaseService.GetFieldList(link, childTable?.table); DbTableFieldModel? childPrimary = tableList.Find(t => t.primaryKey); @@ -960,42 +1007,53 @@ public class RunService : IRunService, ITransient { foreach (KeyValuePair child in data) { - if (child.Key.IsNotEmptyOrNull() && child.Value != null && child.Value.ToString() != "[]" && child.Value.ToString() != string.Empty) + if (child.Key.IsNotEmptyOrNull() && child.Key != "id" && child.Value != null && child.Value.ToString() != "[]" && child.Value.ToString() != string.Empty) { - childColumn.AppendFormat("{0},", child.Key); // Column部分 - childValues.Add(_formDataParsing.InsertValueHandle(dbType, tableList, child.Key, child.Value, fieldsConfig.children, "update")); // Values部分 + childColumn.Add(child.Key); // Column部分 + var value = _formDataParsing.InsertValueHandle(dbType, tableList, child.Key, child.Value, fieldsConfig.children, "update"); + childValues.Add(value); // Values部分 + updateFieldSql.Add(string.Format("{0}={1}", child.Key, value)); } } if (!string.IsNullOrEmpty(childColumn.ToString())) { - // 主键策略(雪花Id) - if (templateInfo.FormModel.primaryKeyPolicy.Equals(1)) + if (data.ContainsKey("id")) { - mainSql.Add(string.Format( - "insert into {0}({6},{4},{1}) values('{3}','{5}',{2});", - fieldsModel.__config__.tableName, - childColumn.ToString().Trim(','), - string.Join(",", childValues), - SnowflakeIdHelper.NextId(), - childTable.tableField, - id, - childPrimary.field)); + if (updateFieldSql.Any()) + mainSql.Add(string.Format("update {0} set {1} where {2}='{3}';", fieldsModel.__config__.tableName, string.Join(',', updateFieldSql), childPrimary.field, data["id"])); } else { - mainSql.Add(string.Format( - "insert into {0}({1},{2}) values('{3}',{4});", - fieldsModel.__config__.tableName, - childTable.tableField, - childColumn.ToString().Trim(','), - id, - string.Join(",", childValues))); + // 主键策略(雪花Id) + if (templateInfo.FormModel.primaryKeyPolicy.Equals(1)) + { + mainSql.Add(string.Format( + "insert into {0}({6},{4}{1}) values('{3}','{5}'{2});", + fieldsModel.__config__.tableName, + childColumn.Any() ? "," + string.Join(",", childColumn) : string.Empty, + childColumn.Any() ? "," + string.Join(",", childValues) : string.Empty, + SnowflakeIdHelper.NextId(), + childTable.tableField, + id, + childPrimary.field)); + } + else + { + mainSql.Add(string.Format( + "insert into {0}({1}{2}) values('{3}'{4});", + fieldsModel.__config__.tableName, + childTable.tableField, + childColumn.Any() ? "," + string.Join(",", childColumn) : string.Empty, + id, + childColumn.Any() ? "," + string.Join(",", childValues) : string.Empty)); + } } } - childColumn = new StringBuilder(); - childValues = new List(); + childColumn.Clear(); + childValues.Clear(); + updateFieldSql.Clear(); } } } @@ -1020,9 +1078,10 @@ public class RunService : IRunService, ITransient /// 表单模板. /// 表单数据json. /// 主键Id. + /// flowId. /// 是否修改. /// - public async Task SaveFlowFormData(FlowFormEntity fEntity, string formData, string dataId, bool isUpdate = false) + public async Task SaveFlowFormData(FlowFormEntity fEntity, string formData, string dataId, string flowId, bool isUpdate = false) { if (fEntity != null) { @@ -1032,6 +1091,9 @@ public class RunService : IRunService, ITransient var vEntity = new VisualDevEntity() { FormData = fEntity.PropertyJson, Tables = fEntity.TableJson, WebType = 2, FullName = fEntity.FullName, FlowId = fEntity.FlowId, EnableFlow = 1 }; var tInfo = new TemplateParsingBase(vEntity, true); tInfo.DbLink = await GetDbLink(fEntity.DbLinkId); + var dic = formData.ToObject>(); + dic["flowId"] = flowId; + formData = dic.ToJsonString(); if (isUpdate) { // modified by PhilPan 2023-04-12 提交和返回值不序列化 @@ -1052,19 +1114,22 @@ public class RunService : IRunService, ITransient { // 新增,修改 var dic = formData.ToObject>(); + dic["flowId"] = flowId; var dicHerader = new Dictionary(); dicHerader.Add("JNPF_API", true); if (_userManager.ToKen != null && !_userManager.ToKen.Contains("::")) dicHerader.Add("Authorization", _userManager.ToKen); // 本地url地址 - var localAddress = App.Configuration["Kestrel:Endpoints:Http:Url"]; + // var localAddress = App.Configuration["Kestrel:Endpoints:Http:Url"]; + var localAddress = GetLocalAddress(); // 请求地址拼接 + if (fEntity.InterfaceUrl.First().Equals('/')) fEntity.InterfaceUrl = fEntity.InterfaceUrl.Substring(1, fEntity.InterfaceUrl.Length - 1); var path = string.Format("{0}/{1}/{2}", localAddress, fEntity.InterfaceUrl, dataId); try { - await path.SetJsonSerialization().SetContentType("application/json").SetHeaders(dicHerader).SetBody(dic).PostAsStringAsync(); + var result = await path.SetJsonSerialization().SetContentType("application/json").SetHeaders(dicHerader).SetBody(dic).PostAsStringAsync(); } catch (Exception ex) { @@ -1094,9 +1159,11 @@ public class RunService : IRunService, ITransient dicHerader.Add("Authorization", _userManager.ToKen); // 本地url地址 - var localAddress = App.Configuration["Kestrel:Endpoints:Http:Url"]; + // var localAddress = App.Configuration["Kestrel:Endpoints:Http:Url"]; + var localAddress = GetLocalAddress(); // 请求地址拼接 + if (fEntity.InterfaceUrl.First().Equals('/')) fEntity.InterfaceUrl = fEntity.InterfaceUrl.Substring(1, fEntity.InterfaceUrl.Length - 1); var path = string.Format("{0}/{1}/{2}", localAddress, fEntity.InterfaceUrl, dataId); try { @@ -1131,7 +1198,7 @@ public class RunService : IRunService, ITransient var oldTInfo = new TemplateParsingBase(oldFEntity.PropertyJson, oldFEntity.TableJson, (int)oldFEntity.FormType); // 旧模板 var newTInfo = new TemplateParsingBase(newFEntity.PropertyJson, newFEntity.TableJson, (int)newFEntity.FormType); // 新模板 - if (oldFEntity.FormType.Equals(1) || newFEntity.FormType.Equals(1)) + if(oldFEntity.FormType.Equals(1) || newFEntity.FormType.Equals(1)) { oldTInfo.AllFieldsModel.ForEach(it => { @@ -1159,7 +1226,6 @@ public class RunService : IRunService, ITransient if (!mapRule.Any(x => x.Any(xx => xx.Value.Equals(item.Value)) || x.Any(xx => xx.Key.Equals(item.Key)))) mapRule.Add(new Dictionary() { { item.Key, item.Value } }); } - var res = new Dictionary(); var childTableSplitKey = "tablefield"; // 三个特殊的系统表单 (请假申请、销售订单、订单示例) @@ -1266,6 +1332,7 @@ public class RunService : IRunService, ITransient } } + var res = new Dictionary(); foreach (var dicItems in mapRule) { var dicItem = dicItems.First(); @@ -1295,9 +1362,11 @@ public class RunService : IRunService, ITransient dicHerader.Add("Authorization", _userManager.ToKen); // 本地url地址 - var localAddress = App.Configuration["Kestrel:Endpoints:Http:Url"]; + // var localAddress = App.Configuration["Kestrel:Endpoints:Http:Url"]; + var localAddress = GetLocalAddress(); // 请求地址拼接 + if (newFEntity.InterfaceUrl.First().Equals('/')) newFEntity.InterfaceUrl = newFEntity.InterfaceUrl.Substring(1, newFEntity.InterfaceUrl.Length - 1); var path = string.Format("{0}/{1}/{2}", localAddress, newFEntity.InterfaceUrl, formData["id"].ToString()); try { @@ -1350,16 +1419,43 @@ public class RunService : IRunService, ITransient else isUpdate = false; // 新增 } + if (mapRule.Any(x => x.ContainsKey("@prevNodeFormId"))) res[mapRule.Find(x => x.ContainsKey("@prevNodeFormId")).First().Value] = formData["id"]; + // 保存到数据库 res["id"] = formData["id"]; + + if (newTInfo.ChildTableFieldsModelList.Any()) + { + var tInfoList = new List(); + newTInfo.ChildTableFieldsModelList.ForEach(x => + { + var newValueMapRule = mapRule.Select(xx => xx.FirstOrDefault().Value).ToList(); + if (!res.ContainsKey(x.__vModel__) && (!newValueMapRule.Contains(x.__vModel__))) tInfoList.Add(x.__vModel__); + }); + if (tInfoList.Any()) + { + var vEntity = new VisualDevEntity() { FormData = newFEntity.PropertyJson, Tables = newFEntity.TableJson, FlowId = newFEntity.FlowId, EnableFlow = 1, WebType = 3, FullName = newFEntity.FullName, DbLinkId = newFEntity.DbLinkId }; + var nDataInfo = await GetHaveTableInfo(res["id"].ToString(), vEntity); + if (nDataInfo != null) tInfoList.ForEach(ctDataItem => { if (nDataInfo.ContainsKey(ctDataItem)) res[ctDataItem] = nDataInfo[ctDataItem]; }); + } + } + if (!isSubFlow) { - await SaveFlowFormData(newFEntity, res.ToJsonString(), formData["id"].ToString(), isUpdate); + await SaveFlowFormData(newFEntity, res.ToJsonString(), formData["id"].ToString(), formData["flowId"].ToString(), isUpdate); } return res; } + private string GetLocalAddress() + { + using var scope = _serviceScopeFactory.CreateScope(); + var server = scope.ServiceProvider.GetRequiredService(); + var addressesFeature = server.Features.Get(); + var addresses = addressesFeature?.Addresses; + return addresses.FirstOrDefault().Replace("[::]", "localhost"); + } #endregion #region 公用方法 @@ -1388,41 +1484,55 @@ public class RunService : IRunService, ITransient DbLinkEntity link = await GetDbLink(templateEntity.DbLinkId); templateInfo.DbLink = link; string? mainPrimary = GetPrimary(link, templateInfo.MainTableName); - var resId = GetPIdsByFlowIds(link, templateInfo, mainPrimary, new List() { id }); - id = resId.First().Value; - if (templateInfo.FormModel.logicalDelete) + + // 树形表格 删除父节点时同时删除子节点数据 + if (templateInfo.ColumnData.type.Equals(5)) { - LogicalDelete(templateInfo); // 处理软删除. - await _databaseService.ExecuteSql(link, string.Format("update {0} set f_deletemark=1 where {1}='{2}'", templateInfo.MainTableName, mainPrimary, id)); // 删除标识 - if (templateEntity.EnableFlow == 1) - { - FlowTaskEntity? entity = _flowTaskRepository.GetTaskFirstOrDefault(resId.First().Key); - if (entity != null) - { - if (!entity.ParentId.Equals("0")) throw Oops.Oh(ErrorCode.WF0003, entity.FullName); - await _flowTaskRepository.DeleteTask(entity); - } - } + var delIdDic = new Dictionary(); + var dataList = _databaseService.GetData(link, templateInfo.MainTableName).ToObject>>(); + dataList.ForEach(item => delIdDic.Add(item[mainPrimary], item[templateInfo.ColumnData.parentField])); + var delIds = new List(); + CodeGenHelper.GetChildIdList(delIdDic, id, delIds); + await BatchDelHaveTableData(delIds.Distinct().ToList(), templateEntity); } else { - List? allDelSql = new List(); // 拼接语句 - allDelSql.Add(string.Format("delete from {0} where {1} = '{2}';", templateInfo.MainTable.table, mainPrimary, id)); - if (templateInfo.AllTable.Any(x => x.typeId.Equals("0"))) + var resId = GetPIdsByFlowIds(link, templateInfo, mainPrimary, new List() { id }); + id = resId.First().Value; + if (templateInfo.FormModel.logicalDelete) { - templateInfo.AllTable.Where(x => x.typeId.Equals("0")).ToList() - .ForEach(item => allDelSql.Add(string.Format("delete from {0} where {1}='{2}';", item.table, item.tableField, id))); // 删除所有涉及表数据 sql - } - - foreach (string? item in allDelSql) await _databaseService.ExecuteSql(link, item); // 删除有表数据 - - if (templateEntity.EnableFlow == 1) - { - FlowTaskEntity? entity = _flowTaskRepository.GetTaskFirstOrDefault(resId.First().Key); - if (entity != null) + LogicalDelete(templateInfo); // 处理软删除. + await _databaseService.ExecuteSql(link, string.Format("update {0} set f_deletemark=1 where {1}='{2}'", templateInfo.MainTableName, mainPrimary, id)); // 删除标识 + if (templateEntity.EnableFlow == 1) { - if (!entity.ParentId.Equals("0")) throw Oops.Oh(ErrorCode.WF0003, entity.FullName); - await _flowTaskRepository.DeleteTask(entity); + FlowTaskEntity? entity = _flowTaskRepository.GetTaskFirstOrDefault(resId.First().Key); + if (entity != null) + { + if (!entity.ParentId.Equals("0")) throw Oops.Oh(ErrorCode.WF0003, entity.FullName); + await _flowTaskRepository.DeleteTask(entity); + } + } + } + else + { + List? allDelSql = new List(); // 拼接语句 + allDelSql.Add(string.Format("delete from {0} where {1} = '{2}';", templateInfo.MainTable.table, mainPrimary, id)); + if (templateInfo.AllTable.Any(x => x.typeId.Equals("0"))) + { + templateInfo.AllTable.Where(x => x.typeId.Equals("0")).ToList() + .ForEach(item => allDelSql.Add(string.Format("delete from {0} where {1}='{2}';", item.table, item.tableField, id))); // 删除所有涉及表数据 sql + } + + foreach (string? item in allDelSql) await _databaseService.ExecuteSql(link, item); // 删除有表数据 + + if (templateEntity.EnableFlow == 1) + { + FlowTaskEntity? entity = _flowTaskRepository.GetTaskFirstOrDefault(resId.First().Key); + if (entity != null) + { + if (!entity.ParentId.Equals("0")) throw Oops.Oh(ErrorCode.WF0003, entity.FullName); + await _flowTaskRepository.DeleteTask(entity); + } } } } @@ -1569,7 +1679,6 @@ public class RunService : IRunService, ITransient { List childFieldsModelList = model.__config__.children; object? objectData = allDataMap[strKey[i]]; - List> childAllDataMapList = objectData.ToJsonString().ToObject>>(); if (childAllDataMapList != null && childAllDataMapList.Count > 0) { @@ -1579,6 +1688,7 @@ public class RunService : IRunService, ITransient Dictionary? newChildData = new Dictionary(); foreach (KeyValuePair item in childmap) { + if(item.Key.Equals("id")) newChildData[item.Key] = childmap[item.Key]; FieldsModel? childFieldsModel = childFieldsModelList.Where(c => c.__vModel__ == item.Key).FirstOrDefault(); if (childFieldsModel != null && childFieldsModel.__vModel__.Equals(item.Key)) { @@ -1738,10 +1848,144 @@ public class RunService : IRunService, ITransient public async Task GetDbLink(string linkId) { DbLinkEntity link = await _dbLinkService.GetInfo(linkId); + if (link == null && _userManager.TenantDbName.IsNullOrWhiteSpace()) + { + return new DbLinkEntity + { + Id = _connectionStrings.ConfigId, + ServiceName = _connectionStrings.DBName, + DbType = _connectionStrings.DBType, + Host = _connectionStrings.Host, + Port = _connectionStrings.Port, + UserName = _connectionStrings.UserName, + Password = _connectionStrings.Password + }; + } + if (link == null) link = _databaseService.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); // 当前数据库连接 return link; } + /// + /// 无限递归 给控件绑定默认值 (绕过 布局控件). + /// + public void FieldBindDefaultValue(ref List> dicFieldsModelList, string defaultUserId, string defaultDepId, List userRelationList) + { + foreach (var item in dicFieldsModelList) + { + var obj = item["__config__"].ToObject>(); + + if (obj.ContainsKey("jnpfKey") && (obj["jnpfKey"].Equals(JnpfKeyConst.USERSELECT) || obj["jnpfKey"].Equals(JnpfKeyConst.DEPSELECT)) && obj["defaultCurrent"].Equals(true)) + { + switch (obj["jnpfKey"]) + { + case JnpfKeyConst.USERSELECT: + if (item.ContainsKey("selectType") && item["selectType"].Equals("custom")) + { + var ableDepIds = item["ableDepIds"].ToObject>(); + if (ableDepIds == null) ableDepIds = new List(); + var ablePosIds = item["ablePosIds"].ToObject>(); + if (ablePosIds == null) ablePosIds = new List(); + var ableUserIds = item["ableUserIds"].ToObject>(); + if (ableUserIds == null) ableUserIds = new List(); + var ableRoleIds = item["ableRoleIds"].ToObject>(); + if (ableRoleIds == null) ableRoleIds = new List(); + var ableGroupIds = item["ableGroupIds"].ToObject>(); + if (ableGroupIds == null) ableGroupIds = new List(); + var userIdList = userRelationList.Where(x => ableUserIds.Contains(x.UserId) || ableDepIds.Contains(x.ObjectId) + || ablePosIds.Contains(x.ObjectId) || ableRoleIds.Contains(x.ObjectId) || ableGroupIds.Contains(x.ObjectId)).Select(x => x.UserId).ToList(); + if (!userIdList.Contains(defaultUserId)) + { + obj["defaultValue"] = null; + break; + } + } + if (item.ContainsKey("multiple") && item["multiple"].Equals(true)) obj["defaultValue"] = new List() { defaultUserId }; + else obj["defaultValue"] = defaultUserId; + break; + case JnpfKeyConst.DEPSELECT: + if (item.ContainsKey("selectType") && item["selectType"].Equals("custom")) + { + var defValue = item["ableDepIds"].ToObject>(); + if (!defValue.Contains(defaultDepId)) + { + obj["defaultValue"] = null; + break; + } + } + if (item.ContainsKey("multiple") && item["multiple"].Equals(true)) obj["defaultValue"] = new List() { defaultDepId }; + else obj["defaultValue"] = defaultDepId; + break; + } + } + + // 子表控件 + if (obj.ContainsKey("jnpfKey") && obj["jnpfKey"].Equals(JnpfKeyConst.TABLE)) + { + var cList = obj["children"].ToObject>>(); + foreach (var child in cList) + { + var cObj = child["__config__"].ToObject>(); + if (cObj.ContainsKey("jnpfKey") && (cObj["jnpfKey"].Equals(JnpfKeyConst.USERSELECT) || cObj["jnpfKey"].Equals(JnpfKeyConst.DEPSELECT)) && cObj["defaultCurrent"].Equals(true)) + { + switch (cObj["jnpfKey"]) + { + case JnpfKeyConst.USERSELECT: + if (item.ContainsKey("multiple") && item["multiple"].Equals(true)) cObj["defaultValue"] = new List() { defaultUserId }; + else obj["defaultValue"] = defaultUserId; + break; + case JnpfKeyConst.DEPSELECT: + if (item.ContainsKey("multiple") && item["multiple"].Equals(true)) cObj["defaultValue"] = new List() { defaultDepId }; + else obj["defaultValue"] = defaultDepId; + break; + } + } + + child["__config__"] = cObj; + } + + obj["children"] = cList; + } + + // 递归布局控件 + if (obj.ContainsKey("children")) + { + var fmList = obj["children"].ToObject>>(); + FieldBindDefaultValue(ref fmList, defaultUserId, defaultDepId, userRelationList); + obj["children"] = fmList; + } + + item["__config__"] = obj; + } + } + + /// + /// 处理模板默认值 (针对流程表单). + /// 用户选择 , 部门选择. + /// + /// 表单json. + /// 关联表单. + /// 表单类型(1:系统表单 2:自定义表单). + /// + public string GetVisualDevModelDataConfig(string propertyJson, string tableJson, int formType) + { + var tInfo = new TemplateParsingBase(propertyJson, tableJson, formType); + if (tInfo.AllFieldsModel.Any(x => (x.__config__.defaultCurrent) && (x.__config__.jnpfKey.Equals(JnpfKeyConst.USERSELECT) || x.__config__.jnpfKey.Equals(JnpfKeyConst.DEPSELECT)))) + { + var userId = _userManager.UserId; + var depId = _visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(_userManager.UserId)).Select(x => x.OrganizeId).First(); + var allUserRelationList = _visualDevRepository.AsSugarClient().Queryable().Select(x => new UserRelationEntity() { UserId = x.UserId, ObjectId = x.ObjectId }).ToList(); + + var configData = propertyJson.ToObject>(); + var columnList = configData["fields"].ToObject>>(); + FieldBindDefaultValue(ref columnList, userId, depId, allUserRelationList); + configData["fields"] = columnList; + propertyJson = configData.ToJsonString(); + } + + return propertyJson; + } + #endregion #region 私有方法 @@ -1754,6 +1998,7 @@ public class RunService : IRunService, ITransient /// private string GetPrimary(DbLinkEntity link, string MainTableName) { + // modified by PhilPan var keys = _databaseService.GetPrimaries(link, MainTableName); if (keys.Count < 1) throw Oops.Oh(ErrorCode.D1402); // 主表未设置主键 return keys.First(); @@ -2095,9 +2340,8 @@ public class RunService : IRunService, ITransient string.Join(",", fieldList), auxiliaryFieldList.Any() ? templateInfo.MainTableName + "," + string.Join(",", auxiliaryFieldList) : templateInfo.MainTableName, string.Join(" and ", relationKey)); // 多表, 联合查询 - if (isUpdate) querStr = string.Format("{0} and {1}<>'{2}'", querStr, templateInfo.MainTableName + "." + mainPrimary, mainId); - + if (templateInfo.FormModel.logicalDelete && _databaseService.IsAnyColumn(templateInfo.DbLink, templateInfo.MainTableName, "f_deletemark")) querStr = string.Format(" {0} and {1} ", querStr, "f_deletemark is null"); var res = _databaseService.GetInterFaceData(link, querStr, null).ToObject>>(); if (res.Any()) @@ -2159,6 +2403,9 @@ public class RunService : IRunService, ITransient var superQueryJson = input.superQueryJson; foreach (var item in templateInfo.AllTableFields) { + if (input.dataRuleJson.IsNotEmptyOrNull() && input.dataRuleJson.Contains(string.Format("\"{0}\"", item.Key))) + input.dataRuleJson = input.dataRuleJson.Replace(string.Format("\"{0}\"", item.Key), string.Format("\"{0}\"", item.Value)); + if (queryJson.Contains(string.Format("\"{0}\"", item.Key))) { queryJson = queryJson.Replace(string.Format("\"{0}\"", item.Key), string.Format("\"{0}\"", item.Value)); @@ -2181,13 +2428,15 @@ public class RunService : IRunService, ITransient superQueryJson = superQueryJson.Replace(string.Format("\"{0}\"", item.Key), string.Format("\"{0}\"", item.Value)); } + var dataRuleQuerDic = new List(); + if (input.dataRuleJson.IsNotEmptyOrNull()) dataRuleQuerDic = _visualDevRepository.AsSugarClient().Utilities.JsonToConditionalModels(input.dataRuleJson); var querDic = queryJson.IsNullOrEmpty() ? null : queryJson.ToObject>(); var superQuerDic = new List(); var superCond = superQueryJson.IsNullOrEmpty() ? null : GetSuperQueryJson(superQueryJson); if (superCond != null) superQuerDic = superCond.ToObject>(); var tableWhere = new Dictionary>(); - + var queryOrSqlList = new List(); templateInfo.AllTable.Select(x => x.table).Distinct().ToList().ForEach(tName => { var query = new Dictionary(); @@ -2213,10 +2462,26 @@ public class RunService : IRunService, ITransient conList.ConditionalList.AddRange(newItems.ConditionalList); } + // 子表字段为空 查询 处理. + if (templateInfo.ChildTableFields.Any(x => x.Value.Contains(tName + "."))&&(dicList.ToJsonString().Contains("\"ConditionalType\":11") || dicList.ToJsonString().Contains("\"ConditionalType\":14"))) + queryOrSqlList.Add(string.Format(" OR ( [{0}] NOT IN ( SELECT {1} FROM {2} ) ) ", primaryKey, templateInfo.AllTable.Where(x => x.table.Equals(tName)).First().tableField, tName)); + if (!tableWhere.ContainsKey(tName)) tableWhere.Add(tName, new List() { conList }); else tableWhere[tName].AddRange(new List() { conList }); } + if (dataRuleQuerDic != null && dataRuleQuerDic.Any() && dataRuleQuerDic.ToJsonString().Contains(tName)) + { + var dicList = GetIConditionalModelListByTableName(dataRuleQuerDic.Copy(), tName); + + // 子表字段为空 查询 处理. + if (templateInfo.ChildTableFields.Any(x => x.Value.Contains(tName + ".")) && (dicList.ToJsonString().Contains("\"ConditionalType\":11") || dicList.ToJsonString().Contains("\"ConditionalType\":14"))) + queryOrSqlList.Add(string.Format(" OR ( [{0}] NOT IN ( SELECT {1} FROM {2} ) ) ", primaryKey, templateInfo.AllTable.Where(x => x.table.Equals(tName)).First().tableField, tName)); + + if (!tableWhere.ContainsKey(tName)) tableWhere.Add(tName, dicList); + else tableWhere[tName].AddRange(dicList); + } + if (!tableWhere.ContainsKey(tName)) tableWhere.Add(tName, new List()); }); @@ -2224,6 +2489,9 @@ public class RunService : IRunService, ITransient var sqlStr = "select {0} from {1} "; if (templateInfo.FormModel.logicalDelete && _databaseService.IsAnyColumn(templateInfo.DbLink, templateInfo.MainTableName, "f_deletemark")) querySqlList.Add(string.Format(" {0} in ({1}) ", primaryKey, string.Format(" select {0} from {1} where f_deletemark is null ", primaryKey, templateInfo.MainTableName))); // 处理软删除 + if (_tenant.MultiTenancy && _databaseService.IsAnyColumn(templateInfo.DbLink, templateInfo.MainTableName, "f_tenantid")) + querySqlList.Add(string.Format(" {0} in ({1}) ", primaryKey, string.Format(" select {0} from {1} where f_tenantid='{2}'", primaryKey, templateInfo.MainTableName, _userManager.TenantId))); // 多租户 + var childNotInQuery = new Dictionary(); // 子表字段为空条件 foreach (var item in tableWhere) { // 拼接数据权限 @@ -2243,7 +2511,7 @@ public class RunService : IRunService, ITransient var idField = templateInfo.AllTable.Where(x => x.table.Equals(item.Key)).First().tableField; var itemSql = string.Format(sqlStr, idField.IsNullOrEmpty() ? primaryKey : idField, item.Key); - dataPermissionsList = GetIConditionalModelListByTableName(dataPermissionsList, item.Key);// 删除非当前表条件 + dataPermissionsList = GetIConditionalModelListByTableName(dataPermissionsList, item.Key); // 删除非当前表条件 var itemWhere = _visualDevRepository.AsSugarClient().SqlQueryable("@").Where(item.Value).Where(dataPermissionsList).ToSqlString(); if (itemWhere.Contains("WHERE")) { @@ -2258,15 +2526,17 @@ public class RunService : IRunService, ITransient var ctFields = templateInfo.ChildTableFields; templateInfo.ChildTableFields = new Dictionary(); var strSql = GetListQuerySql(primaryKey, templateInfo, ref input, ref tableFieldKeyValue, new List()); + input.dataRuleJson = string.Empty; input.queryJson = string.Empty; input.superQueryJson = string.Empty; templateInfo.ChildTableFields = ctFields; - sql = string.Format("select * from ({0}) mt where {1}", strSql, string.Join(" and ", querySqlList)); + sql = string.Format("select * from ({0}) mt where {1} {2}", strSql, string.Join(" and ", querySqlList), string.Join(string.Empty, queryOrSqlList)); } else if (!templateInfo.AuxiliaryTableFieldsModelList.Any()) { fields.Add(primaryKey); // 主键 + if (templateInfo.WebType.Equals(3)) fields.Add("F_FlowId"); // 只查询 要显示的列 if (showColumnList && (templateInfo.SingleFormData.Count > 0 || templateInfo.ColumnData.columnList.Count > 0)) @@ -2277,6 +2547,8 @@ public class RunService : IRunService, ITransient sql = string.Format("select {0} from {1}", string.Join(",", fields), templateInfo.MainTableName); if (templateInfo.FormModel.logicalDelete && _databaseService.IsAnyColumn(templateInfo.DbLink, templateInfo.MainTableName, "f_deletemark")) sql += " where f_deletemark is null "; // 处理软删除 + if (_tenant.MultiTenancy && _tenant.MultiTenancyType.Equals("COLUMN")) + sql += string.Format(" {0} f_tenantid='{1}' ", sql.Contains("where") ? "and" : "where", _userManager.TenantId); // 多租户 // 拼接数据权限 if (dataPermissions != null && dataPermissions.Any()) @@ -2302,7 +2574,9 @@ public class RunService : IRunService, ITransient // 所有主、副表 字段名 fields.Add(templateInfo.MainTableName + "." + primaryKey); + if (templateInfo.WebType.Equals(3)) fields.Add(templateInfo.MainTableName + ".F_FlowId"); tableFieldKeyValue.Add(primaryKey.ToUpper(), primaryKey); + tableFieldKeyValue.Add("F_FlowId".ToUpper(), "F_FlowId"); Dictionary? inputJson = input.queryJson?.ToObject>(); for (int i = 0; i < templateInfo.SingleFormData.Count; i++) { @@ -2322,6 +2596,8 @@ public class RunService : IRunService, ITransient input.queryJson = input.queryJson.Replace("\"" + templateInfo.SingleFormData[i].__vModel__ + "\":", "\"FIELD_" + i + "\":"); if (input.superQueryJson.IsNotEmptyOrNull()) input.superQueryJson = input.superQueryJson.Replace(string.Format("\"field\":\"{0}\"", templateInfo.SingleFormData[i].__vModel__), string.Format("\"field\":\"{0}\"", "FIELD_" + i)); + if (input.dataRuleJson.IsNotEmptyOrNull()) + input.dataRuleJson = input.dataRuleJson.Replace(string.Format("\"FieldName\":\"{0}\"", templateInfo.SingleFormData[i].__vModel__), string.Format("\"FieldName\":\"{0}\"", "FIELD_" + i)); templateInfo.ColumnData.searchList.Where(x => x.__vModel__ == templateInfo.SingleFormData[i].__vModel__).ToList().ForEach(item => { @@ -2350,6 +2626,8 @@ public class RunService : IRunService, ITransient }); if (templateInfo.FormModel.logicalDelete && _databaseService.IsAnyColumn(templateInfo.DbLink, templateInfo.MainTableName, "f_deletemark")) relationKey.Add(templateInfo.MainTableName + ".f_deletemark is null "); // 处理软删除 + if (_tenant.MultiTenancy && _databaseService.IsAnyColumn(templateInfo.DbLink, templateInfo.MainTableName, "f_tenantid")) + relationKey.Add(string.Format(" {0}.f_tenantid='{1}' ", templateInfo.MainTableName, _userManager.TenantId)); // 多租户 string? whereStr = string.Join(" and ", relationKey); #endregion @@ -2395,12 +2673,26 @@ public class RunService : IRunService, ITransient for (int j = 0; j < newItem.ConditionalList.Count; j++) { var value = GetIConditionalModelListByTableName(new List() { newItem.ConditionalList[j].Value }, tableName); - if (value != null && value.Any()) newItem.ConditionalList[j] = new KeyValuePair(newItem.ConditionalList[j].Key, value.First()); - else newItem.ConditionalList.RemoveAt(j); + if (value != null && value.Any()) + { + newItem.ConditionalList[j] = new KeyValuePair(newItem.ConditionalList[j].Key, value.First()); + } + else + { + newItem.ConditionalList.RemoveAt(j); + j--; + } } - if (newItem.ConditionalList.Any()) cList[i] = newItem; - else cList.RemoveAt(i); + if (newItem.ConditionalList.Any()) + { + cList[i] = newItem; + } + else + { + cList.RemoveAt(i); + i--; + } } else if (cList[i] is ConditionalModel) { @@ -2429,6 +2721,7 @@ public class RunService : IRunService, ITransient if (!templateInfo.AuxiliaryTableFieldsModelList.Any()) { fields.Add(mainPrimary); // 主表主键 + if (templateInfo.WebType.Equals(3)) fields.Add("F_FlowId"); templateInfo.MainTableFieldsModelList.Where(x => x.__vModel__.IsNotEmptyOrNull()).ToList().ForEach(item => fields.Add(item.__vModel__)); // 主表列名 sql = string.Format("select {0} from {1} where {2}='{3}'", string.Join(",", fields), templateInfo.MainTableName, mainPrimary, id); } @@ -2436,7 +2729,7 @@ public class RunService : IRunService, ITransient { #region 所有主表、副表 字段名 fields.Add(templateInfo.MainTableName + "." + mainPrimary); // 主表主键 - tableFieldKeyValue.Add(mainPrimary.ToUpper(), mainPrimary); + if (templateInfo.WebType.Equals(3)) fields.Add(templateInfo.MainTableName + ".F_FlowId"); for (int i = 0; i < templateInfo.SingleFormData.Count; i++) { string? vmodel = templateInfo.SingleFormData[i].__vModel__.ReplaceRegex(@"(\w+)_jnpf_", ""); // Field @@ -2481,8 +2774,8 @@ public class RunService : IRunService, ITransient { foreach (KeyValuePair item in keywordJsonDic) { - var model = columnDesign.searchList?.Find(it => it.__vModel__.Equals(item.Key)); - switch (model?.jnpfKey) + var model = columnDesign.searchList.Find(it => it.__vModel__.Equals(item.Key)); + switch (model.jnpfKey) { case JnpfKeyConst.DATE: { @@ -2551,15 +2844,13 @@ public class RunService : IRunService, ITransient { FieldName = item.Key, ConditionalType = ConditionalType.GreaterThanOrEqual, - FieldValue = startTime, - FieldValueConvertFunc = it => Convert.ToDateTime(it) + FieldValue = startTime }), new KeyValuePair(WhereType.And, new ConditionalModel { FieldName = item.Key, ConditionalType = ConditionalType.LessThanOrEqual, - FieldValue = endTime, - FieldValueConvertFunc = it => Convert.ToDateTime(it) + FieldValue = endTime }) } }); @@ -2650,23 +2941,23 @@ public class RunService : IRunService, ITransient case JnpfKeyConst.USERSELECT: case JnpfKeyConst.DEPSELECT: { - var itemValue = item.Value.ToString().Contains("[") ? item.Value.ToJsonString() : item.Value.ToString(); - // 多选时为模糊查询 - if (model.multiple) + if (model.multiple || model.searchMultiple) { - conModels.Add(new ConditionalCollections() + var value = item.Value.ToString().Contains("[") ? item.Value.ToObject>():new List() { item.Value.ToString() }; + var addItems = new List>(); + for (int i = 0; i < value.Count; i++) { - ConditionalList = new List>() + var add = new KeyValuePair(i == 0 ? WhereType.And : WhereType.Or, new ConditionalModel { - new KeyValuePair(WhereType.And, new ConditionalModel - { - FieldName = item.Key, - ConditionalType = ConditionalType.Like, - FieldValue = item.Value.ToString() - }) - } - }); + FieldName = item.Key, + ConditionalType = model.multiple ? ConditionalType.Like : ConditionalType.Equal, + FieldValue = model.multiple ? value[i].ToJsonString() : value[i].ToString() + }); + addItems.Add(add); + } + + conModels.Add(new ConditionalCollections() { ConditionalList = addItems }); } else { @@ -2690,10 +2981,12 @@ public class RunService : IRunService, ITransient { if (item.Value != null) { - if (model.multiple) + if (model.multiple || model.searchMultiple) { - var rIdList = _visualDevRepository.AsSugarClient().Queryable().Where(x => x.UserId.Equals(item.Value.ToString().Replace("--user", string.Empty))).Select(x => new { x.ObjectId, x.ObjectType }).ToList(); - var objIdList = new List() { item.Value.ToString() }; + var objIdList = new List(); + if (item.Value.ToString().Contains("[")) objIdList = item.Value.ToObject>(); + else objIdList.Add(item.Value.ToString()); + var rIdList = _visualDevRepository.AsSugarClient().Queryable().Where(x => objIdList.Select(xx=>xx.Replace("--user", string.Empty)).Contains(x.UserId)).Select(x => new { x.ObjectId, x.ObjectType }).ToList(); rIdList.ForEach(x => { if (x.ObjectType.Equals("Organize")) @@ -2827,7 +3120,7 @@ public class RunService : IRunService, ITransient break; case JnpfKeyConst.CASCADER: { - var itemValue = item.Value.ToString().Contains("[") ? item.Value?.ToString().ToObject>().LastOrDefault() : item.Value.ToString(); + var itemValue = item.Value.ToString().Contains("[") ? item.Value?.ToString().ToObject>().ToJsonString() : item.Value.ToString(); conModels.Add(new ConditionalCollections() { ConditionalList = new List>() @@ -2846,28 +3139,29 @@ public class RunService : IRunService, ITransient case JnpfKeyConst.COMSELECT: { // 多选时为模糊查询 - if (model.multiple) + if (model.multiple || model.searchMultiple) { - var value = item.Value?.ToString().ToObject>(); + var value = item.Value?.ToString().ToObject>(); if (value.Any()) { - conModels.Add(new ConditionalCollections() + var addItems = new List>(); + for (int i = 0; i < value.Count; i++) { - ConditionalList = new List>() - { - new KeyValuePair(WhereType.And, new ConditionalModel - { - FieldName = item.Key, - ConditionalType = ConditionalType.Like, - FieldValue = item.Value.ToJsonString().Replace("[", string.Empty) - }) - } - }); + var add = new KeyValuePair(i == 0 ? WhereType.And : WhereType.Or, new ConditionalModel + { + FieldName = item.Key, + ConditionalType = ConditionalType.Like, + FieldValue = value[i].ToJsonString().Contains("[") ? value[i].ToJsonString().Replace("[", string.Empty) : item.Value?.ToString().Replace("[", string.Empty).Replace("\r\n", string.Empty).Replace(" ", string.Empty), + }); + addItems.Add(add); + } + conModels.Add(new ConditionalCollections() { ConditionalList = addItems }); } } else { var itemValue = item.Value.ToString().Contains("[") ? item.Value.ToJsonString() : item.Value.ToString(); + if (itemValue.Contains("[[")) itemValue = itemValue.ToObject>>().FirstOrDefault().ToJsonString(); conModels.Add(new ConditionalCollections() { ConditionalList = new List>() @@ -2887,55 +3181,27 @@ public class RunService : IRunService, ITransient case JnpfKeyConst.SELECT: { var itemValue = item.Value.ToString().Contains("[") ? item.Value.ToJsonString() : item.Value.ToString(); - //modified by ly on 20230407 - JArray jarr = null; - if (itemValue!.Contains("[")) - { - jarr = JArray.Parse(itemValue); - } // 多选时为模糊查询 - if (model.multiple) + if (model.multiple || model.searchMultiple) { - if (jarr?.Children() != null && jarr?.Children().ToList().Count > 1) + var value = item.Value.ToString().Contains("[") ? item.Value.ToObject>() : new List() { item.Value.ToString() }; + var addItems = new List>(); + for (int i = 0; i < value.Count; i++) { - var values = string.Join(",", jarr.ToList().Select(t => t.Value())); - conModels.Add(new ConditionalModel { FieldName = item.Key, ConditionalType = ConditionalType.In, FieldValue = values }); - - } - else - { - conModels.Add(new ConditionalCollections() + var add = new KeyValuePair(i == 0 ? WhereType.And : WhereType.Or, new ConditionalModel { - ConditionalList = new List>() - { - new KeyValuePair(WhereType.And, new ConditionalModel - { - FieldName = item.Key, - ConditionalType = ConditionalType.Like, - FieldValue = itemValue - }) - } + FieldName = item.Key, + ConditionalType = model.multiple ? ConditionalType.Like: ConditionalType.Equal, + FieldValue = model.multiple ? value[i].ToJsonString() : value[i].ToString() }); + addItems.Add(add); } - } - //modified by ly on 20230407 - else if (jarr?.Children() != null && jarr?.Children().ToList().Count > 1) - { - var values = string.Join(",", jarr.ToList().Select(t => t.Value())); - conModels.Add(new ConditionalModel { FieldName = item.Key, ConditionalType = ConditionalType.In, FieldValue = values }); - + conModels.Add(new ConditionalCollections() { ConditionalList = addItems }); } else { - //modified by ly on 20230407 - if (itemValue.IsMatch(@"\[(.+)\]")) - { - itemValue = Regex.Match(itemValue, @"\[(.+)\]").Groups[1].Value; - itemValue = itemValue.Trim('"'); - } - conModels.Add(new ConditionalCollections() { ConditionalList = new List>() @@ -3021,7 +3287,6 @@ public class RunService : IRunService, ITransient break; default: { - if (item.Value.IsNullOrEmpty()) continue; var itemValue = item.Value.ToString().Contains("[") ? item.Value.ToJsonString() : item.Value.ToString(); JArray jarr = null; if (itemValue!.Contains("[")) @@ -3140,15 +3405,16 @@ public class RunService : IRunService, ITransient /// /// /// + /// /// /// /// - /// /// private async Task>> GetListChildTable( TemplateParsingBase templateInfo, string primaryKey, List querList, + List dataRuleList, List superQuerList, PageResult> result, List dataPermissions) @@ -3175,30 +3441,44 @@ public class RunService : IRunService, ITransient templateInfo.ChildTableFieldsModelList.ForEach(item => { var tableField = templateInfo.AllTable.Find(tf => tf.table == item.__config__.tableName)?.tableField; - if (!relationField.ContainsKey(item.__config__.tableName)) relationField.Add(item.__config__.tableName, tableField); + if (!relationField.ContainsKey(item.__config__.tableName)) relationField.Add(item.__config__.tableName, tableField.ToLower()); }); + var dataRuleJson = dataRuleList.ToJsonString(); + foreach (var item in templateInfo.AllTableFields) + { + if (dataRuleJson.IsNotEmptyOrNull() && dataRuleJson.Contains(string.Format("\"{0}\"", item.Key))) + dataRuleJson = dataRuleJson.Replace(string.Format("\"{0}\"", item.Key), string.Format("\"{0}\"", item.Value)); + } + // 捞取 所有子表查询条件 var childTableQuery = new Dictionary>(); + var dataRule = _visualDevRepository.AsSugarClient().Utilities.JsonToConditionalModels(dataRuleJson); var query = querList.ToObject>(); var superQuery = superQuerList.ToObject>(); foreach (var item in templateInfo.ChildTableFields) { + var tableName = item.Value.Split(".").FirstOrDefault(); + var dataRuleConList = GetIConditionalModelListByTableName(dataRuleList, tableName); + if (dataRuleConList.Any()) + { + //foreach (var it in dataRuleConList) it.ConditionalList.ForEach(x => x.Value.FieldName = item.Value); + if (!childTableQuery.ContainsKey(tableName)) childTableQuery.Add(tableName, new List()); + childTableQuery[tableName].AddRange(dataRuleConList); + } var conList = query.Where(x => x.ConditionalList.Any(xx => xx.Value.FieldName.Equals(item.Key))).ToList(); if (conList.Any()) { - var tableName = item.Value.Split(".").FirstOrDefault(); foreach (var it in conList) it.ConditionalList.ForEach(x => x.Value.FieldName = item.Value); if (!childTableQuery.ContainsKey(tableName)) childTableQuery.Add(tableName, new List()); childTableQuery[tableName].AddRange(conList); } - var superConList = superQuery.Where(x => x.ConditionalList.Any(xx => xx.Value.FieldName.Equals(item.Key))).ToList(); - if (superConList.Any()) + conList = superQuery.Where(x => x.ConditionalList.Any(xx => xx.Value.FieldName.Equals(item.Key))).ToList(); + if (conList.Any()) { - var tableName = item.Value.Split(".").FirstOrDefault(); - foreach (var it in superConList) it.ConditionalList.ForEach(x => x.Value.FieldName = item.Value); + foreach (var it in conList) it.ConditionalList.ForEach(x => x.Value.FieldName = item.Value); if (!childTableQuery.ContainsKey(tableName)) childTableQuery.Add(tableName, new List()); - childTableQuery[tableName].AddRange(superConList); + childTableQuery[tableName].AddRange(conList); } } @@ -3230,7 +3510,27 @@ public class RunService : IRunService, ITransient dataPermissionsList = _visualDevRepository.AsSugarClient().Utilities.JsonToConditionalModels(json); } } - sql = _visualDevRepository.AsSugarClient().SqlQueryable(sql).Where(dataPermissionsList).ToSqlString(); + + // 数据过滤 + var dataRuleConditionalList = new List(); + if (dataRule != null && dataRule.Any()) + { + var pList = new List(); + var allPersissions = dataRule.ToObject>(); + allPersissions.ForEach(it => + { + if (it.ToJsonString().Contains(item.Key + ".")) pList.Add(it); + }); + if (pList.Any()) + { + dataRuleConditionalList = _visualDevRepository.AsSugarClient().Utilities.JsonToConditionalModels(pList.ToJsonString()); + dataRuleConditionalList = GetIConditionalModelListByTableName(dataRuleConditionalList, item.Key); + var json = dataRuleConditionalList.ToJsonString().Replace(item.Key + ".", string.Empty); + dataRuleConditionalList= _visualDevRepository.AsSugarClient().Utilities.JsonToConditionalModels(json); + } + } + + sql = _visualDevRepository.AsSugarClient().SqlQueryable(sql).Where(dataPermissionsList).Where(dataRuleConditionalList).ToSqlString(); var dt = _databaseService.GetInterFaceData(templateInfo.DbLink, sql).ToObject>>(); var vModel = templateInfo.AllFieldsModel.Find(x => x.__config__.tableName == item.Key)?.__vModel__; @@ -3244,8 +3544,8 @@ public class RunService : IRunService, ITransient var datas = new List>(); if (childTableModel.__config__.children.Any(x => x.__config__.templateJson != null && x.__config__.templateJson.Any())) - datas = (await _formDataParsing.GetKeyData(childTableModel.__config__.children.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), rows, templateInfo.ColumnData, "List", 2, "F_Id", it)); - datas = await _formDataParsing.GetKeyData(childTableModel.__config__.children.Where(x => x.__config__.templateJson == null).ToList(), rows, templateInfo.ColumnData); + datas = (await _formDataParsing.GetKeyData(childTableModel.__config__.children.Where(x => x.__config__.templateJson != null && x.__config__.templateJson.Any()).ToList(), rows, templateInfo.ColumnData, "List", templateInfo.WebType, primaryKey, templateInfo.visualDevEntity.isShortLink)); + datas = await _formDataParsing.GetKeyData(childTableModel.__config__.children.Where(x => x.__config__.templateJson == null || !x.__config__.templateJson.Any()).ToList(), rows, templateInfo.ColumnData, "List", templateInfo.WebType, primaryKey, templateInfo.visualDevEntity.isShortLink); var newDatas = datas.Copy(); newDatas.ForEach(x => x.Remove(relationField[item.Key])); it.Add(vModel, newDatas); @@ -3271,9 +3571,11 @@ public class RunService : IRunService, ITransient { if (!string.IsNullOrEmpty(model.__vModel__)) { - if ("table".Equals(model.__config__.jnpfKey)) + if (model.__config__.jnpfKey.Equals(JnpfKeyConst.TABLE)) { List feilds = new List(); + var ctPrimaryKey = templateInfo.AllTable.Find(x => x.table.Equals(model.__config__.tableName)).fields.Find(x => x.PrimaryKey.Equals(1)).Field; + feilds.Add(ctPrimaryKey + " id "); // 子表主键 foreach (FieldsModel? childModel in model.__config__.children) if (!string.IsNullOrEmpty(childModel.__vModel__)) feilds.Add(childModel.__vModel__); // 拼接查询字段 string relationMainFeildValue = string.Empty; string childSql = string.Format("select {0} from {1} where 1=1 ", string.Join(",", feilds), model.__config__.tableName); // 查询子表数据 @@ -3292,7 +3594,7 @@ public class RunService : IRunService, ITransient } #region 获取关联表单属性 和 弹窗选择属性 - foreach (var item in model.__config__.children.Where(x => x.__config__.jnpfKey == "relationForm").ToList()) + foreach (var item in model.__config__.children.Where(x => x.__config__.jnpfKey == JnpfKeyConst.RELATIONFORM).ToList()) { foreach (var dataItem in childTableData) { @@ -3301,7 +3603,7 @@ public class RunService : IRunService, ITransient var relationValueId = dataItem[item.__vModel__].ToString(); // 获取关联表单id var relationInfo = await _visualDevRepository.AsQueryable().FirstAsync(x => x.Id == item.modelId); // 获取 关联表单 转换后的数据 var relationValueStr = string.Empty; - // modified by pf 2023-04-12 返回值不序列化 + // modified by PhilPan 2023-04-12 返回值不序列化 var relationValue = await GetHaveTableInfoDetails(relationValueId, relationInfo); if (relationValue != null) { @@ -3317,9 +3619,9 @@ public class RunService : IRunService, ITransient } } - if (model.__config__.children.Where(x => x.__config__.jnpfKey == "popupAttr").Any()) + if (model.__config__.children.Where(x => x.__config__.jnpfKey == JnpfKeyConst.POPUPATTR).Any()) { - foreach (var item in model.__config__.children.Where(x => x.__config__.jnpfKey == "popupSelect").ToList()) + foreach (var item in model.__config__.children.Where(x => x.__config__.jnpfKey == JnpfKeyConst.POPUPSELECT).ToList()) { var pDataList = await _formDataParsing.GetPopupSelectDataList(item.interfaceId, model); // 获取接口数据列表 foreach (var dataItem in childTableData) @@ -3526,5 +3828,99 @@ public class RunService : IRunService, ITransient } } } + + /// + /// 处理数据视图. + /// + /// + /// + /// + private async Task>> GetDataViewResults(TemplateParsingBase templateInfo, VisualDevModelListQueryInput input) + { + var searchList = _userManager.UserOrigin.Equals("pc") ? templateInfo.ColumnData.searchList.Copy() : templateInfo.AppColumnData.searchList.Copy(); + PageResult>? realList = new PageResult>() { list = new List>() }; // 返回结果集 + var par = input.Adapt(); + par.paramList = templateInfo.visualDevEntity.InterfaceParam.ToObject>(); + if (par.queryJson.IsNotEmptyOrNull()) + { + var querList = par.queryJson.ToObject>(); + var newList = new Dictionary(); + foreach (var item in querList) + { + var key = item.Key; + var vModel = searchList.Find(x => x.__vModel__.Equals(item.Key)); + if (vModel != null && vModel.searchType.Equals(1)) { key = "jnpf_searchType_equals_" + item.Key; } + newList.Add(key, item.Value.Replace("'", "''")); + } + + par.queryJson = newList.ToJsonString(); + } + + var dataInterface = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(x => x.Id == templateInfo.visualDevEntity.InterfaceId && x.DeleteMark == null); + if (templateInfo.ColumnData.hasPage && dataInterface.DataType.Equals(2)) par.pageSize = 999999; + var res = await _dataInterfaceService.GetResponseByType(templateInfo.visualDevEntity.InterfaceId, 2, string.Empty, par); + if (templateInfo.ColumnData.hasPage && !dataInterface.DataType.Equals(2)) + { + if (!res.ToJsonString().Equals("[]") && res.ToJsonString() != string.Empty) + realList = res.ToObject>>(); + } + else + { + var resList = res.ToObject>>(); + if (par.queryJson.IsNotEmptyOrNull()) + { + var querList = par.queryJson.ToObject>(); + foreach (var item in querList) + { + Console.WriteLine(item.Value); + Console.WriteLine(item.Key.Replace("jnpf_searchType_equals_", "")); + if (item.Key.Contains("jnpf_searchType_equals_")) resList = resList.Where(x => x[item.Key.Replace("jnpf_searchType_equals_","")].ToString().Equals(item.Value)).ToList(); + else resList = resList.Where(x => x[item.Key].ToString().Contains(item.Value)).ToList(); + } + } + if (input.sidx.IsNotEmptyOrNull()) + { + if (input.sort.Equals("desc")) resList = resList.OrderBy(x => x[input.sidx]).ToList(); + else resList = resList.OrderByDescending(x => x[input.sidx]).ToList(); + } + var dt = GetPageToDataTable(resList, input.currentPage, input.pageSize); + realList.pagination = new PageResult() + { + currentPage = input.currentPage, + pageSize = input.pageSize, + total = resList.Count + }; + realList.list = dt.ToObject>>(); + } + + for (int i = 0; i < realList.list.Count; i++) if (!realList.list[i].ContainsKey("id")) realList.list[i].Add("id", i); + + // 分组表格 + if (templateInfo.ColumnData.type == 3 && _userManager.UserOrigin == "pc") + realList.list = CodeGenHelper.GetGroupList(realList.list, templateInfo.ColumnData.groupField, templateInfo.ColumnData.columnList.Find(x => x.__vModel__.ToLower() != templateInfo.ColumnData.groupField.ToLower()).__vModel__); + + return realList; + } + + /// + /// 静态数据分页. + /// + /// 数据源. + /// 第几页. + /// 每页多少条. + /// + private List> GetPageToDataTable(List> dt, int PageIndex, int PageSize) + { + if (PageIndex == 0) return dt; // 0页代表每页数据,直接返回 + if (dt == null) return new List>(); + var newdt = new List>(); + int rowbegin = (PageIndex - 1) * PageSize; + int rowend = PageIndex * PageSize; // 要展示的数据条数 + if (rowbegin >= dt.Count) return dt; // 源数据记录数小于等于要显示的记录,直接返回dt + if (rowend > dt.Count) rowend = dt.Count; + for (int i = rowbegin; i <= rowend - 1; i++) newdt.Add(dt[i]); + return newdt; + } + #endregion } \ No newline at end of file diff --git a/visualdev/Tnb.VisualDev/VisualDevModelDataService.cs b/visualdev/Tnb.VisualDev/VisualDevModelDataService.cs index 64407b37..8013ff80 100644 --- a/visualdev/Tnb.VisualDev/VisualDevModelDataService.cs +++ b/visualdev/Tnb.VisualDev/VisualDevModelDataService.cs @@ -1,5 +1,4 @@ -using System.Data; -using JNPF.Common.Configuration; +using JNPF.Common.Configuration; using JNPF.Common.Const; using JNPF.Common.Core.Manager; using JNPF.Common.Core.Manager.Files; @@ -16,6 +15,7 @@ using JNPF.DataEncryption; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; +using JNPF.Logging.Attributes; using JNPF.RemoteRequest.Extensions; using JNPF.Systems.Entitys.Model.DataInterFace; using JNPF.Systems.Entitys.Permission; @@ -23,19 +23,18 @@ using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.System; using JNPF.VisualDev.Engine; using JNPF.VisualDev.Engine.Core; -using JNPF.VisualDev.Engine.Security; using JNPF.VisualDev.Entitys; using JNPF.VisualDev.Entitys.Dto.VisualDev; using JNPF.VisualDev.Entitys.Dto.VisualDevModelData; using JNPF.VisualDev.Interfaces; +using JNPF.WorkFlow.Entitys.Entity; using JNPF.WorkFlow.Interfaces.Service; using Mapster; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using SqlSugar; -using Tnb.ProductionMgr.Interfaces; -using Yitter.IdGenerator; namespace JNPF.VisualDev { @@ -106,7 +105,6 @@ namespace JNPF.VisualDev /// private readonly ITenant _db; - /// /// 初始化一个类型的新实例. /// @@ -158,7 +156,7 @@ namespace JNPF.VisualDev 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() }; + return new { code = 200, data = GetVisualDevModelDataConfig(data) }; } /// @@ -206,21 +204,21 @@ namespace JNPF.VisualDev [HttpGet("{modelId}/{id}")] public async Task GetInfo(string id, string modelId) { + // modified by PhilPan 2023-04-12 重写接口 var overideSvc = OverideVisualDevManager.GetOrDefault(modelId); if (overideSvc != null && overideSvc.OverideFuncs.GetAsync != null) { return await overideSvc.OverideFuncs.GetAsync(id); } - else - { - VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); // 模板实体 - // 有表 - if (!string.IsNullOrEmpty(templateEntity.Tables) && !"[]".Equals(templateEntity.Tables)) - //modified by pf 2023-04-12 返回值不序列化成字符串 - return new { id = id, data = (await _runService.GetHaveTableInfo(id, templateEntity)) }; + VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); // 模板实体 + + // 有表 + if (!string.IsNullOrEmpty(templateEntity.Tables) && !"[]".Equals(templateEntity.Tables)) + // modified by PhilPan 2023-04-12 返回值不序列化成字符串 + return new { id = id, data = (await _runService.GetHaveTableInfo(id, templateEntity)) }; + else return null; - } } /// @@ -232,21 +230,20 @@ namespace JNPF.VisualDev [HttpGet("{modelId}/{id}/DataChange")] public async Task GetDetails(string id, string modelId) { + //modified by PhilPan 2023-04-12 重写接口 var overideSvc = OverideVisualDevManager.GetOrDefault(modelId); if (overideSvc != null && overideSvc.OverideFuncs.GetDetailsAsync != null) { return await overideSvc.OverideFuncs.GetDetailsAsync(id); } - else - { - VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); // 模板实体 - // 有表 - if (!string.IsNullOrEmpty(templateEntity.Tables) && !"[]".Equals(templateEntity.Tables)) - //modified by pf 2023-04-12 返回值不序列化成字符串 - return new { id = id, data = await _runService.GetHaveTableInfoDetails(id, templateEntity) }; + 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 @@ -309,16 +306,31 @@ namespace JNPF.VisualDev [HttpPost("{modelId}/List")] public async Task List(string modelId, [FromBody] VisualDevModelListQueryInput input) { + //modified by PhilPan 2023-04-12 重写接口 var overideSvc = OverideVisualDevManager.GetOrDefault(modelId); if (overideSvc != null && overideSvc.OverideFuncs.GetListAsync != null) { return await overideSvc.OverideFuncs.GetListAsync(input); } - else - { - VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); - return await _runService.GetListResult(templateEntity, input); - } + + VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); + return await _runService.GetListResult(templateEntity, input); + } + + /// + /// 外链获取数据列表. + /// + /// 主键id. + /// 分页查询条件. + /// + [HttpPost("{modelId}/ListLink")] + [AllowAnonymous] + [IgnoreLog] + public async Task ListLink(string modelId, [FromBody] VisualDevModelListQueryInput input) + { + VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); + if (templateEntity == null) throw Oops.Oh(ErrorCode.D1420); + return await _runService.GetListResult(templateEntity, input); } /// @@ -330,6 +342,7 @@ namespace JNPF.VisualDev [HttpPost("{modelId}")] public async Task Create(string modelId, [FromBody] VisualDevModelDataCrInput visualdevModelDataCrForm) { + //modified by PhilPan 2023-04-12 重写接口 var overideSvc = OverideVisualDevManager.GetOrDefault(modelId); if (overideSvc != null && overideSvc.OverideFuncs.CreateAsync != null) { @@ -352,6 +365,7 @@ namespace JNPF.VisualDev [HttpPut("{modelId}/{id}")] public async Task Update(string modelId, string id, [FromBody] VisualDevModelDataUpInput visualdevModelDataUpForm) { + //modified by PhilPan 2023-04-12 重写接口 var overideSvc = OverideVisualDevManager.GetOrDefault(modelId); if (overideSvc != null && overideSvc.OverideFuncs.UpdateAsync != null) { @@ -373,6 +387,7 @@ namespace JNPF.VisualDev [HttpDelete("{modelId}/{id}")] public async Task Delete(string id, string modelId) { + //modified by PhilPan 2023-04-12 重写接口 var overideSvc = OverideVisualDevManager.GetOrDefault(modelId); if (overideSvc != null && overideSvc.OverideFuncs.DeleteAsync != null) { @@ -394,6 +409,7 @@ namespace JNPF.VisualDev [HttpPost("batchDelete/{modelId}")] public async Task BatchDelete(string modelId, [FromBody] VisualDevModelDataBatchDelInput input) { + //modified by PhilPan 2023-04-12 重写接口 var overideSvc = OverideVisualDevManager.GetOrDefault(modelId); if (overideSvc != null && overideSvc.OverideFuncs.DeleteRangeAsync != null) { @@ -416,7 +432,6 @@ namespace JNPF.VisualDev public async Task Export(string modelId, [FromBody] VisualDevModelListQueryInput input) { VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); - List list = new List(); if (input.dataType == "1") input.pageSize = 99999999; PageResult>? pageList = await _runService.GetListResult(templateEntity, input); @@ -439,6 +454,16 @@ namespace JNPF.VisualDev var firstColumns = res.First().ToObject>(); var resultList = res.Last().ToObject>>(); var newResultList = new List>(); + + // 行内编辑 + if (templateInfo.ColumnData.type.Equals(4)) + { + resultList.ForEach(row => + { + foreach (var data in row) if (data.Key.Contains("_name") && row.ContainsKey(data.Key.Replace("_name", string.Empty))) row[data.Key.Replace("_name", string.Empty)] = data.Value; + }); + } + resultList.ForEach(row => { foreach (var item in input.selectKey) @@ -451,7 +476,7 @@ namespace JNPF.VisualDev } }); - var excelName = string.Format("{0}", SnowflakeIdHelper.NextId()); + var excelName = string.Format("表单信息{0}", DateTime.Now.ToString("yyyyMMddHHmmssf")); _cacheManager.Set(excelName + ".xls", string.Empty); return firstColumns.Any() ? await ExcelCreateModel(templateInfo.AllFieldsModel, resultList, input.selectKey, excelName, firstColumns) : await ExcelCreateModel(templateInfo.AllFieldsModel, resultList, input.selectKey, excelName); @@ -724,7 +749,7 @@ namespace JNPF.VisualDev resData.ForEach(items => { - foreach (var item in items) + foreach(var item in items) { var vmodel = tInfo.AllFieldsModel.FirstOrDefault(x => x.__vModel__.Equals(item.Key)); if (vmodel != null && vmodel.__config__.jnpfKey.Equals(JnpfKeyConst.DATE) && item.Value.IsNotEmptyOrNull()) items[item.Key] = item.Value + " "; @@ -872,7 +897,7 @@ namespace JNPF.VisualDev var len = rowChildDatas.Select(x => x.Value.Count()).OrderByDescending(x => x).FirstOrDefault(); - if (len > 0) + if (len != null && len > 0) { for (int i = 0; i < len; i++) { @@ -1020,7 +1045,8 @@ namespace JNPF.VisualDev if (tInfo.visualDevEntity.EnableFlow.Equals(1)) { var flowId = _visualDevRepository.AsSugarClient().Queryable().First(x => x.Id.Equals(tInfo.visualDevEntity.Id)).FlowId; - await _flowTaskService.Create(new Common.Models.WorkFlow.FlowTaskSubmitModel() { formData = item, flowId = flowId, flowUrgent = 1, status = 1 }); + var id = (await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.TemplateId == flowId && x.EnabledMark == 1 && x.DeleteMark == null).Select(x => x.Id).FirstAsync()); + await _flowTaskService.Create(new Common.Models.WorkFlow.FlowTaskSubmitModel() { formData = item, flowId = id, flowUrgent = 1, status = 1 }); } else { @@ -1178,7 +1204,7 @@ namespace JNPF.VisualDev for (var i = 1; i < vlist.Count; i++) { var errorTxt = tInfo.AllFieldsModel.Find(x => x.__vModel__.Equals(uniqueKey)).__config__.label + ": 值不能重复"; - if (!ctItemErrors.Any(x => x.Equals(errorTxt))) ctItemErrors.Add(errorTxt); + if (!ctItemErrors.Any(x=>x.Equals(errorTxt))) ctItemErrors.Add(errorTxt); } } } @@ -1498,7 +1524,7 @@ namespace JNPF.VisualDev foreach (var it in dictionaryDataList) { Dictionary dictionary = new Dictionary(); - if (propsValue.Equals("id")) dictionary.Add(it.Id, it.FullName); + if(propsValue.Equals("id")) dictionary.Add(it.Id, it.FullName); if (propsValue.Equals("enCode")) dictionary.Add(it.EnCode, it.FullName); addItem.Add(dictionary); } @@ -1709,7 +1735,7 @@ namespace JNPF.VisualDev Dictionary dic = new Dictionary(); dic[data.Value(propsValue)] = data.Value(propsLabel); list.Add(dic); - if (children != null && data.Value(children) != null && data.Value(children).ToString().IsNotEmptyOrNull()) + if (children!=null && data.Value(children) != null && data.Value(children).ToString().IsNotEmptyOrNull()) list.AddRange(GetDynamicInfiniteData(data.Value(children).ToString(), item.props.props)); } } @@ -2635,7 +2661,7 @@ namespace JNPF.VisualDev } } - if (newDataItems.ContainsKey(errorKey)) + if(newDataItems.ContainsKey(errorKey)) { if (dataItems.ContainsKey(errorKey)) dataItems[errorKey] = newDataItems[errorKey].ToString(); else dataItems.Add(errorKey, newDataItems[errorKey]); @@ -2920,6 +2946,52 @@ namespace JNPF.VisualDev return pEntity.Id; } } + + /// + /// 处理模板默认值. + /// 用户选择 , 部门选择. + /// + /// 模板. + /// + private VisualDevModelDataConfigOutput GetVisualDevModelDataConfig(VisualDevEntity config) + { + if(config.WebType.Equals(4)) return config.Adapt(); + var tInfo = new TemplateParsingBase(config); + if (tInfo.AllFieldsModel.Any(x => (x.__config__.defaultCurrent) && (x.__config__.jnpfKey.Equals(JnpfKeyConst.USERSELECT) || x.__config__.jnpfKey.Equals(JnpfKeyConst.DEPSELECT)))) + { + var userId = _userManager.UserId; + var depId = _visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(_userManager.UserId)).Select(x => x.OrganizeId).First(); + var allUserRelationList = _visualDevRepository.AsSugarClient().Queryable().Select(x => new UserRelationEntity() { UserId = x.UserId, ObjectId = x.ObjectId }).ToList(); + + var configData = config.FormData.ToObject>(); + var columnList = configData["fields"].ToObject>>(); + _runService.FieldBindDefaultValue(ref columnList, userId, depId, allUserRelationList); + configData["fields"] = columnList; + config.FormData = configData.ToJsonString(); + + configData = config.ColumnData.ToObject>(); + var searchList = configData["searchList"].ToObject>>(); + columnList = configData["columnList"].ToObject>>(); + _runService.FieldBindDefaultValue(ref searchList, userId, depId, allUserRelationList); + _runService.FieldBindDefaultValue(ref columnList, userId, depId, allUserRelationList); + configData["searchList"] = searchList; + configData["columnList"] = columnList; + config.ColumnData = configData.ToJsonString(); + + configData = config.AppColumnData.ToObject>(); + searchList = configData["searchList"].ToObject>>(); + columnList = configData["columnList"].ToObject>>(); + _runService.FieldBindDefaultValue(ref searchList, userId, depId, allUserRelationList); + _runService.FieldBindDefaultValue(ref columnList, userId, depId, allUserRelationList); + configData["searchList"] = searchList; + configData["columnList"] = columnList; + config.AppColumnData = configData.ToJsonString(); + } + + return config.Adapt(); + } + #endregion + } } diff --git a/visualdev/Tnb.VisualDev/VisualDevService.cs b/visualdev/Tnb.VisualDev/VisualDevService.cs index 242d3198..0d9ca71d 100644 --- a/visualdev/Tnb.VisualDev/VisualDevService.cs +++ b/visualdev/Tnb.VisualDev/VisualDevService.cs @@ -4,7 +4,6 @@ using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; using JNPF.Common.Models.Authorize; -using JNPF.Common.Options; using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController; @@ -16,7 +15,6 @@ using JNPF.Systems.Interfaces.System; using JNPF.VisualDev.Engine; using JNPF.VisualDev.Engine.Core; using JNPF.VisualDev.Engine.Model; -using JNPF.VisualDev.Engine.Security; using JNPF.VisualDev.Entitys; using JNPF.VisualDev.Entitys.Dto.VisualDev; using JNPF.VisualDev.Entitys.Dto.VisualDevModelData; @@ -25,7 +23,6 @@ using JNPF.WorkFlow.Entitys.Entity; using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; -using Yitter.IdGenerator; namespace JNPF.VisualDev; @@ -170,15 +167,24 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans /// 获取表单主表属性下拉框. /// /// + /// 1:过滤指定控件. /// [HttpGet("{id}/FormDataFields")] - public async Task GetFormDataFields(string id) + public async Task GetFormDataFields(string id, [FromQuery] int filterType) { - VisualDevEntity? templateEntity = await _visualDevRepository.AsQueryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); - //modified by PhilPan - if (templateEntity == null) throw Oops.Oh(ErrorCode.D1418, id); - TemplateParsingBase? tInfo = new TemplateParsingBase(templateEntity); // 解析模板 + var templateEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); + TemplateParsingBase? tInfo = new TemplateParsingBase(templateEntity.Adapt()); // 解析模板 List? fieldsModels = tInfo.SingleFormData.FindAll(x => x.__vModel__.IsNotEmptyOrNull() && !JnpfKeyConst.RELATIONFORM.Equals(x.__config__.jnpfKey)); + if (filterType.Equals(1)) + { + fieldsModels = fieldsModels.FindAll(x => !JnpfKeyConst.UPLOADIMG.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.UPLOADFZ.Equals(x.__config__.jnpfKey) + && !JnpfKeyConst.MODIFYUSER.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.MODIFYTIME.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.LINK.Equals(x.__config__.jnpfKey) + && !JnpfKeyConst.BUTTON.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.ALERT.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.JNPFTEXT.Equals(x.__config__.jnpfKey) + && !JnpfKeyConst.BARCODE.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.QRCODE.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.TABLE.Equals(x.__config__.jnpfKey) + && !JnpfKeyConst.CREATEUSER.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.CREATETIME.Equals(x.__config__.jnpfKey) && !JnpfKeyConst.BILLRULE.Equals(x.__config__.jnpfKey) + && !JnpfKeyConst.POPUPSELECT.Equals(x.__config__.jnpfKey)); + } + List? output = fieldsModels.Select(x => new VisualDevFormDataFieldsOutput() { label = x.__config__.label, @@ -199,9 +205,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans Dictionary queryDic = new Dictionary(); if (!string.IsNullOrWhiteSpace(input.relationField) && !string.IsNullOrWhiteSpace(input.keyword)) queryDic.Add(input.relationField, input.keyword); - VisualDevEntity? templateEntity = await _visualDevRepository.AsQueryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); // 取数据 - //modified by PhilPan - if (templateEntity == null) throw Oops.Oh(ErrorCode.D1418, id); + VisualDevEntity? templateEntity = await GetInfoById(id, true); // 取数据 TemplateParsingBase? tInfo = new TemplateParsingBase(templateEntity); // 解析模板 // 指定查询字段 @@ -309,7 +313,6 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans TemplateParsingBase? tInfo = new TemplateParsingBase(entity); // 解析模板 if (!tInfo.VerifyTemplate()) throw Oops.Oh(ErrorCode.D1401); // 验证模板 await VerifyPrimaryKeyPolicy(tInfo, entity.DbLinkId); // 验证雪花Id 和自增长Id 主键是否支持 - } _db.BeginTran(); // 开启事务 entity.State = 0; @@ -317,6 +320,19 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans // 添加功能 entity = await _visualDevRepository.AsSugarClient().Insertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + // 同步流程相关 + if (entity.EnableFlow.Equals(1) && (!entity.Type.Equals(3) && !entity.Type.Equals(4))) + { + var fEntity = entity.Adapt(); + fEntity.PropertyJson = entity.FormData; + fEntity.TableJson = entity.Tables; + fEntity.DraftJson = fEntity.ToJsonString(); + fEntity.FlowType = 1; + fEntity.FormType = 2; + fEntity.FlowId = entity.Id; + await _visualDevRepository.AsSugarClient().Insertable(fEntity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + await SaveFlowTemplate(entity); + } _db.CommitTran(); // 提交事务 } catch (Exception) @@ -338,7 +354,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans VisualDevEntity? entity = input.Adapt(); try { - if (await _visualDevRepository.AsQueryable().AnyAsync(x => x.Id.Equals(id) && x.State.Equals(1)) && (entity.Tables.IsNullOrEmpty() || entity.Tables.Equals("[]"))) + if (!input.webType.Equals(4) && await _visualDevRepository.AsQueryable().AnyAsync(x => x.Id.Equals(id) && x.State.Equals(1)) && (entity.Tables.IsNullOrEmpty() || entity.Tables.Equals("[]"))) throw Oops.Oh(ErrorCode.D1416); // 已发布的模板 表不能为空. // 验证名称和编码是否重复 @@ -353,11 +369,10 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans _db.BeginTran(); // 开启事务 // 修改功能 - await _visualDevRepository.AsSugarClient().Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); - // 修改流程表单 - if (entity.EnableFlow.Equals(1)) + // 同步流程相关 + if (entity.EnableFlow.Equals(1) && (!entity.Type.Equals(3) && !entity.Type.Equals(4))) { var fEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(x => x.Id.Equals(id)); if (fEntity != null) @@ -380,9 +395,24 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans fEntity.DraftJson = dEntity.ToJsonString(); fEntity.Id = id; } + fEntity.FlowType = 1; + fEntity.FormType = 2; + fEntity.FlowId = id; - // 修改流程表单 await _visualDevRepository.AsSugarClient().Updateable(fEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); + await SaveFlowTemplate(entity); + } + else + { + fEntity = entity.Adapt(); + fEntity.PropertyJson = entity.FormData; + fEntity.TableJson = entity.Tables; + fEntity.DraftJson = fEntity.ToJsonString(); + fEntity.FlowType = 1; + fEntity.FormType = 2; + fEntity.FlowId = id; + await _visualDevRepository.AsSugarClient().Insertable(fEntity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + await SaveFlowTemplate(entity); } } _db.CommitTran(); // 关闭事务 @@ -404,16 +434,24 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans { var entity = await _visualDevRepository.AsQueryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); await _visualDevRepository.AsSugarClient().Updateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync(); - if (entity.State.Equals(1)) + + // 同步删除线上版本 + var rEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); + if (rEntity != null) await _visualDevRepository.AsSugarClient().Updateable(rEntity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync(); + + // 同步删除流程表单 + var fEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); + if (fEntity != null) { - var rEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); - await _visualDevRepository.AsSugarClient().Updateable(rEntity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync(); - var fEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); - if (fEntity != null) - { - await _visualDevRepository.AsSugarClient().Updateable(fEntity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync(); - await _visualDevRepository.AsSugarClient().Deleteable().Where(x => x.FormId.Equals(fEntity.FlowId)).ExecuteCommandAsync(); - } + await _visualDevRepository.AsSugarClient().Updateable(fEntity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync(); + await _visualDevRepository.AsSugarClient().Deleteable().Where(x => x.FormId.Equals(fEntity.FlowId)).ExecuteCommandAsync(); + } + + // 同步删除流程引擎 + var tEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); + if (tEntity != null) + { + await _visualDevRepository.AsSugarClient().Updateable(tEntity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync(); } } @@ -427,7 +465,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans { string? random = new Random().NextLetterAndNumberString(5); VisualDevEntity? entity = await _visualDevRepository.AsQueryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); - if (entity.State.Equals(1)) + if (entity.State.Equals(1) && (!entity.Type.Equals(3) && !entity.Type.Equals(4))) { var vREntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == id && v.DeleteMark == null); entity = vREntity.Adapt(); @@ -438,7 +476,9 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans entity.EnCode += random; entity.State = 0; entity.Id = null; // 复制的数据需要把Id清空,否则会主键冲突错误 - if (entity.WebType == 3) + entity.LastModifyTime = null; + + if (entity.EnableFlow.Equals(1)) { DictionaryDataEntity? categoryData = await _dictionaryDataService.GetInfo(entity.Category); FlowEngineEntity? flowEngine = new FlowEngineEntity(); @@ -455,12 +495,13 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans flowEngine.DbLinkId = entity.DbLinkId; flowEngine.FormTemplateJson = entity.FormData; flowEngine.Version = "1"; + flowEngine.LastModifyTime = null; try { // 添加流程引擎 FlowEngineEntity? engineEntity = await _visualDevRepository.AsSugarClient().Insertable(flowEngine).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync(); entity.Id = engineEntity.Id; - await _visualDevRepository.AsSugarClient().Insertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteCommandAsync(); + entity = await _visualDevRepository.AsSugarClient().Insertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); } catch { @@ -480,6 +521,20 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans else throw; } } + + // 同步流程相关 + if (entity.EnableFlow.Equals(1) && (!entity.Type.Equals(3) && !entity.Type.Equals(4))) + { + var fEntity = entity.Adapt(); + fEntity.PropertyJson = entity.FormData; + fEntity.TableJson = entity.Tables; + fEntity.DraftJson = fEntity.ToJsonString(); + fEntity.FlowType = 1; + fEntity.FormType = 2; + fEntity.FlowId = entity.Id; + await _visualDevRepository.AsSugarClient().Insertable(fEntity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + await SaveFlowTemplate(entity); + } } /// @@ -499,11 +554,11 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans input.appModuleParentId = input.appModuleParentId.IsNullOrWhiteSpace() ? "-1" : input.appModuleParentId; //if (entity.State == 0) throw Oops.Oh(ErrorCode.D1405); - if (entity.FormData.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.COM1013); - if(entity.WebType.Equals(2) && entity.ColumnData.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.COM1014); + if (entity.FormData.IsNullOrEmpty() && !entity.WebType.Equals(4)) throw Oops.Oh(ErrorCode.COM1013); + if ((entity.WebType.Equals(2) || entity.WebType.Equals(4)) && entity.ColumnData.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.COM1014); #region 旧的菜单、权限数据 - var oldWebModule = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(x => x.ModuleId == input.id && x.Category == "Web" && x.PropertyJson.Contains("\"isAutoRelease\":true") && x.DeleteMark == null); + var oldWebModule = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(x => x.ModuleId == input.id && x.Category == "Web" && x.DeleteMark == null); var oldWebModuleButtonEntity = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.DeleteMark == null) .WhereIF(oldWebModule != null, x => x.ModuleId == oldWebModule.Id).WhereIF(oldWebModule == null, x => x.ModuleId == "0").ToListAsync(); var oldWebModuleColumnEntity = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.DeleteMark == null) @@ -511,7 +566,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans var oldWebModuleFormEntity = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.DeleteMark == null) .WhereIF(oldWebModule != null, x => x.ModuleId == oldWebModule.Id).WhereIF(oldWebModule == null, x => x.ModuleId == "0").ToListAsync(); - var oldAppModule = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(x => x.ModuleId == input.id && x.Category == "App" && x.PropertyJson.Contains("\"isAutoRelease\":true") && x.DeleteMark == null); + var oldAppModule = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(x => x.ModuleId == input.id && x.Category == "App" && x.DeleteMark == null); var oldAppModuleButtonEntity = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.DeleteMark == null) .WhereIF(oldAppModule != null, x => x.ModuleId == oldAppModule.Id).WhereIF(oldAppModule == null, x => x.ModuleId == "0").ToListAsync(); var oldAppModuleColumnEntity = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.DeleteMark == null) @@ -527,6 +582,78 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans if (_visualDevRepository.AsSugarClient().Queryable().Any(x => (x.EnCode == entity.EnCode || x.FullName == entity.FullName) && x.Id != oldAppId && x.Category == "App" && x.DeleteMark == null)) throw Oops.Oh(ErrorCode.COM1015); + #region 数据视图 + if (entity.WebType.Equals(4)) + { + #region 菜单组装 + var moduleModel = new ModuleEntity(); + moduleModel.Id = oldWebModule != null ? oldWebModule.Id : SnowflakeIdHelper.NextId(); + moduleModel.ModuleId = input.id; + moduleModel.ParentId = oldWebModule != null ? oldWebModule.ParentId : (input.pcModuleParentId.Equals(input.pcSystemId) ? "-1" : input.pcModuleParentId); // 父级菜单节点 + moduleModel.Category = "Web"; + moduleModel.FullName = entity.FullName; + moduleModel.EnCode = entity.EnCode; + moduleModel.Icon = "icon-ym icon-ym-webForm"; + moduleModel.UrlAddress = oldWebModule != null ? oldWebModule.UrlAddress : "model/" + entity.EnCode; + moduleModel.Type = 3; + moduleModel.EnabledMark = 1; + moduleModel.IsColumnAuthorize = 1; + moduleModel.IsButtonAuthorize = 1; + moduleModel.IsFormAuthorize = 1; + moduleModel.IsDataAuthorize = 1; + moduleModel.SortCode = 999; + moduleModel.CreatorTime = DateTime.Now; + moduleModel.PropertyJson = (new { moduleId = input.id, iconBackgroundColor = string.Empty, isTree = 0 }).ToJsonString(); + moduleModel.SystemId = oldWebModule != null ? oldWebModule.SystemId : input.pcSystemId; + + #endregion + + // 添加PC菜单 + if (input.pc == 1) + { + var storModuleModel = _visualDevRepository.AsSugarClient().Storageable(moduleModel).Saveable().ToStorage(); // 存在更新不存在插入 根据主键 + await storModuleModel.AsInsertable.ExecuteCommandAsync(); // 执行插入 + await storModuleModel.AsUpdateable.ExecuteCommandAsync(); // 执行更新 + } + + // 添加App菜单 + if (input.app == 1) + { + #region App菜单 + moduleModel.Id = oldAppModule != null ? oldAppModule.Id : SnowflakeIdHelper.NextId(); + moduleModel.ModuleId = input.id; + moduleModel.ParentId = oldAppModule != null ? oldAppModule.ParentId : (input.appModuleParentId.Equals(input.appSystemId) ? "-1" : input.appModuleParentId); // 父级菜单节点 + moduleModel.Category = "App"; + moduleModel.UrlAddress = oldAppModule != null ? oldAppModule.UrlAddress : "/pages/apply/dynamicModel/index?id=" + entity.EnCode; + moduleModel.SystemId = oldAppModule != null ? oldAppModule.SystemId : input.appSystemId; + + #endregion + + var storModuleModel = _visualDevRepository.AsSugarClient().Storageable(moduleModel).Saveable().ToStorage(); // 存在更新不存在插入 根据主键 + await storModuleModel.AsInsertable.ExecuteCommandAsync(); // 执行插入 + await storModuleModel.AsUpdateable.ExecuteCommandAsync(); // 执行更新 + + } + + // 修改功能发布状态 + await _visualDevRepository.AsUpdateable().SetColumns(it => it.State == 1).Where(it => it.Id == id).ExecuteCommandHasChangeAsync(); + + // 线上版本 + if (!await _visualDevRepository.AsSugarClient().Queryable().AnyAsync(x => x.Id.Equals(id))) + { + var vReleaseEntity = entity.Adapt(); + await _visualDevRepository.AsSugarClient().Insertable(vReleaseEntity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteCommandAsync(); + } + else + { + var vReleaseEntity = entity.Adapt(); + await _visualDevRepository.AsSugarClient().Updateable(vReleaseEntity).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); + } + + return; + } + #endregion + TemplateParsingBase? tInfo = new TemplateParsingBase(entity); // 解析模板 // 无表转有表 @@ -539,6 +666,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans else throw Oops.Oh(ErrorCode.D1414); tInfo = new TemplateParsingBase(res); // 解析模板 + entity = res; } ColumnDesignModel? columnData = new ColumnDesignModel(); @@ -607,7 +735,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans moduleModel.IsDataAuthorize = 1; moduleModel.SortCode = oldWebModule != null ? oldWebModule.SortCode : 999; //modifyby zhoukeda 发布功能不更新名称排序图标 moduleModel.CreatorTime = DateTime.Now; - moduleModel.PropertyJson = (new { moduleId = input.id, iconBackgroundColor = string.Empty, isTree = 0, isAutoRelease = true }).ToJsonString(); + moduleModel.PropertyJson = (new { moduleId = input.id, iconBackgroundColor = string.Empty, isTree = 0 }).ToJsonString(); moduleModel.SystemId = oldWebModule != null ? oldWebModule.SystemId : input.pcSystemId; #endregion @@ -816,7 +944,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans // 创建用户和所属组织权限方案 // 只添加 主表控件的数据权限 var fList = fieldList.Where(x => !x.__vModel__.Contains("_jnpf_") && x.__vModel__.IsNotEmptyOrNull() && x.__config__.visibility.Contains("pc")) - .Where(x => x.__config__.jnpfKey == "createUser" || x.__config__.jnpfKey == "currOrganize").ToList(); + .Where(x => x.__config__.jnpfKey == JnpfKeyConst.CREATEUSER || x.__config__.jnpfKey == JnpfKeyConst.CURRORGANIZE).ToList(); var authList = await MenuMergeDataAuth(moduleModel.Id, fList); await MenuMergeDataAuthScheme(moduleModel.Id, authList, fList); @@ -1021,7 +1149,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans // 创建用户和所属组织权限方案 // 只添加 主表控件的数据权限 var fList = fieldList.Where(x => !x.__vModel__.Contains("_jnpf_") && x.__vModel__.IsNotEmptyOrNull() && x.__config__.visibility.Contains("app")) - .Where(x => x.__config__.jnpfKey == "createUser" || x.__config__.jnpfKey == "currOrganize").ToList(); + .Where(x => x.__config__.jnpfKey == JnpfKeyConst.CREATEUSER || x.__config__.jnpfKey == JnpfKeyConst.CURRORGANIZE).ToList(); var authList = await MenuMergeDataAuth(moduleModel.Id, fList); await MenuMergeDataAuthScheme(moduleModel.Id, authList, fList); @@ -1041,6 +1169,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans // 同步添加流程表单 if (entity.EnableFlow.Equals(1)) { + if (!_visualDevRepository.AsSugarClient().Queryable().Any(x => x.TemplateId.Equals(entity.Id))) throw Oops.Oh(ErrorCode.D1421); var fEntity = entity.Adapt(); fEntity.TableJson = entity.Tables; fEntity.FlowType = 1; @@ -1048,7 +1177,8 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans fEntity.EnabledMark = 1; fEntity.PropertyJson = entity.FormData; fEntity.DraftJson = fEntity.ToJsonString(); - await _visualDevRepository.AsSugarClient().Insertable(fEntity).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnEntityAsync(); + await _visualDevRepository.AsSugarClient().Updateable(fEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); + await _visualDevRepository.AsSugarClient().Updateable().SetColumns(x => x.EnabledMark == 1).Where(it => it.Id == entity.Id).ExecuteCommandHasChangeAsync(); } } else @@ -1058,6 +1188,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans if (entity.EnableFlow.Equals(1)) { + if (!_visualDevRepository.AsSugarClient().Queryable().Any(x => x.TemplateId.Equals(entity.Id))) throw Oops.Oh(ErrorCode.D1421); var fEntity = entity.Adapt(); fEntity.TableJson = entity.Tables; fEntity.FlowType = 1; @@ -1065,14 +1196,28 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans fEntity.EnabledMark = 1; fEntity.PropertyJson = entity.FormData; fEntity.DraftJson = fEntity.ToJsonString(); - fEntity.FlowId = _visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(entity.Id)).Select(x => x.FlowId).First(); if (!await _visualDevRepository.AsSugarClient().Queryable().AnyAsync(x => x.Id.Equals(id))) await _visualDevRepository.AsSugarClient().Insertable(fEntity).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnEntityAsync(); else - await _visualDevRepository.AsSugarClient().Updateable(fEntity).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); + await _visualDevRepository.AsSugarClient().Updateable(fEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); + + await _visualDevRepository.AsSugarClient().Updateable().SetColumns(x => x.EnabledMark == 1).Where(it => it.Id == entity.Id).ExecuteCommandHasChangeAsync(); } } + var dbLink = await _runService.GetDbLink(entity.DbLinkId); + var MainTable = entity.Tables.ToList().Find(m => m.typeId.Equals("1")); // 主表 + if (!_changeDataBase.IsAnyColumn(dbLink, MainTable?.table, "f_flowtaskid")) + { + var pFieldList = new List() { new DbTableFieldModel() { field = "F_FlowTaskId", fieldName = "流程任务Id", dataType = "varchar", dataLength = "50", allowNull = 1 } }; + _changeDataBase.AddTableColumn(dbLink, MainTable?.table, pFieldList); + } + if (!_changeDataBase.IsAnyColumn(dbLink, MainTable?.table, "f_flowid")) + { + var pFieldList = new List() { new DbTableFieldModel() { field = "F_FlowId", fieldName = "流程引擎Id", dataType = "varchar", dataLength = "50", allowNull = 1 } }; + _changeDataBase.AddTableColumn(dbLink, MainTable?.table, pFieldList); + } + _db.CommitTran(); } catch (Exception) @@ -1098,13 +1243,12 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans if (isGetRelease) { var vREntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(x => x.Id == id && x.DeleteMark == null); - if (_visualDevRepository.AsSugarClient().Queryable().Any(x => x.Id.Equals(id))) + if (vREntity != null && vREntity.EnableFlow == 1 && _visualDevRepository.AsSugarClient().Queryable().Any(x => x.Id.Equals(id))) { vREntity.FlowId = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(id)).Select(x => x.FlowId).FirstAsync(); if (vREntity.FlowId.IsNotEmptyOrNull()) { - var tempId = _visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(vREntity.FlowId)).Select(x => x.TemplateId).First(); - if (!_visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(tempId) && x.EnabledMark.Equals(1)).Any()) + if (!_visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(vREntity.FlowId) && x.EnabledMark.Equals(1)).Any()) vREntity.EnableFlow = -1; } } @@ -1155,6 +1299,26 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans await stor.AsInsertable.ExecuteCommandAsync(); // 执行插入 await _visualDevRepository.AsSugarClient().Updateable(input).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); + // 同步流程表单 + var fEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == input.Id); + if (fEntity != null) + { + fEntity.DeleteMark = null; + fEntity.DeleteTime = null; + fEntity.DeleteUserId = null; + await _visualDevRepository.AsSugarClient().Updateable(fEntity).CallEntityMethod(m => m.LastModify()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId, it.LastModifyTime, it.LastModifyUserId }).ExecuteCommandAsync(); + } + + // 同步程引擎 + var tEntity = await _visualDevRepository.AsSugarClient().Queryable().FirstAsync(v => v.Id == input.Id); + if (tEntity != null) + { + tEntity.DeleteMark = null; + tEntity.DeleteTime = null; + tEntity.DeleteUserId = null; + await _visualDevRepository.AsSugarClient().Updateable(tEntity).CallEntityMethod(m => m.LastModify()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId, it.LastModifyTime, it.LastModifyUserId }).ExecuteCommandAsync(); + } + _db.CommitTran(); // 关闭事务 } catch (Exception) @@ -1173,7 +1337,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans [NonAction] public async Task NoTblToTable(VisualDevEntity vEntity, string mainTableName) { - var dbtype = App.Configuration["ConnectionStrings:DBType"]; // 读取数据库连接配置 + var dbtype = _visualDevRepository.AsSugarClient().CurrentConnectionConfig.DbType.ToString(); var isUpper = false; // 是否大写 if (dbtype.ToLower().Equals("oracle") || dbtype.ToLower().Equals("dm") || dbtype.ToLower().Equals("dm8")) isUpper = true; else isUpper = false; @@ -1181,7 +1345,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans // Oracle和Dm数据库 表名全部大写, 其他全部小写 mainTableName = isUpper ? mainTableName.ToUpper() : mainTableName.ToLower(); - FormDataModel formModel = vEntity.FormData.ToObject(); + FormDataModel formModel = vEntity.FormData.ToObjectOld(); List? fieldsModelList = TemplateAnalysis.AnalysisTemplateData(formModel.fields); #region 创表信息组装 @@ -1193,12 +1357,13 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans mainInfo.table = mainTableName; mainInfo.tableName = vEntity.FullName; mainInfo.FieldList = FieldsModelToTableFile(fieldsModelList, formModel.primaryKeyPolicy == 2); - if (vEntity.WebType.Equals(3)) mainInfo.FieldList.Add(new DbTableFieldModel() { field = "F_FlowTaskId", fieldName = "流程任务Id", dataType = "varchar", dataLength = "50", allowNull = 1 }); + if (vEntity.EnableFlow.Equals(1)) mainInfo.FieldList.Add(new DbTableFieldModel() { field = "F_FlowTaskId", fieldName = "流程任务Id", dataType = "varchar", dataLength = "50", allowNull = 1 }); + if (vEntity.EnableFlow.Equals(1)) mainInfo.FieldList.Add(new DbTableFieldModel() { field = "F_FlowId", fieldName = "流程引擎Id", dataType = "varchar", dataLength = "50", allowNull = 1 }); if (formModel.logicalDelete) mainInfo.FieldList.Add(new DbTableFieldModel() { field = "F_DeleteMark", fieldName = "删除标识", dataType = "int", dataLength = "50", allowNull = 1 }); // 子表信息 Dictionary? childTableDic = new Dictionary(); - fieldsModelList.Where(x => x.__config__.jnpfKey == "table").ToList().ForEach(item => + fieldsModelList.Where(x => x.__config__.jnpfKey == JnpfKeyConst.TABLE).ToList().ForEach(item => { DbTableAndFieldModel? childTInfo = new DbTableAndFieldModel(); childTInfo.table = "ct" + SnowflakeIdHelper.NextId(); @@ -1246,7 +1411,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans { EntityFieldModel? etFieldModel = new EntityFieldModel(); etFieldModel.DataLength = it.dataLength; - etFieldModel.PrimaryKey = 0; + etFieldModel.PrimaryKey = it.primaryKey.ParseToInt(); etFieldModel.DataType = it.dataType; etFieldModel.Field = it.field; etFieldModel.FieldName = it.fieldName; @@ -1259,8 +1424,8 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans #region 给控件绑定 tableName、relationTable 属性 // 用字典反序列化, 避免多增加不必要的属性 - Dictionary? dicFormModel = vEntity.FormData.ToObject>(); - List>? dicFieldsModelList = dicFormModel.FirstOrDefault(x => x.Key == "fields").Value.ToObject>>(); + Dictionary? dicFormModel = vEntity.FormData.ToObjectOld>(); + List>? dicFieldsModelList = dicFormModel.FirstOrDefault(x => x.Key == "fields").Value.ToJsonString().ToObjectOld>>(); // 主表 MainFieldsBindTable(dicFieldsModelList, childTableDic, mainTableName); @@ -1285,7 +1450,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans foreach (DbTableAndFieldModel? item in addTableList) { bool res = await _changeDataBase.Create(link, item, item.FieldList); - if (!res) Oops.Oh(ErrorCode.COM1008); // throw null; + if (!res) throw null; } if (await _visualDevRepository.IsAnyAsync(x => x.Id.Equals(vEntity.Id))) @@ -1304,35 +1469,6 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans } } - /// - /// 数据 转 插入Sql语句. - /// - /// 表名. - /// 数据包字符串. - /// - [NonAction] - public List DataToInsertSql(string tableName, string dataStr) - { - List? sqlList = new List(); - string? sql = "insert into [{0}] ({1}) values('{2}');"; - - List>? dataMap = dataStr.ToObject>>(); - - List? fielsKeyList = new List(); - List? fieldValueList = new List(); - - dataMap.ForEach(item => - { - string? fielsKey = item.Keys.FirstOrDefault(); - fielsKeyList.Add(fielsKey); - fieldValueList.Add(item[fielsKey]); - }); - - sqlList.Add(string.Format(sql, tableName, string.Join(",", fielsKeyList), string.Join("','", fieldValueList))); - - return sqlList; - } - #endregion #region Private @@ -1348,7 +1484,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans { List? fieldList = new List(); // 表字段 List? mList = fmList.Where(x => x.__config__.jnpfKey.IsNotEmptyOrNull()) - .Where(x => x.__config__.jnpfKey != "qrcode" && x.__config__.jnpfKey != "barcode" && x.__config__.jnpfKey != "table").ToList(); // 非存储字段 + .Where(x => x.__config__.jnpfKey != JnpfKeyConst.QRCODE && x.__config__.jnpfKey != JnpfKeyConst.BARCODE && x.__config__.jnpfKey != JnpfKeyConst.TABLE).ToList(); // 非存储字段 fieldList.Add(new DbTableFieldModel() { primaryKey = true, @@ -1437,7 +1573,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans List? noDelData = new List(); // 记录未删除 // 当前用户 - FieldsModel? item = fields.FirstOrDefault(x => x.__config__.jnpfKey == "createUser"); + FieldsModel? item = fields.FirstOrDefault(x => x.__config__.jnpfKey == JnpfKeyConst.CREATEUSER); if (item != null) { var fRule = item.__vModel__.Contains("_jnpf_") ? 1 : 0; @@ -1494,7 +1630,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans } // 所属组织 - item = fields.FirstOrDefault(x => x.__config__.jnpfKey == "currOrganize"); + item = fields.FirstOrDefault(x => x.__config__.jnpfKey == JnpfKeyConst.CURRORGANIZE); if (item != null) { var fRule = item.__vModel__.Contains("_jnpf_") ? 1 : 0; @@ -1551,7 +1687,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans } // 当前分管组织 - item = fields.FirstOrDefault(x => x.__config__.jnpfKey == "currOrganize"); + item = fields.FirstOrDefault(x => x.__config__.jnpfKey == JnpfKeyConst.CURRORGANIZE); if (item != null) { var fRule = item.__vModel__.Contains("_jnpf_") ? 1 : 0; @@ -1638,7 +1774,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans List? authSchemeList = new List(); // 方案管理 // 当前用户 - FieldsModel? item = fields.FirstOrDefault(x => x.__config__.jnpfKey == "createUser"); + FieldsModel? item = fields.FirstOrDefault(x => x.__config__.jnpfKey == JnpfKeyConst.CREATEUSER); var condJson = new AuthorizeModuleResourceConditionModelInput() { logic = "and", @@ -1710,7 +1846,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans } // 当前组织 - item = fields.FirstOrDefault(x => x.__config__.jnpfKey == "currOrganize"); + item = fields.FirstOrDefault(x => x.__config__.jnpfKey == JnpfKeyConst.CURRORGANIZE); if (item != null) { ModuleDataAuthorizeEntity? model = authList.FirstOrDefault(x => x.EnCode == item.__vModel__ && x.ConditionText.Equals("@organizeId")); @@ -1777,7 +1913,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans } // 当前分管组织 - item = fields.FirstOrDefault(x => x.__config__.jnpfKey == "currOrganize"); + item = fields.FirstOrDefault(x => x.__config__.jnpfKey == JnpfKeyConst.CURRORGANIZE); if (item != null) { ModuleDataAuthorizeEntity? model = authList.FirstOrDefault(x => x.EnCode == item.__vModel__ && x.ConditionText.Equals("@branchManageOrganize")); @@ -1858,11 +1994,11 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans { var obj = item["__config__"].ToObject>(); - if (obj.ContainsKey("jnpfKey") && obj["jnpfKey"].Equals("table")) obj["tableName"] = childTableDic[item["__vModel__"].ToString()]; - else if(obj.ContainsKey("tableName")) obj["tableName"] = tableName; + if (obj.ContainsKey("jnpfKey") && obj["jnpfKey"].Equals(JnpfKeyConst.TABLE)) obj["tableName"] = childTableDic[item["__vModel__"].ToString()]; + else if (obj.ContainsKey("tableName")) obj["tableName"] = tableName; // 关联表单属性和弹窗属性 - if (obj.ContainsKey("jnpfKey") && (obj["jnpfKey"].Equals("relationFormAttr") || obj["jnpfKey"].Equals("popupAttr"))) + if (obj.ContainsKey("jnpfKey") && (obj["jnpfKey"].Equals(JnpfKeyConst.RELATIONFORMATTR) || obj["jnpfKey"].Equals(JnpfKeyConst.POPUPATTR))) { string relationField = Convert.ToString(item["relationField"]); string? rField = relationField.ReplaceRegex(@"_jnpfTable_(\w+)", string.Empty); @@ -1917,7 +2053,7 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans if (cObj.ContainsKey("tableName")) cObj["tableName"] = tableName; // 关联表单属性和弹窗属性 - if (cObj.ContainsKey("jnpfKey") && (cObj["jnpfKey"].Equals("relationFormAttr") || cObj["jnpfKey"].Equals("popupAttr"))) + if (cObj.ContainsKey("jnpfKey") && (cObj["jnpfKey"].Equals(JnpfKeyConst.RELATIONFORMATTR) || cObj["jnpfKey"].Equals(JnpfKeyConst.POPUPATTR))) { string relationField = Convert.ToString(child["relationField"]); string? rField = relationField.ReplaceRegex(@"_jnpfTable_(\w+)", string.Empty); @@ -1941,10 +2077,10 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans obj["children"] = fmList; } - if(obj["jnpfKey"].Equals(JnpfKeyConst.TAB)) + if (obj["jnpfKey"].Equals(JnpfKeyConst.TAB)) { var fmList = obj["children"].ToObject>>(); - foreach(var it in fmList) + foreach (var it in fmList) { var fmChild = it["__config__"].ToObject>(); var fmChildList = fmChild["children"].ToObject>>(); @@ -1987,5 +2123,32 @@ public class VisualDevService : IVisualDevService, IDynamicApiController, ITrans } } + /// + /// 同步到流程相关. + /// + /// + /// + private async Task SaveFlowTemplate(VisualDevEntity input) + { + if (!(await _visualDevRepository.AsSugarClient().Queryable().AnyAsync(x => x.Id.Equals(input.Id)))) + { + if (await _visualDevRepository.AsSugarClient().Queryable().AnyAsync(x => (x.EnCode == input.EnCode || x.FullName == input.FullName) && x.DeleteMark == null)) + throw Oops.Oh(ErrorCode.COM1004); + + var dicType = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.Id.Equals(input.Category)).FirstAsync(); + var flowType = await _visualDevRepository.AsSugarClient().Queryable().Where(x => x.EnCode.Equals(dicType.EnCode) && x.DictionaryTypeId.Equals("507f4f5df86b47588138f321e0b0dac7")).FirstAsync(); + + var flowTemplateEntity = input.Adapt(); + flowTemplateEntity.EnabledMark = 0; + flowTemplateEntity.Type = 1; + flowTemplateEntity.Category = flowType.Id; + //flowTemplateEntity.IconBackground = "#008cff";. + //flowTemplateEntity.Icon = "icon-ym icon-ym-node"; + + var result = await _visualDevRepository.AsSugarClient().Insertable(flowTemplateEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + if (result == null) + throw Oops.Oh(ErrorCode.COM1005); + } + } #endregion } diff --git a/visualdev/Tnb.VisualDev/VisualdevModelAppService.cs b/visualdev/Tnb.VisualDev/VisualdevModelAppService.cs index 04233a29..24ce3a77 100644 --- a/visualdev/Tnb.VisualDev/VisualdevModelAppService.cs +++ b/visualdev/Tnb.VisualDev/VisualdevModelAppService.cs @@ -7,21 +7,18 @@ 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; @@ -284,7 +281,6 @@ public class VisualdevModelAppService : IDynamicApiController, ITransient public async Task Export(string modelId, [FromBody] VisualDevModelListQueryInput input) { VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(modelId, true); - List list = new List(); PageResult>? pageList = await _runService.GetListResult(templateEntity, input); #region 如果是 分组表格 模板 @@ -409,7 +405,7 @@ public class VisualdevModelAppService : IDynamicApiController, ITransient var len = rowChildDatas.Select(x => x.Value.Count()).OrderByDescending(x => x).FirstOrDefault(); - if (len > 0) + if (len != null && len > 0) { for (int i = 0; i < len; i++) { diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListOutput.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListOutput.cs index dd15cf09..b40b487b 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListOutput.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListOutput.cs @@ -132,5 +132,13 @@ public class FlowBeforeListOutput /// public string? templateId { get; set; } -} + /// + /// 委托发起人. + /// + public string? delegateUser { get; set; } + /// + /// 挂起(0:否,1:是). + /// + public int? suspend { get; set; } +} \ No newline at end of file diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListQuery.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListQuery.cs index d968ba2a..d0229985 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListQuery.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowBefore/FlowBeforeListQuery.cs @@ -17,7 +17,12 @@ public class FlowBeforeListQuery : PageInputBase public long? endTime { get; set; } /// - /// 引擎id. + /// 所属流程. + /// + public string templateId { get; set; } + + /// + /// 所属流程. /// public string flowId { get; set; } diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListOutput.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListOutput.cs index afb1b7df..6a2028f0 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListOutput.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListOutput.cs @@ -106,7 +106,12 @@ public class FlowLaunchListOutput public long? sortCode { get; set; } /// - /// 委托发起人 + /// 委托发起人. /// public string? delegateUser { get; set; } + + /// + /// 挂起(0:否,1:是). + /// + public int? suspend { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListQuery.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListQuery.cs index e31616e9..700a3f52 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListQuery.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowLaunch/FlowLaunchListQuery.cs @@ -14,6 +14,11 @@ public class FlowLaunchListQuery : PageInputBase /// /// 所属流程. /// + public string? templateId { get; set; } + + /// + /// 所属名称. + /// public string? flowId { get; set; } /// diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListOutput.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListOutput.cs index 526d8364..433c3b96 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListOutput.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListOutput.cs @@ -114,4 +114,14 @@ public class FlowMonitorListOutput /// 流程主表id. /// public string? templateId { get; set; } + + /// + /// 挂起(0:否,1:是). + /// + public int? suspend { get; set; } + + /// + /// 版本. + /// + public string? flowVersion { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListQuery.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListQuery.cs index 68a89f5e..fe3bdeea 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListQuery.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowMonitor/FlowMonitorListQuery.cs @@ -27,9 +27,9 @@ public class FlowMonitorListQuery : PageInputBase public long? endTime { get; set; } /// - /// 流程主键. + /// 所属流程. /// - public string? flowId { get; set; } + public string? templateId { get; set; } /// /// 流程状态. @@ -40,4 +40,9 @@ public class FlowMonitorListQuery : PageInputBase /// 紧急程度. /// public int? flowUrgent { get; set; } + + /// + /// 所属名称. + /// + public string? flowId { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowJsonInfo.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowJsonInfo.cs new file mode 100644 index 00000000..6b85b462 --- /dev/null +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowJsonInfo.cs @@ -0,0 +1,31 @@ +using JNPF.WorkFlow.Entitys.Model; + +namespace JNPF.WorkFlow.Entitys.Dto.FlowTemplate; + +public class FlowJsonInfo +{ + /// + /// id. + /// + public string? id { get; set; } + + /// + /// 流程编码. + /// + public string? flowId { get; set; } + + /// + /// 流程名称. + /// + public string? fullName { get; set; } + + /// + /// 流程JOSN包. + /// + public FlowTemplateJsonModel? flowTemplateJson { get; set; } + + /// + /// 是否删除. + /// + public bool? isDelete { get; set; } +} diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateImportOutput.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateImportOutput.cs index b6aa2aea..4623c407 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateImportOutput.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateImportOutput.cs @@ -14,7 +14,7 @@ public class FlowTemplateImportOutput /// /// 流程实例. /// - public FlowTemplateJsonEntity flowTemplateJson { get; set; } + public List flowTemplateJson { get; set; } /// /// 流程可见范围. diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateInfoOutput.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateInfoOutput.cs index e53061f6..8a8ba4e0 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateInfoOutput.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateInfoOutput.cs @@ -53,4 +53,19 @@ public class FlowTemplateInfoOutput /// 流程设计信息. /// public string? flowTemplateJson { get; set; } + + /// + /// 是否在线开发. + /// + public bool? onlineDev { get; set; } + + /// + /// 启用标识. + /// + public int? enabledMark { get; set; } + + /// + /// 在线开发流程表单id. + /// + public string? onlineFormId { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateJsonInfoOutput.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateJsonInfoOutput.cs index 1c332776..eade01e0 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateJsonInfoOutput.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateJsonInfoOutput.cs @@ -14,6 +14,11 @@ public class FlowTemplateJsonInfoOutput /// public string? templateId { get; set; } + /// + /// 流程名称. + /// + public string? fullName { get; set; } + /// /// 可见范围. /// @@ -53,4 +58,9 @@ public class FlowTemplateJsonInfoOutput /// 标识. /// public int? enabledMark { get; set; } + + /// + /// 排序码. + /// + public long? sortCode { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateListQuery.cs b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateListQuery.cs index 4e6e2a34..75fc3ba5 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateListQuery.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Dto/FlowTemplate/FlowTemplateListQuery.cs @@ -24,4 +24,9 @@ public class FlowTemplateListQuery : PageInputBase /// 0:发起流程 1:功能流程. /// public int? flowType { get; set; } + + /// + /// 所属流程. + /// + public string? flowId { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskEntity.cs b/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskEntity.cs index 240f8624..82601346 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskEntity.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskEntity.cs @@ -182,4 +182,10 @@ public class FlowTaskEntity : CLDEntityBase /// [SugarColumn(ColumnName = "F_DELEGATEUSER")] public string? DelegateUser { get; set; } + + /// + /// 挂起(0:否,1:是). + /// + [SugarColumn(ColumnName = "F_Suspend")] + public int? Suspend { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskOperatorUserEntity.cs b/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskOperatorUserEntity.cs index 0e2bd253..c892696b 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskOperatorUserEntity.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTaskOperatorUserEntity.cs @@ -23,18 +23,6 @@ public class FlowTaskOperatorUserEntity : EntityBase [SugarColumn(ColumnName = "F_HANDLEID")] public string? HandleId { get; set; } - /// - /// 处理状态:【0-拒绝、1-同意】. - /// - [SugarColumn(ColumnName = "F_HANDLESTATUS")] - public int? HandleStatus { get; set; } - - /// - /// 处理时间. - /// - [SugarColumn(ColumnName = "F_HANDLETIME")] - public DateTime? HandleTime { get; set; } - /// /// 节点编码. /// @@ -95,12 +83,6 @@ public class FlowTaskOperatorUserEntity : EntityBase [SugarColumn(ColumnName = "F_PARENTID")] public string? ParentId { get; set; } - /// - /// 保存数据. - /// - [SugarColumn(ColumnName = "F_DRAFTDATA")] - public string? DraftData { get; set; } - /// /// 排序. /// diff --git a/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTemplateJsonEntity.cs b/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTemplateJsonEntity.cs index 86371d82..f460b479 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTemplateJsonEntity.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Entity/FlowTemplateJsonEntity.cs @@ -34,4 +34,22 @@ public class FlowTemplateJsonEntity : CLDEntityBase /// [SugarColumn(ColumnName = "F_FLOWTEMPLATEJSON")] public string? FlowTemplateJson { get; set; } + + /// + /// 流程名称. + /// + [SugarColumn(ColumnName = "F_FULLNAME")] + public string? FullName { get; set; } + + /// + /// 排序码. + /// + [SugarColumn(ColumnName = "F_SORTCODE")] + public long? SortCode { get; set; } + + /// + /// 分组id. + /// + [SugarColumn(ColumnName = "F_GROUPID")] + public string? GroupId { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Model/FlowHandleModel.cs b/workflow/Tnb.WorkFlow.Entitys/Model/FlowHandleModel.cs index 02e33f71..f2a400f6 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Model/FlowHandleModel.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Model/FlowHandleModel.cs @@ -86,6 +86,11 @@ public class FlowHandleModel : PageInputBase /// public string taskId { get; set; } + /// + /// 任务id. + /// + public string id { get; set; } + /// /// false 变更 true 复活. /// @@ -100,4 +105,14 @@ public class FlowHandleModel : PageInputBase /// 驳回节点. /// public string rejectStep { get; set; } + + /// + /// true 全部 flase 主流程. + /// + public bool suspend { get; set; } + + /// + /// 驳回类型. + /// + public string rejectType { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Model/FlowTaskModel.cs b/workflow/Tnb.WorkFlow.Entitys/Model/FlowTaskModel.cs index 149ae1fd..f1964796 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Model/FlowTaskModel.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Model/FlowTaskModel.cs @@ -124,4 +124,9 @@ public class FlowTaskModel /// 标识. /// public int? enabledMark { get; set; } + + /// + /// 是否挂起. + /// + public bool suspend { get; set; } } diff --git a/workflow/Tnb.WorkFlow.Entitys/Model/FlowTemplateModel.cs b/workflow/Tnb.WorkFlow.Entitys/Model/FlowTemplateModel.cs deleted file mode 100644 index 3089c480..00000000 --- a/workflow/Tnb.WorkFlow.Entitys/Model/FlowTemplateModel.cs +++ /dev/null @@ -1,29 +0,0 @@ -using JNPF.DependencyInjection; -using Newtonsoft.Json.Linq; - -namespace JNPF.WorkFlow.Entitys.Model; - -[SuppressSniffer] -public class FlowTemplateModel -{ - /// - /// id. - /// - public string id { get; set; } = ""; - - /// - /// 流程id. - /// - public string flowId { get; set; } = ""; - - /// - /// 流程名称. - /// - public string fullName { get; set; } = ""; - - /// - /// 子节点. - /// - public FlowTemplateJsonModel? flowTemplateJson { get; set; } - -} diff --git a/workflow/Tnb.WorkFlow.Entitys/Model/Item/ConditionsItem.cs b/workflow/Tnb.WorkFlow.Entitys/Model/Item/ConditionsItem.cs index 1002b019..163cfc71 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Model/Item/ConditionsItem.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Model/Item/ConditionsItem.cs @@ -45,6 +45,11 @@ public class ConditionsItem /// public string? jnpfKey { get; set; } + /// + /// 控件类型. + /// + public string? fieldValueJnpfKey { get; set; } + /// /// 条件类型 1:字段 3:聚合函数匹配. /// diff --git a/workflow/Tnb.WorkFlow.Entitys/Model/PortalWaitListModel.cs b/workflow/Tnb.WorkFlow.Entitys/Model/PortalWaitListModel.cs index adf69ecb..2875e17f 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Model/PortalWaitListModel.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Model/PortalWaitListModel.cs @@ -59,4 +59,9 @@ public class PortalWaitListModel /// 类型. /// public int? type { get; set; } -} \ No newline at end of file + + /// + /// 委托发起人. + /// + public string? delegateUser { get; set; } +} diff --git a/workflow/Tnb.WorkFlow.Entitys/Model/Properties/ApproversProperties.cs b/workflow/Tnb.WorkFlow.Entitys/Model/Properties/ApproversProperties.cs index d6467088..f96f1791 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Model/Properties/ApproversProperties.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Model/Properties/ApproversProperties.cs @@ -95,7 +95,7 @@ public class ApproversProperties /// /// 打印id. /// - public string? printId { get; set; } + public List printId { get; set; } = new List(); /// /// 表单字段审核方式的类型(1-用户 2-部门). @@ -150,6 +150,11 @@ public class ApproversProperties /// public List? assignList { get; set; } + /// + /// 是否抄送发起人. + /// + public bool isInitiatorCopy { get; set; } + #region 人员 /// diff --git a/workflow/Tnb.WorkFlow.Entitys/Model/Properties/StartProperties.cs b/workflow/Tnb.WorkFlow.Entitys/Model/Properties/StartProperties.cs index ebc241c3..5521dbed 100644 --- a/workflow/Tnb.WorkFlow.Entitys/Model/Properties/StartProperties.cs +++ b/workflow/Tnb.WorkFlow.Entitys/Model/Properties/StartProperties.cs @@ -69,7 +69,7 @@ public class StartProperties /// /// 打印id. /// - public string? printId { get; set; } + public List printId { get; set; } = new List(); /// /// 是否评论. diff --git a/workflow/Tnb.WorkFlow.Interfaces/Manager/IFlowTaskManager.cs b/workflow/Tnb.WorkFlow.Interfaces/Manager/IFlowTaskManager.cs index a873a6ff..95131c81 100644 --- a/workflow/Tnb.WorkFlow.Interfaces/Manager/IFlowTaskManager.cs +++ b/workflow/Tnb.WorkFlow.Interfaces/Manager/IFlowTaskManager.cs @@ -155,4 +155,18 @@ public interface IFlowTaskManager /// 经办id. /// Task RejectNodeList(string taskOperatorId); + + /// + /// 挂起. + /// + /// 任务参数. + /// + Task Suspend(FlowTaskParamter flowTaskParamter); + + /// + /// 恢复. + /// + /// 任务参数. + /// + Task Restore(FlowTaskParamter flowTaskParamter); } diff --git a/workflow/Tnb.WorkFlow.Interfaces/Repository/IFlowTaskRepository.cs b/workflow/Tnb.WorkFlow.Interfaces/Repository/IFlowTaskRepository.cs index 32b31be1..c5e0dfe6 100644 --- a/workflow/Tnb.WorkFlow.Interfaces/Repository/IFlowTaskRepository.cs +++ b/workflow/Tnb.WorkFlow.Interfaces/Repository/IFlowTaskRepository.cs @@ -584,9 +584,9 @@ public interface IFlowTaskRepository /// 驳回数据创建. /// /// - /// + /// /// - Task CreateRejectData(string taskId, string taskNodeIds); + Task CreateRejectData(string taskId, string taskNodeId); /// /// 驳回数据重启. diff --git a/workflow/Tnb.WorkFlow/Manager/FlowTaskManager.cs b/workflow/Tnb.WorkFlow/Manager/FlowTaskManager.cs index ada2d26c..009f9f21 100644 --- a/workflow/Tnb.WorkFlow/Manager/FlowTaskManager.cs +++ b/workflow/Tnb.WorkFlow/Manager/FlowTaskManager.cs @@ -83,6 +83,29 @@ public class FlowTaskManager : IFlowTaskManager, ITransient { output.flowFormInfo = await _flowTaskRepository.GetFlowFromModel(flowTaskParamter.startProperties.formId); output.flowTaskInfo = flowTaskParamter.flowTaskEntity.Adapt(); + output.flowFormInfo.propertyJson = _runService.GetVisualDevModelDataConfig(output.flowFormInfo.propertyJson, output.flowFormInfo.tableJson, (int)output.flowFormInfo.formType); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) + { + // 判断子流程的父流程是否被挂起 + if (!flowTaskParamter.flowTaskEntity.ParentId.Equals("0")) + { + if (!await _flowTaskRepository.AnyFlowTask(x => x.Id == flowTaskParamter.flowTaskEntity.ParentId && x.DeleteMark == null && x.Suspend == 1)) + { + output.flowTaskInfo.suspend = false; + output.flowTaskInfo.status = 6; + } + else + { + output.flowTaskInfo.status = 6; + output.flowTaskInfo.suspend = true; + } + } + else + { + output.flowTaskInfo.suspend = false; + output.flowTaskInfo.status = 6; + } + } output.flowTaskOperatorRecordList = await _flowTaskRepository.GetTaskOperatorRecordModelList(id); if (flowTaskParamter.flowTaskNodeEntityList.IsNotEmptyOrNull()) { @@ -139,6 +162,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient { var startProperties = output.flowTemplateInfo.flowTemplateJson.ToObject().properties.ToObject(); output.flowFormInfo = await _flowTaskRepository.GetFlowFromModel(startProperties.formId); + output.flowFormInfo.propertyJson = _runService.GetVisualDevModelDataConfig(output.flowFormInfo.propertyJson, output.flowFormInfo.tableJson, (int)output.flowFormInfo.formType); output.formData = await _runService.GetFlowFormDataDetails(output.flowFormInfo.id, id); output.formOperates = startProperties.formOperates; output.approversProperties = startProperties.ToObject(); @@ -161,8 +185,8 @@ public class FlowTaskManager : IFlowTaskManager, ITransient try { var flowTaskEntity = new FlowTaskEntity(); - flowTaskSubmitModel.isDev = _flowTaskRepository.IsDevFlow(flowTaskSubmitModel.flowId);//是否为功能表单 var flowJsonInfo = _flowTaskRepository.GetFlowTemplateInfo(flowTaskSubmitModel.flowId); + flowTaskSubmitModel.isDev = _flowTaskRepository.IsDevFlow(flowJsonInfo.templateId);//是否为功能表单 flowTaskSubmitModel.flowJsonModel = flowJsonInfo; await flowTaskOtherUtil.GetFlowTitle(flowTaskSubmitModel); // 表单数据处理 @@ -178,7 +202,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient flowTaskEntity.FlowUrgent = flowTaskSubmitModel.flowUrgent; flowTaskEntity.FlowId = flowJsonInfo.id; flowTaskEntity.FlowCode = flowJsonInfo.enCode; - flowTaskEntity.FlowName = flowJsonInfo.fullName; + flowTaskEntity.FlowName = flowJsonInfo.flowName; flowTaskEntity.FlowType = flowJsonInfo.type; flowTaskEntity.FlowCategory = flowJsonInfo.category; flowTaskEntity.FlowTemplateJson = flowJsonInfo.flowTemplateJson; @@ -205,6 +229,8 @@ public class FlowTaskManager : IFlowTaskManager, ITransient if (!(flowTaskSubmitModel.isDev && flowTaskSubmitModel.status == 1 && flowTaskSubmitModel.parentId.Equals("0"))) { flowTaskEntity = _flowTaskRepository.GetTaskFirstOrDefault(flowTaskSubmitModel.id); + if (flowTaskEntity.Suspend == 1) + throw Oops.Oh(ErrorCode.WF0046); if (flowTaskEntity.Status == FlowTaskStatusEnum.Handle.ParseToInt() && flowTaskSubmitModel.approvaUpType == 0) throw Oops.Oh(ErrorCode.WF0031); flowTaskEntity.FlowUrgent = flowTaskSubmitModel.flowUrgent; @@ -328,9 +354,6 @@ public class FlowTaskManager : IFlowTaskManager, ITransient foreach (var item in messageDic.Keys) { var userList = messageDic[item].Select(x => x.HandleId).ToList(); - // 委托人 - //var delegateUserIds = await _flowTaskRepository.GetDelegateUserIds(userList, flowTaskParamter.flowTaskEntity.TemplateId); - //userList = userList.Union(delegateUserIds).ToList(); bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, messageDic[item], 2); await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.waitMsgConfig, bodyDic.Keys.ToList(), flowTaskParamter, "MBXTLC001", bodyDic); // 超时提醒 @@ -345,7 +368,13 @@ public class FlowTaskManager : IFlowTaskManager, ITransient #endregion bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, new List() { flowTaskParamter.flowTaskEntity.CreatorUserId }, null, 1); - await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.endMsgConfig, new List() { flowTaskParamter.flowTaskEntity.CreatorUserId }, flowTaskParamter, "MBXTLC0010", bodyDic); + await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.endMsgConfig, new List() { flowTaskParamter.flowTaskEntity.CreatorUserId }, flowTaskParamter, "MBXTLC010", bodyDic); + } + + //委托发起消息 + if (flowTaskSubmitModel.isDelegate) + { + await flowTaskMsgUtil.SendDelegateMsg("发起", flowTaskParamter.flowTaskEntity.CreatorUserId, flowTaskParamter.flowTaskEntity.FlowName); } #endregion @@ -379,7 +408,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient if (flowTaskParamter.flowTaskOperatorEntity.Id.IsNotEmptyOrNull() && FlowTaskNodeTypeEnum.approver.ParseToString().Equals(flowTaskParamter.flowTaskNodeEntity.NodeType)) { var fEntity = _flowTaskRepository.GetFlowFromEntity(flowTaskParamter.flowTaskNodeEntity.FormId); - await _runService.SaveFlowFormData(fEntity, flowTaskParamter.formData.ToJsonString(), flowTaskParamter.flowTaskEntity.Id, true); + await _runService.SaveFlowFormData(fEntity, flowTaskParamter.formData.ToJsonString(), flowTaskParamter.flowTaskEntity.Id, flowTaskParamter.flowTaskEntity.FlowId, true); } } if (flowTaskParamter.flowTaskEntity.RejectDataId.IsNullOrEmpty()) @@ -416,7 +445,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient if (flowTaskParamter.approversProperties.counterSign == 0 || flowTaskOtherUtil.IsAchievebilProportion(flowTaskParamter, 1)) { var fEntity = _flowTaskRepository.GetFlowFromEntity(flowTaskParamter.flowTaskNodeEntity.FormId); - await _runService.SaveFlowFormData(fEntity, flowTaskParamter.formData.ToJsonString(), flowTaskParamter.flowTaskEntity.Id, true); + await _runService.SaveFlowFormData(fEntity, flowTaskParamter.formData.ToJsonString(), flowTaskParamter.flowTaskEntity.Id, flowTaskParamter.flowTaskEntity.FlowId, true); var rejectDataEntity = await _flowTaskRepository.GetRejectDataInfo(flowTaskParamter.flowTaskEntity.RejectDataId); await _flowTaskRepository.UpdateRejectData(rejectDataEntity); _db.CommitTran(); @@ -508,6 +537,12 @@ public class FlowTaskManager : IFlowTaskManager, ITransient bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, new List() { flowTaskParamter.flowTaskEntity.CreatorUserId }, null, 1); await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.endMsgConfig, new List() { flowTaskParamter.flowTaskEntity.CreatorUserId }, flowTaskParamter, "MBXTLC010", bodyDic); } + + //委托审批消息 + if (flowTaskParamter.flowTaskOperatorEntity.HandleId.IsNotEmptyOrNull() && !_userManager.UserId.Equals(flowTaskParamter.flowTaskOperatorEntity.HandleId)) + { + await flowTaskMsgUtil.SendDelegateMsg("审批", flowTaskParamter.flowTaskOperatorEntity.HandleId, flowTaskParamter.flowTaskEntity.FlowName); + } } #endregion @@ -605,10 +640,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient foreach (var item in messageDic.Keys) { var userList = messageDic[item].Select(x => x.HandleId).ToList(); - //委托人 - var delegateUserIds = await _flowTaskRepository.GetDelegateUserIds(userList, flowTaskParamter.flowTaskEntity.TemplateId); - //userList = userList.Union(delegateUserIds).ToList(); - //bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, messageDic[item], 2); + bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, messageDic[item], 2); await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.waitMsgConfig, bodyDic.Keys.ToList(), flowTaskParamter, "MBXTLC001", bodyDic); await flowTaskMsgUtil.Alerts(flowTaskParamter.approversProperties.rejectMsgConfig, bodyDic.Keys.ToList(), flowTaskParamter, "MBXTLC003", bodyDic); // 超时提醒 @@ -617,6 +649,12 @@ public class FlowTaskManager : IFlowTaskManager, ITransient #endregion } + + //委托审批消息 + if (!_userManager.UserId.Equals(flowTaskParamter.flowTaskOperatorEntity.HandleId)) + { + await flowTaskMsgUtil.SendDelegateMsg("审批", flowTaskParamter.flowTaskOperatorEntity.HandleId, flowTaskParamter.flowTaskEntity.FlowName); + } //退回到发起. if (flowTaskParamter.flowTaskEntity.Status == FlowTaskStatusEnum.Reject.ParseToInt()) { @@ -660,7 +698,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient if (flowTaskParamter.flowTaskEntity.RejectDataId.IsNotEmptyOrNull()) throw Oops.Oh(ErrorCode.WF0046); //撤回经办记录 if (flowTaskOperatorRecordEntity.Status == -1) - throw Oops.Oh(ErrorCode.WF0011); + throw Oops.Oh(ErrorCode.WF0051); //所有经办 var flowTaskOperatorEntityList = await _flowTaskRepository.GetTaskOperatorList(x => x.TaskId == flowTaskOperatorRecordEntity.TaskId && x.State == "0"); #region 撤回判断 @@ -673,7 +711,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient //撤回节点下一节点已操作 var recallNextOperatorList = flowTaskOperatorEntityList.FindAll(x => flowTaskParamter.flowTaskNodeEntity.NodeNext.Contains(x.NodeCode)); if (recallNextOperatorList.FindAll(x => x.Completion == 1 && x.HandleStatus == 1).Count > 0 || flowTaskParamter.flowTaskNodeEntityList.Any(x => flowTaskParamter.flowTaskNodeEntity.NodeNext.Contains(x.NodeCode) && x.Completion == 1)) - throw Oops.Oh(ErrorCode.WF0011); + throw Oops.Oh(ErrorCode.WF0050); #endregion #region 经办修改 @@ -931,6 +969,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient if (flowTaskParamter.flowTaskOperatorEntity == null) throw Oops.Oh(ErrorCode.COM1005); flowTaskParamter.flowTaskOperatorEntity.HandleId = flowTaskParamter.freeApproverUserId; + flowTaskParamter.flowTaskOperatorEntity.CreatorTime = DateTime.Now; var isOk = await _flowTaskRepository.UpdateTaskOperator(flowTaskParamter.flowTaskOperatorEntity); if (!isOk) throw Oops.Oh(ErrorCode.WF0007); @@ -941,9 +980,6 @@ public class FlowTaskManager : IFlowTaskManager, ITransient _db.CommitTran(); var userList = new List() { flowTaskParamter.freeApproverUserId }; - //委托人 - //var delegateUserIds = await _flowTaskRepository.GetDelegateUserIds(userList, flowTaskParamter.flowTaskEntity.TemplateId); - //userList = userList.Union(delegateUserIds).ToList(); var bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, new List() { flowTaskParamter.flowTaskOperatorEntity }, 2); await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.waitMsgConfig, bodyDic.Keys.ToList(), flowTaskParamter, "MBXTLC001", bodyDic); // 超时提醒 @@ -981,10 +1017,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient foreach (var item in messageDic.Keys) { var userList = messageDic[item].Select(x => x.HandleId).ToList(); - //委托人 - //var delegateUserIds = await _flowTaskRepository.GetDelegateUserIds(userList, flowTaskParamter.flowTaskEntity.TemplateId); - //userList = userList.Union(delegateUserIds).ToList(); - bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, new List() { flowTaskParamter.flowTaskOperatorEntity }, 2); + bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, messageDic[item], 2); await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.waitMsgConfig, bodyDic.Keys.ToList(), flowTaskParamter, "MBXTLC001", bodyDic); } } @@ -1027,7 +1060,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient var flowTaskOperator = await _flowTaskRepository.GetTaskOperatorInfo(id); if (flowTaskOperator.ParentId.IsNotEmptyOrNull() && type == 0) return output;// 加签不弹窗 // 选择分支:初始审批人前加签不算审批 后加签算审批 - var flowTaskOperatorList = await _flowTaskRepository.GetTaskOperatorList(x => x.TaskId == flowTaskOperator.TaskId && x.TaskNodeId == flowTaskOperator.TaskNodeId && x.State == "0" && (SqlFunc.IsNullOrEmpty(x.ParentId)|| !SqlFunc.IsNullOrEmpty(x.RollbackId))); + var flowTaskOperatorList = await _flowTaskRepository.GetTaskOperatorList(x => x.TaskId == flowTaskOperator.TaskId && x.TaskNodeId == flowTaskOperator.TaskNodeId && x.State == "0" && (SqlFunc.IsNullOrEmpty(x.ParentId) || !SqlFunc.IsNullOrEmpty(x.RollbackId))); var flowTaskNodeEntity = await _flowTaskRepository.GetTaskNodeInfo(flowTaskOperator.TaskNodeId); flowTaskNodeEntityList = await _flowTaskRepository.GetTaskNodeList(x => x.State == "0" && x.TaskId == flowTaskOperator.TaskId); #region 审批驳回撤回还原选择分支父节点下一节点数据 @@ -1054,10 +1087,10 @@ public class FlowTaskManager : IFlowTaskManager, ITransient return flowTaskUserUtil.GetCandidateItems(nextNodeEntity, flowHandleModel); } await flowTaskUserUtil.GetCandidates(output, nextNodeEntityList, flowTaskNodeEntityList); - //return output; // 弹窗类型 1:条件分支弹窗(包含候选人) 2:候选人弹窗 3:无弹窗 var branchType = output.Count > 0 ? (output.Any(x => x.isBranchFlow) ? 1 : 2) : 3; - if (!isCom && branchType == 1) + // 无弹窗:1.条件分支且未达到会签比例,2.任务冻结驳回 + if ((!isCom && branchType == 1) || await _flowTaskRepository.AnyFlowTask(x => x.Id == flowHandleModel.id && !SqlFunc.IsNullOrEmpty(x.RejectDataId))) { branchType = 3; } @@ -1070,10 +1103,9 @@ public class FlowTaskManager : IFlowTaskManager, ITransient /// /// 流程id. /// - public async Task NodeSelector(string templateId) + public async Task NodeSelector(string flowId) { - var flowJsonEntity = _flowTaskRepository.GetFlowTemplateJsonInfo(x => x.TemplateId == templateId && x.EnabledMark == 1 && x.DeleteMark == null); - var flowJsonModel = _flowTaskRepository.GetFlowTemplateInfo(flowJsonEntity.Id); + var flowJsonModel = _flowTaskRepository.GetFlowTemplateInfo(flowId); flowTemplateUtil.Load(flowJsonModel, null, string.Empty); var taskNodeList = flowTemplateUtil.flowTaskNodeEntityList; return taskNodeList.FindAll(x => FlowTaskNodeTypeEnum.approver.ParseToString().Equals(x.NodeType)).Select(x => new { id = x.NodeCode, fullName = x.NodePropertyJson.ToObject().title }).ToList(); @@ -1201,6 +1233,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient public async Task Validation(string taskOperatorId, FlowHandleModel flowHandleModel) { var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByOperatorId(taskOperatorId, flowHandleModel); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); if (flowTaskParamter.flowTaskOperatorEntity.IsNullOrEmpty() || flowTaskParamter.flowTaskOperatorEntity.Completion != 0 || flowTaskParamter.flowTaskOperatorEntity.State == "-1") throw Oops.Oh(ErrorCode.WF0030); if (flowTaskParamter.flowTaskEntity.IsNullOrEmpty() || flowTaskParamter.flowTaskEntity.Status != 1 || flowTaskParamter.flowTaskEntity.DeleteMark.IsNotEmptyOrNull()) @@ -1217,7 +1250,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient /// /// 变更/复活. /// - /// 变更/复活参数. + /// 任务参数. /// public async Task Change(FlowTaskParamter flowTaskParamter) { @@ -1287,9 +1320,6 @@ public class FlowTaskManager : IFlowTaskManager, ITransient return flowTaskParamter.errorNodeList; } - // 清空变更/复活流程候选人数据 - //_flowTaskRepository.DeleteFlowCandidates(x => x.TaskId == changeNode.TaskId); - //await _flowTaskRepository.DeleteTaskOperatorRecord(x => x.TaskId == changeNode.TaskId); await _flowTaskRepository.DeleteTaskOperatorRecord(x => x.TaskId == changeNode.TaskId && changeNodeNextIds.Contains(x.TaskNodeId)); foreach (var item in await _flowTaskRepository.GetTaskNodeList(x => x.TaskId == flowTaskParamter.flowTaskEntity.Id)) { @@ -1340,9 +1370,6 @@ public class FlowTaskManager : IFlowTaskManager, ITransient foreach (var item in messageDic.Keys) { var userList = messageDic[item].Select(x => x.HandleId).ToList(); - //委托人 - //var delegateUserIds = await _flowTaskRepository.GetDelegateUserIds(userList, flowTaskParamter.flowTaskEntity.TemplateId); - //userList = userList.Union(delegateUserIds).ToList(); var bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, new List() { flowTaskParamter.flowTaskOperatorEntity }, 2); await flowTaskMsgUtil.Alerts(flowTaskParamter.startProperties.waitMsgConfig, bodyDic.Keys.ToList(), flowTaskParamter, "MBXTLC001", bodyDic); await TimeoutOrRemind(flowTaskParamter, item, messageDic[item]);// 超时提醒 @@ -1384,6 +1411,63 @@ public class FlowTaskManager : IFlowTaskManager, ITransient return new { list = upNodeCodeList, isLastAppro = true }; } } + + /// + /// 挂起. + /// + /// 任务参数. + /// + public async Task Suspend(FlowTaskParamter flowTaskParamter) + { + flowTaskParamter.flowTaskEntity.Suspend = 1; + await _flowTaskRepository.UpdateTask(flowTaskParamter.flowTaskEntity); + + #region 流转记录 + await flowTaskOtherUtil.CreateOperatorRecode(flowTaskParamter, 11); + #endregion + + if (!flowTaskParamter.suspend) + { + var childTask = await _flowTaskRepository.GetTaskList(x => flowTaskParamter.flowTaskEntity.Id == x.ParentId && x.DeleteMark == null); + foreach (var item in childTask) + { + var childFlowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(item.Id, null); + childFlowTaskParamter.handleOpinion = flowTaskParamter.handleOpinion; + childFlowTaskParamter.signImg = flowTaskParamter.signImg; + childFlowTaskParamter.suspend = flowTaskParamter.suspend; + childFlowTaskParamter.fileList = flowTaskParamter.fileList; + await this.Suspend(childFlowTaskParamter); + } + } + } + + /// + /// 恢复. + /// + /// 任务参数. + /// + public async Task Restore(FlowTaskParamter flowTaskParamter) + { + flowTaskParamter.flowTaskEntity.Suspend = null; + await _flowTaskRepository.UpdateTask(flowTaskParamter.flowTaskEntity); + + #region 流转记录 + await flowTaskOtherUtil.CreateOperatorRecode(flowTaskParamter, 12); + #endregion + + var childTask = await _flowTaskRepository.GetTaskList(x => flowTaskParamter.flowTaskEntity.Id == x.ParentId && x.DeleteMark == null); + foreach (var item in childTask) + { + if (item.Suspend == 1) + { + var childFlowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(item.Id, null); + childFlowTaskParamter.handleOpinion = flowTaskParamter.handleOpinion; + childFlowTaskParamter.signImg = flowTaskParamter.signImg; + childFlowTaskParamter.fileList = flowTaskParamter.fileList; + await this.Restore(childFlowTaskParamter); + } + } + } #endregion #region PrivateMethod @@ -1599,6 +1683,9 @@ public class FlowTaskManager : IFlowTaskManager, ITransient isAsync = childTaskPro.isAsync }; var childTaskEntity = await this.Save(flowTaskSubmitModel); + var flowTaskParamter = new FlowTaskParamter { flowTaskEntity = childTaskEntity }; + var bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, new List { item }, null, 1); + await flowTaskMsgUtil.Alerts(childTaskPro.launchMsgConfig, new List { item }, flowTaskParamter, "MBXTLC011", bodyDic); childTaskId.Add(childTaskEntity.Id); } return childTaskId; @@ -1755,7 +1842,7 @@ public class FlowTaskManager : IFlowTaskManager, ITransient flowTaskSubmitModel.formData = formDic; } var fEntity = _flowTaskRepository.GetFlowFromEntity(formId); - await _runService.SaveFlowFormData(fEntity, flowTaskSubmitModel.formData.ToJsonString(), id, isUpdate); + await _runService.SaveFlowFormData(fEntity, flowTaskSubmitModel.formData.ToJsonString(), id, flowTaskSubmitModel.flowId, isUpdate); // 功能流程提交 if (flowTaskSubmitModel.isDev && flowTaskSubmitModel.id.IsNotEmptyOrNull() && flowTaskSubmitModel.status == 0) { @@ -1868,35 +1955,39 @@ public class FlowTaskManager : IFlowTaskManager, ITransient /// private async Task NotifyEvent(ApproversProperties approPro, FlowTaskParamter flowTaskParamter, string nodeId, int count, bool isTimeOut) { - var msgEncode = isTimeOut ? "MBXTLC009" : "MBXTLC008"; - var msgReMark = isTimeOut ? "超时" : "提醒"; - var msgConfig = isTimeOut ? approPro.overTimeMsgConfig : approPro.noticeMsgConfig; - var funcConfig = isTimeOut ? approPro.overTimeFuncConfig : approPro.noticeFuncConfig; - var timeOutConfig = isTimeOut ? approPro.overTimeConfig : approPro.noticeConfig; - // 通知 - if (timeOutConfig.overNotice) + var flowTask = await _flowTaskRepository.GetTaskInfo(flowTaskParamter.flowTaskEntity.Id); + if (flowTask.IsNotEmptyOrNull() && flowTask.Suspend != 1) { - var operatorList = await _flowTaskRepository.GetTaskOperatorList(x => x.TaskId == flowTaskParamter.flowTaskEntity.Id && x.TaskNodeId == nodeId && x.Completion == 0 && x.State != "-1"); - var userList = operatorList.Select(x => x.HandleId).ToList(); - var remark = string.Format("现在时间:{3},节点{0}:第{1}次{2}通知", nodeId, count, msgReMark, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); - Console.WriteLine(remark); - var bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, operatorList, 2, remark); - if (msgConfig.on > 0) + var msgEncode = isTimeOut ? "MBXTLC009" : "MBXTLC008"; + var msgReMark = isTimeOut ? "超时" : "提醒"; + var msgConfig = isTimeOut ? approPro.overTimeMsgConfig : approPro.noticeMsgConfig; + var funcConfig = isTimeOut ? approPro.overTimeFuncConfig : approPro.noticeFuncConfig; + var timeOutConfig = isTimeOut ? approPro.overTimeConfig : approPro.noticeConfig; + // 通知 + if (timeOutConfig.overNotice) { - await flowTaskMsgUtil.Alerts(msgConfig, userList, flowTaskParamter, msgEncode, bodyDic); + var operatorList = await _flowTaskRepository.GetTaskOperatorList(x => x.TaskId == flowTaskParamter.flowTaskEntity.Id && x.TaskNodeId == nodeId && x.Completion == 0 && x.State != "-1"); + var userList = operatorList.Select(x => x.HandleId).ToList(); + var remark = string.Format("现在时间:{3},节点{0}:第{1}次{2}通知", nodeId, count, msgReMark, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + Console.WriteLine(remark); + var bodyDic = flowTaskMsgUtil.GetMesBodyText(flowTaskParamter, userList, operatorList, 2, remark); + if (msgConfig.on > 0) + { + await flowTaskMsgUtil.Alerts(msgConfig, userList, flowTaskParamter, msgEncode, bodyDic); + } + } + // 事件 + if (funcConfig.on && timeOutConfig.overEvent && timeOutConfig.overEventTime == count) + { + Console.WriteLine(string.Format("开始执行{0}事件,现在时间:{1}", msgReMark, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); + await flowTaskMsgUtil.RequestEvents(funcConfig, flowTaskParamter); + } + //自动审批 + if (isTimeOut && timeOutConfig.overAutoApproveTime == count && timeOutConfig.overAutoApprove) + { + Console.WriteLine("开始自动审批,现在时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + await AutoAudit(flowTaskParamter, true); } - } - // 事件 - if (funcConfig.on && timeOutConfig.overEvent && timeOutConfig.overEventTime == count) - { - Console.WriteLine(string.Format("开始执行{0}事件,现在时间:{1}", msgReMark, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); - await flowTaskMsgUtil.RequestEvents(funcConfig, flowTaskParamter); - } - //自动审批 - if (isTimeOut && timeOutConfig.overAutoApproveTime == count && timeOutConfig.overAutoApprove) - { - Console.WriteLine("开始自动审批,现在时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); - await AutoAudit(flowTaskParamter, true); } } diff --git a/workflow/Tnb.WorkFlow/Manager/FlowTaskMsgUtil.cs b/workflow/Tnb.WorkFlow/Manager/FlowTaskMsgUtil.cs index dc6ad48e..f4ea1ecf 100644 --- a/workflow/Tnb.WorkFlow/Manager/FlowTaskMsgUtil.cs +++ b/workflow/Tnb.WorkFlow/Manager/FlowTaskMsgUtil.cs @@ -61,7 +61,9 @@ public class FlowTaskMsgUtil //默认消息 if (msgConfig.on == 3) { - await _sendMessageService.SendMessageDefult(enCode, users, flowTaskParamter.flowTaskEntity.FullName, bodyDic); + var crUser =await _usersService.GetUserName(flowTaskParamter.flowTaskEntity.CreatorUserId, false); + var flowName = _flowTaskRepository.GetFlowTemplateJsonInfo(x => x.Id == flowTaskParamter.flowTaskEntity.FlowId).FullName; + await _sendMessageService.SendMessageDefult(enCode, users, crUser, flowName, bodyDic); } } @@ -162,8 +164,7 @@ public class FlowTaskMsgUtil { foreach (var item in flowTaskOperatorEntities) { - var value = new - { + var value = new { enCode = flowTaskParamter.flowTaskEntity.FlowCode, flowId = flowTaskParamter.flowTaskEntity.FlowId, status = type == 1 ? 0 : 1, @@ -183,8 +184,7 @@ public class FlowTaskMsgUtil } else { - var value = new - { + var value = new { enCode = flowTaskParamter.flowTaskEntity.FlowCode, flowId = flowTaskParamter.flowTaskEntity.FlowId, status = type == 1 ? 0 : 1, @@ -214,5 +214,16 @@ public class FlowTaskMsgUtil } } + /// + /// 委托消息通知. + /// + /// 委托类型:发起,审批. + /// 通知人员. + /// 流程名. + /// + public async Task SendDelegateMsg(string delegateType, string ToUserId, string flowName) + { + await _sendMessageService.SendMessageDelegate(delegateType, ToUserId, flowName); + } #endregion } diff --git a/workflow/Tnb.WorkFlow/Manager/FlowTaskNodeUtil.cs b/workflow/Tnb.WorkFlow/Manager/FlowTaskNodeUtil.cs index 6650ada5..39d1f7ee 100644 --- a/workflow/Tnb.WorkFlow/Manager/FlowTaskNodeUtil.cs +++ b/workflow/Tnb.WorkFlow/Manager/FlowTaskNodeUtil.cs @@ -340,7 +340,7 @@ public class FlowTaskNodeUtil // 保存驳回现有数据. if (flowTaskParamter.approversProperties.rejectType == 2) { - flowTaskParamter.flowTaskEntity.RejectDataId = await _flowTaskRepository.CreateRejectData(flowTaskParamter.flowTaskEntity.Id, flowTaskParamter.flowTaskEntity.ThisStepId); + flowTaskParamter.flowTaskEntity.RejectDataId = await _flowTaskRepository.CreateRejectData(flowTaskParamter.flowTaskEntity.Id, flowTaskParamter.flowTaskNodeEntity.Id); } // 驳回节点下所有节点. var rejectNodeNextAllList = new List(); diff --git a/workflow/Tnb.WorkFlow/Manager/FlowTaskOtherUtil.cs b/workflow/Tnb.WorkFlow/Manager/FlowTaskOtherUtil.cs index 77a6daeb..cb054ccf 100644 --- a/workflow/Tnb.WorkFlow/Manager/FlowTaskOtherUtil.cs +++ b/workflow/Tnb.WorkFlow/Manager/FlowTaskOtherUtil.cs @@ -88,8 +88,6 @@ public class FlowTaskOtherUtil var rollBackOprtator = await _flowTaskRepository.GetTaskOperatorInfo(flowTaskParamter.flowTaskOperatorEntity.RollbackId); if (rollBackOprtator.IsNotEmptyOrNull()) { - //rollBackOprtator.State = "0"; - //await _flowTaskRepository.UpdateTaskOperator(rollBackOprtator); rollBackOprtator.Id = SnowflakeIdHelper.NextId(); rollBackOprtator.State = "0"; rollBackOprtator.Completion = 0; @@ -98,15 +96,6 @@ public class FlowTaskOtherUtil rollBackOprtator.HandleTime = null; await _flowTaskRepository.CreateTaskOperator(rollBackOprtator); } - //else - //{ - // rollBackOprtator.Id = SnowflakeIdHelper.NextId(); - // rollBackOprtator.State = "0"; - // rollBackOprtator.Completion = 0; - // rollBackOprtator.HandleStatus = 0; - // rollBackOprtator.HandleTime = null; - // await _flowTaskRepository.CreateTaskOperator(rollBackOprtator); - //} } flowTaskParamter.flowTaskOperatorEntity.HandleStatus = handleStatus; flowTaskParamter.flowTaskOperatorEntity.Completion = 1; @@ -263,7 +252,21 @@ public class FlowTaskOtherUtil { FlowTaskOperatorRecordEntity flowTaskOperatorRecordEntity = new FlowTaskOperatorRecordEntity(); flowTaskOperatorRecordEntity.HandleTime = DateTime.Now; - flowTaskOperatorRecordEntity.HandleId = handleStatus == 2 ? flowTaskParamter.flowTaskEntity.CreatorUserId : _userManager.UserId; + if (handleStatus == 2) + { + flowTaskOperatorRecordEntity.HandleId = flowTaskParamter.flowTaskEntity.CreatorUserId; + } + else + { + if (flowTaskParamter.flowTaskOperatorEntity.IsNotEmptyOrNull() && flowTaskParamter.flowTaskOperatorEntity.HandleId.IsNotEmptyOrNull()) + { + flowTaskOperatorRecordEntity.HandleId = flowTaskParamter.flowTaskOperatorEntity.HandleId; + } + else + { + flowTaskOperatorRecordEntity.HandleId = _userManager.UserId; + } + } flowTaskOperatorRecordEntity.HandleStatus = handleStatus; flowTaskOperatorRecordEntity.HandleOpinion = flowTaskParamter.handleOpinion; flowTaskOperatorRecordEntity.SignImg = flowTaskParamter.signImg; @@ -361,15 +364,11 @@ public class FlowTaskOtherUtil { try { - //modified by PhilPan - if (jobj[timeOutConfig.formField].Type == Newtonsoft.Json.Linq.JTokenType.Integer) + var value=jobj[timeOutConfig.formField].ToString(); + if (!DateTime.TryParse(value, out dt)) { dt = jobj[timeOutConfig.formField].ParseToLong().TimeStampToDateTime(); } - else - { - dt = jobj[timeOutConfig.formField].ToString().ParseToDateTime(); - } } catch (Exception) { diff --git a/workflow/Tnb.WorkFlow/Manager/FlowTaskUserUtil.cs b/workflow/Tnb.WorkFlow/Manager/FlowTaskUserUtil.cs index bb0bdb8d..89d3762e 100644 --- a/workflow/Tnb.WorkFlow/Manager/FlowTaskUserUtil.cs +++ b/workflow/Tnb.WorkFlow/Manager/FlowTaskUserUtil.cs @@ -138,7 +138,7 @@ public class FlowTaskUserUtil try { var Token = _userManager.ToKen.IsNotEmptyOrNull() ? _userManager.ToKen : _cacheManager.Get>(CommonConst.CACHEKEYONLINEUSER + _userManager.TenantId).Find(x => x.userId == _userManager.UserId).token; - var data = await approversProperties.getUserUrl.SetHeaders(new { Authorization = Token }).GetAsStringAsync(); + var data = await approversProperties.getUserUrl.SetHeaders(new { Authorization = Token }).SetBody(flowTaskParamter.formData).PostAsStringAsync(); var result = data.ToObject>(); if (result.IsNotEmptyOrNull()) { @@ -250,15 +250,13 @@ public class FlowTaskUserUtil { startProperties.errorRule = "3"; } - // 创建人 - var userId = type == 0 ? _userManager.UserId : flowTaskParamter.flowTaskEntity.CreatorUserId; var handleIds = await GetFlowUserId(flowTaskParamter, approverPropertiers, nextFlowTaskNodeEntity); if (handleIds.Count == 0 && isShuntNodeCompletion) { switch (startProperties.errorRule) { case "1": - handleIds.Add("admin"); + handleIds.Add(_userManager.GetAdminUserId()); break; case "2": if ((await _usersService.GetUserListByExp(x => startProperties.errorRuleUser.Contains(x.Id) && x.DeleteMark == null && x.EnabledMark == 1)).Any()) @@ -267,7 +265,7 @@ public class FlowTaskUserUtil } else { - handleIds.Add("admin"); + handleIds.Add(_userManager.GetAdminUserId()); } break; case "3": @@ -291,7 +289,7 @@ public class FlowTaskUserUtil && x.NodePropertyJson.ToObject().assigneeType == 7); if (falag) { - handleIds.Add("admin"); + handleIds.Add(_userManager.GetAdminUserId()); } else { @@ -370,6 +368,14 @@ public class FlowTaskUserUtil var userList = await GetUserDefined(flowTaskParamter.approversProperties, 1); userList = await GetExtraRuleUsers(userList, flowTaskParamter.approversProperties.extraCopyRule, flowTaskParamter.flowTaskOperatorEntity.TaskId); circulateUserList = circulateUserList.Union(userList).ToList(); + if (flowTaskParamter.approversProperties.isInitiatorCopy) + { + circulateUserList.Add(flowTaskParamter.flowTaskEntity.CreatorUserId); + //if (flowTaskParamter.flowTaskEntity.DelegateUser.IsNotEmptyOrNull()) + //{ + // circulateUserList.Add(flowTaskParamter.flowTaskEntity.DelegateUser); + //} + } } foreach (var item in circulateUserList.Distinct()) { @@ -555,14 +561,14 @@ public class FlowTaskUserUtil } else { - childTaskCrUserList.Add("admin"); + childTaskCrUserList.Add(_userManager.GetAdminUserId()); } break; case "6": childTaskCrUserList.Add(flowTaskParamter.flowTaskEntity.CreatorUserId); break; default: - childTaskCrUserList.Add("admin"); + childTaskCrUserList.Add(_userManager.GetAdminUserId()); break; } } diff --git a/workflow/Tnb.WorkFlow/Manager/FlowTemplateUtil.cs b/workflow/Tnb.WorkFlow/Manager/FlowTemplateUtil.cs index b704c1f5..42513703 100644 --- a/workflow/Tnb.WorkFlow/Manager/FlowTemplateUtil.cs +++ b/workflow/Tnb.WorkFlow/Manager/FlowTemplateUtil.cs @@ -1,4 +1,5 @@ using System.Text; +using JNPF.Common.Const; using JNPF.Common.Core.Manager; using JNPF.Common.Extension; using JNPF.Common.Models.WorkFlow; @@ -97,8 +98,11 @@ public class FlowTemplateUtil } else { - string formId = item.propertyJson.formId; - flowTaskNodeEntity.FormId = formId.IsNotEmptyOrNull() ? formId : defaultFormId; + if (!"timer".Equals(item.type)) + { + string formId = item.propertyJson.formId; + flowTaskNodeEntity.FormId = formId.IsNotEmptyOrNull() ? formId : defaultFormId; + } } flowTaskNodeEntityList.Add(flowTaskNodeEntity); } @@ -416,10 +420,10 @@ public class FlowTemplateUtil if (flowNodeWhereModel.fieldValueType.ParseToInt() == 2) { //数组类型控件 - var jnpfKeyList = new List() { "cascader", "comSelect", "address", "currOrganize" }; + var jnpfKeyList = new List() { JnpfKeyConst.CASCADER, JnpfKeyConst.COMSELECT, JnpfKeyConst.ADDRESS, JnpfKeyConst.CURRORGANIZE }; if (jnpfKeyList.Contains(flowNodeWhereModel.jnpfKey) && flowNodeWhereModel.fieldValue.Count > 0) { - if (flowNodeWhereModel.jnpfKey.Equals("currOrganize")) + if (flowNodeWhereModel.jnpfKey.Equals(JnpfKeyConst.CURRORGANIZE)) { value = flowNodeWhereModel.fieldValue[flowNodeWhereModel.fieldValue.Count - 1]; } @@ -438,7 +442,7 @@ public class FlowTemplateUtil value = _userManager.UserId; } - if ("time".Equals(flowNodeWhereModel.jnpfKey)) + if (JnpfKeyConst.TIME.Equals(flowNodeWhereModel.jnpfKey)) { formValue = formValue.Replace(":", string.Empty); value = value.Replace(":", string.Empty); @@ -446,7 +450,7 @@ public class FlowTemplateUtil } else { - value = GetConditionValue(flowNodeWhereModel.fieldValueType.ParseToInt(), formData, flowNodeWhereModel.fieldValue, taskId, flowNodeWhereModel.jnpfKey); + value = GetConditionValue(flowNodeWhereModel.fieldValueType.ParseToInt(), formData, flowNodeWhereModel.fieldValue, taskId, flowNodeWhereModel.fieldValueJnpfKey); } if (symbol.Equals("=") || symbol.Equals("<>")) @@ -527,8 +531,8 @@ public class FlowTemplateUtil if (formData[field].IsNotEmptyOrNull()) { conditionValue = formData[field].ToString(); - SysWidgetFormValue(taskId, jnpfKey, ref conditionValue); } + SysWidgetFormValue(taskId, jnpfKey, ref conditionValue); } } } @@ -581,34 +585,34 @@ public class FlowTemplateUtil var creatorUser = _usersService.GetInfoByUserId(taskEntity.CreatorUserId); switch (jnpfKey) { - case "createUser": + case JnpfKeyConst.CREATEUSER: formValue = taskEntity.CreatorUserId; break; - case "modifyUser": + case JnpfKeyConst.MODIFYUSER: if (taskEntity.LastModifyUserId.IsNotEmptyOrNull()) { formValue = _userManager.UserId; } break; - case "currOrganize": + case JnpfKeyConst.CURRORGANIZE: if (creatorUser.OrganizeId.IsNotEmptyOrNull()) { formValue = creatorUser.OrganizeId; } break; - case "createTime": + case JnpfKeyConst.CREATETIME: formValue = ((DateTime)taskEntity.CreatorTime).ParseToUnixTime().ToString(); break; - case "modifyTime": + case JnpfKeyConst.MODIFYTIME: if (taskEntity.LastModifyTime.IsNotEmptyOrNull()) { formValue = DateTime.Now.ParseToUnixTime().ToString(); } break; - case "currPosition": + case JnpfKeyConst.CURRPOSITION: if (creatorUser.PositionId.IsNotEmptyOrNull()) { formValue = creatorUser.PositionId; @@ -621,26 +625,26 @@ public class FlowTemplateUtil { switch (jnpfKey) { - case "createUser": + case JnpfKeyConst.CREATEUSER: formValue = _userManager.UserId; break; - case "modifyUser": + case JnpfKeyConst.MODIFYUSER: formValue = " "; break; - case "currOrganize": + case JnpfKeyConst.CURRORGANIZE: if (_userManager.User.OrganizeId.IsNotEmptyOrNull()) { formValue = _userManager.User.OrganizeId; } break; - case "createTime": + case JnpfKeyConst.CREATETIME: formValue = DateTime.Now.ParseToUnixTime().ToString(); break; - case "modifyTime": + case JnpfKeyConst.MODIFYTIME: formValue = "0"; break; - case "currPosition": + case JnpfKeyConst.CURRPOSITION: if (_userManager.User.PositionId.IsNotEmptyOrNull()) { formValue = _userManager.User.PositionId; diff --git a/workflow/Tnb.WorkFlow/Repository/FlowTaskRepository.cs b/workflow/Tnb.WorkFlow/Repository/FlowTaskRepository.cs index eaa5b4f4..0f01c60f 100644 --- a/workflow/Tnb.WorkFlow/Repository/FlowTaskRepository.cs +++ b/workflow/Tnb.WorkFlow/Repository/FlowTaskRepository.cs @@ -1,5 +1,4 @@ -using System.Linq.Expressions; -using JNPF.Common.Core.Manager; +using JNPF.Common.Core.Manager; using JNPF.Common.Extension; using JNPF.Common.Filter; using JNPF.Common.Models.WorkFlow; @@ -13,7 +12,6 @@ using JNPF.WorkFlow.Entitys; using JNPF.WorkFlow.Entitys.Dto.FlowBefore; using JNPF.WorkFlow.Entitys.Dto.FlowLaunch; using JNPF.WorkFlow.Entitys.Dto.FlowMonitor; -using JNPF.WorkFlow.Entitys.Dto.FlowTemplate; using JNPF.WorkFlow.Entitys.Dto.WorkFlowForm.LeaveApply; using JNPF.WorkFlow.Entitys.Dto.WorkFlowForm.SalesOrder; using JNPF.WorkFlow.Entitys.Entity; @@ -23,6 +21,7 @@ using JNPF.WorkFlow.Entitys.Model.Properties; using JNPF.WorkFlow.Interfaces.Repository; using Mapster; using SqlSugar; +using System.Linq.Expressions; namespace JNPF.WorkFlow.Repository; @@ -38,7 +37,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient /// /// 构造. /// - /// + /// /// /// public FlowTaskRepository( @@ -72,11 +71,17 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient if (!input.creatorUserId.IsNullOrEmpty()) whereLambda = whereLambda.And(x => x.creatorUserId == input.creatorUserId); if (!input.flowCategory.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.flowCategory == input.flowCategory); + whereLambda = whereLambda.And(x => input.flowCategory.Contains(x.flowCategory)); if (!input.creatorUserId.IsNullOrEmpty()) whereLambda = whereLambda.And(m => m.creatorUserId.Contains(input.creatorUserId)); - if (!input.flowId.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.templateId == input.flowId); + if (!input.templateId.IsNullOrEmpty()) + whereLambda = whereLambda.And(x => x.templateId == input.templateId); + var flowJosnEntity = _repository.AsSugarClient().Queryable().First(x => x.Id == input.flowId && x.DeleteMark == null); + if (flowJosnEntity.IsNotEmptyOrNull()) + { + var flowIds = _repository.AsSugarClient().Queryable().Where(x => x.GroupId == flowJosnEntity.GroupId).Select(x => x.Id).ToList(); + whereLambda = whereLambda.And(x => flowIds.Contains(x.flowId)); + } if (!input.status.IsNullOrEmpty()) whereLambda = whereLambda.And(x => x.status == input.status); if (!input.flowUrgent.IsNullOrEmpty()) @@ -105,9 +110,11 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient startTime = a.StartTime, thisStep = a.ThisStep, userName = SqlFunc.Subqueryable().Where(u => u.Id == a.CreatorUserId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), - status = a.Status, + status = SqlFunc.IIF(a.Suspend == 1, 6, a.Status), sortCode = a.SortCode, templateId = a.TemplateId, + suspend = a.Suspend, + flowVersion = a.FlowVersion, }).MergeTable().Where(whereLambda).OrderBy(a => a.sortCode) .OrderBy(a => a.creatorTime, OrderByType.Desc) .ToPagedListAsync(input.currentPage, input.pageSize); @@ -137,9 +144,15 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient whereLambda = whereLambda.And(a => SqlFunc.Between(a.creatorTime, startTime, endTime)); } if (!input.flowCategory.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.flowCategory == input.flowCategory); - if (!input.flowId.IsNullOrEmpty())//flowId为流程主表id - whereLambda = whereLambda.And(x => x.templateId == input.flowId); + whereLambda = whereLambda.And(x => input.flowCategory.Contains(x.flowCategory)); + if (!input.templateId.IsNullOrEmpty()) + whereLambda = whereLambda.And(x => x.templateId == input.templateId); + var flowJosnEntity = _repository.AsSugarClient().Queryable().First(x => x.Id == input.flowId && x.DeleteMark == null); + if (flowJosnEntity.IsNotEmptyOrNull()) + { + var flowIds = _repository.AsSugarClient().Queryable().Where(x => x.GroupId == flowJosnEntity.GroupId).Select(x => x.Id).ToList(); + whereLambda = whereLambda.And(x => flowIds.Contains(x.flowId)); + } if (!input.status.IsNullOrEmpty()) whereLambda = whereLambda.And(x => x.status == input.status); if (!input.flowUrgent.IsNullOrEmpty()) @@ -156,7 +169,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient thisStep = a.ThisStep, flowUrgent = a.FlowUrgent, enCode = a.EnCode, - status = a.Status, + status = SqlFunc.IIF(a.Suspend == 1, 6, a.Status), flowCategory = a.FlowCategory, flowCode = a.FlowCode, completion = a.Completion, @@ -165,7 +178,8 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient flowId = a.FlowId, templateId = a.TemplateId, sortCode = a.SortCode, - delegateUser = a.DelegateUser + delegateUser = a.DelegateUser, + suspend = a.Suspend, }).MergeTable().Where(whereLambda).OrderBy(a => a.status).OrderBy(a => a.startTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } @@ -185,9 +199,15 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient whereLambda = whereLambda.And(a => SqlFunc.Between(a.creatorTime, startTime, endTime)); } if (input.flowCategory.IsNotEmptyOrNull()) - whereLambda = whereLambda.And(x => x.flowCategory == input.flowCategory); - if (input.flowId.IsNotEmptyOrNull()) - whereLambda = whereLambda.And(x => x.templateId == input.flowId); + whereLambda = whereLambda.And(x => input.flowCategory.Contains(x.flowCategory)); + if (input.templateId.IsNotEmptyOrNull()) + whereLambda = whereLambda.And(x => x.templateId == input.templateId); + var flowJosnEntity = _repository.AsSugarClient().Queryable().First(x => x.Id == input.flowId && x.DeleteMark == null); + if (flowJosnEntity.IsNotEmptyOrNull()) + { + var flowIds = _repository.AsSugarClient().Queryable().Where(x => x.GroupId == flowJosnEntity.GroupId).Select(x => x.Id).ToList(); + whereLambda = whereLambda.And(x => flowIds.Contains(x.flowId)); + } if (input.keyword.IsNotEmptyOrNull()) whereLambda = whereLambda.And(m => m.enCode.Contains(input.keyword) || m.fullName.Contains(input.keyword)); if (input.creatorUserId.IsNotEmptyOrNull()) @@ -198,7 +218,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient // 经办审核 var list1 = _repository.AsSugarClient().Queryable( (a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId)) - .Where((a, b) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" + .Where((a, b) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.Suspend == null && b.HandleId == _userManager.UserId && b.CreatorTime < SqlFunc.GetDate()) .Select((a, b) => new FlowBeforeListOutput() { @@ -221,6 +241,8 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient startTime = a.CreatorTime, completion = a.Completion, nodeName = b.NodeName, + delegateUser = null, + suspend = a.Suspend, templateId = a.TemplateId, }); @@ -228,7 +250,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient var list2 = _repository.AsSugarClient().Queryable( (a, b, c) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId, JoinType.Left, (a.TemplateId == SqlFunc.ToString(c.FlowId) || SqlFunc.ToString(c.FlowName) == "全部流程") && c.EndTime > DateTime.Now)) - .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" + .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.Suspend == null && b.HandleId == c.UserId && c.Type == "1" && c.ToUserId == _userManager.UserId && c.DeleteMark == null && c.EnabledMark == 1 && c.EndTime > DateTime.Now && c.StartTime < DateTime.Now && b.CreatorTime < SqlFunc.GetDate()) @@ -240,7 +262,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient thisStep = a.ThisStep, thisStepId = b.TaskNodeId, flowCategory = a.FlowCategory, - fullName = SqlFunc.MergeString(a.FullName, "(", SqlFunc.Subqueryable().Where(u => u.Id == c.UserId).Select(u => u.RealName), "的委托)"), + fullName = a.FullName, flowName = a.FlowName, status = a.Status, id = b.Id, @@ -253,6 +275,8 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient startTime = a.CreatorTime, completion = a.Completion, nodeName = b.NodeName, + delegateUser = c.ToUserId, + suspend = a.Suspend, templateId = a.TemplateId, }); var output = await _repository.AsSugarClient().UnionAll(list1, list2).Where(whereLambda).MergeTable().OrderBy(x => x.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); @@ -274,9 +298,11 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient whereLambda = whereLambda.And(a => SqlFunc.Between(a.creatorTime, startTime, endTime)); } if (!input.flowCategory.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.flowCategory == input.flowCategory); + whereLambda = whereLambda.And(x => input.flowCategory.Contains(x.flowCategory)); + if (!input.templateId.IsNullOrEmpty()) + whereLambda = whereLambda.And(x => x.templateId == input.templateId); if (!input.flowId.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.templateId == input.flowId); + whereLambda = whereLambda.And(x => x.flowId == input.flowId); if (!input.keyword.IsNullOrEmpty()) whereLambda = whereLambda.And(m => m.enCode.Contains(input.keyword) || m.fullName.Contains(input.keyword)); if (!input.creatorUserId.IsNullOrEmpty()) @@ -288,7 +314,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient //经办审核 var list1 = _repository.AsSugarClient().Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId, JoinType.Left, b.TaskNodeId == c.Id)) - .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" + .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.Suspend == null && b.CreatorTime < SqlFunc.GetDate() && b.HandleId == _userManager.UserId && a.IsBatch == 1) .Select((a, b, c) => new FlowBeforeListOutput() @@ -316,12 +342,14 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient flowVersion = a.FlowVersion, nodeCode = b.NodeCode, templateId = a.TemplateId, + delegateUser = null, + suspend = a.Suspend, }); //委托审核 var list2 = _repository.AsSugarClient().Queryable((a, b, c, d) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId, JoinType.Left, (a.TemplateId == SqlFunc.ToString(c.FlowId) || SqlFunc.ToString(c.FlowName) == "全部流程") && c.EndTime > DateTime.Now, JoinType.Left, b.TaskNodeId == d.Id)) - .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.IsBatch == 1 + .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.IsBatch == 1 && a.Suspend == null && b.HandleId == c.UserId && c.Type == "1" && b.CreatorTime < SqlFunc.GetDate() && c.ToUserId == _userManager.UserId && c.DeleteMark == null && c.EnabledMark == 1 && c.EndTime > DateTime.Now && c.StartTime < DateTime.Now) .Select((a, b, c, d) => new FlowBeforeListOutput() @@ -332,7 +360,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient thisStep = a.ThisStep, thisStepId = b.TaskNodeId, flowCategory = a.FlowCategory, - fullName = SqlFunc.MergeString(a.FullName, "(", SqlFunc.Subqueryable().Where(u => u.Id == c.UserId).Select(u => u.RealName), "的委托)"), + fullName = a.FullName, flowName = a.FlowName, status = a.Status, id = b.Id, @@ -349,6 +377,8 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient flowVersion = a.FlowVersion, nodeCode = b.NodeCode, templateId = a.TemplateId, + delegateUser = c.ToUserId, + suspend = a.Suspend, }); var output = await _repository.AsSugarClient().UnionAll(list1, list2).Where(whereLambda).MergeTable().OrderBy(x => x.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(output); @@ -370,9 +400,15 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient whereLambda = whereLambda.And(a => SqlFunc.Between(a.creatorTime, startTime, endTime)); } if (!input.flowCategory.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.flowCategory == input.flowCategory); - if (input.flowId.IsNotEmptyOrNull()) - whereLambda = whereLambda.And(x => x.templateId == input.flowId); + whereLambda = whereLambda.And(x => input.flowCategory.Contains(x.flowCategory)); + if (input.templateId.IsNotEmptyOrNull()) + whereLambda = whereLambda.And(x => x.templateId == input.templateId); + var flowJosnEntity = _repository.AsSugarClient().Queryable().First(x => x.Id == input.flowId && x.DeleteMark == null); + if (flowJosnEntity.IsNotEmptyOrNull()) + { + var flowIds = _repository.AsSugarClient().Queryable().Where(x => x.GroupId == flowJosnEntity.GroupId).Select(x => x.Id).ToList(); + whereLambda = whereLambda.And(x => flowIds.Contains(x.flowId)); + } if (!input.creatorUserId.IsNullOrEmpty()) whereLambda = whereLambda.And(m => m.creatorUserId.Contains(input.creatorUserId)); if (!input.keyword.IsNullOrEmpty()) @@ -393,7 +429,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient thisStep = c.ThisStep, thisStepId = b.TaskNodeId, flowCategory = c.FlowCategory, - fullName = b.HandleId == d.HandleId || c.Id == null ? c.FullName : SqlFunc.Subqueryable().Where(u => u.Id == d.HandleId).Select(u => SqlFunc.MergeString(c.FullName, "(", u.RealName, "的委托)")), + fullName = c.FullName, flowName = c.FlowName, status = b.HandleStatus, id = b.Id, @@ -404,6 +440,9 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient processId = c.ProcessId, flowUrgent = c.FlowUrgent, startTime = c.CreatorTime, + templateId = c.TemplateId, + delegateUser = b.HandleId == d.HandleId || c.Id == null ? null : d.HandleId, + suspend = c.Suspend, }).MergeTable().Where(whereLambda).OrderBy(a => a.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } @@ -423,16 +462,22 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient whereLambda = whereLambda.And(a => SqlFunc.Between(a.creatorTime, startTime, endTime)); } if (!input.flowCategory.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.flowCategory == input.flowCategory); - if (!input.flowId.IsNullOrEmpty()) - whereLambda = whereLambda.And(x => x.templateId == input.flowId); + whereLambda = whereLambda.And(x => input.flowCategory.Contains(x.flowCategory)); + if (!input.templateId.IsNullOrEmpty()) + whereLambda = whereLambda.And(x => x.templateId == input.templateId); + var flowJosnEntity = _repository.AsSugarClient().Queryable().First(x => x.Id == input.flowId && x.DeleteMark == null); + if (flowJosnEntity.IsNotEmptyOrNull()) + { + var flowIds = _repository.AsSugarClient().Queryable().Where(x => x.GroupId == flowJosnEntity.GroupId).Select(x => x.Id).ToList(); + whereLambda = whereLambda.And(x => flowIds.Contains(x.flowId)); + } if (!input.creatorUserId.IsNullOrEmpty()) whereLambda = whereLambda.And(m => m.creatorUserId.Contains(input.creatorUserId)); if (!input.keyword.IsNullOrEmpty()) whereLambda = whereLambda.And(m => m.enCode.Contains(input.keyword) || m.fullName.Contains(input.keyword)); if (!input.flowUrgent.IsNullOrEmpty()) whereLambda = whereLambda.And(x => x.flowUrgent == input.flowUrgent); - var list = await _repository.AsSugarClient().Queryable((a, b, c, d) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId, JoinType.Left, a.CreatorUserId == c.Id, JoinType.Left, a.FlowId == d.Id)).Where((a, b) => b.ObjectId == _userManager.UserId).Select((a, b, c, d) => new FlowBeforeListOutput() + var list = await _repository.AsSugarClient().Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId, JoinType.Left, a.CreatorUserId == c.Id)).Where((a, b) => b.ObjectId == _userManager.UserId).Select((a, b, c) => new FlowBeforeListOutput() { enCode = a.EnCode, creatorUserId = a.CreatorUserId, @@ -449,9 +494,10 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient flowCode = a.FlowCode, flowId = a.FlowId, processId = a.ProcessId, - formType = d.FormType, flowUrgent = a.FlowUrgent, startTime = a.CreatorTime, + suspend = a.Suspend, + templateId = a.TemplateId, }).MergeTable().Where(whereLambda).OrderBy(x => x.creatorTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } @@ -462,12 +508,11 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient /// public async Task BatchFlowSelector() { - var list = (await GetWaitList()).FindAll(x => x.IsBatch == 1); + var list = (await GetWaitList()).FindAll(x => x.IsBatch == 1 && x.Suspend == null); var output = new List(); foreach (var item in list.GroupBy(x => x.TemplateId)) { - output.Add(new - { + output.Add(new { id = item.Key, fullName = string.Format("{0}({1})", item.FirstOrDefault().FlowName, item.Count()), count = item.Count() @@ -561,7 +606,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient { // 经办审核 var list1 = _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId)) - .Where((a, b) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" + .Where((a, b) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.Suspend == null && b.CreatorTime < SqlFunc.GetDate() && b.HandleId == _userManager.UserId) .Select((a, b) => new FlowTaskEntity() { @@ -587,13 +632,15 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient LastModifyUserId = a.LastModifyUserId, IsBatch = a.IsBatch, TemplateId = a.TemplateId, + DelegateUser = null, + Suspend = a.Suspend, }); // 委托审核 var list2 = _repository.AsSugarClient().Queryable((a, b, c, d) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId, JoinType.Left, (a.TemplateId == SqlFunc.ToString(c.FlowId) || SqlFunc.ToString(c.FlowName) == "全部流程"), JoinType.Left, c.UserId == d.Id)).Where((a, b, c) => - a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" + a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.Suspend == null && b.CreatorTime < SqlFunc.GetDate() && b.HandleId == c.UserId && c.Type == "1" && c.ToUserId == _userManager.UserId && c.DeleteMark == null && c.EndTime > DateTime.Now && c.StartTime < DateTime.Now) .Select((a, b, c, d) => new FlowTaskEntity() @@ -602,11 +649,11 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient ParentId = a.ParentId, ProcessId = a.ProcessId, EnCode = a.EnCode, - FullName = SqlFunc.MergeString(a.FullName, "(", d.RealName, "的委托)"), + FullName = a.FullName, FlowUrgent = a.FlowUrgent, FlowId = a.FlowId, - FlowName = a.FlowName, FlowCode = a.FlowCode, + FlowName = a.FlowName, FlowCategory = a.FlowCategory, StartTime = a.StartTime, EndTime = a.EndTime, @@ -620,6 +667,8 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient LastModifyUserId = a.LastModifyUserId, IsBatch = a.IsBatch, TemplateId = a.TemplateId, + DelegateUser = c.ToUserId, + Suspend = a.Suspend, }); return await _repository.AsSugarClient().UnionAll(list1, list2).MergeTable().ToListAsync(); } @@ -632,7 +681,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient { // 经办审核 var list1 = _repository.AsSugarClient().Queryable((a, b) => - new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId)).Where((a, b) => a.Status == 1 && a.DeleteMark == null + new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId)).Where((a, b) => a.Status == 1 && a.DeleteMark == null && a.Suspend == null && b.Completion == 0 && b.State == "0" && b.CreatorTime < SqlFunc.GetDate() && b.HandleId == _userManager.UserId) .Select((a, b) => new PortalWaitListModel() { @@ -645,20 +694,21 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient taskNodeId = b.TaskNodeId, taskOperatorId = b.Id, creatorTime = b.CreatorTime, - type = 2 + type = 2, + delegateUser = null, }); // 委托审核 var list2 = _repository.AsSugarClient().Queryable((a, b, c, d) => new JoinQueryInfos(JoinType.Left, a.Id == b.TaskId, JoinType.Left, (a.TemplateId == SqlFunc.ToString(c.FlowId) || SqlFunc.ToString(c.FlowName) == "全部流程"), JoinType.Left, c.UserId == d.Id)) - .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" + .Where((a, b, c) => a.Status == 1 && a.DeleteMark == null && b.Completion == 0 && b.State == "0" && a.Suspend == null && b.CreatorTime < SqlFunc.GetDate() && b.HandleId == c.UserId && c.Type == "1" && c.ToUserId == _userManager.UserId && c.DeleteMark == null && c.EndTime > DateTime.Now && c.StartTime < DateTime.Now) .Select((a, b, c, d) => new PortalWaitListModel() { id = b.Id, - fullName = SqlFunc.MergeString(a.FullName, "(", d.RealName, "的委托)"), + fullName = a.FullName, enCode = a.EnCode, flowId = a.FlowId, status = a.Status, @@ -666,7 +716,8 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient taskNodeId = b.TaskNodeId, taskOperatorId = b.Id, creatorTime = b.CreatorTime, - type = 2 + type = 2, + delegateUser = c.ToUserId, }); return await _repository.AsSugarClient().UnionAll(list1, list2).MergeTable().ToListAsync(); } @@ -686,7 +737,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient ParentId = a.ParentId, ProcessId = a.ProcessId, EnCode = a.EnCode, - FullName = b.HandleId == c.HandleId || c.Id == null ? a.FullName : SqlFunc.MergeString(a.FullName, "(", d.RealName, "的委托)"), + FullName = a.FullName, FlowUrgent = a.FlowUrgent, FlowId = a.FlowId, FlowCode = a.FlowCode, @@ -719,7 +770,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient } /// - /// 流程信息 . + /// 流程信息. /// /// /// @@ -735,8 +786,9 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient flowTemplateJson = a.FlowTemplateJson, type = b.Type, enCode = b.EnCode, - fullName = b.FullName, + fullName = a.FullName, category = b.Category, + flowName = b.FullName }).First(); } @@ -1337,7 +1389,7 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient status = a.Status, userName = SqlFunc.Subqueryable().Where(u => u.Id == a.HandleId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), operatorId = SqlFunc.Subqueryable().Where(u => u.Id == a.OperatorId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), - creatorTime = b.CreatorTime, + creatorTime = SqlFunc.IsNullOrEmpty(b.CreatorTime) ? a.HandleTime : b.CreatorTime, fileList = a.FileList }).ToListAsync(); } @@ -1599,15 +1651,20 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient /// 驳回数据创建. /// /// - /// + /// /// - public async Task CreateRejectData(string taskId, string taskNodeIds) + public async Task CreateRejectData(string taskId, string taskNodeId) { var entity = new FlowRejectDataEntity(); entity.Id = SnowflakeIdHelper.NextId(); - entity.TaskJson = GetTaskFirstOrDefault(taskId).ToJsonString(); + #region 解决mysql字段长度太小 + var taskEntity = GetTaskFirstOrDefault(taskId); + taskEntity.FlowFormContentJson = null; + taskEntity.FlowTemplateJson = null; + #endregion + entity.TaskJson = taskEntity.ToJsonString(); entity.TaskNodeJson = (await GetTaskNodeList(taskId)).ToJsonString(); - entity.TaskOperatorJson = (await GetTaskOperatorList(x => x.TaskId == taskId && x.State != "-1" && SqlFunc.IsNullOrEmpty(x.ParentId) && taskNodeIds.Contains(x.NodeCode))).ToJsonString(); + entity.TaskOperatorJson = (await GetTaskOperatorList(x => x.TaskId == taskId && x.State != "-1" && SqlFunc.IsNullOrEmpty(x.ParentId) && x.TaskNodeId == taskNodeId)).ToJsonString(); await _repository.AsSugarClient().GetSimpleClient().InsertAsync(entity); return entity.Id; } @@ -1620,6 +1677,11 @@ public class FlowTaskRepository : IFlowTaskRepository, ITransient public async Task UpdateRejectData(FlowRejectDataEntity entity) { var taskEntity = entity.TaskJson.ToObject(); + #region 解决mysql字段长度太小 + var thisTaskEntity = GetTaskFirstOrDefault(taskEntity.Id); + taskEntity.FlowFormContentJson = thisTaskEntity.FlowFormContentJson; + taskEntity.FlowTemplateJson = thisTaskEntity.FlowTemplateJson; + #endregion var taskNodeEntityList = entity.TaskNodeJson.ToObject>(); var taskOperatorEntityList = entity.TaskOperatorJson.ToObject>(); foreach (var item in taskOperatorEntityList) diff --git a/workflow/Tnb.WorkFlow/Service/FlowBeforeService.cs b/workflow/Tnb.WorkFlow/Service/FlowBeforeService.cs index ea118f3c..b4a66a95 100644 --- a/workflow/Tnb.WorkFlow/Service/FlowBeforeService.cs +++ b/workflow/Tnb.WorkFlow/Service/FlowBeforeService.cs @@ -10,6 +10,7 @@ using JNPF.FriendlyException; using JNPF.WorkFlow.Entitys.Dto.FlowBefore; using JNPF.WorkFlow.Entitys.Enum; using JNPF.WorkFlow.Entitys.Model; +using JNPF.WorkFlow.Entitys.Model.Properties; using JNPF.WorkFlow.Interfaces.Manager; using JNPF.WorkFlow.Interfaces.Repository; using Microsoft.AspNetCore.Mvc; @@ -59,12 +60,32 @@ public class FlowBeforeService : IDynamicApiController, ITransient case "4": return await _flowTaskRepository.GetBatchWaitList(input); default: - return PageResult.SqlSugarPageResult(new SqlSugarPagedList()); + var pageList = new SqlSugarPagedList() + { + list = new List(), + pagination = new Pagination() + { + CurrentPage = input.currentPage, + PageSize = input.pageSize, + Total = 0 + } + }; + return PageResult.SqlSugarPageResult(pageList); } } catch (Exception ex) { - return PageResult.SqlSugarPageResult(new SqlSugarPagedList()); + var pageList = new SqlSugarPagedList() + { + list = new List(), + pagination = new Pagination() + { + CurrentPage = input.currentPage, + PageSize = input.pageSize, + Total = 0 + } + }; + return PageResult.SqlSugarPageResult(pageList); } } @@ -149,7 +170,7 @@ public class FlowBeforeService : IDynamicApiController, ITransient } /// - /// 批量审批流程列表. + /// 批量审批流程分类列表. /// /// [HttpGet("BatchFlowSelector")] @@ -158,15 +179,36 @@ public class FlowBeforeService : IDynamicApiController, ITransient return await _flowTaskRepository.BatchFlowSelector(); } + /// + /// 批量审批流程列表. + /// + /// + /// + [HttpGet("BatchFlowJsonList/{templateId}")] + public async Task BatchFlowJsonList(string templateId) + { + var list = (await _flowTaskRepository.GetWaitList()).FindAll(x => x.IsBatch == 1 && x.TemplateId == templateId); + var output = new List(); + foreach (var item in list) + { + var flowJson = _flowTaskRepository.GetFlowTemplateJsonInfo(x => x.Id == item.FlowId && x.DeleteMark == null); + if (flowJson.IsNotEmptyOrNull()) + { + output.Add(new { id = flowJson.Id, fullName =string.Format("{0}(v{1})", flowJson.FullName, flowJson.Version), flowTemplateJson= flowJson.FlowTemplateJson }); + } + } + return output.Distinct(); + } + /// /// 批量审批节点列表. /// /// 流程id. /// - [HttpGet("NodeSelector/{templateId}")] - public async Task NodeSelector(string templateId) + [HttpGet("NodeSelector/{flowId}")] + public async Task NodeSelector(string flowId) { - return await _flowTaskManager.NodeSelector(templateId); + return await _flowTaskManager.NodeSelector(flowId); } /// @@ -231,6 +273,39 @@ public class FlowBeforeService : IDynamicApiController, ITransient { return await _flowTaskManager.RejectNodeList(taskOperatorId); } + + /// + /// 子流程详情. + /// + /// 节点id. + /// + [HttpGet("SubFlowInfo/{taskNodeId}")] + public async Task SubFlowInfo(string taskNodeId) + { + var output = new List(); + var taskNodeEntity = await _flowTaskRepository.GetTaskNodeInfo(taskNodeId); + if (FlowTaskNodeTypeEnum.subFlow.ParseToString().Equals(taskNodeEntity.NodeType)) + { + var childProp = taskNodeEntity.NodePropertyJson.ToObject(); + foreach (var item in childProp.childTaskId) + { + var childTaskInfo = await _flowTaskManager.GetFlowBeforeInfo(item, childProp.flowId, null, null); + output.Add(childTaskInfo); + } + } + return output; + } + + /// + /// 挂起任务是否存在异步子流程. + /// + /// 任务id. + /// + [HttpGet("Suspend/{taskId}")] + public async Task Suspend(string taskId) + { + return await _flowTaskRepository.AnyFlowTask(x => x.ParentId == taskId && x.IsAsync == 1 && x.DeleteMark == null); + } #endregion #region POST @@ -258,8 +333,13 @@ public class FlowBeforeService : IDynamicApiController, ITransient public async Task Reject(string taskOperatorId, [FromBody] FlowHandleModel flowHandleModel) { var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByOperatorId(taskOperatorId, flowHandleModel); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); if (_flowTaskManager.IsSubFlowUpNode(flowTaskParamter)) throw Oops.Oh(ErrorCode.WF0019); + if (flowHandleModel.rejectType.IsNotEmptyOrNull()) + { + flowTaskParamter.approversProperties.rejectType = flowHandleModel.rejectType.ParseToInt(); + } return await _flowTaskManager.Reject(flowTaskParamter); } @@ -277,6 +357,7 @@ public class FlowBeforeService : IDynamicApiController, ITransient if (await _flowTaskRepository.AnyFlowTask(x => x.ParentId == flowTaskOperatorRecord.TaskId && x.Status != FlowTaskStatusEnum.Cancel.ParseToInt() && x.DeleteMark == null)) throw Oops.Oh(ErrorCode.WF0018); var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByOperatorId(flowTaskOperatorRecord.TaskOperatorId, flowHandleModel); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); await _flowTaskManager.Recall(flowTaskParamter, flowTaskOperatorRecord); } @@ -290,6 +371,7 @@ public class FlowBeforeService : IDynamicApiController, ITransient public async Task Cancel(string taskId, [FromBody] FlowHandleModel flowHandleModel) { var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(taskId, flowHandleModel); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); if (flowTaskParamter.flowTaskEntity.FlowType == 1) throw Oops.Oh(ErrorCode.WF0016); await _flowTaskManager.Cancel(flowTaskParamter); @@ -321,6 +403,7 @@ public class FlowBeforeService : IDynamicApiController, ITransient if (nodeEntity.IsNotEmptyOrNull() && nodeEntity.Count > 0) throw Oops.Oh(ErrorCode.WF0014); var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(taskId, flowHandleModel); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); flowTaskParamter.thisFlowTaskOperatorEntityList = await _flowTaskRepository.GetTaskOperatorList(x => x.State == "0" && x.NodeCode == flowHandleModel.nodeCode && x.TaskId == taskId); await _flowTaskManager.Assigned(flowTaskParamter); } @@ -336,6 +419,7 @@ public class FlowBeforeService : IDynamicApiController, ITransient public async Task SaveAudit(string taskOperatorId, [FromBody] FlowHandleModel flowHandleModel) { var flowTaskParamter = await _flowTaskManager.Validation(taskOperatorId, flowHandleModel); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); flowTaskParamter.flowTaskOperatorEntity.DraftData = flowHandleModel.formData.ToJsonString(); await _flowTaskRepository.UpdateTaskOperator(flowTaskParamter.flowTaskOperatorEntity); } @@ -381,6 +465,7 @@ public class FlowBeforeService : IDynamicApiController, ITransient public async Task Change([FromBody] FlowHandleModel flowHandleModel) { // 清除依次经办数据 + if (await _flowTaskRepository.AnyFlowTask(x => x.Id == flowHandleModel.taskId && x.Suspend == 1 && x.DeleteMark == null)) throw Oops.Oh(ErrorCode.WF0046); await _flowTaskRepository.DeleteTaskOperatorUser(flowHandleModel.taskId); _flowTaskRepository.DeleteFlowCandidates(x => x.TaskId == flowHandleModel.taskId); var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(flowHandleModel.taskId, flowHandleModel); @@ -398,5 +483,31 @@ public class FlowBeforeService : IDynamicApiController, ITransient { return await Audit(taskOperatorId, flowHandleModel); } + + /// + /// 挂起. + /// + /// 任务id. + /// 审批参数. + /// + [HttpPost("Suspend/{taskId}")] + public async Task Suspend(string taskId,[FromBody] FlowHandleModel flowHandleModel) + { + var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(taskId, flowHandleModel); + await _flowTaskManager.Suspend(flowTaskParamter); + } + + /// + /// 恢复. + /// + /// 任务id. + /// 审批参数. + /// + [HttpPost("Restore/{taskId}")] + public async Task Restore(string taskId, [FromBody] FlowHandleModel flowHandleModel) + { + var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(taskId, flowHandleModel); + await _flowTaskManager.Restore(flowTaskParamter); + } #endregion } diff --git a/workflow/Tnb.WorkFlow/Service/FlowDelegateService.cs b/workflow/Tnb.WorkFlow/Service/FlowDelegateService.cs index 0aca381a..d12b1df6 100644 --- a/workflow/Tnb.WorkFlow/Service/FlowDelegateService.cs +++ b/workflow/Tnb.WorkFlow/Service/FlowDelegateService.cs @@ -6,13 +6,13 @@ using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; +using JNPF.Message.Interfaces.Message; using JNPF.Systems.Entitys.Dto.User; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Interfaces.Permission; using JNPF.WorkFlow.Entitys.Dto.FlowDelegete; using JNPF.WorkFlow.Entitys.Dto.FlowTemplate; using JNPF.WorkFlow.Entitys.Entity; -using JNPF.WorkFlow.Interfaces.Repository; using JNPF.WorkFlow.Interfaces.Service; using Mapster; using Microsoft.AspNetCore.Mvc; @@ -29,15 +29,15 @@ public class FlowDelegateService : IDynamicApiController, ITransient { private readonly ISqlSugarRepository _repository; private readonly IFlowTemplateService _flowTemplateService; - private readonly IFlowTaskRepository _flowTaskRepository; + private readonly IMessageService _messageService; private readonly IOrganizeService _organizeService; private readonly IUserManager _userManager; - public FlowDelegateService(ISqlSugarRepository repository, IFlowTemplateService flowTemplateService, IFlowTaskRepository flowTaskRepository, IOrganizeService organizeService, IUserManager userManager) + public FlowDelegateService(ISqlSugarRepository repository, IFlowTemplateService flowTemplateService, IMessageService messageService, IOrganizeService organizeService, IUserManager userManager) { _repository = repository; _flowTemplateService = flowTemplateService; - _flowTaskRepository = flowTaskRepository; + _messageService = messageService; _organizeService = organizeService; _userManager = userManager; } @@ -72,7 +72,7 @@ public class FlowDelegateService : IDynamicApiController, ITransient else { output = await _repository.AsQueryable().Where(x => x.ToUserId == _userManager.UserId && x.DeleteMark == null) - .WhereIF(!input.keyword.IsNullOrEmpty(), m => m.FlowName.Contains(input.keyword) || m.ToUserName.Contains(input.keyword)).OrderBy(t => t.SortCode) + .WhereIF(!input.keyword.IsNullOrEmpty(), m => m.FlowName.Contains(input.keyword) || m.UserName.Contains(input.keyword)).OrderBy(t => t.SortCode) .OrderBy(x => x.CreatorTime, OrderByType.Desc).OrderByIF(!string.IsNullOrEmpty(input.keyword), t => t.LastModifyTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); } var pageList = new SqlSugarPagedList() @@ -105,76 +105,102 @@ public class FlowDelegateService : IDynamicApiController, ITransient var output = new List(); //委托给我的发起流程 var flowDelegateList = await _repository.GetListAsync(x => x.ToUserId == _userManager.UserId && x.Type == "0" && x.EndTime > DateTime.Now && x.StartTime < DateTime.Now && x.DeleteMark == null); - foreach (var item in flowDelegateList) + if (!flowDelegateList.Any()) { - var flowList = await _flowTemplateService.GetFlowFormList(input.flowType.ParseToInt(), item.UserId); - // 非全部流程 - if (item.FlowId.IsNotEmptyOrNull()) + var pageList = new SqlSugarPagedList() { - output = output.Union(flowList.FindAll(x => item.FlowId.Contains(x.templateId))).DistinctBy(x => x.id).ToList(); - } - else - { - output = output.Union(flowList).DistinctBy(x => x.id).ToList(); - } + list = output, + pagination = new Pagination() + { + CurrentPage = input.currentPage, + PageSize = input.pageSize, + Total = output.Count + } + }; + return PageResult.SqlSugarPageResult(pageList); } - if (input.keyword.IsNotEmptyOrNull()) - output = output.FindAll(o => o.fullName.Contains(input.keyword) || o.enCode.Contains(input.keyword)); - var pageList = new SqlSugarPagedList() + //foreach (var item in flowDelegateList) + //{ + // var flowList = await _flowTemplateService.GetFlowFormList(input.flowType.ParseToInt(), item.UserId); + // // 非全部流程 + // if (item.FlowId.IsNotEmptyOrNull()) + // { + // output = output.Union(flowList.FindAll(x => item.FlowId.Contains(x.templateId))).DistinctBy(x => x.id).ToList(); + // } + // else + // { + // output = output.Union(flowList).DistinctBy(x => x.id).ToList(); + // } + //} + //if (input.keyword.IsNotEmptyOrNull()) + // output = output.FindAll(o => o.fullName.Contains(input.keyword) || o.enCode.Contains(input.keyword)); + //var pageList = new SqlSugarPagedList() + //{ + // list = output.Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).ToList(), + // pagination = new Pagination() + // { + // PageIndex = input.currentPage, + // PageSize = input.pageSize, + // Total = output.Count + // } + //}; + //return PageResult.SqlSugarPageResult(pageList); + var flowIds = string.Empty; + if (!flowDelegateList.Any(x => x.FlowId.IsNullOrEmpty())) { - list = output.Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).ToList(), - pagination = new Pagination() - { - CurrentPage = input.currentPage, - PageSize = input.pageSize, - Total = output.Count - } - }; - return PageResult.SqlSugarPageResult(pageList); + flowIds = string.Join(",", flowDelegateList.Select(x => x.FlowId).ToList()); + } + var list = await _repository.AsSugarClient().Queryable() + .Where(a => a.DeleteMark == null && a.EnabledMark == 1) + .WhereIF(flowIds.IsNotEmptyOrNull(), x => flowIds.Contains(x.Id)) + .WhereIF(input.category.IsNotEmptyOrNull(), a => a.Category == input.category) + .WhereIF(input.flowType.IsNotEmptyOrNull(), a => a.Type == input.flowType) + .WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) + .Select(a => new FlowTemplateTreeOutput + { + id = a.Id, + category = a.Category, + enCode = a.EnCode, + fullName = a.FullName, + sortCode = a.SortCode, + creatorTime = a.CreatorTime, + lastModifyTime = a.LastModifyTime, + icon = a.Icon, + iconBackground = a.IconBackground, + type = a.Type, + }).MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc) + .OrderBy(a => a.lastModifyTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); + return PageResult.SqlSugarPageResult(list); } /// /// 发起流程委托人. /// - /// 请求参数. + /// 请求参数. /// [HttpGet("userList")] public async Task GetFlowList([FromQuery] string flowId) { - var output = new List(); + var userList = await _repository.AsSugarClient() + .Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, b.FlowId.Contains(a.TemplateId)||b.FlowName=="全部流程", JoinType.Left, b.UserId == c.Id)) + .Where((a, b, c) => a.Id == flowId && b.Type == "0" && b.ToUserId == _userManager.UserId && b.EndTime > DateTime.Now && b.StartTime < DateTime.Now).Select((a, b, c) => new UserListOutput + { + id = c.Id, + headIcon = SqlFunc.MergeString("/api/File/Image/userAvatar/", c.HeadIcon), + fullName = SqlFunc.MergeString(c.RealName, "/", c.Account), + organizeId = c.OrganizeId + }).Distinct().ToListAsync(); + if (!userList.Any()) + throw Oops.Oh(ErrorCode.WF0049); var orgList = _organizeService.GetOrgListTreeName(); - var flowJsonModel = _flowTaskRepository.GetFlowTemplateInfo(flowId); - // 委托给我的发起流程 - var delagateToMeList = await _repository.GetListAsync(x => x.ToUserId == _userManager.UserId && x.Type == "0" && x.EndTime > DateTime.Now && x.StartTime < DateTime.Now && x.DeleteMark == null); - foreach (var item in delagateToMeList) + foreach (var item in userList) { - var isDelagateUser = false; - if (item.IsNotEmptyOrNull()) + if (!item.id.Equals(_userManager.GetAdminUserId())) { - if (item.FlowId.IsNotEmptyOrNull()) - { - // 非全部流程 - isDelagateUser = item.FlowId.Contains(flowJsonModel.templateId); - } - else - { - // 全部流程 - var flowList = await _flowTemplateService.GetFlowFormList(flowJsonModel.type.ParseToInt(), item.UserId); - isDelagateUser = flowList.Select(x => x.id).Contains(flowId); - } - } - if (isDelagateUser) - { - UserListOutput userListOutput = new UserListOutput(); - var delagateUser = _repository.AsSugarClient().Queryable().First(x => x.Id == item.UserId && x.EnabledMark == 1 && x.DeleteMark == null); - userListOutput.id = delagateUser.Id; - userListOutput.headIcon = string.Format("/api/File/Image/userAvatar/{0}", delagateUser.HeadIcon); - userListOutput.fullName = string.Format("{0}/{1}", delagateUser.RealName, delagateUser.Account); - userListOutput.organize = orgList.FirstOrDefault(x => x.Id == delagateUser.OrganizeId).Description; - output.Add(userListOutput); + item.organize = orgList.FirstOrDefault(x => x.Id == item.organizeId).Description; } } - return new { list = output }; + return new { list = userList }; } #endregion @@ -207,6 +233,16 @@ public class FlowDelegateService : IDynamicApiController, ITransient var isOk = await _repository.AsInsertable(entity).CallEntityMethod(m => m.Create()).ExecuteCommandAsync(); if (isOk < 1) throw Oops.Oh(ErrorCode.COM1000); + + #region 委托通知 + var toUserIds = new List() { entity.ToUserId }; + var type = entity.Type == "0" ? "发起" : "审批"; + var title = string.Format("{0}委托人向您发起了{1}委托!", entity.UserName, type); + var parameter = new { type = "2" }; + var bodyDic = new Dictionary(); + bodyDic.Add(entity.ToUserId, parameter); + await _messageService.SentMessage(toUserIds, title, null, bodyDic, 2, "2"); + #endregion } /// @@ -224,6 +260,32 @@ public class FlowDelegateService : IDynamicApiController, ITransient if (!isOk) throw Oops.Oh(ErrorCode.COM1001); } + + /// + /// 结束委托. + /// + /// id. + [HttpPut("Stop/{id}")] + public async Task Create(string id) + { + var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); + if (entity == null) + throw Oops.Oh(ErrorCode.COM1005); + entity.StartTime = DateTime.Now; + entity.EndTime = DateTime.Now; + var isOk = await _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); + if (!isOk) + throw Oops.Oh(ErrorCode.COM1001); + + #region 委托通知 + var toUserIds = new List() { entity.ToUserId }; + var title = string.Format("{0}向您发起的委托已结束!", entity.UserName); + var parameter = new { type = "2" }; + var bodyDic = new Dictionary(); + bodyDic.Add(entity.ToUserId, parameter); + await _messageService.SentMessage(toUserIds, title, null, bodyDic, 2, "2"); + #endregion + } #endregion /// diff --git a/workflow/Tnb.WorkFlow/Service/FlowEngineService.cs b/workflow/Tnb.WorkFlow/Service/FlowEngineService.cs index 51342c86..802cddc3 100644 --- a/workflow/Tnb.WorkFlow/Service/FlowEngineService.cs +++ b/workflow/Tnb.WorkFlow/Service/FlowEngineService.cs @@ -1,4 +1,5 @@ -using JNPF.Common.Core.Manager; +using JNPF.Common.Const; +using JNPF.Common.Core.Manager; using JNPF.Common.Core.Manager.Files; using JNPF.Common.Enums; using JNPF.Common.Extension; @@ -225,7 +226,7 @@ public class FlowEngineService : IFlowEngineService, IDynamicApiController, ITra { var formTemplateBase = new TemplateParsingBase(entity.FormTemplateJson, entity.Tables, true); formDataFieldList = formTemplateBase.SingleFormData - .Where(x => x.__config__.jnpfKey != "relationForm" && x.__config__.jnpfKey != "relationFlow") + .Where(x => x.__config__.jnpfKey != JnpfKeyConst.RELATIONFORM && x.__config__.jnpfKey != "relationFlow") .Select(x => new FlowEngineFieldOutput() { vmodel = x.__vModel__, label = x.__config__.label }).ToList(); } @@ -543,21 +544,6 @@ public class FlowEngineService : IFlowEngineService, IDynamicApiController, ITra FormData = entity.FormTemplateJson }; var res = await _visualDevService.NoTblToTable(devEntity, mTableName); - entity.Tables = res.Tables; - entity.FormTemplateJson = res.FormData; - var entityData = await _runService.GetInfo(entity.Id); - if (entityData != null && entityData.Data != null) - { - var sqlList = _visualDevService.DataToInsertSql(mTableName, entityData.Data); - if (sqlList.Any()) - { - var link = await _flowTaskRepository.GetLinkInfo(entity.DbLinkId) ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); - foreach (var item in sqlList) - { - await _dataBaseManager.ExecuteSql(link, item); - } - } - } } #endregion } diff --git a/workflow/Tnb.WorkFlow/Service/FlowFormService.cs b/workflow/Tnb.WorkFlow/Service/FlowFormService.cs index 73fbaf77..be19f111 100644 --- a/workflow/Tnb.WorkFlow/Service/FlowFormService.cs +++ b/workflow/Tnb.WorkFlow/Service/FlowFormService.cs @@ -7,11 +7,13 @@ using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; +using JNPF.Systems.Entitys.Dto.ModuleForm; using JNPF.Systems.Entitys.Model.DataBase; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.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; @@ -163,6 +165,7 @@ public class FlowFormService : IDynamicApiController, ITransient 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); } @@ -175,19 +178,20 @@ public class FlowFormService : IDynamicApiController, ITransient [HttpGet("GetFormById/{id}")] public async Task GetFormById(string id) { - var entity = await GetInfo(id); - if (entity == null || entity.EnabledMark != 1) throw Oops.Oh(ErrorCode.COM1016); - var tempId = _repository.AsSugarClient().Queryable().Where(x => x.Id.Equals(entity.FlowId)).Select(x => x.TemplateId).First(); - if (tempId == null) throw Oops.Oh(ErrorCode.COM1016); - if (!_repository.AsSugarClient().Queryable().Where(x => x.Id.Equals(tempId) && x.EnabledMark.Equals(1)).Any()) throw Oops.Oh(ErrorCode.COM1017); - var res = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.TemplateId == b.Id)) - .Select((a, b) => new - { - id = SqlFunc.IIF(b.EnabledMark == 0, null, a.Id), - enCode = b.EnCode, - }).MergeTable().FirstAsync(a => a.id.Equals(entity.FlowId)); - if (res == null) throw Oops.Oh(ErrorCode.COM1016); - return res; + 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().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 @@ -372,6 +376,7 @@ public class FlowFormService : IDynamicApiController, ITransient Id = entity.Id, State = 1, WebType = 3, + EnableFlow = 1, FullName = entity.FullName, EnCode = entity.EnCode, FormData = entity.PropertyJson @@ -387,6 +392,22 @@ public class FlowFormService : IDynamicApiController, ITransient } + var dbLink = await _runService.GetDbLink(newEntity.DbLinkId); + var MainTable = newEntity.TableJson.ToList().Find(m => m.typeId.Equals("1")); // 主表 + if (MainTable != null) + { + if (!_dataBaseManager.IsAnyColumn(dbLink, MainTable?.table, "f_flowtaskid")) + { + var pFieldList = new List() { 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() { 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(); diff --git a/workflow/Tnb.WorkFlow/Service/FlowLaunchService.cs b/workflow/Tnb.WorkFlow/Service/FlowLaunchService.cs index 866eba2e..7a8e59ac 100644 --- a/workflow/Tnb.WorkFlow/Service/FlowLaunchService.cs +++ b/workflow/Tnb.WorkFlow/Service/FlowLaunchService.cs @@ -54,6 +54,7 @@ public class FlowLaunchService : IDynamicApiController, ITransient var entity = _flowTaskRepository.GetTaskFirstOrDefault(id); if (entity == null) throw Oops.Oh(ErrorCode.COM1005); + if (entity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); if (!entity.ParentId.Equals("0") && entity.ParentId.IsNotEmptyOrNull()) throw Oops.Oh(ErrorCode.WF0003, entity.FullName); if (entity.FlowType == 1) @@ -75,6 +76,8 @@ public class FlowLaunchService : IDynamicApiController, ITransient public async Task Revoke(string id, [FromBody] FlowHandleModel flowHandleModel) { var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(id, flowHandleModel); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); + if (await _flowTaskRepository.AnyFlowTask(x => flowTaskParamter.flowTaskEntity.Id == x.ParentId && x.DeleteMark == null && x.Suspend == 1)) throw Oops.Oh(ErrorCode.WF0046); if (flowTaskParamter.flowTaskEntity.Status != 1) throw Oops.Oh(ErrorCode.WF0011); if (flowTaskParamter.flowTaskEntity.ParentId.IsNotEmptyOrNull()&& !flowTaskParamter.flowTaskEntity.ParentId.Equals("0")) @@ -91,6 +94,7 @@ public class FlowLaunchService : IDynamicApiController, ITransient public async Task Press(string id) { var flowTaskParamter = await _flowTaskRepository.GetTaskParamterByTaskId(id, null); + if (flowTaskParamter.flowTaskEntity.Suspend == 1) throw Oops.Oh(ErrorCode.WF0046); await _flowTaskManager.Press(flowTaskParamter); } #endregion diff --git a/workflow/Tnb.WorkFlow/Service/FlowMonitorService.cs b/workflow/Tnb.WorkFlow/Service/FlowMonitorService.cs index ebd0fbf1..70d01151 100644 --- a/workflow/Tnb.WorkFlow/Service/FlowMonitorService.cs +++ b/workflow/Tnb.WorkFlow/Service/FlowMonitorService.cs @@ -51,6 +51,10 @@ public class FlowMonitorService : IDynamicApiController, ITransient if (tsakList.Any()) throw Oops.Oh(ErrorCode.WF0012, tsakList.FirstOrDefault().FullName); tsakList = await _flowTaskRepository.GetTaskList(x => ids.Contains(x.Id) && !x.ParentId.Equals("0") && !SqlFunc.IsNullOrEmpty(x.ParentId)); if (tsakList.Any()) throw Oops.Oh(ErrorCode.WF0003, tsakList.FirstOrDefault().FullName); + tsakList = await _flowTaskRepository.GetTaskList(x => ids.Contains(x.Id) && x.Suspend == 1); + if (tsakList.Any()) throw Oops.Oh(ErrorCode.WF0047, tsakList.FirstOrDefault().FullName); + tsakList = await _flowTaskRepository.GetTaskList(x => ids.Contains(x.ParentId) && x.DeleteMark == null && x.Suspend == 1); + if (tsakList.Any()) throw Oops.Oh(ErrorCode.WF0047, tsakList.FirstOrDefault().FullName); foreach (var item in input.ids.Split(",")) { var entity = _flowTaskRepository.GetTaskFirstOrDefault(item); diff --git a/workflow/Tnb.WorkFlow/Service/FlowTemplateService.cs b/workflow/Tnb.WorkFlow/Service/FlowTemplateService.cs index 9a2b233e..9eea97f7 100644 --- a/workflow/Tnb.WorkFlow/Service/FlowTemplateService.cs +++ b/workflow/Tnb.WorkFlow/Service/FlowTemplateService.cs @@ -13,6 +13,7 @@ using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.Permission; using JNPF.Systems.Interfaces.System; +using JNPF.VisualDev.Entitys; using JNPF.WorkFlow.Entitys.Dto.FlowTemplate; using JNPF.WorkFlow.Entitys.Entity; using JNPF.WorkFlow.Entitys.Model; @@ -36,7 +37,6 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, private readonly ISqlSugarRepository _repository; private readonly IFlowTaskRepository _flowTaskRepository; private readonly IDictionaryDataService _dictionaryDataService; - private readonly IUserRelationService _userRelationService; private readonly IUserManager _userManager; private readonly IFileManager _fileManager; private readonly ITenant _db; @@ -45,7 +45,6 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, ISqlSugarRepository repository, IFlowTaskRepository flowTaskRepository, IDictionaryDataService dictionaryDataService, - IUserRelationService userRelationService, IUserManager userManager, IFileManager fileManager, ISqlSugarClient context) @@ -53,7 +52,6 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, _repository = repository; _flowTaskRepository = flowTaskRepository; _dictionaryDataService = dictionaryDataService; - _userRelationService = userRelationService; _userManager = userManager; _fileManager = fileManager; _db = context.AsTenant(); @@ -70,12 +68,12 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, public async Task GetList([FromQuery] FlowTemplateListQuery input) { var objList = _flowTaskRepository.GetCurrentUserObjId(); - var list = await _repository.AsSugarClient().Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, a.Id == b.TemplateId, JoinType.Left, a.Id == c.FlowId)) - .Where((a, b) => a.DeleteMark == null && b.DeleteMark == null && b.EnabledMark == 1) - .WhereIF(_userManager.User.IsAdministrator == 0, (a, b, c) => a.CreatorUserId == _userManager.UserId || (objList.Contains(c.OperatorId) && c.Type == "2")) + var list = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.FlowId)) + .Where(a => a.DeleteMark == null) + .WhereIF(_userManager.User.IsAdministrator == 0, (a, b) => a.CreatorUserId == _userManager.UserId || (objList.Contains(b.OperatorId) && b.Type == "2")) .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, b) => new FlowTemplateListOutput + .Select(a => new FlowTemplateListOutput { category = SqlFunc.Subqueryable().Where(d => d.Id == a.Category).Select(d => d.FullName), id = a.Id, @@ -90,8 +88,6 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, lastModifyUser = SqlFunc.Subqueryable().Where(u => u.Id == a.LastModifyUserId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), sortCode = a.SortCode, type = a.Type, - visibleType = b.VisibleType, - version = b.Version, hasAssistBtn = SqlFunc.IIF((_userManager.UserId == a.CreatorUserId || _userManager.User.IsAdministrator == 1), 1, 0), }).Distinct().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); @@ -105,11 +101,25 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, [HttpGet("ListAll")] public async Task GetListAll() { - var list1 = await GetFlowFormList(0); - foreach (var item in list1) - { - item.id = item.templateId; - } + //var list1 = await GetFlowFormList(0); + var list1 = await _repository.AsSugarClient().Queryable() + .Where(a => a.DeleteMark == null && a.EnabledMark == 1) + .Select(a => new FlowTemplateTreeOutput + { + id = a.Id, + creatorTime = a.CreatorTime, + enCode = a.EnCode, + enabledMark = a.EnabledMark, + fullName = a.FullName, + icon = a.Icon, + iconBackground = a.IconBackground, + lastModifyTime = a.LastModifyTime, + sortCode = a.SortCode, + parentId = a.Category, + category = a.Category, + type = a.Type, + }).Distinct().MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc) + .OrderBy(t => t.lastModifyTime, OrderByType.Desc).ToListAsync(); if (list1.Any()) { var dicDataInfo = await _dictionaryDataService.GetInfo(list1.FirstOrDefault().parentId); @@ -143,22 +153,41 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, [HttpGet("PageListAll")] public async Task GetListPageAll([FromQuery] FlowTemplateListQuery input) { - var data = await GetFlowFormList(input.flowType.ParseToInt()); - if (input.category.IsNotEmptyOrNull()) - data = data.FindAll(x => x.category == input.category); - if (input.keyword.IsNotEmptyOrNull()) - data = data.FindAll(o => o.fullName.Contains(input.keyword) || o.enCode.Contains(input.keyword)); - var pageList = new SqlSugarPagedList() - { - list = data.Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).ToList(), - pagination = new Pagination() + //var data = await GetFlowFormList(input.flowType.ParseToInt()); + //if (input.category.IsNotEmptyOrNull()) + // data = data.FindAll(x => x.category == input.category); + //if (input.keyword.IsNotEmptyOrNull()) + // data = data.FindAll(o => o.fullName.Contains(input.keyword) || o.enCode.Contains(input.keyword)); + //var pageList = new SqlSugarPagedList() + //{ + // list = data.Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).ToList(), + // pagination = new Pagination() + // { + // PageIndex = input.currentPage, + // PageSize = input.pageSize, + // Total = data.Count + // } + //}; + //return PageResult.SqlSugarPageResult(pageList); + var list = await _repository.AsSugarClient().Queryable() + .Where(a => a.DeleteMark == null && a.Type == 0 && a.EnabledMark == 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 FlowTemplateListOutput { - CurrentPage = input.currentPage, - PageSize = input.pageSize, - Total = data.Count - } - }; - return PageResult.SqlSugarPageResult(pageList); + id = a.Id, + creatorTime = a.CreatorTime, + enCode = a.EnCode, + enabledMark = a.EnabledMark, + fullName = a.FullName, + icon = a.Icon, + iconBackground = a.IconBackground, + lastModifyTime = a.LastModifyTime, + sortCode = a.SortCode, + type = a.Type, + }).Distinct().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.SqlSugarPageResult(list); } /// @@ -169,8 +198,23 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, [HttpGet("{id}/FlowJsonList")] public async Task GetFlowJsonList(string id, [FromQuery] FlowTemplateListQuery input) { + var flowJosnEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == input.flowId && x.DeleteMark == null); + if (flowJosnEntity.IsNullOrEmpty()) + { + var pageList = new SqlSugarPagedList() + { + list = new List(), + pagination = new Pagination() + { + CurrentPage = input.currentPage, + PageSize = input.pageSize, + Total = 0 + } + }; + return PageResult.SqlSugarPageResult(pageList); + } var whereLambda = LinqExpression.And(); - whereLambda = whereLambda.And(x => x.DeleteMark == null && x.TemplateId == id); + whereLambda = whereLambda.And(x => x.DeleteMark == null && x.TemplateId == flowJosnEntity.TemplateId && x.FullName == flowJosnEntity.FullName); var start = new DateTime(); var end = new DateTime(); if (input.endTime != null && input.startTime != null) @@ -188,13 +232,14 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, .Select((a) => new FlowTemplateJsonInfoOutput { id = a.Id, + fullName = a.FullName, version = a.Version, enabledMark = a.EnabledMark, creatorUser = SqlFunc.Subqueryable().Where(u => u.Id == a.CreatorUserId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), creatorTime = a.CreatorTime, lastModifyTime = a.LastModifyTime, flowTemplateJson = a.FlowTemplateJson, - }).MergeTable().OrderBy(a => a.creatorTime, OrderByType.Desc) + }).MergeTable().OrderBy(a => a.enabledMark, OrderByType.Desc).OrderBy(a => a.creatorTime, OrderByType.Desc) .OrderByIF(!string.IsNullOrEmpty(input.keyword), t => t.lastModifyTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } @@ -207,8 +252,32 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, [HttpGet("{id}")] public async Task GetInfo(string id) { + //var output = (await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null)).Adapt(); + //output.onlineDev = _repository.AsSugarClient().Queryable().Any(x => x.Id == id && x.DeleteMark == null); + //var flowJsonList = await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == id && x.EnabledMark == 1 && x.DeleteMark == null).Select(x => new { id = x.Id, flowId = x.Id, fullName = x.FullName, flowTemplateJson = x.FlowTemplateJson }).ToListAsync(); + //output.flowTemplateJson = flowJsonList.ToJsonString(); + //return output; var output = (await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null)).Adapt(); - output.flowTemplateJson = _repository.AsSugarClient().Queryable().First(x => x.TemplateId == id && x.EnabledMark == 1 && x.DeleteMark == null)?.FlowTemplateJson; + var flowFormEntity = _repository.AsSugarClient().Queryable().First(x => x.FlowId == id && x.FlowType == 1 && x.FormType == 2 && x.DeleteMark == null); + if (flowFormEntity.IsNotEmptyOrNull()) + { + output.onlineDev = true; + output.onlineFormId = flowFormEntity.Id; + } + var flowJsonList = new List(); + var flowTemplateJsonEntityList = await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == id && x.EnabledMark == 1 && x.DeleteMark == null).OrderBy(x => x.SortCode).ToListAsync(); + foreach (var item in flowTemplateJsonEntityList) + { + var flowJosn = new FlowJsonInfo(); + flowJosn.id = item.Id; + flowJosn.flowId = item.Id; + flowJosn.fullName = item.FullName; + var flowIds = _repository.AsSugarClient().Queryable().Where(x => x.GroupId == item.GroupId && x.DeleteMark == null).Select(x => x.Id).ToList(); + flowJosn.isDelete = await _flowTaskRepository.AnyFlowTask(x => x.DeleteMark == null && flowIds.Contains(x.FlowId)); + flowJosn.flowTemplateJson = item.FlowTemplateJson?.ToObject(); + flowJsonList.Add(flowJosn); + } + output.flowTemplateJson = flowJsonList.ToJsonString(); return output; } @@ -245,6 +314,29 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, return new { list = output }; } + /// + /// 列表(子流程选择流程). + /// + /// (预留字段). + /// + [HttpGet("PageChildListAll")] + public async Task PageChildListAll([FromQuery] FlowTemplateListQuery input) + { + var list = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Right, a.Id == b.TemplateId)) + .Where((a, b) => a.DeleteMark == null && a.EnabledMark == 1 && a.Type == input.flowType && b.DeleteMark == null && b.EnabledMark == 1) + .WhereIF(input.keyword.IsNotEmptyOrNull(), (a, b) => b.FullName.Contains(input.keyword)) + .Select((a, b) => new FlowTemplateTreeOutput + { + id = b.Id, + fullName = b.FullName, + creatorTime = a.CreatorTime, + lastModifyTime = a.LastModifyTime, + sortCode = a.SortCode, + }).MergeTable().OrderBy(a => a.sortCode).OrderBy(a => a.creatorTime, OrderByType.Desc) + .OrderBy(a => a.lastModifyTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize); + return PageResult.SqlSugarPageResult(list); + } + /// /// 导出. /// @@ -255,8 +347,9 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, { var importModel = new FlowTemplateImportOutput(); importModel.flowTemplate = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); - importModel.flowTemplateJson = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.TemplateId == id && x.EnabledMark == 1 && x.DeleteMark == null); - importModel.visibleList = await _repository.AsSugarClient().Queryable().Where(x => x.FlowId == importModel.flowTemplateJson.Id).ToListAsync(); + importModel.flowTemplateJson = await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == id && x.EnabledMark == 1 && x.DeleteMark == null).ToListAsync(); + var flowJsonIds = importModel.flowTemplateJson.Select(x => x.Id).ToList(); + importModel.visibleList = await _repository.AsSugarClient().Queryable().Where(x => flowJsonIds.Contains(x.FlowId)).ToListAsync(); var jsonStr = importModel.ToJsonString(); return await _fileManager.Export(jsonStr, importModel.flowTemplate.FullName, ExportFileType.ffe); } @@ -333,9 +426,34 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, { var entity = await _repository.GetFirstAsync(x => x.EnCode == code && x.DeleteMark == null); if (entity == null) Oops.Oh(ErrorCode.COM1005); - var jsonEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.TemplateId == entity.Id && x.EnabledMark == 1 && x.DeleteMark == null); - if (jsonEntity == null) Oops.Oh(ErrorCode.COM1005); - return jsonEntity.Id; + return entity.Id; + } + + /// + /// 发起流程列表(下拉). + /// + /// + [HttpGet("FlowJsonList/{teplateId}")] + public async Task GetFlowJsonList(string teplateId, string type) + { + var flowJsonList = (await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == teplateId && x.EnabledMark == 1 && x.DeleteMark == null).OrderBy(x => x.SortCode).ToListAsync()).Adapt>(); + if (!flowJsonList.Any()) throw Oops.Oh(ErrorCode.COM1016); + if (!_userManager.IsAdministrator && type == "1") + { + // 判断当前用户是否有发起权限 + foreach (var item in flowJsonList.FindAll(x => x.visibleType == 1)) + { + // 指定发起人. + var visibleUserList = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.OperatorId == b.ObjectId || a.OperatorId == b.UserId)) + .Where((a, b) => a.FlowId == item.id && a.Type == "1").Select((a, b) => b.UserId).Distinct().ToListAsync(); + if (!visibleUserList.Contains(_userManager.UserId)) + { + flowJsonList.Remove(item); + } + } + } + if (!flowJsonList.Any()) throw Oops.Oh(ErrorCode.WF0049); + return flowJsonList; } #endregion @@ -355,11 +473,13 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, var flowTemplateJsonIdList = await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == id).Select(x => x.Id).ToListAsync(); if (await _flowTaskRepository.AnyFlowTask(x => x.DeleteMark == null && flowTemplateJsonIdList.Contains(x.FlowId))) throw Oops.Oh(ErrorCode.WF0037); + if (await _repository.AsSugarClient().Queryable().AnyAsync(x => x.FlowId == id)) + throw Oops.Oh(ErrorCode.WF0052); _db.BeginTran(); await _repository.AsSugarClient().Deleteable(a => flowTemplateJsonIdList.Contains(a.FlowId)).ExecuteCommandHasChangeAsync(); - await _repository.AsSugarClient().Deleteable(a => flowTemplateJsonIdList.Contains(a.FlowId)).ExecuteCommandHasChangeAsync(); await _repository.AsSugarClient().Deleteable(a => flowTemplateJsonIdList.Contains(a.Id)).ExecuteCommandHasChangeAsync(); - await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == null).Where(x => flowTemplateJsonIdList.Contains(x.FlowId)).ExecuteCommandAsync(); + await _repository.AsSugarClient().Deleteable(a => a.FlowId == id).ExecuteCommandHasChangeAsync(); + await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == null).Where(x => x.FlowId == id).ExecuteCommandAsync(); var isOk = await _repository.AsUpdateable(flowTemplateEntity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandHasChangeAsync(); _db.CommitTran(); if (!isOk) @@ -393,7 +513,7 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, if (await _repository.IsAnyAsync(x => x.Id != id && (x.EnCode == input.enCode || x.FullName == input.fullName) && x.DeleteMark == null)) throw Oops.Oh(ErrorCode.COM1004); var flowTemplateEntity = input.Adapt(); - var result = await Update(flowTemplateEntity, input.flowTemplateJson); + var result = await Update(flowTemplateEntity, input.flowTemplateJson, input.onlineFormId); if (result.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.COM1001); return result; @@ -410,13 +530,24 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); if (entity == null) throw Oops.Oh(ErrorCode.COM1005); - var flowTemplateJsonEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.TemplateId == id && x.EnabledMark == 1 && x.DeleteMark == null); var random = RandomExtensions.NextLetterAndNumberString(new Random(), 5).ToLower(); 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); - var result = await Create(entity, flowTemplateJsonEntity.FlowTemplateJson); + var flowJsonList = new List(); + var flowTemplateJsonEntityList = await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == id && x.EnabledMark == 1 && x.DeleteMark == null).ToListAsync(); + foreach (var item in flowTemplateJsonEntityList) + { + var flowJosn = new FlowJsonInfo(); + flowJosn.id = item.Id; + flowJosn.flowId = item.Id; + flowJosn.fullName = item.FullName; + flowJosn.isDelete = await _flowTaskRepository.AnyFlowTask(x => x.DeleteMark == null && x.FlowId == item.Id); + flowJosn.flowTemplateJson = item.FlowTemplateJson?.ToObject(); + flowJsonList.Add(flowJosn); + } + var result = await Create(entity, flowJsonList.ToJsonString()); _ = result ?? throw Oops.Oh(ErrorCode.WF0002); } @@ -494,11 +625,24 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, [HttpPost("{id}/MainVersion")] public async Task MainVersion(string id) { - var jsonInfo = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == id && x.DeleteMark == null); - await _repository.AsSugarClient().Updateable().SetColumns(it => it.EnabledMark == 0).Where(it => it.Id != id && it.TemplateId == jsonInfo.TemplateId).ExecuteCommandHasChangeAsync(); - var isOk = await _repository.AsSugarClient().Updateable().SetColumns(it => it.EnabledMark == 1).Where(it => it.Id == id && it.TemplateId == jsonInfo.TemplateId).ExecuteCommandHasChangeAsync(); - if (!isOk) - throw Oops.Oh(ErrorCode.COM1003); + foreach (var item in id.Split(",")) + { + var jsonInfo = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == item && x.DeleteMark == null); + await _repository.AsSugarClient().Updateable().SetColumns(it => new FlowTemplateJsonEntity() + { + EnabledMark = 0, + LastModifyUserId = _userManager.UserId, + LastModifyTime = SqlFunc.GetDate() + }).Where(it => it.EnabledMark == 1 && it.TemplateId == jsonInfo.TemplateId && it.FullName == jsonInfo.FullName).ExecuteCommandHasChangeAsync(); + var isOk = await _repository.AsSugarClient().Updateable().SetColumns(it => new FlowTemplateJsonEntity() + { + EnabledMark = 1, + LastModifyUserId = _userManager.UserId, + LastModifyTime = SqlFunc.GetDate() + }).Where(it => it.Id == item && it.TemplateId == jsonInfo.TemplateId && it.FullName == jsonInfo.FullName).ExecuteCommandHasChangeAsync(); + if (!isOk) + throw Oops.Oh(ErrorCode.COM1003); + } } /// @@ -511,9 +655,11 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, { if (await _flowTaskRepository.AnyFlowTask(x => x.DeleteMark == null && x.FlowId == id)) throw Oops.Oh(ErrorCode.WF0037); + var jsonInfo = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == id && x.DeleteMark == null); + var launchFormIdList = new List(); + GetFormIdList(jsonInfo.FlowTemplateJson.ToObject(), launchFormIdList); + await _repository.AsSugarClient().Deleteable(a => a.FlowId == id && launchFormIdList.Contains(a.FormId)).ExecuteCommandHasChangeAsync(); var isOk = await _repository.AsSugarClient().Updateable().SetColumns(it => new FlowTemplateJsonEntity() { DeleteMark = 1, DeleteTime = SqlFunc.GetDate(), DeleteUserId = _userManager.UserId }).Where(it => it.Id == id).ExecuteCommandHasChangeAsync(); - await _repository.AsSugarClient().Deleteable(a => a.FlowId == id).ExecuteCommandHasChangeAsync(); - await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == null).Where(x => x.FlowId==id).ExecuteCommandAsync(); if (!isOk) throw Oops.Oh(ErrorCode.COM1003); } @@ -597,46 +743,65 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, _db.BeginTran(); var formIdList = new List(); entity.Id = SnowflakeIdHelper.NextId(); - entity.EnabledMark = entity.EnabledMark == null ? 0 : entity.EnabledMark; - var flowTemplateJsonEntity = new FlowTemplateJsonEntity(); - flowTemplateJsonEntity.Id = SnowflakeIdHelper.NextId(); - flowTemplateJsonEntity.TemplateId = entity.Id; - flowTemplateJsonEntity.Version = "1"; - flowTemplateJsonEntity.FlowTemplateJson = flowTemplateJson; + entity.EnabledMark = 0; if (flowTemplateJson.IsNotEmptyOrNull()) { - var visibleList = GetFlowEngineVisibleList(flowTemplateJson); - flowTemplateJsonEntity.VisibleType = visibleList.Count == 0 ? 0 : 1; - foreach (var item in visibleList) + var index = 0; + foreach (var item in flowTemplateJson.ToObject>()) { - item.FlowId = flowTemplateJsonEntity.Id; - item.SortCode = visibleList.IndexOf(item); - item.Type = "1"; - } - if (visibleList.Count > 0) - await _repository.AsSugarClient().Insertable(visibleList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); - - #region 功能流程则要回写到对应的表单表中 - GetFormIdList(flowTemplateJson.ToObject(), formIdList); - foreach (var item in formIdList) - { - var formRelationEntity = new FlowFormRelationEntity + var flowTemplateJsonEntity = new FlowTemplateJsonEntity(); + flowTemplateJsonEntity.Id = SnowflakeIdHelper.NextId(); + flowTemplateJsonEntity.TemplateId = entity.Id; + flowTemplateJsonEntity.Version = "1"; + flowTemplateJsonEntity.FlowTemplateJson = item.flowTemplateJson.ToJsonString(); + flowTemplateJsonEntity.FullName = item.fullName; + flowTemplateJsonEntity.SortCode = index++; + flowTemplateJsonEntity.GroupId = SnowflakeIdHelper.NextId(); + var visibleList = GetFlowEngineVisibleList(item.flowTemplateJson.ToJsonString()); + flowTemplateJsonEntity.VisibleType = visibleList.Count == 0 ? 0 : 1; + foreach (var visible in visibleList) { - Id = SnowflakeIdHelper.NextId(), - FlowId = flowTemplateJsonEntity.Id, - FormId = item - }; - await _repository.AsSugarClient().Insertable(formRelationEntity).ExecuteReturnEntityAsync(); + visible.FlowId = flowTemplateJsonEntity.Id; + visible.SortCode = visibleList.IndexOf(visible); + visible.Type = "1"; + } + if (visibleList.Count > 0) + await _repository.AsSugarClient().Insertable(visibleList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); + await _repository.AsSugarClient().Insertable(flowTemplateJsonEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + #region 功能流程则要回写到对应的表单表中 + if (entity.Type == 1) + { + var formId = item.flowTemplateJson.properties.ToObject()?.formId; + if (formIdList.Any() && !formIdList.Contains(formId)) + { + throw Oops.Oh(ErrorCode.WF0043); + } + else + { + formIdList.Add(formId); + } + if (await _repository.AsSugarClient().Queryable().AnyAsync(x => x.Id == formId && x.FlowId != entity.Id && !SqlFunc.IsNullOrEmpty(x.FlowId))) + throw Oops.Oh(ErrorCode.WF0043); + await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == entity.Id).Where(x => x.Id == formId).ExecuteCommandAsync(); + } + else + { + var launchFormIdList = new List(); + GetFormIdList(item.flowTemplateJson, launchFormIdList); + foreach (var launchFormId in launchFormIdList) + { + var formRelationEntity = new FlowFormRelationEntity + { + Id = SnowflakeIdHelper.NextId(), + FlowId = entity.Id, + FormId = launchFormId + }; + await _repository.AsSugarClient().Insertable(formRelationEntity).ExecuteReturnEntityAsync(); + } + } + #endregion } - if (entity.Type == 1) - { - if (await _repository.AsSugarClient().Queryable().AnyAsync(x => x.Id == formIdList.FirstOrDefault() && !SqlFunc.IsNullOrEmpty(x.FlowId))) - throw Oops.Oh(ErrorCode.WF0043); - await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == flowTemplateJsonEntity.Id).Where(x => x.Id == formIdList.FirstOrDefault()).ExecuteCommandAsync(); - } - #endregion } - await _repository.AsSugarClient().Insertable(flowTemplateJsonEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); var result = await _repository.AsSugarClient().Insertable(entity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); if (result == null) throw Oops.Oh(ErrorCode.COM1005); @@ -657,75 +822,134 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, /// 可见范围. /// [NonAction] - private async Task Update(FlowTemplateEntity entity, string flowTemplateJson) + private async Task Update(FlowTemplateEntity entity, string flowTemplateJson, string onlineFormId) { try { _db.BeginTran(); var flag = false; + var isMainVersionId = new List(); var formIdList = new List(); - var flowTemplateJsonEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.TemplateId == entity.Id && x.DeleteMark == null && x.EnabledMark == 1); - if (flowTemplateJsonEntity.FlowTemplateJson.IsNotEmptyOrNull()) - { - // 清空就模板关联表单数据 - string oldFormId = flowTemplateJsonEntity.FlowTemplateJson.ToObject().properties.ToObject().formId; - await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == null).Where(x => x.Id == oldFormId).ExecuteCommandAsync(); - await _repository.AsSugarClient().Deleteable().Where(x => x.FlowId == flowTemplateJsonEntity.Id).ExecuteCommandAsync(); - - } - var isCreate = flowTemplateJsonEntity.FlowTemplateJson.Equals(flowTemplateJson);//流程json是否变更 - flowTemplateJsonEntity.FlowTemplateJson = flowTemplateJson; + var groupIdList = new List(); // 未删除的分组id. if (flowTemplateJson.IsNotEmptyOrNull()) { - var visibleList = GetFlowEngineVisibleList(flowTemplateJson); - flowTemplateJsonEntity.VisibleType = visibleList.Count == 0 ? 0 : 1; - if ((await _flowTaskRepository.AnyFlowTask(x => x.DeleteMark == null && x.FlowId == flowTemplateJsonEntity.Id)) && !isCreate) + var index = 0; + foreach (var item in flowTemplateJson.ToObject>()) { - flag = true; - flowTemplateJsonEntity.Version = ((await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == entity.Id).Select(x => SqlFunc.AggregateMax(SqlFunc.ToInt64(x.Version))).FirstAsync()).ParseToInt() + 1).ToString(); - flowTemplateJsonEntity.Id = SnowflakeIdHelper.NextId(); - flowTemplateJsonEntity.EnabledMark = 0; - await _repository.AsSugarClient().Insertable(flowTemplateJsonEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); - } - else - { - await _repository.AsSugarClient().Updateable(flowTemplateJsonEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); - await _repository.AsSugarClient().Deleteable(a => a.FlowId == flowTemplateJsonEntity.Id).ExecuteCommandHasChangeAsync(); - } - foreach (var item in visibleList) - { - item.FlowId = flowTemplateJsonEntity.Id; - item.SortCode = visibleList.IndexOf(item); - item.Type = "1"; - } - if (visibleList.Count > 0) - await _repository.AsSugarClient().Insertable(visibleList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); - GetFormIdList(flowTemplateJson.ToObject(), formIdList); - foreach (var item in formIdList) - { - var formRelationEntity = new FlowFormRelationEntity + var flowTemplateJsonEntity = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == item.id && x.DeleteMark == null); + var visibleList = GetFlowEngineVisibleList(item.flowTemplateJson.ToJsonString()); + if (flowTemplateJsonEntity.IsNullOrEmpty()) { - Id = SnowflakeIdHelper.NextId(), - FlowId = flowTemplateJsonEntity.Id, - FormId = item - }; - await _repository.AsSugarClient().Insertable(formRelationEntity).ExecuteReturnEntityAsync(); - } - if (entity.Type == 1) - { - if (await _repository.AsSugarClient().Queryable().AnyAsync(x => x.Id == formIdList.FirstOrDefault() && !SqlFunc.IsNullOrEmpty(x.FlowId))) - throw Oops.Oh(ErrorCode.WF0043); - await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == flowTemplateJsonEntity.Id).Where(x => x.Id == formIdList.FirstOrDefault()).ExecuteCommandAsync(); + flowTemplateJsonEntity = new FlowTemplateJsonEntity(); + flowTemplateJsonEntity.Id = SnowflakeIdHelper.NextId(); + flowTemplateJsonEntity.TemplateId = entity.Id; + flowTemplateJsonEntity.Version = "1"; + flowTemplateJsonEntity.FlowTemplateJson = item.flowTemplateJson.ToJsonString(); + flowTemplateJsonEntity.FullName = item.fullName; + flowTemplateJsonEntity.SortCode = index++; + flowTemplateJsonEntity.VisibleType = visibleList.Count == 0 ? 0 : 1; + flowTemplateJsonEntity.GroupId = SnowflakeIdHelper.NextId(); + foreach (var visible in visibleList) + { + visible.FlowId = flowTemplateJsonEntity.Id; + visible.SortCode = visibleList.IndexOf(visible); + visible.Type = "1"; + } + if (visibleList.Count > 0) + await _repository.AsSugarClient().Insertable(visibleList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); + await _repository.AsSugarClient().Insertable(flowTemplateJsonEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + groupIdList.Add(flowTemplateJsonEntity.GroupId); + } + else + { + // 清空就模板关联表单数据 + if (entity.Type == 1) + { + string oldFormId = flowTemplateJsonEntity.FlowTemplateJson.ToObject().properties.ToObject().formId; + await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == null).Where(x => x.Id == oldFormId).ExecuteCommandAsync(); + } + else + { + await _repository.AsSugarClient().Deleteable().Where(x => x.FlowId == entity.Id).ExecuteCommandAsync(); + } + if (!groupIdList.Contains(flowTemplateJsonEntity.GroupId)) + { + groupIdList.Add(flowTemplateJsonEntity.GroupId); + } + var isCreate = flowTemplateJsonEntity.FlowTemplateJson.Equals(item.flowTemplateJson.ToJsonString());//流程json是否变更 + flowTemplateJsonEntity.FlowTemplateJson = item.flowTemplateJson.ToJsonString(); + flowTemplateJsonEntity.SortCode = index++; + flowTemplateJsonEntity.FullName = item.fullName; + flowTemplateJsonEntity.VisibleType = visibleList.Count == 0 ? 0 : 1; + if ((await _flowTaskRepository.AnyFlowTask(x => x.DeleteMark == null && x.FlowId == flowTemplateJsonEntity.Id)) && !isCreate) + { + flag = true; + await _repository.AsSugarClient().Updateable(flowTemplateJsonEntity).UpdateColumns(it => new { it.FullName, it.SortCode }).ExecuteCommandHasChangeAsync(); + flowTemplateJsonEntity.Version = ((await _repository.AsSugarClient().Queryable().Where(x => x.TemplateId == entity.Id && x.FullName == item.fullName).Select(x => SqlFunc.AggregateMax(SqlFunc.ToInt64(x.Version))).FirstAsync()).ParseToInt() + 1).ToString(); + flowTemplateJsonEntity.Id = SnowflakeIdHelper.NextId(); + flowTemplateJsonEntity.EnabledMark = 0; + flowTemplateJsonEntity.LastModifyTime = null; + flowTemplateJsonEntity.LastModifyUserId = null; + await _repository.AsSugarClient().Insertable(flowTemplateJsonEntity).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync(); + isMainVersionId.Add(flowTemplateJsonEntity.Id); + } + else + { + await _repository.AsSugarClient().Updateable(flowTemplateJsonEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); + await _repository.AsSugarClient().Deleteable(a => a.FlowId == flowTemplateJsonEntity.Id).ExecuteCommandHasChangeAsync(); + } + } + foreach (var visible in visibleList) + { + visible.FlowId = flowTemplateJsonEntity.Id; + visible.SortCode = visibleList.IndexOf(visible); + visible.Type = "1"; + } + if (visibleList.Count > 0) + await _repository.AsSugarClient().Insertable(visibleList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); + if (entity.Type == 1) + { + var formId = item.flowTemplateJson.properties.ToObject()?.formId; + if (formIdList.Any() && !formIdList.Contains(formId)) + { + throw Oops.Oh(ErrorCode.WF0043); + } + else + { + formIdList.Add(formId); + } + if ((await _repository.AsSugarClient().Queryable().AnyAsync(x => x.Id == formId && x.FlowId != entity.Id && !SqlFunc.IsNullOrEmpty(x.FlowId))) && formId != onlineFormId) + throw Oops.Oh(ErrorCode.WF0043); + await _repository.AsSugarClient().Updateable().SetColumns(x => x.FlowId == entity.Id).Where(x => x.Id == formId).ExecuteCommandAsync(); + } + else + { + // 发起流程表单id + var launchFormIdList = new List(); + GetFormIdList(item.flowTemplateJson, launchFormIdList); + foreach (var launchFormId in launchFormIdList) + { + var formRelationEntity = new FlowFormRelationEntity + { + Id = SnowflakeIdHelper.NextId(), + FlowId = entity.Id, + FormId = launchFormId + }; + await _repository.AsSugarClient().Insertable(formRelationEntity).ExecuteReturnEntityAsync(); + } + } } + // 删除未使用的流程 + await _repository.AsSugarClient().Deleteable().Where(x => x.TemplateId == entity.Id && !groupIdList.Contains(x.GroupId)).ExecuteCommandAsync(); } var isOk = await _repository.AsSugarClient().Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); _db.CommitTran(); - return new { isMainVersion = flag, id = flowTemplateJsonEntity.Id }; + return new { isMainVersion = flag, id = string.Join(",", isMainVersionId) }; } - catch (AppFriendlyException ex) + catch (Exception ex) { _db.RollbackTran(); - throw Oops.Oh(ex.ErrorCode); + return null; } } @@ -818,7 +1042,7 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, .Select((a, b) => new FlowTemplateTreeOutput { category = a.Category, - id = b.Id, + id = a.Id, description = a.Description, creatorTime = a.CreatorTime, creatorUser = SqlFunc.Subqueryable().Where(u => u.Id == a.CreatorUserId).Select(u => SqlFunc.MergeString(u.RealName, "/", u.Account)), @@ -871,7 +1095,7 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, /// private void GetFormIdList(FlowTemplateJsonModel template, List formIdList) { - if (template.IsNotEmptyOrNull()&&!template.type.Equals("subFlow")) + if (template.IsNotEmptyOrNull() && !template.type.Equals("subFlow") && !template.type.Equals("timer")) { if (template.properties["formId"].ToString().IsNotEmptyOrNull()) { @@ -884,4 +1108,4 @@ public class FlowTemplateService : IFlowTemplateService, IDynamicApiController, } } #endregion -} +} \ No newline at end of file diff --git a/workflow/Tnb.WorkFlow/WorkFlowForm/LeaveApplyService.cs b/workflow/Tnb.WorkFlow/WorkFlowForm/LeaveApplyService.cs index 38b26359..2c6f73cf 100644 --- a/workflow/Tnb.WorkFlow/WorkFlowForm/LeaveApplyService.cs +++ b/workflow/Tnb.WorkFlow/WorkFlowForm/LeaveApplyService.cs @@ -5,6 +5,7 @@ using JNPF.Common.Core.Manager.Files; using JNPF.Common.Extension; using JNPF.Common.Manager; using JNPF.Common.Models; +using JNPF.Common.Models.WorkFlow; using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController; diff --git a/workflow/Tnb.WorkFlow/WorkFlowForm/SalesOrderService.cs b/workflow/Tnb.WorkFlow/WorkFlowForm/SalesOrderService.cs index e903a450..7422205f 100644 --- a/workflow/Tnb.WorkFlow/WorkFlowForm/SalesOrderService.cs +++ b/workflow/Tnb.WorkFlow/WorkFlowForm/SalesOrderService.cs @@ -5,6 +5,7 @@ using JNPF.Common.Core.Manager.Files; using JNPF.Common.Extension; using JNPF.Common.Manager; using JNPF.Common.Models; +using JNPF.Common.Models.WorkFlow; using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController;