关键事项、邮件管理、任务管理

This commit is contained in:
2025-03-13 10:52:32 +08:00
parent 7a242ed776
commit c73bb1124d
99 changed files with 9738 additions and 3791 deletions
+403
View File
@@ -0,0 +1,403 @@
using System.Linq;
using System.Timers;
using System;
using System.Net.Mail;
using System.Net;
using System.Collections.Generic;
using Model;
using System.Data.SqlClient;
using System.Data;
using NPOI.SS.Formula.Functions;
using System.Reflection;
using System.Text;
namespace BLL
{
public static class GJSXMonitorService
{
public static Model.SGGLDB db = Funs.DB;
#region
/// <summary>
/// 监视组件
/// </summary>
private static Timer messageTimer1;
/// <summary>
/// 关键事项超期预警定时提醒邮箱
/// </summary>
public static void StartMonitorOverdueWarningPushEmail()
{
int adTimeJ = 60 * 4;
if (messageTimer1 != null)
{
messageTimer1.Stop();
messageTimer1.Dispose();
messageTimer1 = null;
}
if (adTimeJ > 0)
{
messageTimer1 = new Timer
{
AutoReset = true
};
messageTimer1.Elapsed += new ElapsedEventHandler(OverdueWarningPushEmail);
messageTimer1.Interval = 1000 * 60 * adTimeJ;// 60分钟 60000 * adTimeJ;
messageTimer1.Start();
}
}
/// <summary>
/// 流程确认 定时执行 系统启动5分钟
/// </summary>
/// <param name="sender">Timer组件</param>
/// <param name="e">事件参数</param>
private static void OverdueWarningPushEmail(object sender, ElapsedEventArgs e)
{
try
{
Model.SGGLDB db = Funs.DB;
//取未关闭且已经超期的数据
string strSql = @"select
DATEDIFF(DAY, CompleteDate, isnull(CloseDate,getdate())) AS DateDiffDays
,a.GJSXID,a.ProjectId,a.Detail,a.UserID,a.createDate,Base_Project.ProjectName,Base_Unit.UnitName,a.CloseDate,a.IsManypeople,a.CompleteDate,a.AttachUrl
,case a.state when 2 then '正在进行' when 3 then '待办' when 0 then '已关闭' when 1 then '开放' end as state
,CNProfessionalName = STUFF((SELECT ',' + Base_CNProfessional.ProfessionalName FROM dbo.Base_CNProfessional where PATINDEX('%,' + RTRIM(Base_CNProfessional.CNProfessionalId) + ',%', ',' + a.CNProfessional_ID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,QuestionTypeName = STUFF((SELECT ',' + Base_QuestionType.QuestionTypeName FROM dbo.Base_QuestionType where PATINDEX('%,' + RTRIM(Base_QuestionType.QuestionTypeID) + ',%', ',' + a.QuestionTypeID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,GJSXTypeName = STUFF((SELECT ',' + Base_GJSXType.GJSXTypeName FROM dbo.Base_GJSXType where PATINDEX('%,' + RTRIM(Base_GJSXType.GJSXTypeID) + ',%', ',' + a.GJSXTypeID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,b.UserName,b.Email as UserEmail
,User_ReceiveUserName = STUFF((SELECT ',' + p2.UserName FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.User_ReceiveID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,User_ReceiveUserEmail = STUFF((SELECT ',' + p2.Email FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.User_ReceiveID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,User_AcceptanceUserName = STUFF((SELECT ',' + p2.UserName FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.user_Acceptance + ',') > 0 FOR XML PATH('')), 1, 1,'')
,User_AcceptanceUserEmail = STUFF((SELECT ',' + p2.Email FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.user_Acceptance + ',') > 0 FOR XML PATH('')), 1, 1,'')
,User_CsUsers = STUFF((SELECT ',' + p2.UserName FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.CsUsers + ',') > 0 FOR XML PATH('')), 1, 1,'')
,User_CsUsersUserEmail = STUFF((SELECT ',' + p2.Email FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.CsUsers + ',') > 0 FOR XML PATH('')), 1, 1,'')
from GJSX as a
left join Sys_User as b on a.UserId = b.UserId
left join[dbo].[Base_Project] on a.ProjectId = Base_Project.ProjectId
left join[dbo].[Base_Unit] on a.UnitId = Base_Unit.UnitId
where 1=1 and a.state<>'0' and GETDATE()>a.CompleteDate ";
List<SqlParameter> listStr = new List<SqlParameter>();
SqlParameter[] parameter = listStr.ToArray();
DataTable table = SQLHelper.GetDataTableRunText(strSql, parameter);
// 使用LINQ将DataTable转换为List<GJSXItem>
var lstOverdue = table.AsEnumerable()
.Select(row => new GJSXItem
{
DateDiffDays = Convert.ToInt32(row["DateDiffDays"]),
GJSXID = row["GJSXID"].ToString(),
ProjectId = row["ProjectId"].ToString(),
ProjectName = row["ProjectName"].ToString(),
UnitName = row["UnitName"].ToString(),
Detail = row["Detail"].ToString(),
CNProfessionalName = row["CNProfessionalName"].ToString(),
QuestionTypeName = row["QuestionTypeName"].ToString(),
GJSXTypeName = row["GJSXTypeName"].ToString(),
UserName = row["UserName"].ToString(),
//UserEmail = row["UserEmail"].ToString(),
User_ReceiveUserName = row["User_ReceiveUserName"].ToString(),
//User_ReceiveUserEmail = row["User_ReceiveUserEmail"].ToString(),
User_AcceptanceUserName = row["User_AcceptanceUserName"].ToString(),
//User_AcceptanceUserEmail = row["User_AcceptanceUserEmail"].ToString(),
User_CsUsers = row["User_CsUsers"].ToString(),
//User_CsUsersUserEmail = row["User_CsUsersUserEmail"].ToString(),
CompleteDate = Convert.ToDateTime(row["CompleteDate"].ToString())
})
.ToList();
////超期一周
//var allItems1 = from x in db.GJSX
// join a in db.Base_Project on x.ProjectId equals a.ProjectId
// join b in db.Base_Unit on x.UnitId equals b.UnitId
// where x.State != "0" && x.CloseDate == null && DateTime.Now > Convert.ToDateTime(x.CompleteDate).AddDays(7)
// && DateTime.Now < Convert.ToDateTime(x.CompleteDate).AddDays(14)
// select x;
////超期两周
//var allItems2 = from x in db.GJSX
// where x.State != "0" && x.CloseDate == null && DateTime.Now > Convert.ToDateTime(x.CompleteDate).AddDays(14)
// && DateTime.Now < Convert.ToDateTime(x.CompleteDate).AddDays(21)
// select x;
////超期三周
//var allItems3 = from x in db.GJSX
// where x.State != "0" && x.CloseDate == null && DateTime.Now > Convert.ToDateTime(x.CompleteDate).AddDays(21)
// select x;
if (lstOverdue.Any())
{
foreach (var item in lstOverdue)
{
if (item.DateDiffDays > 6)
{//超期一周
MailMessage mail = new MailMessage();
//邮件主题
mail.Subject = "关键事项超期预警提醒";
//邮件正文
mail.Body = $@"责任单位:{item.UnitName}
项目名称:{item.ProjectName}
事项ID{item.GJSXID}
事项描述:{item.Detail}
事项类别:{item.GJSXTypeName}
紧急程度:{item.QuestionTypeName}
专业:{item.CNProfessionalName}
约定完成时间:{item.CompleteDate.ToShortDateString()}";
mail.To.Add("1923421292@qq.com");
mail.To.Add("765289303@qq.com");
mail.CC.Add("1784803958@qq.com");
//if (!string.IsNullOrWhiteSpace(item.UserEmail))
//{//提出人
// mail.To.Add(item.UserEmail);
//}
//if (!string.IsNullOrWhiteSpace(item.User_AcceptanceUserEmail))
//{//责任人
// mail.To.Add(item.User_AcceptanceUserEmail);
//}
//if (!string.IsNullOrWhiteSpace(item.User_ReceiveUserEmail))
//{//跟踪人
// mail.To.Add(item.User_ReceiveUserEmail);
//}
//if (!string.IsNullOrWhiteSpace(item.User_CsUsersUserEmail))
//{//抄送人
// //mail.CC.Add("765289303@qq.com");
// mail.CC.Add(item.User_CsUsersUserEmail);
//}
if (item.DateDiffDays > 21)
{//超期三周——增加抄送主管
}
else if (item.DateDiffDays > 13)
{//超期两周——增加项目经理、部门主管
}
PushEmail(mail);
}
}
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 关键事项超期预警定时提醒发送邮箱
/// </summary>
public static void OverdueWarningSendEmail()
{
try
{
Model.SGGLDB db = Funs.DB;
//取未关闭且已经超期的数据
string strSql = @"select
DATEDIFF(DAY, CompleteDate, isnull(CloseDate,getdate())) AS DateDiffDays
,a.GJSXID,a.ProjectId,a.Detail,a.createDate,Base_Project.ProjectName,Base_Unit.UnitName,a.CloseDate,a.IsManypeople,a.CompleteDate,a.AttachUrl
,case a.state when 2 then '正在进行' when 3 then '待办' when 0 then '已关闭' when 1 then '开放' end as state
,CNProfessionalName = STUFF((SELECT ',' + Base_CNProfessional.ProfessionalName FROM dbo.Base_CNProfessional where PATINDEX('%,' + RTRIM(Base_CNProfessional.CNProfessionalId) + ',%', ',' + a.CNProfessional_ID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,QuestionTypeName = STUFF((SELECT ',' + Base_QuestionType.QuestionTypeName FROM dbo.Base_QuestionType where PATINDEX('%,' + RTRIM(Base_QuestionType.QuestionTypeID) + ',%', ',' + a.QuestionTypeID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,GJSXTypeName = STUFF((SELECT ',' + Base_GJSXType.GJSXTypeName FROM dbo.Base_GJSXType where PATINDEX('%,' + RTRIM(Base_GJSXType.GJSXTypeID) + ',%', ',' + a.GJSXTypeID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,a.UserID,b.UserName
--,b.Email as UserEmail
,a.User_ReceiveID as User_ReceiveUserId
,User_ReceiveUserName = STUFF((SELECT ',' + p2.UserName FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.User_ReceiveID + ',') > 0 FOR XML PATH('')), 1, 1,'')
--,User_ReceiveUserEmail = STUFF((SELECT ',' + p2.Email FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.User_ReceiveID + ',') > 0 FOR XML PATH('')), 1, 1,'')
,a.user_Acceptance as User_AcceptanceUserId
,User_AcceptanceUserName = STUFF((SELECT ',' + p2.UserName FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.user_Acceptance + ',') > 0 FOR XML PATH('')), 1, 1,'')
--,User_AcceptanceUserEmail = STUFF((SELECT ',' + p2.Email FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.user_Acceptance + ',') > 0 FOR XML PATH('')), 1, 1,'')
,a.CsUsers as User_CsUserIds
,User_CsUsers = STUFF((SELECT ',' + p2.UserName FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.CsUsers + ',') > 0 FOR XML PATH('')), 1, 1,'')
--,User_CsUsersUserEmail = STUFF((SELECT ',' + p2.Email FROM dbo.Sys_User as p2 where PATINDEX('%,' + RTRIM(p2.UserId) + ',%', ',' + a.CsUsers + ',') > 0 FOR XML PATH('')), 1, 1,'')
from GJSX as a
left join Sys_User as b on a.UserId = b.UserId
left join[dbo].[Base_Project] on a.ProjectId = Base_Project.ProjectId
left join[dbo].[Base_Unit] on a.UnitId = Base_Unit.UnitId
where 1=1 and a.state<>'0' and GETDATE()>a.CompleteDate ";
List<SqlParameter> listStr = new List<SqlParameter>();
SqlParameter[] parameter = listStr.ToArray();
DataTable table = SQLHelper.GetDataTableRunText(strSql, parameter);
// 使用LINQ将DataTable转换为List<GJSXItem>
var lstOverdue = table.AsEnumerable().Select(row => new GJSXItem
{
DateDiffDays = Convert.ToInt32(row["DateDiffDays"]),
GJSXID = row["GJSXID"].ToString(),
ProjectId = row["ProjectId"].ToString(),
ProjectName = row["ProjectName"].ToString(),
UnitName = row["UnitName"].ToString(),
Detail = row["Detail"].ToString(),
CNProfessionalName = row["CNProfessionalName"].ToString(),
QuestionTypeName = row["QuestionTypeName"].ToString(),
GJSXTypeName = row["GJSXTypeName"].ToString(),
UserID = row["UserID"].ToString(),
UserName = row["UserName"].ToString(),
//UserEmail = row["UserEmail"].ToString(),
User_ReceiveUserId = row["User_ReceiveUserId"].ToString(),
User_ReceiveUserName = row["User_ReceiveUserName"].ToString(),
//User_ReceiveUserEmail = row["User_ReceiveUserEmail"].ToString(),
User_AcceptanceUserId = row["User_AcceptanceUserId"].ToString(),
User_AcceptanceUserName = row["User_AcceptanceUserName"].ToString(),
//User_AcceptanceUserEmail = row["User_AcceptanceUserEmail"].ToString(),
User_CsUserIds = row["User_CsUserIds"].ToString(),
User_CsUsers = row["User_CsUsers"].ToString(),
//User_CsUsersUserEmail = row["User_CsUsersUserEmail"].ToString(),
CompleteDate = Convert.ToDateTime(row["CompleteDate"].ToString())
}).ToList();
#region
//获取有邮箱的用户
var userIds = BLL.UserService.GetUserHaveEmailList();
if (userIds.Any() && lstOverdue.Any())
{
var lstProject = lstOverdue.Select(x => new { x.ProjectId ,x.ProjectName}).Distinct().ToList();
foreach (var pro in lstProject)
{
var lstProjectOverdue = lstOverdue.Where(x => x.ProjectId == pro.ProjectId).ToList();
if (lstProjectOverdue.Any())
{
string projectName = pro.ProjectName;
foreach (var user in userIds)
{
MailMessage mail = new MailMessage();
//邮件主题
mail.Subject = $"关键事项超期预警提醒——{projectName}";
mail.To.Add(user.Email);
mail.IsBodyHtml = true;//确保邮件正文被当作HTML解析
StringBuilder tbodyStr = new StringBuilder();
int index = 1;
//责任人为本人
var acceptanceItems = lstProjectOverdue.Where(x => x.User_AcceptanceUserId.Contains(user.UserId)).OrderByDescending(x => x.DateDiffDays).ToList();
if (acceptanceItems.Any())
{
foreach (var item in acceptanceItems)
{
tbodyStr.Append($"<tr><td>{index}</td><td>本人负责</td><td>{item.UnitName}</td><td>{item.ProjectName}</td><td>{item.Detail}</td><td>{item.GJSXTypeName}</td><td>{item.UserName}</td><td>{item.User_AcceptanceUserName}</td><td>{item.CompleteDate.ToShortDateString()}</td><td>{(item.DateDiffDays > 0 ? item.DateDiffDays : "")}</td></tr>");
index++;
}
}
//发起人为本人
var userItems = lstProjectOverdue.Where(x => x.UserID == user.UserId).OrderByDescending(x => x.DateDiffDays).ToList();
if (userItems.Any())
{
foreach (var item in userItems)
{
tbodyStr.Append($"<tr><td>{index}</td><td>本人发起</td><td>{item.UnitName}</td><td>{item.ProjectName}</td><td>{item.Detail}</td><td>{item.GJSXTypeName}</td><td>{item.UserName}</td><td>{item.User_AcceptanceUserName}</td><td>{item.CompleteDate.ToShortDateString()}</td><td>{(item.DateDiffDays > 0 ? item.DateDiffDays : "")}</td></tr>");
index++;
}
}
//跟踪人为本人
var receiveItems = lstProjectOverdue.Where(x => x.User_ReceiveUserId.Contains(user.UserId)).OrderByDescending(x => x.DateDiffDays).ToList();
if (receiveItems.Any())
{
foreach (var item in receiveItems)
{
tbodyStr.Append($"<tr><td>{index}</td><td>本人跟踪</td><td>{item.UnitName}</td><td>{item.ProjectName}</td><td>{item.Detail}</td><td>{item.GJSXTypeName}</td><td>{item.UserName}</td><td>{item.User_AcceptanceUserName}</td><td>{item.CompleteDate.ToShortDateString()}</td><td>{(item.DateDiffDays > 0 ? item.DateDiffDays : "")}</td></tr>");
index++;
}
}
//抄送人为本人
var csUserItems = lstProjectOverdue.Where(x => x.User_CsUserIds.Contains(user.UserId)).OrderByDescending(x => x.DateDiffDays).ToList();
if (csUserItems.Any())
{
foreach (var item in csUserItems)
{
tbodyStr.Append($"<tr><td>{index}</td><td>抄送本人</td><td>{item.UnitName}</td><td>{item.ProjectName}</td><td>{item.Detail}</td><td>{item.GJSXTypeName}</td><td>{item.UserName}</td><td>{item.User_AcceptanceUserName}</td><td>{item.CompleteDate.ToShortDateString()}</td><td>{(item.DateDiffDays > 0 ? item.DateDiffDays : "")}</td></tr>");
index++;
}
}
//邮件正文
string bodyStr = @"<html>
<head>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
</style>
</head>
<body>
<h2>关键事项超期预警提醒</h2>
<table>
<thead>
<tr>
<th>序号</th>
<th>类型</th>
<th>责任单位</th>
<th>项目名称</th>
<th>事项描述</th>
<th>事项类别</th>
<th>发起人</th>
<th>责任人</th>
<th>约定完成时间</th>
<th>超期时间(天)</th>
</tr>
</thead>
<tbody>" + tbodyStr.ToString() + "</tbody></table></body></html>";
mail.Body = bodyStr;
PushEmail(mail);
}
}
}
}
#endregion
}
catch (Exception ex)
{
}
}
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="mail"></param>
private static void PushEmail(MailMessage mail)
{
//获取发送邮箱配置
Email_Pop pops = BLL.Email_PopService.GetEmail_Pop("7EC5E991-B7A0-495A-90ED-2BE15370C959");
if (pops != null)
{
SmtpClient client = new SmtpClient(pops.EmailFwq);//替换为你的SMTP服务器地址
client.Port = int.Parse(pops.EmailDk);//587或465如果使用SSL
client.EnableSsl = true;//如果服务器支持SSL,设置为true
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(pops.EmailYx, pops.EmailPass);//替换为你的邮箱和服务授权码
mail.From = new MailAddress(pops.EmailYx);//发件人邮箱地址
try
{
client.Send(mail);
//Console.WriteLine("Email sent successfully.");
}
catch (Exception ex)
{
//Console.WriteLine("Email sending failed: " + ex.Message);
}
}
}
#endregion
}
}
+35 -21
View File
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace BLL
{
public static class GJSXService
public static class GJSXService
{
public static Model.SGGLDB db = Funs.DB;
@@ -29,23 +29,25 @@ namespace BLL
Model.SGGLDB db = Funs.DB;
Model.GJSX newGJSX = new Model.GJSX
{
GJSXID = _GJSX.GJSXID,
Detail = _GJSX.Detail,
UserID = _GJSX.UserID,
CreateDate = _GJSX.CreateDate,
User_ReceiveID = _GJSX.User_ReceiveID,
CNProfessional_ID = _GJSX.CNProfessional_ID,
ProjectId = _GJSX.ProjectId,
UnitId = _GJSX.UnitId,
CloseDate = _GJSX.CloseDate,
State = _GJSX.State,
QuestionTypeID = _GJSX.QuestionTypeID,
IsManypeople = _GJSX.IsManypeople,
CompleteDate = _GJSX.CompleteDate,
AttachUrl = _GJSX.AttachUrl,
User_Acceptance = _GJSX.User_Acceptance,
GJSXID = _GJSX.GJSXID,
Detail = _GJSX.Detail,
UserID = _GJSX.UserID,
CreateDate = _GJSX.CreateDate,
User_ReceiveID = _GJSX.User_ReceiveID,
CNProfessional_ID = _GJSX.CNProfessional_ID,
ProjectId = _GJSX.ProjectId,
UnitId = _GJSX.UnitId,
CloseDate = _GJSX.CloseDate,
State = _GJSX.State,
QuestionTypeID = _GJSX.QuestionTypeID,
GJSXTypeId = _GJSX.GJSXTypeId,
IsManypeople = _GJSX.IsManypeople,
CompleteDate = _GJSX.CompleteDate,
AttachUrl = _GJSX.AttachUrl,
User_Acceptance = _GJSX.User_Acceptance,
ProgressStatus = _GJSX.ProgressStatus,
CsUsers=_GJSX.CsUsers
CsUsers = _GJSX.CsUsers
};
db.GJSX.InsertOnSubmit(newGJSX);
@@ -73,11 +75,13 @@ namespace BLL
newGJSX.CloseDate = _GJSX.CloseDate;
newGJSX.State = _GJSX.State;
newGJSX.QuestionTypeID = _GJSX.QuestionTypeID;
newGJSX.GJSXTypeId = _GJSX.GJSXTypeId;
newGJSX.IsManypeople = _GJSX.IsManypeople;
newGJSX.CompleteDate = _GJSX.CompleteDate;
newGJSX.AttachUrl = _GJSX.AttachUrl;
newGJSX.User_Acceptance = _GJSX.User_Acceptance;
newGJSX.CsUsers = _GJSX.CsUsers;
newGJSX.ProgressStatus = _GJSX.ProgressStatus;
db.SubmitChanges();
}
}
@@ -97,17 +101,15 @@ namespace BLL
}
private static int count;
public static System.Collections.IEnumerable GetListData(string projectId)
{
IQueryable<Model.GJSX> q =GetGJSXList().AsQueryable();
IQueryable<Model.GJSX> q = GetGJSXList().AsQueryable();
if (!string.IsNullOrEmpty(projectId))
{
q = q.Where(e => e.ProjectId == projectId);
}
count = q.Count();
if (count == 0)
@@ -131,6 +133,7 @@ namespace BLL
x.CloseDate,
x.State,
x.QuestionTypeID,
x.GJSXTypeId,
x.CompleteDate,
x.AttachUrl,
x.User_Acceptance
@@ -138,6 +141,17 @@ namespace BLL
};
}
/// <summary>
/// 根据项目Id,获取关键事项责任人list
/// </summary>
/// <param name="projectId"></param>
/// <returns></returns>
public static List<string> GetGJSXUserList(string projectId)
{
var list = (from x in Funs.DB.GJSX where x.ProjectId == projectId select x.User_Acceptance).Distinct().ToList();
return list;
}
/// <summary>
/// 获取问题下拉项
/// </summary>