Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
2023-05-31 14:46:23 +08:00
263 changed files with 10563 additions and 4165 deletions

View File

@@ -11,6 +11,10 @@ namespace Tnb.EquipMgr.Entities.Consts
/// <summary>
/// 模具使用状态在库状态ID
/// </summary>
public const string MOLDUSESTATUSZKID = "26149307089941";
public const string MOLD_USE_STATUS_ZK_ID = "26149307089941";
/// <summary>
/// 模具使用状态-保养Id
/// </summary>
public const string MOLD_USE_STATUS_MAINTAIN_ID = "26149311082005";
}
}

View File

@@ -66,6 +66,10 @@ public partial class ToolMoldMaintainItem : BaseEntity<string>
/// <summary>
/// 保养项完成状态 0未完成1,已完成
/// </summary>
public int? status { get; set; }
public int status { get; set; } = 0;
/// <summary>
/// 模具id
/// </summary>
public string mold_id { get; set; }
}

View File

@@ -0,0 +1,46 @@
using JNPF.Common.Contracts;
using JNPF.Common.Security;
using SqlSugar;
namespace Tnb.EquipMgr.Entities;
/// <summary>
/// 模具保养
/// </summary>
[SugarTable("tool_mold_maintain_item_record")]
public partial class ToolMoldMaintainItemRecord : BaseEntity<string>
{
public ToolMoldMaintainItemRecord()
{
id = SnowflakeIdHelper.NextId();
}
/// <summary>
/// 保养项 保养状态 0 未完成1 已完成
/// </summary>
public int status { get; set; }
/// <summary>
/// 保养组Id
/// </summary>
public string? item_group_id { get; set; }
/// <summary>
/// 保养组名称
/// </summary>
public string? item_group_name { get; set; }
/// <summary>
/// 保养项Id
/// </summary>
public string? item_id { get; set; }
/// <summary>
/// 保养项名称
/// </summary>
public string? item_name { get; set; }
/// <summary>
/// 模具ID
/// </summary>
public string mold_id { get; set; }
}

View File

@@ -59,26 +59,6 @@ public partial class ToolMoldMaintainRunRecord : BaseEntity<string>
/// </summary>
public string? eqp_name { get; set; }
/// <summary>
/// 保养组编码
/// </summary>
public string? group_code { get; set; }
/// <summary>
/// 保养组名称
/// </summary>
public string? group_name { get; set; }
/// <summary>
/// 保养项编号
/// </summary>
public string? check_item_code { get; set; }
/// <summary>
/// 保养项名称
/// </summary>
public string? check_item_name { get; set; }
/// <summary>
/// 计划开始时间
/// </summary>
@@ -94,4 +74,14 @@ public partial class ToolMoldMaintainRunRecord : BaseEntity<string>
/// </summary>
public decimal? plan_time { get; set; }
/// <summary>
/// 维保人
/// </summary>
public string? maintain_person { get; set; }
/// <summary>
/// 异常记录
/// </summary>
public string? exception_record { get; set; }
}

View File

@@ -0,0 +1,42 @@
using JNPF.Common.Contracts;
using JNPF.Common.Security;
using SqlSugar;
namespace Tnb.EquipMgr.Entities;
/// <summary>
/// 模具保养计划记录表子表
/// </summary>
[SugarTable("tool_mold_maintain_run_record_d")]
public partial class ToolMoldMaintainRunRecordD : BaseEntity<string>
{
public ToolMoldMaintainRunRecordD()
{
id = SnowflakeIdHelper.NextId();
}
/// <summary>
/// 模具编号
/// </summary>
public string? mold_id { get; set; }
/// <summary>
/// 保养组编码
/// </summary>
public string? group_id { get; set; }
/// <summary>
/// 保养组名称
/// </summary>
public string? group_name { get; set; }
/// <summary>
/// 保养项编号
/// </summary>
public string? check_item_id { get; set; }
/// <summary>
/// 保养项名称
/// </summary>
public string? check_item_name { get; set; }
}

View File

@@ -133,5 +133,9 @@ public partial class ToolMolds : BaseEntity<string>
/// 模具型号
/// </summary>
public string? mold_type_code { get; set; }
/// <summary>
/// 关联保养项信息
/// </summary>
public string item_json { get; set; }
}

View File

@@ -5,11 +5,11 @@ namespace Tnb.EquipMgr.Interfaces
{
public interface IEqpEquipFileService
{
/// <summary>
/// 上传附件
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public Task<string> Upload(string equip_id,IFormFile file);
///// <summary>
///// 上传附件
///// </summary>
///// <param name="file"></param>
///// <returns></returns>
//public Task<string> Upload(string equip_id,IFormFile file);
}
}

View File

@@ -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<string> Upload([FromForm]string equip_id,[FromForm]IFormFile file)
public async Task<string> 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,

View File

@@ -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
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task RelevanceMaintianGroupAndItem(MoldMaintainGroupItemInput input) =>
await Relevance<MoldMaintainGroupItemInput, ToolMoldMaintainGroupItem>(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<MoldMaintainGroupItemInput, ToolMoldMaintainGroupItem>(input, nameof(ToolMoldMaintainGroupItem.item_group_id), nameof(ToolMoldMaintainGroupItem.item_id), it => it.item_group_id == input.id);
List<ToolMoldMaintainItemRecord> itemRecords = new();
var grpIds = await _db.Queryable<ToolMoldMaintainGroupItem>().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<ToolMoldMaintainGroup>().Where(it => grpIds.Contains(it.id)).ToListAsync();
foreach (var grp in grps)
{
var molds = await _db.Queryable<ToolMoldMaintainGroupRelation>().Where(it => it.item_group_id == grp.id).ToListAsync();
if (molds?.Count > 0)
{
foreach (var mold in molds)
{
var dbItIds = await _db.Queryable<ToolMoldMaintainItemRecord>().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<ToolMoldMaintainItem>().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;
}
}
/// <summary>
/// 关联项目组与模具
@@ -88,8 +142,45 @@ namespace Tnb.EquipMgr
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task RelevanceMaintianGroupAndMold(MoldMaintainGroupItemRelationInput input) =>
public async Task RelevanceMaintianGroupAndMold(MoldMaintainGroupItemRelationInput input)
{
await Relevance<MoldMaintainGroupItemRelationInput, ToolMoldMaintainGroupRelation>(input, nameof(ToolMoldMaintainGroupRelation.item_group_id), nameof(ToolMoldMaintainGroupRelation.mold_id), it => it.item_group_id == input.id);
List<ToolMoldMaintainItemRecord> itemRecords = new();
foreach (var moldId in input.ids)
{
var grpIds = await _db.Queryable<ToolMoldMaintainGroupRelation>().Where(it => it.mold_id == moldId).Select(it => it.item_group_id).Distinct().ToListAsync();
if (grpIds?.Count > 0)
{
var grps = await _db.Queryable<ToolMoldMaintainGroup>().Where(it => grpIds.Contains(it.id)).ToListAsync();
foreach (var grp in grps)
{
var itemIds = await _db.Queryable<ToolMoldMaintainGroupItem>().Where(it => it.item_group_id == grp.id).Select(it => it.item_id).ToListAsync();
if (itemIds?.Count > 0)
{
var dbItemIds = await _db.Queryable<ToolMoldMaintainItemRecord>().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<ToolMoldMaintainItem>().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();
}
/// <summary>
/// 删除项目组与模具检查项信息
/// </summary>
@@ -98,14 +189,15 @@ namespace Tnb.EquipMgr
[HttpPost]
public async Task Delete(MoldMaintainDelInput input)
{
if (input.table_name == "item")
{
await Delete<ToolMoldMaintainGroupItem>(it => it.item_group_id == input.id && input.ids.Contains(it.item_id));
await Delete<ToolMoldMaintainItemRecord>(it => it.item_group_id == input.id && input.ids.Contains(it.item_id));
}
else
{
await Delete<ToolMoldMaintainGroupRelation>(it => it.item_group_id == input.id && input.ids.Contains(it.mold_id));
await Delete<ToolMoldMaintainItemRecord>(it => it.item_group_id == input.id && input.ids.Contains(it.mold_id));
}
}

View File

@@ -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<dynamic> GetMaintainInfoFromByPlanId([FromRoute] string planId)
{
dynamic info = new ExpandoObject();
var planMoldRelation = await _db.Queryable<ToolMoldMaintainPlanRelation>()
List<dynamic> result = new();
var planMoldRelations = await _db.Queryable<ToolMoldMaintainPlanRelation>()
.LeftJoin<ToolMoldMaintainPlan>((a, b) => a.maintain_plan_id == b.id)//ToolMoldMaintainPlan
.LeftJoin<ToolMoldMaintainRunRecord>((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<ToolMolds>().FirstAsync(it => it.id == planMoldRelation.mold_id);
if (mold != null)
var mids = planMoldRelations.Select(x => x.mold_id).ToList();
var molds = await _db.Queryable<ToolMolds>().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<ToolMoldsEquipment>().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<EqpEquipment>().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<ToolMoldsEquipment>().FirstAsync(it => it.mold_id == mold.id);
if (moldEqpRelation != null)
{
var eqp = await _db.Queryable<EqpEquipment>().FirstAsync(it => it.id == moldEqpRelation.equipment_id);
info.eqp_code = eqp.code;
info.eqp_name = eqp.name;
}
result.Add(info);
}
}
}
return info;
return result;
}
/// <summary>
/// 根据模具ID获取保养组及项目信息
@@ -92,23 +102,32 @@ namespace Tnb.EquipMgr
public async Task<dynamic> GetCheckItemAndGrpByMoldId([FromRoute] string moldId)
{
if (moldId.IsNullOrEmpty()) throw new ArgumentException($"parameter {nameof(moldId)} not be null or empty");
var itemGroupRelation = await _db.Queryable<ToolMoldMaintainGroupRelation>().FirstAsync(it => it.mold_id == moldId);
if (itemGroupRelation != null)
{
var checkItems = await _db.Queryable<ToolMoldMaintainGroup, ToolMoldMaintainGroupItem, ToolMoldMaintainItem>((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<ToolMoldMaintainItemRecord>().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<ToolMoldMaintainGroupRelation, ToolMoldMaintainGroup, ToolMoldMaintainGroupItem, ToolMoldMaintainItem>((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<dynamic>();
@@ -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<ToolMoldMaintainPlan>().FirstAsync(it => it.id == input.plan_id);
if (plan != null)
var mold = await _db.Queryable<ToolMolds>().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<ToolMoldMaintainPlanRelation>().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<ToolMolds>(mold).Where(it => it.id == input.mold_id).ExecuteCommandHasChangeAsync();
if (!isOk) throw Oops.Oh(ErrorCode.COM1001);
var plan = await _db.Queryable<ToolMoldMaintainPlanRelation>().LeftJoin<ToolMoldMaintainPlan>((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<ToolMolds>().FirstAsync(it => it.id == moldPlanRelation.mold_id);
record.mold_code = mold?.mold_code;
record.mold_name = mold?.mold_name;
var moldGroupRelation = await _db.Queryable<ToolMoldMaintainGroupRelation>().FirstAsync(it => it.mold_id == mold.id);
if (moldGroupRelation != null)
{
var maintainGroup = await _db.Queryable<ToolMoldMaintainGroup>().FirstAsync(it => it.id == moldGroupRelation.item_group_id);
record.group_name = maintainGroup.name;
var itemGrpRelation = await _db.Queryable<ToolMoldMaintainGroupItem>().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<ToolMoldMaintainGroupRelation>()
.LeftJoin<ToolMoldMaintainGroup>((a, b) => a.item_group_id == b.id)
.LeftJoin<ToolMoldMaintainGroupItem>((a, b, c) => b.id == c.item_group_id)
.LeftJoin<ToolMoldMaintainItem>((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<ToolMoldMaintainItem>().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<ToolMoldMaintainRunRecordD> 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<ToolMoldMaintainItem>().SetColumns(it => new ToolMoldMaintainItem { status = input.status }).Where(it => input.itemIds.Contains(it.id)).ExecuteCommandAsync();
var row = await _db.Updateable<ToolMoldMaintainItemRecord>().SetColumns(it => new ToolMoldMaintainItemRecord { status = 1 }).Where(it => input.itemIds.Contains(it.id)).ExecuteCommandAsync();
if (row < 1) throw Oops.Oh(ErrorCode.COM1001);
}
/// <summary>
/// 模具保养计划执行-保养完成
/// </summary>
@@ -204,18 +243,18 @@ namespace Tnb.EquipMgr
var itemIds = await _db.Queryable<ToolMoldMaintainGroupItem>().Where(it => grpIds.Contains(it.item_group_id)).Select(it => it.item_id).ToListAsync();
if (itemIds?.Count > 0)
{
var items = await _db.Queryable<ToolMoldMaintainItem>().Where(it => itemIds.Contains(it.id) && it.status.HasValue && it.status.Value == 1).ToListAsync();
var items = await _db.Queryable<ToolMoldMaintainItemRecord>().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<ToolMolds>().SetColumns(it => new ToolMolds { mold_status = MoldUseStatus.MOLDUSESTATUSZKID }).Where(it => it.id == input.mold_id).ExecuteCommandAsync();
var row = await _db.Updateable<ToolMolds>().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<ToolMoldMaintainPlanRelation>().InnerJoin<ToolMolds>((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<ToolMoldMaintainPlan>().SetColumns(it => new ToolMoldMaintainPlan { status = MoldPlanMaintainStatus.MOLDPLAN_MAINTAIN_STATUS_COMPLETED_CODE }).Where(it => it.id == input.plan_id).ExecuteCommandAsync();
}

View File

@@ -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
{
/// <summary>
/// 更换载具输入参数
/// </summary>
public class ExChangeCarryInput
{
/// <summary>
/// 老载具ID
/// </summary>
public string old_carry_id { get; set; }
/// <summary>
/// 新载具ID
/// </summary>
public string new_carry_id { get; set; }
}
}

View File

@@ -97,12 +97,12 @@ public partial class WmsCarryCode : BaseEntity<string>
/// <summary>
/// 创建用户
/// </summary>
public string create_id { get; set; } = string.Empty;
public string? create_id { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime create_time { get; set; } = DateTime.Now;
public DateTime? create_time { get; set; }
/// <summary>
/// 修改用户

View File

@@ -42,12 +42,12 @@ public partial class WmsCarryD : BaseEntity<string>
/// <summary>
/// 创建用户
/// </summary>
public string create_id { get; set; } = string.Empty;
public string? create_id { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime create_time { get; set; } = DateTime.Now;
public DateTime? create_time { get; set; }
/// <summary>
/// 最后修改人员ID

View File

@@ -42,7 +42,7 @@ public partial class WmsCarryH : BaseEntity<string>
/// <summary>
/// 载具状态
/// </summary>
public string carry_status { get; set; } = string.Empty;
public int carry_status { get; set; };
/// <summary>
/// 载具分类ID
@@ -114,4 +114,19 @@ public partial class WmsCarryH : BaseEntity<string>
/// </summary>
public DateTime? timestamp { get; set; }
/// <summary>
/// 打包号
/// </summary>
public string? bale_num { get; set; }
/// <summary>
/// 齐套搭配方案ID
/// </summary>
public string? collocation_scheme_id { get; set; }
/// <summary>
/// 齐套搭配方案编号
/// </summary>
public string? collocation_scheme_code { get; set; }
}

View File

@@ -82,12 +82,12 @@ public partial class WmsCarryMat : BaseEntity<string>
/// <summary>
/// 时间戳
/// </summary>
public DateTime time_stamp { get; set; } = DateTime.Now;
public DateTime? time_stamp { get; set; }
/// <summary>
/// 创建用户
/// </summary>
public string create_id { get; set; } = string.Empty;
public string? create_id { get; set; }
/// <summary>
/// 创建时间

View File

@@ -77,12 +77,12 @@ public partial class WmsCarryReplaceCode : BaseEntity<string>
/// <summary>
/// 创建用户
/// </summary>
public string create_id { get; set; } = string.Empty;
public string? create_id { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime create_time { get; set; } = DateTime.Now;
public DateTime? create_time { get; set; }
/// <summary>
/// 修改用户
@@ -94,9 +94,4 @@ public partial class WmsCarryReplaceCode : BaseEntity<string>
/// </summary>
public DateTime? modify_time { get; set; }
/// <summary>
/// 行号
/// </summary>
public int no { get; set; }
}

View File

@@ -17,7 +17,7 @@ public partial class WmsCarryReplaceH : BaseEntity<string>
/// <summary>
/// 租户ID
/// </summary>
public string tenant_id { get; set; } = string.Empty;
public string? tenant_id { get; set; }
/// <summary>
/// 所属组织ID

View File

@@ -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
{
/// <summary>
/// 载具状态枚举
/// </summary>
public enum EnumCarryStatus
{
= 0,
= 1,
= 3,
= 4,
= 5,
}
}

View File

@@ -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
{
/// <summary>
/// 出库状态
/// </summary>
public enum EnumOutStatus
{
= 0,
= 1,
= 2,
= 3,
= 4,
= 5,
}
}

View File

@@ -1,7 +0,0 @@
namespace Tnb.WarehouseMgr.Interfaces
{
public class Class1
{
}
}

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,17 @@
using Tnb.WarehouseMgr.Entities;
namespace Tnb.WarehouseMgr.Interfaces
{
/// <summary>
/// 载具服务接口
/// </summary>
public interface IWmsCarryService
{
/// <summary>
/// 更新空载具
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
Task<int> UpdateNullCarry(WmsCarryH carryObj);
}
}

View File

@@ -1,7 +0,0 @@
namespace Tnb.WarehouseMgr
{
public class Class1
{
}
}

View File

@@ -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
{
/// <summary>
/// 载具服务
/// </summary>
[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<WmsCarryH> repository, IUserManager userManager)
{
_db = repository.AsSugarClient();
_userManager = userManager;
}
/// <summary>
/// 更换载具
/// </summary>
/// <param name="input">
/// 输入参数:
/// <br/>{
/// <br/> old_carry_id:老载具id
/// <br/> new_carry_id新载具ID
/// <br/>}
/// </param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
[HttpPost]
public async Task Exchange(ExChangeCarryInput input)
{
var row = -1;
if (input == null) throw new ArgumentNullException("input");
var oldCarry = await _db.Queryable<WmsCarryH>().FirstAsync(it => it.id == input.old_carry_id && it.is_lock == 0 && it.status == 0 && it.carry_status != 0);
var newCarry = await _db.Queryable<WmsCarryH>().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<WmsCarryD>().Where(it => it.carry_id == oldCarry.id).ToListAsync();
if (subCarrys?.Count > 0)
{
List<WmsCarryD> newSubCarrys = DeepCopyHelper<WmsCarryD>.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<WmsCarryMat>().Where(it => it.carry_id == oldCarry.id).ToListAsync();
if (subCarryMats?.Count > 0)
{
List<WmsCarryMat> newCarryMats = DeepCopyHelper<WmsCarryMat>.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<WmsCarryCode>().Where(it => it.carry_id == oldCarry.id).ToListAsync();
if (subCarryCodes?.Count > 0)
{
List<WmsCarryCode> newCarrayCodes = DeepCopyHelper<WmsCarryCode>.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<int> 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();
}
}
}

View File

@@ -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", //文件预览方式 kkfileyozo默认使用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"
}
}

View File

@@ -0,0 +1,8 @@
{
"EventBus": {
"EventBusType": "Memory", //Memory,RabbitMQ
"HostName": "192.168.0.232",
"UserName": "jnpf",
"Password": "jnpf@2019"
}
}

View File

@@ -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

View File

@@ -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"
}
}

View File

@@ -8,7 +8,7 @@
"Group": "Default",
"Title": "ToTong Next Builder",
"Description": "",
"Version": "3.4.5"
"Version": "3.4.6"
}
],
"LoginInfo": {

View File

@@ -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
/// <returns></returns>
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<EventBusOptions>();
// // 用户名
// 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<RetryEventHandlerExecutor>();
});
// 不启用事件日志
options.LogEnabled = false;
return services;
// 事件执行器(失败重试)
options.AddExecutor<RetryEventHandlerExecutor>();
});
services.AddConfigurableOptions<EventBusOptions>();
return services;
}
}

View File

@@ -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;
/// </summary>
public static class ConfigureMvcControllerExtensions
{
/// <summary>
/// OSS服务配置.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection ConfigureMvcController(this IServiceCollection services)
{
services.AddControllers()
.AddMvcFilter<RequestActionFilter>()
.AddInjectWithUnifyResult<RESTfulResultProvider>()
.AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null)
.AddNewtonsoftJson(options =>
/// <summary>
/// OSS服务配置.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection ConfigureMvcController(this IServiceCollection services)
{
services.AddControllers()
.AddMvcFilter<RequestActionFilter>()
.AddInjectWithUnifyResult<RESTfulResultProvider>()
.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<ForwardedHeadersOptions>(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<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.All;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
// Jwt处理程序
services.AddJwt<JwtHandler>(enableGlobalAuthorize: true);
// Jwt处理程序
services.AddJwt<JwtHandler>(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<CacheOptions>();
services.AddSession();
services.AddMemoryCache(); // 使用本地缓存必须添加
return Task.CompletedTask;
},
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Token 验证通过处理
OnTokenValidated = context =>
{
return Task.CompletedTask;
},
};
});
return services;
}
// 跨域
services.AddCorsAccessor();
// 注册远程请求
services.AddRemoteRequest();
// 视图引擎
services.AddViewEngine();
// 脱敏词汇检测
services.AddSensitiveDetection();
// WebSocket服务
services.AddWebSocketManager();
services.AddSession();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
return services;
}
}

View File

@@ -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<SqlSugarUnitOfWork>();
services.AddConfigurableOptions<ConnectionStringsOptions>();
services.AddConfigurableOptions<TenantOptions>();
services.AddUnitOfWork<SqlSugarUnitOfWork>();
return services;
}

View File

@@ -7,15 +7,15 @@ public class WebComponent : IWebComponent
{
public void Load(WebApplicationBuilder builder, ComponentContext componentContext)
{
//// <20><>־<EFBFBD><D6BE><EFBFBD><EFBFBD>
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 =>
{
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ò<EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> null
// 长度最好不要设置 null
options.Limits.MaxRequestBodySize = 52428800;
});

View File

@@ -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> senparcSetting, IOptions<SenparcWeixinSetting> 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<IMHandler>());
app.MapWebSocketManager("/websocket", serviceProvider.GetRequiredService<IMHandler>());
// 注册EventBus服务
services.ConfigureEventBus();
app.UseEndpoints(endpoints =>
// 注册和配置日志服务
services.ConfigureLogging();
// 注册和配置存储服务
services.ConfigureOSSService();
// 任务调度
//services.AddSchedule(options =>
//{
// options.AddPersistence<DbJobPersistence>();
//});
// 任务调度
services.AddTaskScheduler();
services.AddMemoryCache(); // 使用本地缓存必须添加
services.AddConfigurableOptions<CacheOptions>();
// 微信
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> senparcSetting, IOptions<SenparcWeixinSetting> senparcWeixinSetting)
{
endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
});
// 添加状态码拦截中间件
app.UseUnifyResultStatusCodes();
SnowflakeIdHelper.InitYitIdWorker();
// app.UseHttpsRedirection(); // 强制https
app.UseStaticFiles();
//serviceProvider.GetRequiredService<ITimeTaskService>().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<IMHandler>());
app.MapWebSocketManager("/websocket", serviceProvider.GetRequiredService<IMHandler>());
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
});
SnowflakeIdHelper.InitYitIdWorker();
//serviceProvider.GetRequiredService<ITimeTaskService>().StartTimerJob();
}
}

View File

@@ -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)
{

View File

@@ -11,7 +11,6 @@
<ItemGroup>
<PackageReference Include="AlipaySDKNet.Standard" Version="4.6.442" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" />
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />

View File

@@ -0,0 +1,55 @@
using JNPF.ConfigurableOptions;
namespace JNPF.Common.Core;
/// <summary>
/// 事件总线配置.
/// </summary>
public class EventBusOptions : IConfigurableOptions
{
/// <summary>
/// 事件总线类型.
/// </summary>
public EventBusType EventBusType { get; set; }
/// <summary>
/// 服务器地址.
/// </summary>
public string HostName { get; set; }
/// <summary>
/// 账号.
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 密码.
/// </summary>
public string Password { get; set; }
}
/// <summary>
/// 事件总线自定义事件源存储器类型.
/// </summary>
public enum EventBusType
{
/// <summary>
/// 内存.
/// </summary>
Memory,
/// <summary>
/// RabbitMQ.
/// </summary>
RabbitMQ,
/// <summary>
/// Redis.
/// </summary>
Redis,
/// <summary>
/// Kafka.
/// </summary>
Kafka,
}

View File

@@ -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();
}
/// <summary>
@@ -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();
}
}

View File

@@ -1,5 +1,5 @@
using JNPF.Systems.Entitys.System;
using JNPF.EventBus;
using JNPF.EventBus;
using JNPF.TaskScheduler.Entitys;
using SqlSugar;
namespace JNPF.EventHandler;

View File

@@ -1,5 +1,5 @@
using JNPF.Systems.Entitys.System;
using JNPF.EventBus;
using JNPF.EventBus;
using JNPF.TaskScheduler.Entitys;
using SqlSugar;
namespace JNPF.EventHandler;

View File

@@ -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<ChannelEventSource>(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);
}
/// <summary>
@@ -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<IEventSource> ReadAsync(CancellationToken cancellationToken)
{
// 读取一条事件源
return await _channel.Reader.ReadAsync(cancellationToken);
var eventSource = await _channel.Reader.ReadAsync(cancellationToken);
return eventSource;
}
/// <summary>

View File

@@ -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<TimeTaskEntity>().SetColumns(x => new TimeTaskEntity()
await _sqlSugarClient.CopyNew().Updateable<TimeTaskEntity>().SetColumns(x => new TimeTaskEntity()
{
RunCount = x.RunCount + 1,
LastRunTime = DateTime.Now,

View File

@@ -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
/// </summary>
private static SqlSugarScope? _sqlSugarClient;
/// <summary>
/// 用户服务.
/// </summary>
private readonly IUsersService _usersService;
/// <summary>
/// 构造函数.
/// </summary>
public UserEventSubscriber(ISqlSugarClient context)
public UserEventSubscriber(
ISqlSugarClient context,
IUsersService usersService)
{
_sqlSugarClient = (SqlSugarScope)context;
_usersService = usersService;
}
/// <summary>
@@ -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();
}
/// <summary>
@@ -47,9 +56,10 @@ public class UserEventSubscriber : IEventSubscriber, ISingleton
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
[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());
}
}

View File

@@ -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;
/// </summary>
public class LogExceptionHandler : IGlobalExceptionHandler, ISingleton
{
private readonly IEventPublisher _eventPublisher;
private readonly IEventPublisher _eventPublisher;
public LogExceptionHandler(IEventPublisher eventPublisher)
{
_eventPublisher = eventPublisher;
}
/// <summary>
/// 异步写入异常日记.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
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<ConnectionConfigOptions>();
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<Claim> claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims;
options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject<ConnectionConfigOptions>();
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;
}
/// <summary>
/// 异步写入异常日记.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
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<ConnectionConfigOptions>();
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<Claim> claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims;
options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject<ConnectionConfigOptions>();
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
}));
}
}
}
}

View File

@@ -22,93 +22,92 @@ namespace JNPF.Common.Core.Filter;
/// </summary>
public class RequestActionFilter : IAsyncActionFilter
{
private readonly IEventPublisher _eventPublisher;
private readonly IEventPublisher _eventPublisher;
public RequestActionFilter(IEventPublisher eventPublisher)
{
_eventPublisher = eventPublisher;
}
/// <summary>
/// 请求日记写入.
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
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<ConnectionConfigOptions>();
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<Claim> claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims;
options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject<ConnectionConfigOptions>();
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;
}
/// <summary>
/// 请求日记写入.
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
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<ConnectionConfigOptions>();
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<Claim> claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims;
options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject<ConnectionConfigOptions>();
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())
}));
}
}
}
}
}

View File

@@ -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<MessageEntity, MessageReceiveEntity>((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<MessageEntity, MessageReceiveEntity>((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<MessageEntity>().Where(x => x.DeleteMark == null && x.EnabledMark == 1).OrderBy(x => x.CreatorTime, OrderByType.Desc).FirstAsync();
var unreadSystemMessageCount = await _sqlSugarClient.Queryable<MessageEntity, MessageReceiveEntity>((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<MessageEntity, MessageReceiveEntity>((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);
}

View File

@@ -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;
/// <summary>
/// 作业持久化(数据库).
/// </summary>
public class DbJobPersistence : IJobPersistence
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public DbJobPersistence(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
/// <summary>
/// 作业调度服务启动时.
/// </summary>
/// <returns></returns>
public IEnumerable<SchedulerBuilder> Preload()
{
using var scope = _serviceScopeFactory.CreateScope();
var sqlSugarClient = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
// 获取到对应库连接
var sqlSugarScope = sqlSugarClient.AsTenant().GetConnectionScopeWithAttr<JobDetails>();
var dynamicJobCompiler = scope.ServiceProvider.GetRequiredService<DynamicJobCompiler>();
// 获取所有定义的作业
var allJobs = App.EffectiveTypes.ScanToBuilders().ToList();
//// 若数据库不存在任何作业,则直接返回
if (!sqlSugarScope.Queryable<JobDetails>().Any(u => true)) return allJobs;
// 遍历所有定义的作业
foreach (var schedulerBuilder in allJobs)
{
// 获取作业信息构建器
var jobBuilder = schedulerBuilder.GetJobBuilder();
// 加载数据库数据
var dbDetail = sqlSugarScope.Queryable<JobDetails>().First(u => u.JobId == jobBuilder.JobId);
if (dbDetail == null) continue;
// 同步数据库数据
jobBuilder.LoadFrom(dbDetail);
// 获取作业的所有数据库的触发器
var dbTriggers = sqlSugarScope.Queryable<JobTriggers>().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<JobDetails>().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<JobTriggers>().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;
}
/// <summary>
/// 作业计划初始化通知.
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public SchedulerBuilder OnLoading(SchedulerBuilder builder)
{
return builder;
}
/// <summary>
/// 作业计划Scheduler的JobDetail变化时.
/// </summary>
/// <param name="context"></param>
public void OnChanged(PersistenceContext context)
{
using var scope = _serviceScopeFactory.CreateScope();
var sqlSugarClient = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
// 获取到对应库连接
var sqlSugarScope = sqlSugarClient.AsTenant().GetConnectionScopeWithAttr<JobDetails>();
var jobDetail = context.JobDetail.Adapt<JobDetails>();
// 忽略记载作业组
var ignoreRecordingTasks = new List<string>() { "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<JobDetails>().Where(u => u.JobId == jobDetail.JobId).ExecuteCommand();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
/// <summary>
/// 作业计划Scheduler的触发器Trigger变化时.
/// </summary>
/// <param name="context"></param>
public void OnTriggerChanged(PersistenceTriggerContext context)
{
using var scope = _serviceScopeFactory.CreateScope();
var sqlSugarClient = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
// 获取到对应库连接
var sqlSugarScope = sqlSugarClient.AsTenant().GetConnectionScopeWithAttr<JobDetails>();
var jobTrigger = context.Trigger.Adapt<JobTriggers>();
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<JobTriggers>().Where(u => u.TriggerId == jobTrigger.TriggerId && u.JobId == jobTrigger.JobId).ExecuteCommand();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}

View File

@@ -0,0 +1,31 @@
using JNPF.DependencyInjection;
using JNPF.Schedule;
namespace JNPF.Common.Core;
/// <summary>
/// 动态作业编译.
/// </summary>
public class DynamicJobCompiler : ISingleton
{
/// <summary>
/// 编译代码并返回其中实现 IJob 的类型.
/// </summary>
/// <param name="script">动态编译的作业代码</param>
/// <returns></returns>
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));
}
}

View File

@@ -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
/// <summary>
/// 初始化客户端.
/// </summary>
private static SqlSugarScope _sqlSugarClient;
private static SqlSugarScope? _sqlSugarClient;
/// <summary>
/// 用户管理器.
@@ -41,17 +42,24 @@ public class DataBaseManager : IDataBaseManager, ITransient
/// </summary>
private readonly ConnectionStringsOptions _connectionStrings;
/// <summary>
/// 多租户配置选项.
/// </summary>
private readonly TenantOptions _tenant;
/// <summary>
/// 构造函数.
/// </summary>
public DataBaseManager(
IOptions<ConnectionStringsOptions> connectionOptions,
IUserManager userManager,
IOptions<TenantOptions> tenantOptions,
ISqlSugarClient context)
{
_sqlSugarClient = (SqlSugarScope)context;
_userManager = userManager;
_connectionStrings = connectionOptions.Value;
_tenant = tenantOptions.Value;
}
/// <summary>
@@ -61,46 +69,66 @@ public class DataBaseManager : IDataBaseManager, ITransient
/// <returns>切库后的SqlSugarClient.</returns>
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<ITenantFilter>(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<string, SugarParameter[]>(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<dynamic>(strSql).Count > 0;
var data = _sqlSugarClient.Ado.SqlQuery<dynamic>(strSql).Count > 0;
_sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId);
return data;
}
/// <summary>
@@ -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<IConditionalModel>();
if (pageInput.dataRuleJson.IsNotEmptyOrNull()) dataRuleJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.dataRuleJson);
var querJson = new List<IConditionalModel>();
if (pageInput.queryJson.IsNotEmptyOrNull()) querJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.queryJson);
var superQueryJson = new List<IConditionalModel>();
if (pageInput.superQueryJson.IsNotEmptyOrNull()) superQueryJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.superQueryJson);
// var sql = _sqlSugarClient.SqlQueryable<object>(strSql)
// .Where(querJson).Where(superQueryJson).Where(dataPermissions).ToSqlString();
// .Where(dataRuleJson).Where(querJson).Where(superQueryJson).Where(dataPermissions).ToSqlString();
DataTable dt = _sqlSugarClient.SqlQueryable<object>(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<Dictionary<string, object>>()
var data = new PageResult<Dictionary<string, object>>()
{
pagination = new PageResult()
{
@@ -339,6 +379,10 @@ public class DataBaseManager : IDataBaseManager, ITransient
},
list = dt.ToObject<List<Dictionary<string, string>>>().ToObject<List<Dictionary<string, object>>>()
};
_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;
}
/// <summary>
/// 表是否存在数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <returns></returns>
public bool IsAnyData(DbLinkEntity link, string table)
{
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
_sqlSugarClient = ChangeDataBase(link);
var data = _sqlSugarClient.Queryable<dynamic>().AS(table).Any();
_sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId);
return data;
}
/// <summary>
@@ -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;
}
/// <summary>
@@ -385,41 +451,20 @@ public class DataBaseManager : IDataBaseManager, ITransient
{
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link);
List<DbTableFieldModel> 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<DbTableFieldModel>(string.Format(sql, tableName)).ToList();
}
else
{
list = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt<List<DbTableFieldModel>>();
}
return list;
var list = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(tableName, false);
_sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId);
return list.Adapt<List<DbTableFieldModel>>();
}
public List<string> GetPrimaries(DbLinkEntity? link, string tableName)
public List<string> 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;
}
/// <summary>
@@ -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<dynamic>().AS(tableName).ToDataTable();
var data = _sqlSugarClient.Queryable<dynamic>().AS(tableName).ToDataTable();
_sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId);
return data;
}
/// <summary>
@@ -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);
}
}
/// <summary>
/// 根据链接获取数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <param name="parameters">参数.</param>
/// <returns></returns>
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);
}
/// <summary>
@@ -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<DynamicDbTableModel>(sql).ToList();
var modelList = _sqlSugarClient.Ado.SqlQuery<DatabaseTableListOutput>(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;
}
/// <summary>
@@ -547,8 +631,7 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position";
RefAsync<int> totalNumber = 0;
var list = await _sqlSugarClient.SqlQueryable<object>(dbSql).ToDataTablePageAsync(pageIndex, pageSize, totalNumber);
return PageResult<dynamic>.SqlSugarPageResult(new SqlSugarPagedList<dynamic>()
var data = PageResult<dynamic>.SqlSugarPageResult(new SqlSugarPagedList<dynamic>()
{
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;
}
/// <summary>
@@ -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<TEntity>().ToPageListAsync(pageIndex, pageSize);
var data = await _sqlSugarClient.Queryable<TEntity>().ToPageListAsync(pageIndex, pageSize);
_sqlSugarClient.ChangeDatabase(_connectionStrings.ConfigId);
return data;
}
/// <summary>
@@ -590,6 +677,7 @@ WHERE pcolumn.table_name='{0}' ORDER BY ordinal_position";
List<Dictionary<string, object>> 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;
}
}
/// <summary>

View File

@@ -15,255 +15,272 @@ namespace JNPF.Common.Core.Manager;
/// </summary>
public interface IDataBaseManager
{
/// <summary>
/// 获取多租户Link.
/// </summary>
/// <param name="tenantId">租户ID.</param>
/// <param name="tenantName">租户数据库.</param>
/// <returns>租户的DBLink实体对象.</returns>
DbLinkEntity GetTenantDbLink(string tenantId, string tenantName);
/// <summary>
/// 获取多租户Link.
/// </summary>
/// <param name="tenantId">租户ID.</param>
/// <param name="tenantName">租户数据库.</param>
/// <returns>租户的DBLink实体对象.</returns>
DbLinkEntity GetTenantDbLink(string tenantId, string tenantName);
/// <summary>
/// 数据库切换.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns>切库后的SqlSugarClient.</returns>
SqlSugarScope ChangeDataBase(DbLinkEntity link);
/// <summary>
/// 数据库切换.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns>切库后的SqlSugarClient.</returns>
SqlSugarScope ChangeDataBase(DbLinkEntity link);
/// <summary>
/// 执行Sql(查询).
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <returns></returns>
Task<int> ExecuteSql(DbLinkEntity link, string strSql);
/// <summary>
/// 执行Sql(查询).
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <returns></returns>
Task<int> ExecuteSql(DbLinkEntity link, string strSql);
/// <summary>
/// 条件动态过滤.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <returns>条件是否成立.</returns>
bool WhereDynamicFilter(DbLinkEntity link, string strSql);
/// <summary>
/// 条件动态过滤.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <returns>条件是否成立.</returns>
bool WhereDynamicFilter(DbLinkEntity link, string strSql);
/// <summary>
/// 执行Sql(新增、修改).
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <param name="dicList">数据.</param>
/// <param name="primaryField">主键字段.</param>
/// <returns></returns>
Task<int> ExecuteSql(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "");
/// <summary>
/// 执行Sql(新增、修改).
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <param name="dicList">数据.</param>
/// <param name="primaryField">主键字段.</param>
/// <returns></returns>
Task<int> ExecuteSql(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "");
/// <summary>
/// 执行Sql 新增 并返回自增长Id.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <param name="dicList">数据.</param>
/// <param name="primaryField">主键字段.</param>
/// <returns></returns>
Task<int> ExecuteReturnIdentityAsync(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "");
/// <summary>
/// 执行Sql 新增 并返回自增长Id.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <param name="dicList">数据.</param>
/// <param name="primaryField">主键字段.</param>
/// <returns></returns>
Task<int> ExecuteReturnIdentityAsync(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "");
/// <summary>
/// 创建表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableModel">表对象.</param>
/// <param name="tableFieldList">字段对象.</param>
/// <returns></returns>
Task<bool> Create(DbLinkEntity link, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList);
/// <summary>
/// 创建表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableModel">表对象.</param>
/// <param name="tableFieldList">字段对象.</param>
/// <returns></returns>
Task<bool> Create(DbLinkEntity link, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList);
/// <summary>
/// sqlsugar添加表字段.
/// </summary>
/// <param name="tableName">表名.</param>
/// <param name="tableFieldList">表字段集合.</param>
void AddTableColumn(DbLinkEntity link, string tableName, List<DbTableFieldModel> tableFieldList);
/// <summary>
/// sqlsugar添加表字段.
/// </summary>
/// <param name="tableName">表名.</param>
/// <param name="tableFieldList">表字段集合.</param>
void AddTableColumn(DbLinkEntity link ,string tableName, List<DbTableFieldModel> tableFieldList);
/// <summary>
/// 删除表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <returns></returns>
bool Delete(DbLinkEntity link, string table);
/// <summary>
/// 删除表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <returns></returns>
bool Delete(DbLinkEntity link, string table);
/// <summary>
/// 修改表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="oldTable">旧表名称.</param>
/// <param name="tableModel">表对象.</param>
/// <param name="tableFieldList">字段对象.</param>
/// <returns></returns>
Task<bool> Update(DbLinkEntity link, string oldTable, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList);
/// <summary>
/// 修改表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="oldTable">旧表名称.</param>
/// <param name="tableModel">表对象.</param>
/// <param name="tableFieldList">字段对象.</param>
/// <returns></returns>
Task<bool> Update(DbLinkEntity link, string oldTable, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList);
/// <summary>
/// 根据链接获取分页数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">Sql语句.</param>
/// <param name="pageInput">页数.</param>
/// <param name="columnDesign">列配置.</param>
/// <param name="dataPermissions">数据权限.</param>
/// <param name="outColumnName">输出列名称.</param>
/// <returns></returns>
PageResult<Dictionary<string, object>> GetInterFaceData(DbLinkEntity link, string strSql, VisualDevModelListQueryInput pageInput, MainBeltViceQueryModel columnDesign, List<IConditionalModel> dataPermissions, Dictionary<string, string> outColumnName = null);
/// <summary>
/// 根据链接获取分页数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">Sql语句.</param>
/// <param name="pageInput">页数.</param>
/// <param name="columnDesign">列配置.</param>
/// <param name="dataPermissions">数据权限.</param>
/// <param name="outColumnName">输出列名称.</param>
/// <returns></returns>
PageResult<Dictionary<string, object>> GetInterFaceData(DbLinkEntity link, string strSql, VisualDevModelListQueryInput pageInput, MainBeltViceQueryModel columnDesign, List<IConditionalModel> dataPermissions, Dictionary<string, string> outColumnName = null);
/// <summary>
/// 表是否存在.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <returns></returns>
bool IsAnyTable(DbLinkEntity link, string table);
/// <summary>
/// 表是否存在.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <returns></returns>
bool IsAnyTable(DbLinkEntity link, string table);
/// <summary>
/// 表字段是否存在.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <param name="column">表字段名.</param>
/// <returns></returns>
bool IsAnyColumn(DbLinkEntity link, string table, string column);
/// <summary>
/// 表是否存在数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <returns></returns>
bool IsAnyData(DbLinkEntity link, string table);
/// <summary>
/// 获取表字段列表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableName">表名.</param>
/// <returns></returns>
List<DbTableFieldModel> GetFieldList(DbLinkEntity? link, string? tableName);
/// <summary>
/// 表字段是否存在.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="table">表名.</param>
/// <param name="column">表字段名.</param>
/// <returns></returns>
bool IsAnyColumn(DbLinkEntity link, string table, string column);
/// <summary>
/// 获取表的主键
/// </summary>
/// <param name="link"></param>
/// <param name="tableName"></param>
/// <returns></returns>
List<string> GetPrimaries(DbLinkEntity? link, string tableName);
/// <summary>
/// 获取表字段列表.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableName">表名.</param>
/// <returns></returns>
List<DbTableFieldModel> GetFieldList(DbLinkEntity? link, string? tableName);
/// <summary>
/// 获取表数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableName">表名.</param>
/// <returns></returns>
DataTable GetData(DbLinkEntity link, string tableName);
/// <summary>
/// 获取表数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableName">表名.</param>
/// <returns></returns>
DataTable GetData(DbLinkEntity link, string tableName);
/// <summary>
/// 根据链接获取数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">Sql语句.</param>
/// <param name="parameters">参数.</param>
/// <returns></returns>
DataTable GetInterFaceData(DbLinkEntity link, string strSql, params SugarParameter[] parameters);
/// <summary>
/// 根据链接获取数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">Sql语句.</param>
/// <param name="parameters">参数.</param>
/// <returns></returns>
DataTable GetInterFaceData(DbLinkEntity link, string strSql, params SugarParameter[] parameters);
/// <summary>
/// 获取表信息.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableName">表名.</param>
/// <returns></returns>
DatabaseTableInfoOutput GetDataBaseTableInfo(DbLinkEntity link, string tableName);
/// <summary>
/// 根据链接获取数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <param name="parameters">参数.</param>
/// <returns></returns>
public DataTable GetInterFaceDataCopyNew(DbLinkEntity link, string strSql, params SugarParameter[] parameters);
/// <summary>
/// 获取数据库表信息.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns></returns>
List<DatabaseTableListOutput> GetDBTableList(DbLinkEntity link);
/// <summary>
/// 获取表信息.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="tableName">表名.</param>
/// <returns></returns>
DatabaseTableInfoOutput GetDataBaseTableInfo(DbLinkEntity link, string tableName);
/// <summary>
/// 获取数据库表信息.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns></returns>
List<DbTableInfo> GetTableInfos(DbLinkEntity link);
/// <summary>
/// 获取数据库表信息.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns></returns>
List<DatabaseTableListOutput> GetDBTableList(DbLinkEntity link);
/// <summary>
/// 获取数据表分页(SQL语句).
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="dbSql">数据SQL.</param>
/// <param name="pageIndex">页数.</param>
/// <param name="pageSize">条数.</param>
/// <returns></returns>
Task<dynamic> GetDataTablePage(DbLinkEntity link, string dbSql, int pageIndex, int pageSize);
/// <summary>
/// 获取数据库表信息.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns></returns>
List<DbTableInfo> GetTableInfos(DbLinkEntity link);
/// <summary>
/// 获取数据表分页(实体).
/// </summary>
/// <typeparam name="TEntity">T.</typeparam>
/// <param name="link">数据连接.</param>
/// <param name="pageIndex">页数.</param>
/// <param name="pageSize">条数.</param>
/// <returns></returns>
Task<List<TEntity>> GetDataTablePage<TEntity>(DbLinkEntity link, int pageIndex, int pageSize);
/// <summary>
/// 获取数据表分页(SQL语句).
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="dbSql">数据SQL.</param>
/// <param name="pageIndex">页数.</param>
/// <param name="pageSize">条数.</param>
/// <returns></returns>
Task<dynamic> GetDataTablePage(DbLinkEntity link, string dbSql, int pageIndex, int pageSize);
/// <summary>
/// 使用存储过程.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="stored">存储过程名称.</param>
/// <param name="parameters">数.</param>
void UseStoredProcedure(DbLinkEntity link, string stored, List<SugarParameter> parameters);
/// <summary>
/// 获取数据表分页(实体).
/// </summary>
/// <typeparam name="TEntity">T.</typeparam>
/// <param name="link">数据连接.</param>
/// <param name="pageIndex">数.</param>
/// <param name="pageSize">条数.</param>
/// <returns></returns>
Task<List<TEntity>> GetDataTablePage<TEntity>(DbLinkEntity link, int pageIndex, int pageSize);
/// <summary>
/// 测试数据库连接.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns></returns>
bool IsConnection(DbLinkEntity link);
/// <summary>
/// 使用存储过程.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="stored">存储过程名称.</param>
/// <param name="parameters">参数.</param>
void UseStoredProcedure(DbLinkEntity link, string stored, List<SugarParameter> parameters);
/// <summary>
/// 同步数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="dt">同步数据.</param>
/// <param name="table">表.</param>
/// <returns></returns>
Task<bool> SyncData(DbLinkEntity link, DataTable dt, string table);
/// <summary>
/// 测试数据库连接.
/// </summary>
/// <param name="link">数据连接.</param>
/// <returns></returns>
bool IsConnection(DbLinkEntity link);
/// <summary>
/// 同步表操作.
/// </summary>
/// <param name="linkFrom">数据.</param>
/// <param name="linkTo">目前数据.</param>
/// <param name="table">表名称.</param>
/// <param name="type">操作类型.</param>
/// <param name="fieldType">数据类型.</param>
void SyncTable(DbLinkEntity linkFrom, DbLinkEntity linkTo, string table, int type, Dictionary<string, string> fieldType);
/// <summary>
/// 同步数据.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="dt">同步数据.</param>
/// <param name="table">表.</param>
/// <returns></returns>
Task<bool> SyncData(DbLinkEntity link, DataTable dt, string table);
/// <summary>
/// 视图数据类型转换.
/// </summary>
/// <param name="fields">字段数据.</param>
/// <param name="databaseType">数据库类型.</param>
List<TableFieldOutput> ViewDataTypeConversion(List<TableFieldOutput> fields, SqlSugar.DbType databaseType);
/// <summary>
/// 同步表操作.
/// </summary>
/// <param name="linkFrom">原数据.</param>
/// <param name="linkTo">目前数据库.</param>
/// <param name="table">表名称.</param>
/// <param name="type">操作类型.</param>
/// <param name="fieldType">数据类型.</param>
void SyncTable(DbLinkEntity linkFrom, DbLinkEntity linkTo, string table, int type, Dictionary<string, string> fieldType);
/// <summary>
/// 转换数据类型.
/// </summary>
/// <param name="dbType">数据库类型.</param>
/// <returns></returns>
SqlSugar.DbType ToDbType(string dbType);
/// <summary>
/// 视图数据类型转换.
/// </summary>
/// <param name="fields">字段数据.</param>
/// <param name="databaseType">数据库类型.</param>
List<TableFieldOutput> ViewDataTypeConversion(List<TableFieldOutput> fields, SqlSugar.DbType databaseType);
/// <summary>
/// 转换连接字符串.
/// </summary>
/// <param name="dbLinkEntity">数据连接.</param>
/// <returns></returns>
string ToConnectionString(DbLinkEntity dbLinkEntity);
/// <summary>
/// 转换数据库类型.
/// </summary>
/// <param name="dbType">数据库类型.</param>
/// <returns></returns>
SqlSugar.DbType ToDbType(string dbType);
/// <summary>
/// 执行增删改sql.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <param name="parameters">参数.</param>
void ExecuteCommand(DbLinkEntity link, string strSql, params SugarParameter[] parameters);
/// <summary>
/// 转换连接字符串.
/// </summary>
/// <param name="dbLinkEntity">数据连接.</param>
/// <returns></returns>
string ToConnectionString(DbLinkEntity dbLinkEntity);
/// <summary>
/// 执行增删改sql.
/// </summary>
/// <param name="link">数据连接.</param>
/// <param name="strSql">sql语句.</param>
/// <param name="parameters">参数.</param>
void ExecuteCommand(DbLinkEntity link, string strSql, params SugarParameter[] parameters);
/// <summary>
/// 获取表的主键
/// </summary>
/// <param name="link"></param>
/// <param name="tableName"></param>
/// <returns></returns>
List<string> GetPrimaries(DbLinkEntity? link, string tableName);
}

View File

@@ -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);
}
}
/// <summary>
/// 复制文件.
/// </summary>
/// <param name="filePath">源文件地址.</param>
/// <param name="toFilePath">剪切地址.</param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取地址和文件名.
/// </summary>
/// <param name="input"></param>
/// <param name="saveFileName"></param>
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;
}
}
}

View File

@@ -80,6 +80,14 @@ namespace JNPF.Common.Core.Manager.Files
/// <param name="toFilePath">剪切地址.</param>
/// <returns></returns>
Task MoveFile(string filePath, string toFilePath);
/// <summary>
/// 复制文件.
/// </summary>
/// <param name="filePath">源文件地址.</param>
/// <param name="toFilePath">剪切地址.</param>
/// <returns></returns>
Task CopyFile(string filePath, string toFilePath);
#endregion
/// <summary>
@@ -109,5 +117,12 @@ namespace JNPF.Common.Core.Manager.Files
/// <param name="size"></param>
/// <returns></returns>
string GetFileSize(long size);
/// <summary>
/// 获取地址和文件名.
/// </summary>
/// <param name="input"></param>
/// <param name="saveFileName"></param>
void GetChunkModel(ChunkModel input, string saveFileName);
}
}

View File

@@ -145,4 +145,16 @@ public interface IUserManager
/// <param name="organizeId">组织Id.</param>
/// <returns></returns>
Task<List<string>> GetUserOrgRoleIds(string roleIds, string organizeId);
/// <summary>
/// 判断是否管理员.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
bool IsAdmin(string userId);
/// <summary>
/// 获取管理员用户id.
/// </summary>
string GetAdminUserId();
}

View File

@@ -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
/// </summary>
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"];
}
/// <summary>
@@ -134,7 +135,7 @@ public class UserManager : IUserManager, IScoped
/// </summary>
public string TenantId
{
get => ConnectionConfig.ConfigId;
get => ConnectionConfig?.ConfigId;
}
/// <summary>
@@ -142,7 +143,7 @@ public class UserManager : IUserManager, IScoped
/// </summary>
public string TenantDbName
{
get => ConnectionConfig.ConfigList.Find(it => it.IsMaster.Equals(true)).ServiceName;
get => ConnectionConfig?.ConfigList?.Find(it => it.IsMaster.Equals(true)).ServiceName;
}
/// <summary>
@@ -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<SysConfigEntity>().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<SignImgEntity>().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<OrganizeEntity>().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<SysConfigEntity>().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
}
}
/// <summary>
/// 会否存在用户缓存.
/// </summary>
/// <param name="cacheKey"></param>
/// <returns></returns>
private async Task<bool> ExistsUserInfo(string cacheKey)
{
return await _cacheManager.ExistsAsync(cacheKey);
}
/// <summary>
/// 保存用户登录信息.
/// </summary>
@@ -2031,4 +2046,35 @@ public class UserManager : IUserManager, IScoped
{
return await _cacheManager.SetAsync(cacheKey, userInfo, timeSpan);
}
/// <summary>
/// 获取用户登录信息.
/// </summary>
/// <param name="cacheKey">key.</param>
/// <returns></returns>
private async Task<UserInfoModel> GetUserInfo(string cacheKey)
{
return (await _cacheManager.GetAsync(cacheKey)).Adapt<UserInfoModel>();
}
/// <summary>
/// 判断是否管理员.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public bool IsAdmin(string userId)
{
if (userId == "admin") return true;
return _repository.AsSugarClient().Queryable<UserEntity>().Any(x => x.Id == userId && x.Account == "admin" && x.DeleteMark == null);
}
/// <summary>
/// 获取管理员用户id.
/// </summary>
public string GetAdminUserId()
{
var user = _repository.AsSugarClient().Queryable<UserEntity>().First(x => x.Account == "admin" && x.DeleteMark == null);
if (user.IsNotEmptyOrNull()) return user.Id;
return string.Empty;
}
}

View File

@@ -12,11 +12,13 @@
<ItemGroup>
<PackageReference Include="RabbitMQ.Client" Version="6.4.0" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.0" />
<PackageReference Include="DotNetCore.Natasha.CSharp" Version="5.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\message\Tnb.Message.Entitys\Tnb.Message.Entitys.csproj" />
<ProjectReference Include="..\..\system\Tnb.Systems.Entitys\Tnb.Systems.Entitys.csproj" />
<ProjectReference Include="..\..\system\Tnb.Systems.Interfaces\Tnb.Systems.Interfaces.csproj" />
<ProjectReference Include="..\..\taskschedule\Tnb.TaskScheduler.Entitys\Tnb.TaskScheduler.Entitys.csproj" />
<ProjectReference Include="..\..\visualdev\Tnb.VisualDev.Entitys\Tnb.VisualDev.Entitys.csproj" />
<ProjectReference Include="..\Tnb.WebSockets\Tnb.WebSockets.csproj" />

View File

@@ -28,6 +28,17 @@ public class KeyVariable
}
}
/// <summary>
/// 多租户模式.
/// </summary>
public static string MultiTenancyType
{
get
{
return _tenant.MultiTenancyType;
}
}
/// <summary>
/// 系统文件路径.
/// </summary>

View File

@@ -42,4 +42,9 @@ public class ClaimConst
/// 单一登录方式1后登录踢出先登录 2同时登录.
/// </summary>
public const string SINGLELOGIN = "SingleLogin";
/// <summary>
/// 单点登录标识.
/// </summary>
public const string OnlineTicket = "OnlineTicket";
}

View File

@@ -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
/// <summary>
/// 用户缓存.
/// </summary>
public const string CACHEKEYUSER = "user_";
public const string CACHEKEYUSER = "jnpf:permission:user";
/// <summary>
/// 菜单缓存.
@@ -102,4 +102,19 @@ public class CommonConst
/// 第三方登录 票据缓存key.
/// </summary>
public const string PARAMS_JNPF_TICKET = "jnpf_ticket";
/// <summary>
/// Cas Key.
/// </summary>
public const string CAS_Ticket = "ticket";
/// <summary>
/// Code.
/// </summary>
public const string Code = "code";
/// <summary>
/// 外链密码开关(1开 , 0关).
/// </summary>
public const int OnlineDevData_State_Enable = 1;
}

View File

@@ -52,7 +52,7 @@ public abstract class CDEntityBase : EntityBase<string>, ICreatorTime, IDeleteTi
/// </summary>
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<string>, ICreatorTime, IDeleteTi
/// </summary>
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;

View File

@@ -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<string>, ICreatorTime
/// </summary>
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))

View File

@@ -64,7 +64,7 @@ public abstract class CLDEntityBase : EntityBase<string>, ICreatorTime, IDeleteT
/// </summary>
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;

View File

@@ -40,7 +40,7 @@ public class CLEntityBase : EntityBase<string>, ICreatorTime
/// </summary>
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))

View File

@@ -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;
/// 实体类基类.
/// </summary>
[SuppressSniffer]
public abstract class EntityBase<TKey> : IEntity<TKey>
public abstract class EntityBase<TKey> : ITenantFilter, IEntity<TKey>
where TKey : IEquatable<TKey>
{
/// <summary>
@@ -15,4 +16,10 @@ public abstract class EntityBase<TKey> : IEntity<TKey>
/// </summary>
[SugarColumn(ColumnName = "F_Id", ColumnDescription = "主键", IsPrimaryKey = true)]
public TKey Id { get; set; }
/// <summary>
/// 获取或设置 租户id.
/// </summary>
[SugarColumn(ColumnName = "F_TenantId", ColumnDescription = "租户id")]
public string TenantId { get; set; }
}

View File

@@ -670,6 +670,11 @@ public enum ErrorCode
[ErrorCodeItemMetadata("第三方登录未配置!")]
D5025,
/// <summary>
/// 修改失败,新建密码不能与旧密码一样.
/// </summary>
[ErrorCodeItemMetadata("修改失败,新建密码不能与旧密码一样")]
D5026,
#endregion
#region 6
@@ -968,6 +973,11 @@ public enum ErrorCode
[ErrorCodeItemMetadata("验证码限定范围:3 - 6位")]
D9009,
/// <summary>
/// 打印模板不存在.
/// </summary>
[ErrorCodeItemMetadata("打印模板不存在")]
D9010,
#endregion
#region 10
@@ -1107,12 +1117,28 @@ public enum ErrorCode
D1417,
/// <summary>
/// 该功能不存在,可能已被删除.
/// 密码错误.
/// </summary>
[ErrorCodeItemMetadata("该功能( id: {0} )不存在,可能已被删除")]
[ErrorCodeItemMetadata("密码错误")]
D1418,
/// <summary>
/// 缺少租户信息.
/// </summary>
[ErrorCodeItemMetadata("缺少租户信息")]
D1419,
/// <summary>
/// 无效链接.
/// </summary>
[ErrorCodeItemMetadata("无效链接")]
D1420,
/// <summary>
/// 发布失败,流程未设计.
/// </summary>
[ErrorCodeItemMetadata("发布失败,流程未设计")]
D1421,
#endregion
#region 15
@@ -1201,6 +1227,18 @@ public enum ErrorCode
[ErrorCodeItemMetadata("Sql不能为空")]
D1513,
/// <summary>
/// 表名超过规定长度.
/// </summary>
[ErrorCodeItemMetadata("表名超过规定长度")]
D1514,
/// <summary>
/// 列名超过规定长度.
/// </summary>
[ErrorCodeItemMetadata("列名超过规定长度")]
D1515,
#endregion
#region 16
@@ -1425,9 +1463,9 @@ public enum ErrorCode
D2104,
/// <summary>
/// 表缺失流程Id.
/// 表缺失流程Id字段.
/// </summary>
[ErrorCodeItemMetadata("表缺失流程Id")]
[ErrorCodeItemMetadata("表缺失流程Id字段F_FLowId")]
D2105,
/// <summary>
@@ -1454,6 +1492,12 @@ public enum ErrorCode
[ErrorCodeItemMetadata("模板主键策略与表主键策略不同")]
D2109,
/// <summary>
/// 表缺失逻辑删除字段.
/// </summary>
[ErrorCodeItemMetadata("表缺失逻辑删除字段F_DeleteMark")]
D2110,
#endregion
#region 22
@@ -1772,11 +1816,46 @@ public enum ErrorCode
WF0045,
/// <summary>
/// 退回至您的审批,不能再撤回审批.
/// 此流程已被挂起,无法操作!.
/// </summary>
[ErrorCodeItemMetadata("退回至您的审批,不能再撤回审批!")]
[ErrorCodeItemMetadata("流程处于挂起状态,不可操作!")]
WF0046,
/// <summary>
/// {0}流程已被挂起,无法操作!.
/// </summary>
[ErrorCodeItemMetadata("{0}流程已被挂起不能删除!")]
WF0047,
/// <summary>
/// 退回至您的审批,不能再撤回审批.
/// </summary>
[ErrorCodeItemMetadata("退回至您的审批,不能再撤回审批!")]
WF0048,
/// <summary>
/// 您没有该流程的发起权限.
/// </summary>
[ErrorCodeItemMetadata("您没有该流程的发起权限")]
WF0049,
/// <summary>
/// 下一节点已审批,不能撤回!
/// </summary>
[ErrorCodeItemMetadata("下一节点已审批,不能撤回!")]
WF0050,
/// <summary>
/// 流程已撤回,不能重复操作!.
/// </summary>
[ErrorCodeItemMetadata("流程已撤回,不能重复操作!")]
WF0051,
/// <summary>
/// 该流程由在线开发生成的,无法直接删除,请在功能设计中删除相关功能!.
/// </summary>
[ErrorCodeItemMetadata("该流程由在线开发生成的,无法直接删除,请在功能设计中删除相关功能!")]
WF0052,
#endregion
#region Ex
@@ -2018,9 +2097,9 @@ public enum ErrorCode
COM1015,
/// <summary>
/// 未找到流程引擎.
/// 流程未设计,请先设计流程.
/// </summary>
[ErrorCodeItemMetadata("未找到流程引擎")]
[ErrorCodeItemMetadata("流程未设计,请先设计流程")]
COM1016,
/// <summary>
@@ -2028,5 +2107,23 @@ public enum ErrorCode
/// </summary>
[ErrorCodeItemMetadata("该功能配置的流程处于停用状态")]
COM1017,
/// <summary>
/// 该功能配置的流程处于停用状态.
/// </summary>
[ErrorCodeItemMetadata("接口请求失败")]
COM1018,
/// <summary>
/// 该功能未导入流程表单!.
/// </summary>
[ErrorCodeItemMetadata("该功能未导入流程表单!")]
COM1019,
/// <summary>
/// 接口数据异常!.
/// </summary>
[ErrorCodeItemMetadata("接口数据异常!")]
COM1020,
#endregion
}

View File

@@ -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
{
/// <summary>
/// 工艺路线类型
/// </summary>
public enum RouteType
{
/// <summary>
/// 标准途程
/// </summary>
[Description("标准途程")]
Standard=1,
/// <summary>
/// 返工途程
/// </summary>
[Description("返工途程")]
Rework=2,
/// <summary>
/// 试制途程
/// </summary>
[Description("试制途程")]
Trial=4,
/// <summary>
/// 返修途程
/// </summary>
[Description("返修途程")]
RMA =8,
}
}

View File

@@ -31,7 +31,7 @@ public static class BooleanExtensions
/// </summary>
private static bool? GetBool(this object data)
{
switch (data.ToString()?.Trim().ToLower())
switch (data.ToString().Trim().ToLower())
{
case "0":
return false;

View File

@@ -18,7 +18,7 @@ public static class DictionaryExtensions
/// <param name="dictionary">要操作的字典.</param>
/// <param name="key">指定键名.</param>
/// <returns>获取到的值.</returns>
public static TValue? GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
{
return dictionary.TryGetValue(key, out TValue value) ? value : default(TValue);
}

View File

@@ -693,4 +693,25 @@ public static partial class Extensions
}
#endregion
#region List
/// <summary>
/// 嵌套List解析
/// 仅限于列表查询条件多选.
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
public static List<string> ParseToNestedList(this List<List<string>> list)
{
List<string> result = new List<string>();
if (list != null && list.Count > 0)
{
foreach (var item in list)
result.Add(item.Last());
}
return result;
}
#endregion
}

View File

@@ -67,7 +67,7 @@ public static class RandomExtensions
public static T NextItem<T>(this Random random, T[] items)
{
if (items == null || items.Length == 0)
return default(T)!;
return default(T);
return items[random.Next(items.Length)];
}

View File

@@ -354,7 +354,7 @@ public static class StringExtensions
/// 指示指定的字符串是 null、空或者仅由空白字符组成.
/// </summary>
[DebuggerStepThrough]
public static bool IsNullOrWhiteSpace(this string value)
public static bool IsNullOrWhiteSpace(this string? value)
{
return string.IsNullOrWhiteSpace(value);
}

View File

@@ -41,4 +41,20 @@ public class CodeGenAuthorizeModuleResource
/// 权限条件.
/// </summary>
public List<object> conditionalModel { get; set; }
}
/// <summary>
/// 代码生成 数据过滤.
/// </summary>
public class CodeGenDataRuleModuleResourceModel : CodeGenAuthorizeModuleResourceModel
{
/// <summary>
/// 请求类型 pc 和 app.
/// </summary>
public string UserOrigin { get; set; }
/// <summary>
/// 权限条件 json.
/// </summary>
public string conditionalModelJson { get; set; }
}

View File

@@ -86,4 +86,19 @@ public class ChunkModel
/// 文件.
/// </summary>
public IFormFile file { get; set; }
/// <summary>
/// 路径类型 defaultPath(默认路径) selfPath(自定义路径).
/// </summary>
public string pathType { get; set; } = "defaultPath";
/// <summary>
/// 是否用户存储0否1是.
/// </summary>
public string isAccount { get; set; } = "0";
/// <summary>
/// 自定义文件夹路径.
/// </summary>
public string folder { get; set; }
}

View File

@@ -32,4 +32,9 @@ public class FileControlsModel
/// 文件后缀.
/// </summary>
public string? fileExtension { get; set; }
/// <summary>
/// 文件名称.
/// </summary>
public string? fileName { get; set; }
}

View File

@@ -6,7 +6,8 @@ namespace JNPF.Common.Models.NPOI;
/// <summary>
/// Excel导出列名
/// 版 本V3.0.0
/// 版 权:拓通智联科技有限公司http://www.tuotong-tech.com
/// 版 权:引迈信息技术有限公司https://www.jnpfsoft.com
/// 作 者JNPF开发平台组
/// 日 期2017.03.09.
/// </summary>
[SuppressSniffer]

View File

@@ -6,7 +6,8 @@ namespace JNPF.Common.Models.NPOI;
/// <summary>
/// Excel导出配置
/// 版 本V3.0.0
/// 版 权:拓通智联科技有限公司http://www.tuotong-tech.com
/// 版 权:引迈信息技术有限公司https://www.jnpfsoft.com
/// 作 者JNPF开发平台组
/// 日 期2017.03.09.
/// </summary>
[SuppressSniffer]

View File

@@ -5,7 +5,8 @@ namespace JNPF.Common.Models.NPOI;
/// <summary>
/// Excel导出模板
/// 版 本V3.0.0
/// 版 权:拓通智联科技有限公司http://www.tuotong-tech.com
/// 版 权:引迈信息技术有限公司https://www.jnpfsoft.com
/// 作 者JNPF开发平台组
/// 日 期2017.03.09.
/// </summary>
[SuppressSniffer]

View File

@@ -5,7 +5,7 @@ namespace JNPF.Common.Models.User
/// <summary>
/// 登录者信息
/// 版 本V3.2.0
/// 版 权:拓通智联科技有限公司http://www.tuotong-tech.com
/// 版 权:引迈信息技术有限公司https://www.jnpfsoft.com
/// 作 者JNPF开发平台组.
/// </summary>
[SuppressSniffer]
@@ -51,6 +51,11 @@ namespace JNPF.Common.Models.User
/// </summary>
public string organizeId { get; set; }
/// <summary>
/// 所属组织 Id 树.
/// </summary>
public List<string> organizeIdList { get; set; }
/// <summary>
/// 组织名称.
/// </summary>
@@ -225,6 +230,11 @@ namespace JNPF.Common.Models.User
/// </summary>
public string signImg { get; set; }
/// <summary>
/// 默认签名.
/// </summary>
public DateTime? changePasswordDate { get; set; }
/// <summary>
/// 系统集合.
/// </summary>

View File

@@ -53,6 +53,11 @@ public class UserOnlineModel
/// </summary>
public string token { get; set; }
/// <summary>
/// 单点登录标识.
/// </summary>
public string onlineTicket { get; set; }
/// <summary>
/// 是否移动端.
/// </summary>

View File

@@ -46,5 +46,10 @@
/// 流程类型.
/// </summary>
public int? type { get; set; }
/// <summary>
/// 所属流程名称.
/// </summary>
public string? flowName { get; set; }
}
}

View File

@@ -0,0 +1,103 @@
using Aspose.Cells;
using JNPF.Common.Enums;
using JNPF.ConfigurableOptions;
using NPOI.SS.Formula.Functions;
namespace JNPF.Common.Options;
/// <summary>
/// 单点登录配置.
/// </summary>
public sealed class OauthOptions : IConfigurableOptions
{
/// <summary>
/// 是否启用.
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 前端登录页面访问登录接口进行单点登录页面跳转, 需要与身份管理系统中的 JNPF-Auth2、JNPF-CAS中的认证地址一致.
/// </summary>
public string LoginPath { get; set; }
/// <summary>
/// 从单点登录中心直接访问JNPF时登录成功后跳转的前端页面.
/// </summary>
public string SucessFrontUrl { get; set; }
/// <summary>
/// 默认接口.
/// </summary>
public string DefaultSSO { get; set; }
/// <summary>
/// 缓存过期时间 / 分钟.
/// </summary>
public int TicketTimeout { get; set; }
/// <summary>
/// 是否前端输出消息.
/// </summary>
public bool TicketOutMessage { get; set; }
/// <summary>
/// 登录模式.
/// </summary>
public SSO SSO { get; set; }
/// <summary>
/// 用户推送.
/// </summary>
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; }
}

View File

@@ -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++)
{

View File

@@ -160,6 +160,79 @@ public static class CodeGenHelper
}
}
/// <summary>
/// 数据列表生成树形表格.
/// </summary>
/// <param name="realList">数据列表.</param>
/// <param name="parentField">树形父级字段.</param>
/// <param name="treeShowField">树形显示字段.</param>
/// <returns></returns>
public static List<Dictionary<string, object>> GetTreeList(List<Dictionary<string, object>> realList, string parentField, string treeShowField)
{
var res = new List<Dictionary<string, object>>();
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<Dictionary<string, object>> allList, Dictionary<string, object> 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;
}
}
/// <summary>
/// 根据集合捞取所有子集id.
/// </summary>
/// <param name="allList">key : 主键Id , value 父亲Id.</param>
/// <param name="currentId">当前id.</param>
/// <param name="resList">res.</param>
public static List<string> GetChildIdList(Dictionary<string, string> allList, string currentId, List<string> resList)
{
if (resList == null) resList = new List<string>() { 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;
}
/// <summary>
/// 获取排序真实字段.
/// </summary>
@@ -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;
}
/// <summary>

View File

@@ -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;

View File

@@ -49,6 +49,17 @@ public static class JsonHelper
return _jsonSerializer.Deserialize<T>(json);
}
/// <summary>
/// JSON 字符串转 Object.
/// </summary>
/// <typeparam name="T">动态类型.</typeparam>
/// <param name="json">对象.</param>
/// <returns></returns>
public static T ToObjectOld<T>(this string json)
{
return _ = JsonConvert.DeserializeObject<T>(json) ?? default(T);
}
/// <summary>
/// JSON 字符串转 Object.
/// </summary>

View File

@@ -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;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,11 @@ namespace JNPF.Common.Security;
public static class XmlHelper
{
/// <summary>
/// 反序列化
/// </summary>
/// <param name="type">类型</param>
/// <param name="xml">XML字符串</param>
/// <summary>
/// 反序列化.
/// </summary>
/// <param name="type">类型.</param>
/// <param name="xml">XML字符串.</param>
/// <returns></returns>
public static object Deserialize(Type type, string xml)
{
@@ -19,13 +19,12 @@ public static class XmlHelper
}
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="type"></param>
/// <param name="xml"></param>
/// <returns></returns>
/// <summary>
/// 反序列化.
/// </summary>
/// <param name="type">类型.</param>
/// <param name="stream">XML流.</param>
/// <returns></returns>
public static object Deserialize(Type type, Stream stream)
{
XmlSerializer xmldes = new XmlSerializer(type);

View File

@@ -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<T> where T : class, new() // 需要无参构造函数,构造表达式树的时候需要利用无参构造函数创建对象
{
/// <summary>
/// 映射表达式,泛型缓存每个类型存一份
/// </summary>
private static readonly Func<T, T> s_CopyFunc = null;
/// <summary>
/// 静态构造函数,每个泛型类型会且只会执行一次
/// </summary>
static DeepCopyHelper()
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "m"); // 参数m :m =>
List<MemberBinding> memberBindingList = new List<MemberBinding>();
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<Func<T, T>> lambda = Expression.Lambda<Func<T, T>>(memberInitExpression, new ParameterExpression[]
{
parameterExpression
}); // m => new T() {Name = m.Name}
s_CopyFunc = lambda.Compile();
}
/// <summary>
/// 对象拷贝拷贝private/public实例成员、属性、静态成员
/// </summary>
/// <param name="data">源</param>
/// <returns></returns>
public static T DeepCopy(T data)
{
return s_CopyFunc(data);
}
/// <summary>
/// 集合拷贝拷贝private/public实例成员、属性、静态成员
/// </summary>
/// <param name="data">源</param>
/// <returns></returns>
public static List<T> DeepCopyList(List<T> data)
{
if (data == null || data.Count < 1)
{
return Enumerable.Empty<T>().ToList();
}
return data.Select(a => DeepCopy(a)).ToList();
}
}
}

View File

@@ -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;
/// </summary>
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
/// </summary>
static JNPFTenantExtensions()
{
var config = new ConfigurationBuilder().AddJsonFile("Configurations/ConnectionStrings.json", true, true).Build();
_connOpt = config.GetSection("ConnectionStrings").Get<ConnectionStringsOptions>();
_config = new ConfigurationBuilder().Add(new JsonConfigurationSource { Path = "Configurations/ConnectionStrings.json", ReloadOnChange = true }).Build();
}
/// <summary>
@@ -33,14 +32,15 @@ public class JNPFTenantExtensions
/// <returns></returns>
public static ConnectionConfigOptions GetLinkToOrdinary(string configId, string tableName)
{
ConnectionStringsOptions conn = App.GetConfig<ConnectionStringsOptions>("ConnectionStrings", true);
List<DBConnectionConfig> configList = new List<DBConnectionConfig>();
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()
{

View File

@@ -0,0 +1,15 @@
using SqlSugar;
namespace JNPF.Extras.DatabaseAccessor.SqlSugar.Models;
/// <summary>
/// 实体类基类.
/// </summary>
public interface ITenantFilter
{
/// <summary>
/// 租户id.
/// </summary>
[SugarColumn(ColumnName = "F_TenantId", ColumnDescription = "租户id")]
string TenantId { get; set; }
}

View File

@@ -46,4 +46,6 @@ public sealed class ConnectionStringsOptions : IConfigurableOptions
/// 默认数据库连接字符串.
/// </summary>
public string DefaultConnection { get; set; }
public string ConnectString { get { return string.Format(DefaultConnection, Host, Port, DBName, UserName, Password); } }
}

View File

@@ -12,6 +12,11 @@ public sealed class TenantOptions : IConfigurableOptions
/// </summary>
public bool MultiTenancy { get; set; }
/// <summary>
/// 数据隔离类型 SCHEMA:库隔离 COLUMN:字段隔离.
/// </summary>
public string MultiTenancyType { get; set; }
/// <summary>
/// 多租户数据接口.
/// </summary>

View File

@@ -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<TEntity> : SimpleClient<TEntity>, ISqlSugarRepository<TEntity>
where TEntity : class, new()
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="context"></param>
public SqlSugarRepository(ISqlSugarClient context = null) : base(context)
{
// 获取数据库连接选项
ConnectionStringsOptions connectionStrings = App.GetConfig<ConnectionStringsOptions>("ConnectionStrings", true);
// 获取多租户选项
TenantOptions tenant = App.GetConfig<TenantOptions>("Tenant", true);
var httpContext = App.HttpContext;
base.Context = (SqlSugarScope)context;
string tenantId = connectionStrings.ConfigId;
if (httpContext?.GetEndpoint()?.Metadata?.GetMetadata<AllowAnonymousAttribute>() == null || !string.IsNullOrEmpty(httpContext?.Request.Query["token"]))
/// <summary>
/// 构造函数
/// </summary>
/// <param name="context"></param>
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<ConnectionStringsOptions>("ConnectionStrings", true);
// 获取多租户选项
TenantOptions tenant = App.GetConfig<TenantOptions>("Tenant", true);
var httpContext = App.HttpContext;
base.Context = (SqlSugarScope)context;
string tenantId = connectionStrings.ConfigId;
string tenantDbName = string.Empty;
if (httpContext?.GetEndpoint()?.Metadata?.GetMetadata<AllowAnonymousAttribute>() == null)
{
connectionConfig = JSON.Deserialize<ConnectionConfigOptions>(httpContext?.User.FindFirst("ConnectionConfig")?.Value);
tenantId = connectionConfig.ConfigId;
if (tenant.MultiTenancy && httpContext != null)
{
var connectionConfig = JSON.Deserialize<ConnectionConfigOptions>(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<ConnectionConfigOptions>(claims.FirstOrDefault(e => e.Type == "ConnectionConfig").Value);
tenantId = connectionConfig.ConfigId;
base.Context.QueryFilter.AddTableFilter<ITenantFilter>(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<string, SugarParameter[]>(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<string, SugarParameter[]>(sql, pars);
};
}
}
}
}

View File

@@ -18,8 +18,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SqlSugarCore" Version="5.1.4.73" />
<PackageReference Include="Tnb.Core" Version="2023.3.24.1010" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.77" />
<PackageReference Include="Tnb.Core" Version="2023.5.25.958" />
<!--<ProjectReference Include="..\..\..\Tnb.Core\Tnb.Core\Tnb.Core.csproj" />-->
</ItemGroup>

View File

@@ -64,6 +64,11 @@ public class WebSocketClient
/// </summary>
public LoginMethod SingleLogin { get; set; }
/// <summary>
/// 单点登录标识.
/// </summary>
public string onlineTicket { get; set; }
/// <summary>
/// token.
/// </summary>

View File

@@ -47,4 +47,19 @@ public class DocumentListOutput
/// 父级Id.
/// </summary>
public string? parentId { get; set; }
/// <summary>
/// 文档下载地址.
/// </summary>
public string? uploaderUrl { get; set; }
/// <summary>
/// 文件路径.
/// </summary>
public string? filePath { get; set; }
/// <summary>
/// 是否支持预览.
/// </summary>
public string? isPreview { get; set; }
}

View File

@@ -87,17 +87,17 @@ public class ProductCrInput
/// <summary>
/// 让利金额.
/// </summary>
public decimal partPrice { get; set; }
public decimal? partPrice { get; set; }
/// <summary>
/// 优惠金额.
/// </summary>
public decimal reducedPrice { get; set; }
public decimal? reducedPrice { get; set; }
/// <summary>
/// 折后金额.
/// </summary>
public decimal discountPrice { get; set; }
public decimal? discountPrice { get; set; }
/// <summary>
/// 备注.

View File

@@ -92,17 +92,17 @@ public class ProductInfoOutput
/// <summary>
/// 让利金额.
/// </summary>
public decimal partPrice { get; set; }
public decimal? partPrice { get; set; }
/// <summary>
/// 优惠金额.
/// </summary>
public decimal reducedPrice { get; set; }
public decimal? reducedPrice { get; set; }
/// <summary>
/// 折后金额.
/// </summary>
public decimal discountPrice { get; set; }
public decimal? discountPrice { get; set; }
/// <summary>
/// 备注.

View File

@@ -67,4 +67,9 @@ public class ProductListOutput
/// 联系人.
/// </summary>
public string contactName { get; set; }
/// <summary>
/// 子表数据.
/// </summary>
public List<ProductEntryEntity> productEntryList { get; set; }
}

Some files were not shown because too many files have changed in this diff Show More