SVN r1211
SVN-Revision: r1211
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using Lskj.Business;
|
||||
using Lskj.Business.Impl;
|
||||
using Lskj.Core;
|
||||
using Lskj.Data;
|
||||
|
||||
namespace Lskj.Control.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// 审核改动日志处理类。
|
||||
/// 用来比较单据主表原始数据和当前表头控件值,并把发生变化的字段写入 P_SystemAuditChangeLog。
|
||||
/// </summary>
|
||||
public class AuditChangeLog
|
||||
{
|
||||
private const string TableName = "P_SystemAuditChangeLog";
|
||||
private const int MaxOrderNumberLength = 50;
|
||||
private const int MaxTextLength = 500;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 比较表头字段是否发生变化,并保存审核改动日志。
|
||||
/// 返回 false 时,errorMessage 会一次性返回所有未记录成功的字段。
|
||||
/// </summary>
|
||||
/// <param name="drBillInfoMsg">改动前数据(单表数据或者单据主表数据)</param>
|
||||
/// <param name="controlObj">控件 mycontrol</param>
|
||||
/// <param name="orderNumber">单号</param>
|
||||
/// <param name="stepCode">步骤号</param>
|
||||
/// <param name="operatorId">登录人id</param>
|
||||
/// <returns></returns>
|
||||
public static bool SaveHeaderChangeLog(DataRow drBillInfoMsg, MyControl controlObj, string orderNumber, string stepCode, string operatorId)
|
||||
{
|
||||
if (SystemInfo.Instance.AuditChangeRecord)
|
||||
{
|
||||
CreateModificationRecordTable();
|
||||
string errorMessage = string.Empty;
|
||||
|
||||
// 原始主表数据或控件对象为空时,没有可比较的数据,直接返回成功。
|
||||
if (drBillInfoMsg == null || controlObj == null || controlObj.ControlModels == null)
|
||||
return true;
|
||||
|
||||
List<string> errorFields = new List<string>();
|
||||
|
||||
// 遍历当前界面的表头控件模型,逐个比较可保存字段。
|
||||
foreach (ControlModel model in controlObj.ControlModels)
|
||||
{
|
||||
string currentFieldName = model == null ? string.Empty : model.FieldName;
|
||||
try
|
||||
{
|
||||
// 只比较可保存、界面真实存在、原始主表行中也存在的普通字段。
|
||||
if (!CanCompare(model, drBillInfoMsg, controlObj))
|
||||
continue;
|
||||
|
||||
// 旧值来自打开审核界面时加载出来的主表原始行。
|
||||
string oldValue = GetRowValue(drBillInfoMsg, model.FieldName);
|
||||
|
||||
// 新值来自当前界面控件值,也就是用户修改后的值。
|
||||
string newValue = controlObj.GetControlValue(model);
|
||||
if (newValue == "****")
|
||||
continue;
|
||||
|
||||
// 日期、数字、空值先做统一处理,避免显示格式不同造成误判。
|
||||
if (IsSameValue(oldValue, newValue))
|
||||
continue;
|
||||
|
||||
// 字段确实发生变化后写入日志;相同单号、步骤、字段已存在时执行更新。
|
||||
SaveChangeLog(orderNumber, model.FieldName, oldValue, newValue, stepCode, operatorId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 单个字段记录失败时先收集错误,继续处理后续字段,最后一次性提示。
|
||||
errorFields.Add(GetErrorFieldName(model, currentFieldName) + "(" + ex.Message + ")");
|
||||
}
|
||||
}
|
||||
|
||||
if (errorFields.Count > 0)
|
||||
{
|
||||
errorMessage = "以下字段审核改动日志未记录:" + Environment.NewLine + string.Join(Environment.NewLine, errorFields.ToArray());
|
||||
MessageUtil.Show(errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断控件字段是否需要参与改动比较。
|
||||
/// </summary>
|
||||
private static bool CanCompare(ControlModel model, DataRow drBillInfoMsg, MyControl controlObj)
|
||||
{
|
||||
if (model == null)
|
||||
return false;
|
||||
|
||||
// 不保存的字段和图片控件不参与本次表头改动日志记录。
|
||||
if (!model.IsSave ||
|
||||
model.FieldType == ControlType.LabPic ||
|
||||
model.FieldType == ControlType.LabPicEx)
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(model.FieldName))
|
||||
return false;
|
||||
|
||||
// 当前界面上没有真实控件的字段不参与比较。
|
||||
if (controlObj.FindControl(model) == null)
|
||||
return false;
|
||||
|
||||
// 原始主表行里必须存在同名数据库字段。
|
||||
return drBillInfoMsg.Table != null && drBillInfoMsg.Table.Columns.Contains(model.FieldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存单个字段的改动记录。
|
||||
/// 如果相同单号、相同步骤、相同字段已存在记录,则更新;否则新增。
|
||||
/// </summary>
|
||||
private static void SaveChangeLog(string orderNumber, string fieldName, string oldValue, string newValue, string stepCode, string operatorId)
|
||||
{
|
||||
//orderNumber = orderNumber == null ? string.Empty : orderNumber;
|
||||
//fieldName = fieldName == null ? string.Empty : fieldName;
|
||||
//oldValue = oldValue == null ? string.Empty : oldValue;
|
||||
//newValue = newValue == null ? string.Empty : newValue;
|
||||
|
||||
//orderNumber = orderNumber.Length > MaxOrderNumberLength ? orderNumber.Substring(0, MaxOrderNumberLength) : orderNumber;
|
||||
//fieldName = fieldName.Length > MaxTextLength ? fieldName.Substring(0, MaxTextLength) : fieldName;
|
||||
//oldValue = oldValue.Length > MaxTextLength ? oldValue.Substring(0, MaxTextLength) : oldValue;
|
||||
//newValue = newValue.Length > MaxTextLength ? newValue.Substring(0, MaxTextLength) : newValue;
|
||||
|
||||
//orderNumber = orderNumber.Replace("'", "''");
|
||||
//fieldName = fieldName.Replace("'", "''");
|
||||
//oldValue = oldValue.Replace("'", "''");
|
||||
//newValue = newValue.Replace("'", "''");
|
||||
|
||||
string sql = string.Format(@"if exists (select 1 from {0} where orderNumber = '{1}' and stepCode = {2} and fieldName = N'{3}')
|
||||
begin
|
||||
update {0}
|
||||
set oldValue = N'{4}',
|
||||
newValue = N'{5}',
|
||||
operatorId = N'{6}'
|
||||
where orderNumber =N'{1}'
|
||||
and stepCode = N'{2}'
|
||||
and fieldName = N'{3}'
|
||||
end
|
||||
else
|
||||
begin
|
||||
insert into {0} (orderNumber, fieldName, oldValue, newValue, stepCode, operatorId)
|
||||
values (N'{1}', N'{3}', N'{4}', N'{5}', N'{2}', N'{6}')
|
||||
end",
|
||||
TableName,
|
||||
orderNumber,
|
||||
stepCode,
|
||||
fieldName,
|
||||
oldValue,
|
||||
newValue,
|
||||
operatorId);
|
||||
|
||||
SqlHelper.ExecuteNonQuery(sql);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从原始主表行中读取字段旧值,数据库 NULL 统一按空字符串处理。
|
||||
/// </summary>
|
||||
private static string GetRowValue(DataRow row, string fieldName)
|
||||
{
|
||||
if (row[fieldName] == DBNull.Value || row[fieldName] == null)
|
||||
return string.Empty;
|
||||
|
||||
return row[fieldName] + "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取错误提示中展示的字段名称,优先显示控件标题,没有标题时显示字段名。
|
||||
/// </summary>
|
||||
private static string GetErrorFieldName(ControlModel model, string fieldName)
|
||||
{
|
||||
if (model != null && !string.IsNullOrWhiteSpace(model.LabelText))
|
||||
return model.LabelText + "[" + model.FieldName + "]";
|
||||
|
||||
return string.IsNullOrWhiteSpace(fieldName) ? "未知字段" : fieldName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断两个值是否相同。
|
||||
/// 优先按日期、数字进行值比较,最后再按普通字符串比较。
|
||||
/// </summary>
|
||||
private static bool IsSameValue(string oldValue, string newValue)
|
||||
{
|
||||
oldValue = NormalizeValue(oldValue);
|
||||
newValue = NormalizeValue(newValue);
|
||||
|
||||
if (oldValue == string.Empty && newValue == string.Empty)
|
||||
return true;
|
||||
|
||||
DateTime oldDate;
|
||||
DateTime newDate;
|
||||
if (DateTime.TryParse(oldValue, out oldDate) && DateTime.TryParse(newValue, out newDate))
|
||||
return oldDate == newDate;
|
||||
|
||||
decimal oldDecimal;
|
||||
decimal newDecimal;
|
||||
if (decimal.TryParse(oldValue, out oldDecimal) && decimal.TryParse(newValue, out newDecimal))
|
||||
return oldDecimal == newDecimal;
|
||||
|
||||
return oldValue == newValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较前统一处理 NULL 和首尾空格。
|
||||
/// </summary>
|
||||
private static string NormalizeValue(string value)
|
||||
{
|
||||
return value == null ? string.Empty : value.Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据单号获取所有审核改动字段名。
|
||||
/// </summary>
|
||||
/// <param name="orderNumber">单号</param>
|
||||
/// <returns>当前单号对应的审核改动字段名集合</returns>
|
||||
public static List<string> GetChangeLogFields(string orderNumber)
|
||||
{
|
||||
List<string> fields = new List<string>();
|
||||
if (SystemInfo.Instance.AuditChangeRecord)
|
||||
{
|
||||
CreateModificationRecordTable();
|
||||
orderNumber = orderNumber == null ? string.Empty : orderNumber.Replace("'", "''");
|
||||
|
||||
string sqlValue = string.Format(@"
|
||||
select distinct fieldName
|
||||
from {0}
|
||||
where orderNumber = N'{1}'
|
||||
order by fieldName", TableName, orderNumber);
|
||||
|
||||
DataTable dataTable = SqlHelper.ExecuteDataTable(sqlValue);
|
||||
|
||||
if (dataTable == null)
|
||||
return fields;
|
||||
|
||||
foreach (DataRow row in dataTable.Rows)
|
||||
{
|
||||
string fieldName = row["fieldName"] + "";
|
||||
if (!string.IsNullOrWhiteSpace(fieldName))
|
||||
fields.Add(fieldName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创��
|
||||
@@ -52,6 +52,7 @@ using DevExpress.Utils;
|
||||
using System.Data.Common;
|
||||
using DevExpress.Spreadsheet;
|
||||
using DevExpress.Docs;
|
||||
using OfficeOpenXml;
|
||||
|
||||
namespace Lskj.Control.Model
|
||||
{
|
||||
@@ -1187,7 +1188,13 @@ namespace Lskj.Control.Model
|
||||
dialog.FileName = menuName + DateTime.Now.ToString(SystemInfo.Instance.ExportFileDateFormat) + suffix;
|
||||
dialog.Filter = SystemInfo.Instance.IsXlsxFirst ? "Excel文件(*.xlsx)|*.xlsx|Excel文件(*.xls)|*.xls|PDF文件|*.PDF|RTF文件|*.RTF|HTML文件|*.html" :
|
||||
"Excel文件(*.xls)|*.xls|Excel文件(*.xlsx)|*.xlsx|PDF文件|*.PDF|RTF文件|*.RTF|HTML文件|*.html";
|
||||
if (SystemInfo.Instance.IsInsertWorksheet) dialog.OverwritePrompt = false; // 不弹系统“是否替换”
|
||||
string FileName = string.Empty;
|
||||
DialogResult result = dialog.ShowDialog();
|
||||
if (!PrepareInsertWorksheetExport(dialog, menuName, result, ref FileName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
WaitForm.ShowForm("导出中,请稍后...");
|
||||
@@ -1254,6 +1261,10 @@ namespace Lskj.Control.Model
|
||||
if (bandedGridControlEx.gridControl.Tag is PanelControl) panel = bandedGridControlEx.gridControl.Tag as PanelControl;
|
||||
SetModuleName(dialog.FileName, fileExt, gridView.Columns.Cast<GridColumn>().Count(column => column.Visible), true, panel);
|
||||
}
|
||||
if (SystemInfo.Instance.IsInsertWorksheet && !string.IsNullOrWhiteSpace(FileName))
|
||||
{
|
||||
AppendWorksheetToExcel(dialog.FileName, FileName);
|
||||
}
|
||||
MessageUtil.Show(ResourceKeys.ExportSuccess);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1297,11 +1308,21 @@ namespace Lskj.Control.Model
|
||||
dialog.Filter = SystemInfo.Instance.IsXlsxFirst ? "Excel文件(*.xlsx)|*.xlsx|Excel文件(*.xls)|*.xls|PDF文件|*.PDF|RTF文件|*.RTF|HTML文件|*.html" :
|
||||
"Excel文件(*.xls)|*.xls|Excel文件(*.xlsx)|*.xlsx|PDF文件|*.PDF|RTF文件|*.RTF|HTML文件|*.html";
|
||||
|
||||
|
||||
if (SystemInfo.Instance.IsInsertWorksheet) dialog.OverwritePrompt = false; // 不弹系统“是否替换”
|
||||
string FileName = string.Empty;
|
||||
|
||||
DialogResult result = dialog.ShowDialog();
|
||||
|
||||
if (!PrepareInsertWorksheetExport(dialog, menuName, result, ref FileName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
WaitForm.ShowForm("导出中,请稍后...");
|
||||
|
||||
try
|
||||
{
|
||||
//获取设置的导出列
|
||||
@@ -1490,6 +1511,12 @@ namespace Lskj.Control.Model
|
||||
SetModuleName(dialog.FileName, fileExt, gridView.Columns.Cast<GridColumn>().Count(column => column.Visible), false, panel);
|
||||
}
|
||||
|
||||
if (SystemInfo.Instance.IsInsertWorksheet &&!string.IsNullOrWhiteSpace(FileName))
|
||||
{
|
||||
AppendWorksheetToExcel(dialog.FileName, FileName);
|
||||
}
|
||||
|
||||
|
||||
MessageUtil.Show(ResourceKeys.ExportSuccess);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1765,8 +1792,14 @@ namespace Lskj.Control.Model
|
||||
dialog.Title = "导出";
|
||||
dialog.FileName = menuName + DateTime.Now.ToString(SystemInfo.Instance.ExportFileDateFormat) + ".xls";
|
||||
dialog.Filter = "Excel文件(*.xls)|*.xls|Excel2007|*.xlsx|PDF文件|*.PDF|RTF文件|*.RTF|HTML文件|*.html";
|
||||
if (SystemInfo.Instance.IsInsertWorksheet) dialog.OverwritePrompt = false; // 不弹系统“是否替换”
|
||||
string FileName = string.Empty;
|
||||
|
||||
DialogResult result = dialog.ShowDialog();
|
||||
if (!PrepareInsertWorksheetExport(dialog, menuName, result, ref FileName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
WaitForm.ShowForm("导出中,请稍后...");
|
||||
@@ -1796,6 +1829,10 @@ namespace Lskj.Control.Model
|
||||
{
|
||||
control.ExportToHtml(dialog.FileName);
|
||||
}
|
||||
if (SystemInfo.Instance.IsInsertWorksheet && !string.IsNullOrWhiteSpace(FileName))
|
||||
{
|
||||
AppendWorksheetToExcel(dialog.FileName, FileName);
|
||||
}
|
||||
|
||||
MessageUtil.Show(ResourceKeys.ExportSuccess);
|
||||
}
|
||||
@@ -2092,8 +2129,6 @@ namespace Lskj.Control.Model
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>说明:获取GridView过滤或排序后的数据集</para>
|
||||
/// <para>创建人:龚宇超</para>
|
||||
@@ -2274,7 +2309,7 @@ namespace Lskj.Control.Model
|
||||
/// </summary>
|
||||
/// <param name="colFields">The col fields.</param>
|
||||
/// <param name="AutoImportCalMode">导入时是否触发关联计算(模块配置)</param>
|
||||
public static DataTable ToExcelDataTable(this GridView gridView, string fileName, string colFields, bool isDirectImport = false, bool isBillImport = false,bool AutoImportCalMode = false)
|
||||
public static DataTable ToExcelDataTable(this GridView gridView, string fileName, string colFields, bool isDirectImport = false, bool isBillImport = false, bool AutoImportCalMode = false)
|
||||
{
|
||||
DataTable table = new DataTable();
|
||||
int index = gridView is BandedGridView ? 1 : 0;
|
||||
@@ -2361,7 +2396,7 @@ namespace Lskj.Control.Model
|
||||
table.Columns.Add("lskjimport_errorFlag");
|
||||
|
||||
|
||||
bool AutoImportCal = SystemInfo.Instance.AutoImportCal|| AutoImportCalMode;//是否执行 关联和计算公式
|
||||
bool AutoImportCal = SystemInfo.Instance.AutoImportCal || AutoImportCalMode;//是否执行 关联和计算公式
|
||||
//bool ImportDefaultValue= SystemInfo.Instance.ImportDefaultValue;//是否为空单元格添加默认值
|
||||
//bool isImportRows = true;//是否是导入行(如果是合计行就不触发默认值)
|
||||
// 添加行
|
||||
@@ -2392,7 +2427,7 @@ namespace Lskj.Control.Model
|
||||
col = index != 1 ? gridView.Columns.OfType<GridColumn>().FirstOrDefault(x => Regex.Replace(x.Caption, @"\s", "") == Regex.Replace(headcell.ToString(), @"\s", "")) : newBandGrid.Columns.OfType<BandedGridColumn>().FirstOrDefault(x => Regex.Replace(x.OwnerBand + x.Caption, @"\s", "") == Regex.Replace(bandTitel + headcell.ToString(), @"\s", ""));
|
||||
if (col == null) continue;
|
||||
GridColumnModel model = col.Tag as GridColumnModel;
|
||||
|
||||
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.CellType == CellType.Error)
|
||||
@@ -2504,7 +2539,7 @@ namespace Lskj.Control.Model
|
||||
|| model.FieldType == ControlType.LabAutoGridValue
|
||||
|| model.FieldType == ControlType.LabAutoGridValueParam
|
||||
|| model.FieldType == ControlType.LabSelectReturnId
|
||||
|| (model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText)||
|
||||
|| (model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText) ||
|
||||
model.FieldType == ControlType.LabModuleAddRowsID
|
||||
))
|
||||
{
|
||||
@@ -2734,7 +2769,7 @@ namespace Lskj.Control.Model
|
||||
if (colFields.IndexOf("lskjimport_errorFlag") != -1 && !table.Columns.Contains("lskjimport_errorFlag"))
|
||||
table.Columns.Add("lskjimport_errorFlag");
|
||||
|
||||
bool AutoImportCal = SystemInfo.Instance.AutoImportCal|| AutoImportCalMode;//是否执行 计算公式
|
||||
bool AutoImportCal = SystemInfo.Instance.AutoImportCal || AutoImportCalMode;//是否执行 计算公式
|
||||
//bool ImportDefaultValue= SystemInfo.Instance.ImportDefaultValue;//是否为空单元格添加默认值
|
||||
//bool isImportRows = true;//是否是导入行(如果是合计行就不触发默认值)
|
||||
// 添加行
|
||||
@@ -2852,7 +2887,7 @@ namespace Lskj.Control.Model
|
||||
|| model.FieldType == ControlType.LabAutoGridValue
|
||||
|| model.FieldType == ControlType.LabAutoGridValueParam
|
||||
|| model.FieldType == ControlType.LabSelectReturnId
|
||||
|| (model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText)||
|
||||
|| (model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText) ||
|
||||
model.FieldType == ControlType.LabModuleAddRowsID
|
||||
))
|
||||
{
|
||||
@@ -3086,7 +3121,7 @@ namespace Lskj.Control.Model
|
||||
|
||||
string fileName = dialog.FileName;
|
||||
string colFields = gridControlEx.GridView.Columns.ToString(',');
|
||||
ImportTable = gridControlEx.GridView.ToExcelDataTable(fileName, colFields, true,false, SysModel.AutoImportCalMode);
|
||||
ImportTable = gridControlEx.GridView.ToExcelDataTable(fileName, colFields, true, false, SysModel.AutoImportCalMode);
|
||||
|
||||
|
||||
if (ImportTable == null && ImportTable.Rows.Count < 1)
|
||||
@@ -3192,7 +3227,7 @@ namespace Lskj.Control.Model
|
||||
DbDataAdapter dat = BaseImpl.GetAdapterResult(sql);
|
||||
DbCommandBuilder cb = SqlHelper.dbFactory.CreateCommandBuilder();
|
||||
cb.DataAdapter = dat;
|
||||
// SqlCommandBuilder scb = new SqlCommandBuilder(dat);
|
||||
// SqlCommandBuilder scb = new SqlCommandBuilder(dat);
|
||||
DataTable datatb = new DataTable();
|
||||
DataTable failedData = new DataTable();
|
||||
dat.Fill(datatb);
|
||||
@@ -3282,7 +3317,7 @@ namespace Lskj.Control.Model
|
||||
model.FieldType == ControlType.LabMultiSelectValueParam ||
|
||||
model.FieldType == ControlType.LabAutoGridValue ||
|
||||
model.FieldType == ControlType.LabSelectReturnId ||
|
||||
(model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText)||
|
||||
(model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText) ||
|
||||
model.FieldType == ControlType.LabModuleAddRowsID
|
||||
))
|
||||
{
|
||||
@@ -3699,7 +3734,7 @@ namespace Lskj.Control.Model
|
||||
|| model.FieldType == ControlType.LabAutoGridValue
|
||||
|| model.FieldType == ControlType.LabAutoGridValueParam
|
||||
|| model.FieldType == ControlType.LabSelectReturnId
|
||||
|| (model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText)||
|
||||
|| (model.FieldType == ControlType.LabSelectReturnIdNew && model.ModuleFrameDisplayText) ||
|
||||
model.FieldType == ControlType.LabModuleAddRowsID
|
||||
)
|
||||
{
|
||||
@@ -3781,9 +3816,9 @@ namespace Lskj.Control.Model
|
||||
{
|
||||
string sqlValue = model.SqlSource;
|
||||
|
||||
if (model.FieldType == ControlType.LabSelectReturnId || model.FieldType == ControlType.LabSelectReturnIdNew|| model.FieldType == ControlType.LabModuleAddRowsID)
|
||||
if (model.FieldType == ControlType.LabSelectReturnId || model.FieldType == ControlType.LabSelectReturnIdNew || model.FieldType == ControlType.LabModuleAddRowsID)
|
||||
{
|
||||
if ((model.IsRadio && !string.IsNullOrWhiteSpace(model.addModuleld)) || model.FieldType == ControlType.LabSelectReturnIdNew|| model.FieldType == ControlType.LabModuleAddRowsID)
|
||||
if ((model.IsRadio && !string.IsNullOrWhiteSpace(model.addModuleld)) || model.FieldType == ControlType.LabSelectReturnIdNew || model.FieldType == ControlType.LabModuleAddRowsID)
|
||||
{
|
||||
//单选模式数据源为模块sql 新版模块选中返回id固定位模块sql
|
||||
DataRow modelRow = Business.Impl.MainImpl.GetSystemdllTab(model.addModuleld);
|
||||
@@ -4089,4 +4124,495 @@ namespace Lskj.Control.Model
|
||||
// 设置填充模式为实心填充
|
||||
cellStyle.FillPattern = FillPattern.SolidForeground;
|
||||
}
|
||||
|
||||
cell.CellStyle = cellStyle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 保存更改回原始文件
|
||||
using (FileStream file = new FileStream(excelFilePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
workbook.Write(file);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否存在未保存的数据
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsDataNotSaved(this GridControlEx control)
|
||||
{
|
||||
DataTable table = control.gridControl.DataSource as DataTable;
|
||||
foreach (DataRow row in table.Rows)
|
||||
{
|
||||
if (row.RowState == DataRowState.Modified || row.RowState == DataRowState.Added)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 准备追加工作表导出:用户选择已存在Excel文件时,先切换到临时文件导出,导出完成后再追加到原文件。
|
||||
/// </summary>
|
||||
/// <param name="dialog">保存文件对话框。</param>
|
||||
/// <param name="menuName">默认工作表名称。</param>
|
||||
/// <param name="result">保存文件对话框返回结果。</param>
|
||||
/// <param name="targetFileName">用户选择的原Excel文件路径。</param>
|
||||
/// <returns>是否继续导出。</returns>
|
||||
private static bool PrepareInsertWorksheetExport(SaveFileDialog dialog, string menuName, DialogResult result, ref string targetFileName)
|
||||
{
|
||||
if (result != DialogResult.OK || !SystemInfo.Instance.IsInsertWorksheet || !File.Exists(dialog.FileName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
string selectedFileExt = Path.GetExtension(dialog.FileName).ToLower();
|
||||
if (!selectedFileExt.Equals(".xlsx") && !selectedFileExt.Equals(".xls"))
|
||||
{
|
||||
MessageUtil.Show("追加工作表功能只支持.xls/.xlsx文件,请选择Excel文件。");
|
||||
return false;
|
||||
}
|
||||
|
||||
FrmSettingTableName frmSettingTableName = new FrmSettingTableName(menuName + DateTime.Now.ToString(SystemInfo.Instance.ExportFileDateFormat));
|
||||
if (frmSettingTableName.ShowDialog() != DialogResult.OK)
|
||||
{
|
||||
// 不导出
|
||||
return false;
|
||||
}
|
||||
|
||||
// 添加页签的形式导出:先保存原文件路径,再将当前导出路径切换到临时文件。
|
||||
targetFileName = dialog.FileName;
|
||||
PubUtil.ClearFilesInDirectory(PubUtil.ExportFilePath);
|
||||
string tempFileName = GetSafeExcelFileName(frmSettingTableName.TabName) + selectedFileExt;
|
||||
dialog.FileName = Path.Combine(PubUtil.ExportFilePath, tempFileName);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将临时导出的Excel工作表追加到用户选择的Excel文件中。
|
||||
/// </summary>
|
||||
/// <param name="sourceFileName">临时导出的Excel文件路径。</param>
|
||||
/// <param name="targetFileName">用户选择的原Excel文件路径。</param>
|
||||
private static void AppendWorksheetToExcel(string sourceFileName, string targetFileName)
|
||||
{
|
||||
// 追加工作表只处理xlsx文件,避免xls/pdf/rtf/html走入不支持的合并逻辑。
|
||||
if (string.IsNullOrWhiteSpace(sourceFileName) || string.IsNullOrWhiteSpace(targetFileName))
|
||||
{
|
||||
throw new Exception("追加工作表失败:文件路径不能为空。");
|
||||
}
|
||||
if (!File.Exists(sourceFileName))
|
||||
{
|
||||
throw new Exception("追加工作表失败:未找到临时导出文件。");
|
||||
}
|
||||
if (!File.Exists(targetFileName))
|
||||
{
|
||||
throw new Exception("追加工作表失败:未找到需要追加的Excel文件。");
|
||||
}
|
||||
string fileExt = Path.GetExtension(targetFileName).ToLower();
|
||||
if (!Path.GetExtension(sourceFileName).ToLower().Equals(fileExt) || (!fileExt.Equals(".xlsx") && !fileExt.Equals(".xls")))
|
||||
{
|
||||
throw new Exception("追加工作表失败:追加工作表功能只支持.xls/.xlsx文件。");
|
||||
}
|
||||
|
||||
if (fileExt.Equals(".xls"))
|
||||
{
|
||||
AppendXlsWorksheetToExcel(sourceFileName, targetFileName);
|
||||
return;
|
||||
}
|
||||
|
||||
// EPPlus 5及以上版本要求先设置LicenseContext,否则创建ExcelPackage时会报LicenseException。
|
||||
ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
|
||||
|
||||
FileInfo targetFileInfo = new FileInfo(targetFileName);
|
||||
using (FileStream sourceStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (ExcelPackage sourcePackage = new ExcelPackage(sourceStream))
|
||||
using (ExcelPackage targetPackage = new ExcelPackage(targetFileInfo))
|
||||
{
|
||||
ExcelWorksheet sourceSheet = GetFirstVisibleWorksheet(sourcePackage);
|
||||
if (sourceSheet == null || sourceSheet.Dimension == null)
|
||||
{
|
||||
throw new Exception("追加工作表失败:临时导出文件中没有可追加的数据。");
|
||||
}
|
||||
|
||||
// 使用临时文件名作为用户输入的工作表名称,并处理重名和Excel名称限制。
|
||||
string sheetName = GetUniqueWorksheetName(targetPackage, Path.GetFileNameWithoutExtension(sourceFileName));
|
||||
try
|
||||
{
|
||||
// 优先复制整个工作表,最大程度保留字体、边框、筛选、列宽等导出格式。
|
||||
targetPackage.Workbook.Worksheets.Add(sheetName, sourceSheet);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 整表复制失败时,退回到逐格复制,仍然尽量保留单元格样式。
|
||||
if (targetPackage.Workbook.Worksheets[sheetName] != null)
|
||||
{
|
||||
targetPackage.Workbook.Worksheets.Delete(sheetName);
|
||||
}
|
||||
ExcelWorksheet targetSheet = targetPackage.Workbook.Worksheets.Add(sheetName);
|
||||
SafeCopyXlsxWorksheetContent(sourceSheet, targetSheet);
|
||||
}
|
||||
targetPackage.Save();
|
||||
}
|
||||
|
||||
// 合并成功后删除临时文件,删除失败不影响导出结果。
|
||||
try
|
||||
{
|
||||
File.Delete(sourceFileName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将临时导出的xls工作表追加到用户选择的xls文件中。
|
||||
/// </summary>
|
||||
/// <param name="sourceFileName">临时导出的xls文件路径。</param>
|
||||
/// <param name="targetFileName">用户选择的原xls文件路径。</param>
|
||||
private static void AppendXlsWorksheetToExcel(string sourceFileName, string targetFileName)
|
||||
{
|
||||
HSSFWorkbook sourceWorkbook;
|
||||
HSSFWorkbook targetWorkbook;
|
||||
|
||||
using (FileStream sourceStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
sourceWorkbook = new HSSFWorkbook(sourceStream);
|
||||
}
|
||||
|
||||
using (FileStream targetStream = new FileStream(targetFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
targetWorkbook = new HSSFWorkbook(targetStream);
|
||||
}
|
||||
|
||||
ISheet sourceSheet = GetFirstVisibleNpoiSheet(sourceWorkbook);
|
||||
if (sourceSheet == null || sourceSheet.PhysicalNumberOfRows == 0)
|
||||
{
|
||||
throw new Exception("追加工作表失败:临时导出文件中没有可追加的数据。");
|
||||
}
|
||||
|
||||
string sheetName = GetUniqueNpoiSheetName(targetWorkbook, Path.GetFileNameWithoutExtension(sourceFileName));
|
||||
ISheet targetSheet = targetWorkbook.CreateSheet(sheetName);
|
||||
SafeCopyNpoiWorksheetContent(sourceSheet, targetSheet, targetWorkbook);
|
||||
|
||||
using (FileStream targetStream = new FileStream(targetFileName, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
targetWorkbook.Write(targetStream);
|
||||
}
|
||||
|
||||
// 合并成功后删除临时文件,删除失败不影响导出结果。
|
||||
try
|
||||
{
|
||||
File.Delete(sourceFileName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取源Excel中第一个可见且有数据的工作表。
|
||||
/// </summary>
|
||||
/// <param name="package">Excel文件包。</param>
|
||||
/// <returns>可追加的工作表。</returns>
|
||||
private static ExcelWorksheet GetFirstVisibleWorksheet(ExcelPackage package)
|
||||
{
|
||||
foreach (ExcelWorksheet worksheet in package.Workbook.Worksheets)
|
||||
{
|
||||
if (worksheet != null && worksheet.Hidden == eWorkSheetHidden.Visible && worksheet.Dimension != null)
|
||||
{
|
||||
return worksheet;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取xls源文件中第一个可见且有数据的工作表。
|
||||
/// </summary>
|
||||
/// <param name="workbook">xls工作簿。</param>
|
||||
/// <returns>可追加的工作表。</returns>
|
||||
private static ISheet GetFirstVisibleNpoiSheet(HSSFWorkbook workbook)
|
||||
{
|
||||
for (int i = 0; i < workbook.NumberOfSheets; i++)
|
||||
{
|
||||
if (!workbook.IsSheetHidden(i) && !workbook.IsSheetVeryHidden(i))
|
||||
{
|
||||
ISheet sheet = workbook.GetSheetAt(i);
|
||||
if (sheet != null && sheet.PhysicalNumberOfRows > 0)
|
||||
{
|
||||
return sheet;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安全复制xlsx工作表内容,复制数据、样式、列宽、行高和合并区域。
|
||||
/// </summary>
|
||||
/// <param name="sourceSheet">源工作表。</param>
|
||||
/// <param name="targetSheet">目标工作表。</param>
|
||||
private static void SafeCopyXlsxWorksheetContent(ExcelWorksheet sourceSheet, ExcelWorksheet targetSheet)
|
||||
{
|
||||
int startRow = sourceSheet.Dimension.Start.Row;
|
||||
int startCol = sourceSheet.Dimension.Start.Column;
|
||||
int endRow = sourceSheet.Dimension.End.Row;
|
||||
int endCol = sourceSheet.Dimension.End.Column;
|
||||
|
||||
sourceSheet.Cells[startRow, startCol, endRow, endCol].Copy(targetSheet.Cells[startRow, startCol, endRow, endCol]);
|
||||
|
||||
for (int row = startRow; row <= endRow; row++)
|
||||
{
|
||||
targetSheet.Row(row).Height = sourceSheet.Row(row).Height;
|
||||
targetSheet.Row(row).Hidden = sourceSheet.Row(row).Hidden;
|
||||
}
|
||||
|
||||
for (int col = startCol; col <= endCol; col++)
|
||||
{
|
||||
targetSheet.Column(col).Width = sourceSheet.Column(col).Width;
|
||||
targetSheet.Column(col).Hidden = sourceSheet.Column(col).Hidden;
|
||||
}
|
||||
|
||||
foreach (string address in sourceSheet.MergedCells)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(address))
|
||||
{
|
||||
targetSheet.Cells[address].Merge = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceSheet.View != null)
|
||||
{
|
||||
targetSheet.View.ShowGridLines = sourceSheet.View.ShowGridLines;
|
||||
targetSheet.View.ZoomScale = sourceSheet.View.ZoomScale;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安全复制xls工作表内容,复制数据、字体样式、列宽、行高和合并区域。
|
||||
/// </summary>
|
||||
/// <param name="sourceSheet">源工作表。</param>
|
||||
/// <param name="targetSheet">目标工作表。</param>
|
||||
/// <param name="targetWorkbook">目标工作簿。</param>
|
||||
private static void SafeCopyNpoiWorksheetContent(ISheet sourceSheet, ISheet targetSheet, HSSFWorkbook targetWorkbook)
|
||||
{
|
||||
int firstColumnIndex = -1;
|
||||
int lastColumnIndex = -1;
|
||||
Dictionary<short, ICellStyle> styleCache = new Dictionary<short, ICellStyle>();
|
||||
|
||||
for (int rowIndex = sourceSheet.FirstRowNum; rowIndex <= sourceSheet.LastRowNum; rowIndex++)
|
||||
{
|
||||
IRow sourceRow = sourceSheet.GetRow(rowIndex);
|
||||
if (sourceRow == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sourceRow.FirstCellNum >= 0)
|
||||
{
|
||||
firstColumnIndex = firstColumnIndex < 0 ? sourceRow.FirstCellNum : Math.Min(firstColumnIndex, sourceRow.FirstCellNum);
|
||||
lastColumnIndex = Math.Max(lastColumnIndex, sourceRow.LastCellNum);
|
||||
}
|
||||
|
||||
IRow targetRow = targetSheet.CreateRow(rowIndex);
|
||||
targetRow.Height = sourceRow.Height;
|
||||
|
||||
for (int cellIndex = sourceRow.FirstCellNum; cellIndex < sourceRow.LastCellNum; cellIndex++)
|
||||
{
|
||||
if (cellIndex < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ICell sourceCell = sourceRow.GetCell(cellIndex);
|
||||
if (sourceCell == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ICell targetCell = targetRow.CreateCell(cellIndex);
|
||||
CopyNpoiCellValue(sourceCell, targetCell);
|
||||
CopyNpoiCellStyle(sourceCell, targetCell, targetWorkbook, styleCache);
|
||||
}
|
||||
}
|
||||
|
||||
if (firstColumnIndex >= 0 && lastColumnIndex > firstColumnIndex)
|
||||
{
|
||||
for (int colIndex = firstColumnIndex; colIndex < lastColumnIndex; colIndex++)
|
||||
{
|
||||
targetSheet.SetColumnWidth(colIndex, sourceSheet.GetColumnWidth(colIndex));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < sourceSheet.NumMergedRegions; i++)
|
||||
{
|
||||
CellRangeAddress sourceRange = sourceSheet.GetMergedRegion(i);
|
||||
if (sourceRange != null)
|
||||
{
|
||||
targetSheet.AddMergedRegion(new CellRangeAddress(
|
||||
sourceRange.FirstRow,
|
||||
sourceRange.LastRow,
|
||||
sourceRange.FirstColumn,
|
||||
sourceRange.LastColumn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制xls单元格的值。
|
||||
/// </summary>
|
||||
/// <param name="sourceCell">源单元格。</param>
|
||||
/// <param name="targetCell">目标单元格。</param>
|
||||
private static void CopyNpoiCellValue(ICell sourceCell, ICell targetCell)
|
||||
{
|
||||
switch (sourceCell.CellType)
|
||||
{
|
||||
case CellType.Boolean:
|
||||
targetCell.SetCellValue(sourceCell.BooleanCellValue);
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
targetCell.SetCellValue(sourceCell.NumericCellValue);
|
||||
break;
|
||||
case CellType.String:
|
||||
targetCell.SetCellValue(sourceCell.StringCellValue);
|
||||
break;
|
||||
case CellType.Formula:
|
||||
targetCell.SetCellFormula(sourceCell.CellFormula);
|
||||
break;
|
||||
case CellType.Error:
|
||||
targetCell.SetCellErrorValue(sourceCell.ErrorCellValue);
|
||||
break;
|
||||
case CellType.Blank:
|
||||
targetCell.SetCellType(CellType.Blank);
|
||||
break;
|
||||
default:
|
||||
targetCell.SetCellValue(sourceCell.ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制xls单元格样式和字体。
|
||||
/// </summary>
|
||||
/// <param name="sourceCell">源单元格。</param>
|
||||
/// <param name="targetCell">目标单元格。</param>
|
||||
/// <param name="targetWorkbook">目标工作簿。</param>
|
||||
/// <param name="styleCache">样式缓存,避免重复创建相同样式。</param>
|
||||
private static void CopyNpoiCellStyle(ICell sourceCell, ICell targetCell, HSSFWorkbook targetWorkbook, Dictionary<short, ICellStyle> styleCache)
|
||||
{
|
||||
if (sourceCell.CellStyle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
short styleIndex = sourceCell.CellStyle.Index;
|
||||
ICellStyle targetStyle = null;
|
||||
if (!styleCache.TryGetValue(styleIndex, out targetStyle))
|
||||
{
|
||||
targetStyle = targetWorkbook.CreateCellStyle();
|
||||
targetStyle.CloneStyleFrom(sourceCell.CellStyle);
|
||||
|
||||
IFont sourceFont = sourceCell.CellStyle.GetFont(sourceCell.Sheet.Workbook);
|
||||
if (sourceFont != null)
|
||||
{
|
||||
IFont targetFont = targetWorkbook.CreateFont();
|
||||
CopyNpoiFont(sourceFont, targetFont);
|
||||
targetStyle.SetFont(targetFont);
|
||||
}
|
||||
|
||||
styleCache.Add(styleIndex, targetStyle);
|
||||
}
|
||||
|
||||
targetCell.CellStyle = targetStyle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制xls字体属性。
|
||||
/// </summary>
|
||||
/// <param name="sourceFont">源字体。</param>
|
||||
/// <param name="targetFont">目标字体。</param>
|
||||
private static void CopyNpoiFont(IFont sourceFont, IFont targetFont)
|
||||
{
|
||||
targetFont.FontName = sourceFont.FontName;
|
||||
targetFont.FontHeight = sourceFont.FontHeight;
|
||||
targetFont.FontHeightInPoints = sourceFont.FontHeightInPoints;
|
||||
targetFont.Boldweight = sourceFont.Boldweight;
|
||||
targetFont.Color = sourceFont.Color;
|
||||
targetFont.IsItalic = sourceFont.IsItalic;
|
||||
targetFont.IsStrikeout = sourceFont.IsStrikeout;
|
||||
targetFont.Underline = sourceFont.Underline;
|
||||
targetFont.TypeOffset = sourceFont.TypeOffset;
|
||||
targetFont.Charset = sourceFont.Charset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取不重复且符合Excel规则的工作表名称。
|
||||
/// </summary>
|
||||
/// <param name="package">目标Excel文件包。</param>
|
||||
/// <param name="sheetName">原始工作表名称。</param>
|
||||
/// <returns>可用的工作表名称。</returns>
|
||||
private static string GetUniqueWorksheetName(ExcelPackage package, string sheetName)
|
||||
{
|
||||
string baseName = GetSafeWorksheetName(sheetName);
|
||||
string result = baseName;
|
||||
int index = 1;
|
||||
while (package.Workbook.Worksheets.Any(item => string.Equals(item.Name, result, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
string suffix = "_" + index++;
|
||||
int maxLength = 31 - suffix.Length;
|
||||
string namePrefix = baseName.Length > maxLength ? baseName.Substring(0, maxLength) : baseName;
|
||||
result = namePrefix + suffix;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取xls中不重复且符合Excel规则的工作表名称。
|
||||
/// </summary>
|
||||
/// <param name="workbook">目标xls工作簿。</param>
|
||||
/// <param name="sheetName">原始工作表名称。</param>
|
||||
/// <returns>可用的工作表名称。</returns>
|
||||
private static string GetUniqueNpoiSheetName(HSSFWorkbook workbook, string sheetName)
|
||||
{
|
||||
string baseName = GetSafeWorksheetName(sheetName);
|
||||
string result = baseName;
|
||||
int index = 1;
|
||||
while (workbook.GetSheet(result) != null)
|
||||
{
|
||||
string suffix = "_" + index++;
|
||||
int maxLength = 31 - suffix.Length;
|
||||
string namePrefix = baseName.Length > maxLength ? baseName.Substring(0, maxLength) : baseName;
|
||||
result = namePrefix + suffix;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取符合Excel工作表命名规则的名称。
|
||||
/// </summary>
|
||||
/// <param name="sheetName">原始工作表名称。</param>
|
||||
/// <returns>处理后的工作表名称。</returns>
|
||||
private static string GetSafeWorksheetName(string sheetName)
|
||||
{
|
||||
string result = (sheetName ?? string.Empty).Trim();
|
||||
char[] invalidChars = new char[] { '\\', '/', '?', '*', '[', ']', ':' };
|
||||
foreach (char invalidChar in invalidChars)
|
||||
{
|
||||
result = result.Replace(invalidChar, '_');
|
||||
}
|
||||
result = Regex.Replace(result,
|
||||
@@ -932,6 +932,9 @@ namespace Lskj.Control.Model
|
||||
SqlStoredProcedurepPrompt.GenerateBillSaveScript_DM(SqlHelper.LastFailureSql);
|
||||
}
|
||||
}
|
||||
string Message = ErrorMessage.PromptErrorMessage(ex);
|
||||
MessageUtil.Show(Message, ex.Message);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -38,14 +38,27 @@ namespace Lskj.Control
|
||||
/// <param name="msg"></param>
|
||||
public static DialogResult Show(string msg)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(msg) && msg.Contains("与另一个进程被死锁在"))
|
||||
if (msg.Contains("未将对象引用设置到对象的实例"))
|
||||
{
|
||||
try
|
||||
{
|
||||
string callStackInfo = GetBusinessCallStack();
|
||||
msg = "未将对象引用设置到对象的实例\r\n" + callStackInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(msg) && msg.Contains("与另一个进程被死锁在")&& !SystemInfo.Instance.PromptDeadlock)
|
||||
msg = "网络连接超时,请稍候再试!";
|
||||
if (Business.Impl.LanguageTranslation.Translatable)
|
||||
{
|
||||
msg = Business.Impl.LanguageTranslation.GetTranslatedText(msg);
|
||||
}
|
||||
|
||||
return XtraMessageBox.Show(msg, ResourceKeys.SystemTip, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,9 +71,21 @@ namespace Lskj.Control
|
||||
/// <para>版本:1.0</para>
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
public static DialogResult Show(string msg, string errorMessage )
|
||||
public static DialogResult Show(string msg, string errorMessage)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(errorMessage) && errorMessage.Contains("与另一个进程被死锁在"))
|
||||
if (errorMessage.Contains("未将对象引用设置到对象的实例"))
|
||||
{
|
||||
try
|
||||
{
|
||||
string callStackInfo = GetBusinessCallStack();
|
||||
errorMessage = "未将对象引用设置到对象的实例\r\n" + callStackInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(errorMessage) && errorMessage.Contains("与另一个进程被死锁在") && !SystemInfo.Instance.PromptDeadlock)
|
||||
{
|
||||
errorMessage = "网络连接超时,请稍候再试!";
|
||||
if (Business.Impl.LanguageTranslation.Translatable)
|
||||
@@ -69,8 +94,8 @@ namespace Lskj.Control
|
||||
}
|
||||
return XtraMessageBox.Show(errorMessage, ResourceKeys.SystemTip, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(errorMessage) && errorMessage.Contains("事务在触发器中结束。批处理已中止"))
|
||||
|
||||
if (!string.IsNullOrEmpty(errorMessage) && errorMessage.Contains("事务在触发器中结束。批处理已中止"))
|
||||
{
|
||||
if (Business.Impl.LanguageTranslation.Translatable)
|
||||
{
|
||||
@@ -89,11 +114,11 @@ namespace Lskj.Control
|
||||
if (dr != DialogResult.Yes && !string.IsNullOrWhiteSpace(errorMessage))
|
||||
{
|
||||
errorMessage = ErrorMessage.StackTrace;
|
||||
if (SystemInfo.Instance.HideErrorSQL)
|
||||
if (SystemInfo.Instance.HideErrorSQL)
|
||||
{
|
||||
errorMessage= errorMessage.Split(new string[] { "SQL=[" }, StringSplitOptions.None)[0];
|
||||
errorMessage = errorMessage.Split(new string[] { "SQL=[" }, StringSplitOptions.None)[0];
|
||||
}
|
||||
XtraMessageBox.Show(errorMessage, ResourceKeys.SystemTip, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
XtraMessageBox.Show(errorMessage, ResourceKeys.SystemTip, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
DevExpress.XtraEditors.Controls.Localizer.Active = null;
|
||||
return DialogResult.OK;
|
||||
@@ -111,10 +136,32 @@ namespace Lskj.Control
|
||||
/// <returns>DialogResult.</returns>
|
||||
public static DialogResult Show(Exception ex)
|
||||
{
|
||||
if (ex.Message.Contains("未将对象引用设置到对象的实例"))
|
||||
{
|
||||
try
|
||||
{
|
||||
//string callStackInfo = GetBusinessCallStack();
|
||||
//string msgnew = "未将对象引用设置到对象的实例\r\n" + callStackInfo;
|
||||
|
||||
string errorInfo = $"【报错时间】:{DateTime.Now}\n" +
|
||||
$"【异常类型】:{ex.GetType().Name}\n" +
|
||||
$"【错误消息】:{ex.Message}\n" +
|
||||
$"【报错方法】:{ex.TargetSite?.DeclaringType?.FullName}.{ex.TargetSite?.Name}\n" +
|
||||
$"【完整调用栈】:\n{ex.StackTrace}\n" +
|
||||
$"【内部异常】:{ex.InnerException?.Message}";
|
||||
|
||||
|
||||
return XtraMessageBox.Show(errorInfo, ResourceKeys.SystemTip, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
string msg = ex == null ? ResourceKeys.UnKownErrorTip : ex.StackTrace;
|
||||
if (!string.IsNullOrEmpty(msg) && msg.Contains("与另一个进程被死锁在"))
|
||||
if (!string.IsNullOrEmpty(msg) && msg.Contains("与另一个进程被死锁在") && !SystemInfo.Instance.PromptDeadlock)
|
||||
msg = "网络连接超时,请稍候再试!";
|
||||
if (Business.Impl.LanguageTranslation.Translatable)
|
||||
{
|
||||
@@ -125,7 +172,7 @@ namespace Lskj.Control
|
||||
else
|
||||
{
|
||||
string msg = ex == null ? ResourceKeys.UnKownErrorTip : ex.Message; //ResourceKeys.SystemErrorTip + "\r\n" + ex.Message + "\r\n" + ex.StackTrace;
|
||||
if (!string.IsNullOrEmpty(msg) && msg.Contains("与另一个进程被死锁在"))
|
||||
if (!string.IsNullOrEmpty(msg) && msg.Contains("与另一个进程被死锁在") && !SystemInfo.Instance.PromptDeadlock)
|
||||
msg = "网络连接超时,请稍候再试!";
|
||||
if (Business.Impl.LanguageTranslation.Translatable)
|
||||
{
|
||||
@@ -155,8 +202,67 @@ namespace Lskj.Control
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
public static DialogResult Show(string msg, MessageBoxButtons buttons)
|
||||
{
|
||||
|
||||
if (msg.Contains("未将对象引用设置到对象的实例"))
|
||||
{
|
||||
try
|
||||
{
|
||||
string callStackInfo = GetBusinessCallStack();
|
||||
msg = "未将对象引用设置到对象的实例\r\n" + callStackInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (Business.Impl.LanguageTranslation.Translatable)
|
||||
{
|
||||
msg = Business.Impl.LanguageTranslation.GetTranslatedText(msg);
|
||||
}
|
||||
return XtraMessageBox.Show(msg, ResourceKeys.SystemTip, buttons, M
|
||||
return XtraMessageBox.Show(msg, ResourceKeys.SystemTip, buttons, MessageBoxIcon.Information);
|
||||
}
|
||||
/// <summary>
|
||||
/// <para>说明:弹出是否对话框</para>
|
||||
/// <para>创建人:龚宇超</para>
|
||||
/// <para>创建日期:2017-12-07 </para>
|
||||
/// <para>修改人:</para>
|
||||
/// <para>修改日期:</para>
|
||||
/// <para>修改备注:</para>
|
||||
/// <para>版本:1.0</para>
|
||||
/// </summary>
|
||||
/// <param name="ex">The ex.</param>
|
||||
/// <param name="buttons">The buttons.</param>
|
||||
/// <returns>DialogResult.</returns>
|
||||
public static DialogResult Show(Exception ex, MessageBoxButtons buttons)
|
||||
{
|
||||
string msg = ex == null ? "未知提示." : ex.StackTrace;
|
||||
if (Business.Impl.LanguageTranslation.Translatable)
|
||||
{
|
||||
msg = Business.Impl.LanguageTranslation.GetTranslatedText(msg);
|
||||
}
|
||||
return XtraMessageBox.Show(msg, ResourceKeys.SystemTip, buttons, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取业务代码的调用栈(过滤框架/自身方法,只保留业务层调用)
|
||||
/// </summary>
|
||||
private static string GetBusinessCallStack()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 创建堆栈跟踪,true 表示包含文件路径和行号(需生成pdb文件)
|
||||
StackTrace stackTrace = new StackTrace(true);
|
||||
StackFrame[] frames = stackTrace.GetFrames();
|
||||
|
||||
if (frames == null) return "无法获取调用栈";
|
||||
|
||||
// 过滤堆栈帧:跳过当前方法(GetBusinessCallStack)和 Show 方法,只保留业务调用层
|
||||
var businessFrames = frames
|
||||
.SkipWhile(frame =>
|
||||
frame.GetMethod()?.DeclaringType == typeof(MessageUtil) // 跳过当前类的方法
|
||||
|| frame.GetMethod()?.Module.ScopeName.StartsWith("System.") == true // 跳过系统框架方法
|
||||
|| fr
|
||||
@@ -159,6 +159,11 @@ namespace Lskj.Control.Model
|
||||
/// </summary>
|
||||
public string BillSourceControlId = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 保存验证条件表
|
||||
/// </summary>
|
||||
public DataTable SaveCondTab = new DataTable();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 执行查询之前验证
|
||||
@@ -1648,7 +1653,7 @@ namespace Lskj.Control.Model
|
||||
{
|
||||
SetControlValue(model, this.ParentKey);
|
||||
}
|
||||
else if (model.RememberValue&& ConditionalCaching.ConditionalCaches.ContainsKey(model.id) && !string.IsNullOrWhiteSpace(ConditionalCaching.ConditionalCaches[model.id]))
|
||||
else if (model.RememberValue && ConditionalCaching.ConditionalCaches.ContainsKey(model.id) && !string.IsNullOrWhiteSpace(ConditionalCaching.ConditionalCaches[model.id]))
|
||||
{
|
||||
SetControlValue(model, ConditionalCaching.ConditionalCaches[model.id]);
|
||||
}
|
||||
@@ -1658,7 +1663,7 @@ namespace Lskj.Control.Model
|
||||
SetControlValue(model, defaultValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
//智能搜索框第一次加载时手动触发
|
||||
@@ -1710,7 +1715,7 @@ namespace Lskj.Control.Model
|
||||
/// </summary>
|
||||
/// <param name="rowItem">The row item.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||
public void CopyControlValue(bool Association = true,bool refreshSearchSource = false)
|
||||
public void CopyControlValue(bool Association = true, bool refreshSearchSource = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -2898,6 +2903,27 @@ namespace Lskj.Control.Model
|
||||
/// <returns>返回保存成功于否</returns>
|
||||
public bool SaveBaseModuleData(string menuCode, string tableName, string primaryKey, ref string primaryValue, bool isAdd = true, string leftField = "", bool isTip = true, int newVer = 0)
|
||||
{
|
||||
|
||||
if (this.SaveCondTab != null && this.SaveCondTab.Rows.Count > 0)
|
||||
{
|
||||
foreach (DataRow CondItem in SaveCondTab.Rows)
|
||||
{
|
||||
string condition = CondItem["condition"] + "";
|
||||
if (!string.IsNullOrWhiteSpace(condition))
|
||||
{
|
||||
string cond = this.ReplaceControlValue(condition);
|
||||
if (!ValidateCond(condition, null))
|
||||
{
|
||||
MessageUtil.Show(string.IsNullOrWhiteSpace(CondItem["hintmsg"] + "") ? "条件验证失败" : CondItem["hintmsg"] + "");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
string execSql = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(tableName))
|
||||
{
|
||||
@@ -3383,13 +3409,20 @@ namespace Lskj.Control.Model
|
||||
}
|
||||
if (RememberRow)
|
||||
{
|
||||
if (this.GridRowCount <= oldRowHandle && SystemInfo.Instance.DeleteSelectedEndOf)
|
||||
if (this._mainGridEx.GridView.OptionsSelection.MultiSelectMode == GridMultiSelectMode.CheckBoxRowSelect)
|
||||
{
|
||||
oldRowHandle = this.GridRowCount - 1;
|
||||
//多选框不选中,但滚动条移动到上一次点击的行
|
||||
if (oldRowHandle >= 0 && oldRowHandle < this._mainGridEx.GridView.RowCount)
|
||||
this._mainGridEx.GridView.MakeRowVisible(oldRowHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.GridRowCount <= oldRowHandle && SystemInfo.Instance.DeleteSelectedEndOf)
|
||||
{
|
||||
oldRowHandle = this.GridRowCount - 1;
|
||||
}
|
||||
SetFocusedRowHandle(oldRowHandle);
|
||||
}
|
||||
|
||||
SetFocusedRowHandle(oldRowHandle);
|
||||
//SetTopRowHandle(oldTopRowHandle);
|
||||
}
|
||||
//执行删除或者右键后,主表没有数据时清空明细表格数据
|
||||
if (this.GridRowCount == 0 && OnLastQueryTriggered != null) OnLastQueryTriggered(null, null);
|
||||
@@ -3490,11 +3523,20 @@ namespace Lskj.Control.Model
|
||||
}
|
||||
if (RememberRow)
|
||||
{
|
||||
if (this.GridRowCount <= oldRowHandle && SystemInfo.Instance.DeleteSelectedEndOf)
|
||||
if (this._mainGridEx.GridView.OptionsSelection.MultiSelectMode == GridMultiSelectMode.CheckBoxRowSelect)
|
||||
{
|
||||
oldRowHandle = this.GridRowCount - 1;
|
||||
//多选框不选中,但滚动条移动到上一次点击的行
|
||||
if (oldRowHandle >= 0 && oldRowHandle < this._mainGridEx.GridView.RowCount)
|
||||
this._mainGridEx.GridView.MakeRowVisible(oldRowHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.GridRowCount <= oldRowHandle && SystemInfo.Instance.DeleteSelectedEndOf)
|
||||
{
|
||||
oldRowHandle = this.GridRowCount - 1;
|
||||
}
|
||||
SetFocusedRowHandle(oldRowHandle);
|
||||
}
|
||||
SetFocusedRowHandle(oldRowHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3546,11 +3588,20 @@ namespace Lskj.Control.Model
|
||||
}
|
||||
if (RememberRow)
|
||||
{
|
||||
if (this.GridRowCount <= oldRowHandle && SystemInfo.Instance.DeleteSelectedEndOf)
|
||||
if (this._mainGridEx.GridView.OptionsSelection.MultiSelectMode == GridMultiSelectMode.CheckBoxRowSelect)
|
||||
{
|
||||
oldRowHandle = this.GridRowCount - 1;
|
||||
//多选框不选中,但滚动条移动到上一次点击的行
|
||||
if (oldRowHandle >= 0 && oldRowHandle < this._mainGridEx.GridView.RowCount)
|
||||
this._mainGridEx.GridView.MakeRowVisible(oldRowHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.GridRowCount <= oldRowHandle && SystemInfo.Instance.DeleteSelectedEndOf)
|
||||
{
|
||||
oldRowHandle = this.GridRowCount - 1;
|
||||
}
|
||||
SetFocusedRowHandle(oldRowHandle);
|
||||
}
|
||||
SetFocusedRowHandle(oldRowHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4265,6 +4316,9 @@ namespace Lskj.Control.Model
|
||||
{
|
||||
dateEdit.TextEdit.Properties.VistaCalendarViewStyle = DevExpress.XtraEditors.VistaCalendarViewStyle.YearView;
|
||||
}
|
||||
|
||||
//dateEdit.TextEdit.Properties.Appearance.BackColor = ColorTranslator.FromHtml("#00FF00");
|
||||
|
||||
baseControl = dateEdit;
|
||||
break;
|
||||
case ControlType.LabDateHalfDay:
|
||||
@@ -4351,6 +4405,7 @@ namespace Lskj.Control.Model
|
||||
autoEdit.Button.Visible = true;
|
||||
autoEdit.RefreshDataSource += new EventHandler(OnLabelAutoGridLookRefreshDataSource);
|
||||
}
|
||||
//autoEdit.TextEdit.Properties.Appearance.BackColor = ColorTranslator.FromHtml("#00FF00");
|
||||
autoEdit.clickAfterEmpty = model.clickAfterEmpty;
|
||||
autoEdit.ValueMember = ControlType.LabAutoCompleteValue == model.FieldType || ControlType.LabAutoCompleteValueParam == model.FieldType ? model.ValueMember : model.TextMember;
|
||||
autoEdit.ValueField = model.ValueMember;
|
||||
@@ -4707,6 +4762,7 @@ namespace Lskj.Control.Model
|
||||
//设置了ModuleFrameDisplayText(显示text值),就把配置的模块sql传给model.SourceSql
|
||||
if (model.FieldType == ControlType.LabSelectReturnIdNew)
|
||||
{
|
||||
model.ModuleFrameDisplayText = true;
|
||||
moduleReturnsIdNew.ModuleFrameDisplayText = true;
|
||||
model.SourceSql = moduleReturnsIdNew._lookUpForm.SysModel.MenuSql;
|
||||
}
|
||||
@@ -6303,4 +6359,36 @@ namespace Lskj.Control.Model
|
||||
LabelDateEdit dateEdit = controlObj as LabelDateEdit;
|
||||
value = dateEdit.TextEdit.EditValue == null ? dateEdit.EditText : dateEdit.TextEdit.DateTime.ToString("yyyy-MM-dd");
|
||||
}
|
||||
else if (
|
||||
else if (controlObj is LabelCheckEdit)
|
||||
{
|
||||
LabelCheckEdit checkEdit = controlObj as LabelCheckEdit;
|
||||
value = checkEdit.EditText;
|
||||
}
|
||||
else if (controlObj is LabelComboxEdit)
|
||||
{
|
||||
LabelComboxEdit autoEdit = controlObj as LabelComboxEdit;
|
||||
value = autoEdit.EditValue;
|
||||
}
|
||||
else if (controlObj is LabelTextEdit)
|
||||
{
|
||||
LabelTextEdit textIntEdit = controlObj as LabelTextEdit;
|
||||
if (textIntEdit != null) value = string.IsNullOrEmpty(textIntEdit.EditText) ? "0" : textIntEdit.EditText;
|
||||
}
|
||||
|
||||
defaultValue = defaultValue.Replace(item, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设置控件背景颜色(无需传入txt_ 内部已经追加)
|
||||
/// </summary>
|
||||
/// <param name="controlName"></param>
|
||||
public void SetBackgroundColor(string controlName)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Printing;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Windows.Forms;
|
||||
using iTextSharp.text.pdf;
|
||||
using Lskj.Util;
|
||||
using O2S.Components.PDFView4NET;
|
||||
using O2S.Components.PDFView4NET.Printing;
|
||||
|
||||
namespace Lskj.Control.Model
|
||||
{
|
||||
public class SignaturePrinting
|
||||
{
|
||||
private const string DefaultSignatureImageFileName = "signature.png";
|
||||
private const float DefaultSignatureWidth = 160f;
|
||||
private const float DefaultSignatureOpacity = 1f;
|
||||
|
||||
public static string PreviewByUrl(string pdfUrl)
|
||||
{
|
||||
return PreviewByUrls(new string[] { pdfUrl });
|
||||
}
|
||||
|
||||
public static string PreviewByUrls(string pdfUrls)
|
||||
{
|
||||
return PreviewByUrls(SplitUrls(pdfUrls));
|
||||
}
|
||||
|
||||
public static string PreviewByUrls(IEnumerable<string> pdfUrls)
|
||||
{
|
||||
return PreviewByUrls(pdfUrls, null);
|
||||
}
|
||||
|
||||
public static string PreviewByUrls(IEnumerable<string> pdfUrls, string signatureImagePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string previewFile = CreateSignedPreviewFile(pdfUrls, signatureImagePath);
|
||||
ShowPreviewForm(previewFile);
|
||||
return previewFile;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageUtil.Show("签章打印预览失败", ex.Message);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static string CreateSignedPreviewFile(IEnumerable<string> pdfUrls, string signatureImagePath)
|
||||
{
|
||||
List<string> urls = NormalizeUrls(pdfUrls);
|
||||
if (urls.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("未传入需要打印的PDF文件地址。");
|
||||
}
|
||||
|
||||
string signatureImage = ResolveSignatureImagePath(signatureImagePath);
|
||||
string tempPath = PubUtil.SignatureFilePath;
|
||||
PubUtil.ClearFilesInDirectory(tempPath);
|
||||
|
||||
List<string> signedFiles = new List<string>();
|
||||
for (int i = 0; i < urls.Count; i++)
|
||||
{
|
||||
string downloadedFile = DownloadPdf(urls[i], tempPath, i + 1);
|
||||
string signedFile = Path.Combine(tempPath, "signed_" + (i + 1).ToString("000") + "_" + Path.GetFileName(downloadedFile));
|
||||
AddCenteredSignature(downloadedFile, signedFile, signatureImage, DefaultSignatureWidth, DefaultSignatureOpacity);
|
||||
signedFiles.Add(signedFile);
|
||||
}
|
||||
|
||||
if (signedFiles.Count == 1)
|
||||
{
|
||||
return signedFiles[0];
|
||||
}
|
||||
|
||||
string mergedFile = Path.Combine(tempPath, "signature_preview_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".pdf");
|
||||
MergePdfFiles(signedFiles, mergedFile);
|
||||
return mergedFile;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> SplitUrls(string pdfUrls)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pdfUrls))
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
return pdfUrls.Split(new string[] { "\r\n", "\n", ";", "|" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
private static List<string> NormalizeUrls(IEnumerable<string> pdfUrls)
|
||||
{
|
||||
List<string> urls = new List<string>();
|
||||
if (pdfUrls == null)
|
||||
{
|
||||
return urls;
|
||||
}
|
||||
|
||||
foreach (string item in pdfUrls)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item))
|
||||
{
|
||||
urls.Add(item.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
private static string ResolveSignatureImagePath(string signatureImagePath)
|
||||
{
|
||||
string imagePath = signatureImagePath;
|
||||
if (string.IsNullOrWhiteSpace(imagePath))
|
||||
{
|
||||
imagePath = Path.Combine(PubUtil.PdfSignImagePath, DefaultSignatureImageFileName);
|
||||
}
|
||||
else if (!Path.IsPathRooted(imagePath))
|
||||
{
|
||||
imagePath = Path.Combine(PubUtil.AbsolutelyPath, imagePath);
|
||||
}
|
||||
|
||||
if (File.Exists(imagePath))
|
||||
{
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
string[] extensions = new string[] { "*.png", "*.jpg", "*.jpeg", "*.bmp", "*.gif" };
|
||||
foreach (string extension in extensions)
|
||||
{
|
||||
string[] files = Directory.GetFiles(PubUtil.PdfSignImagePath, extension);
|
||||
if (files.Length > 0)
|
||||
{
|
||||
return files[0];
|
||||
}
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("未找到签章图片,请将签章图片放到:" + imagePath);
|
||||
}
|
||||
|
||||
private static string DownloadPdf(string sourceUrl, string tempPath, int index)
|
||||
{
|
||||
string fileName = GetSafePdfFileName(sourceUrl, index);
|
||||
string localFile = Path.Combine(tempPath, "download_" + index.ToString("000") + "_" + fileName);
|
||||
|
||||
if (File.Exists(sourceUrl))
|
||||
{
|
||||
File.Copy(sourceUrl, localFile, true);
|
||||
return localFile;
|
||||
}
|
||||
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(sourceUrl, UriKind.Absolute, out uri))
|
||||
{
|
||||
throw new ArgumentException("PDF文件地址无效:" + sourceUrl);
|
||||
}
|
||||
|
||||
TryEnableTls12();
|
||||
using (TimeoutWebClient client = new TimeoutWebClient())
|
||||
{
|
||||
client.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0");
|
||||
client.DownloadFile(uri, localFile);
|
||||
}
|
||||
|
||||
return localFile;
|
||||
}
|
||||
|
||||
private static string GetSafePdfFileName(string sourceUrl, int index)
|
||||
{
|
||||
string fileName = string.Empty;
|
||||
Uri uri;
|
||||
if (Uri.TryCreate(sourceUrl, UriKind.Absolute, out uri))
|
||||
{
|
||||
fileName = HttpUtility.UrlDecode(Path.GetFileName(uri.LocalPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = Path.GetFileName(sourceUrl);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
fileName = "file_" + index.ToString("000") + ".pdf";
|
||||
}
|
||||
|
||||
foreach (char invalidChar in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
fileName = fileName.Replace(invalidChar, '_');
|
||||
}
|
||||
|
||||
if (!Path.GetExtension(fileName).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
fileName = Path.GetFileNameWithoutExtension(fileName) + ".pdf";
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private static void AddCenteredSignature(string inputPdfPath, string outputPdfPath, string signatureImagePath, float signatureWidth, float opacity)
|
||||
{
|
||||
using (PdfReader reader = new PdfReader(inputPdfPath))
|
||||
{
|
||||
using (FileStream outputStream = new FileStream(outputPdfPath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
PdfStamper stamper = null;
|
||||
try
|
||||
{
|
||||
stamper = new PdfStamper(reader, outputStream);
|
||||
for (int pageIndex = 1; pageIndex <= reader.NumberOfPages; pageIndex++)
|
||||
{
|
||||
iTextSharp.text.Rectangle pageSize = reader.GetPageSizeWithRotation(pageIndex);
|
||||
iTextSharp.text.Image signature = iTextSharp.text.Image.GetInstance(signatureImagePath);
|
||||
float width = Math.Min(signatureWidth, pageSize.Width * 0.6f);
|
||||
float height = width * signature.Height / signature.Width;
|
||||
float left = pageSize.Left + (pageSize.Width - width) / 2f;
|
||||
float bottom = pageSize.Bottom + (pageSize.Height - height) / 2f;
|
||||
|
||||
signature.ScaleAbsolute(width, height);
|
||||
signature.SetAbsolutePosition(left, bottom);
|
||||
|
||||
PdfContentByte content = stamper.GetOverContent(pageIndex);
|
||||
PdfGState state = new PdfGState();
|
||||
state.FillOpacity = opacity;
|
||||
content.SaveState();
|
||||
content.SetGState(state);
|
||||
content.AddImage(signature);
|
||||
content.RestoreState();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (stamper != null)
|
||||
{
|
||||
stamper.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void MergePdfFiles(List<string> pdfFiles, string outputPdfPath)
|
||||
{
|
||||
iTextSharp.text.Document document = null;
|
||||
PdfCopy copy = null;
|
||||
FileStream outputStream = null;
|
||||
|
||||
try
|
||||
{
|
||||
outputStream = new FileStream(outputPdfPath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
for (int fileIndex = 0; fileIndex < pdfFiles.Count; fileIndex++)
|
||||
{
|
||||
using (PdfReader reader = new PdfReader(pdfFiles[fileIndex]))
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
document = new iTextSharp.text.Document(reader.GetPageSizeWithRotation(1));
|
||||
copy = new PdfCopy(document, outputStream);
|
||||
document.Open();
|
||||
}
|
||||
|
||||
for (int pageIndex = 1; pageIndex <= reader.NumberOfPages; pageIndex++)
|
||||
{
|
||||
copy.AddPage(copy.GetImportedPage(reader, pageIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (document != null)
|
||||
{
|
||||
document.Close();
|
||||
}
|
||||
else if (outputStream != null)
|
||||
{
|
||||
outputStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ShowPreviewForm(string pdfFile)
|
||||
{
|
||||
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
|
||||
{
|
||||
throw new InvalidOperationException("签章打印预览需要在UI线程调用。");
|
||||
}
|
||||
|
||||
using (SignaturePreviewForm previewForm = new SignaturePreviewForm(pdfFile))
|
||||
{
|
||||
Form owner = Form.ActiveForm;
|
||||
if (owner != null && !owner.IsDisposed)
|
||||
{
|
||||
previewForm.ShowDialog(owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
previewForm.ShowDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryEnableTls12()
|
||||
{
|
||||
try
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol | (SecurityProtocolType)3072;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TimeoutWebClient : WebClient
|
||||
{
|
||||
public int Timeout { get; set; }
|
||||
|
||||
public TimeoutWebClient()
|
||||
{
|
||||
Timeout = 60000;
|
||||
}
|
||||
|
||||
protected override WebRequest GetWebRequest(Uri address)
|
||||
{
|
||||
WebRequest request = base.GetWebRequest(address);
|
||||
if (request != null)
|
||||
{
|
||||
request.Timeout = Timeout;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
private class SignaturePreviewForm : Form
|
||||
{
|
||||
private readonly string _pdfFile;
|
||||
private readonly PDFDocument _document;
|
||||
private readonly PDFPageView _pageView;
|
||||
private readonly ToolStripLabel _pageLabel;
|
||||
|
||||
public SignaturePreviewForm(string pdfFile)
|
||||
{
|
||||
_pdfFile = pdfFile;
|
||||
_document = new PDFDocument();
|
||||
_pageView = new PDFPageView();
|
||||
_pageLabel = new ToolStripLabel();
|
||||
|
||||
InitializeComponent();
|
||||
Load += OnFormLoad;
|
||||
FormClosed += OnFormClosed;
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
Text = "签章打印预览";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Width = 1000;
|
||||
Height = 760;
|
||||
|
||||
ToolStrip toolStrip = new ToolStrip();
|
||||
toolStrip.GripStyle = ToolStripGripStyle.Hidden;
|
||||
toolStrip.Dock = DockStyle.Top;
|
||||
|
||||
ToolStripButton printButton = new ToolStripButton("打印");
|
||||
printButton.Click += OnPrintClick;
|
||||
ToolStripButton firstButton = new ToolStripButton("首页");
|
||||
firstButton.Click += OnFirstClick;
|
||||
ToolStripButton prevButton = new ToolStripButton("上一页");
|
||||
prevButton.Click += OnPrevClick;
|
||||
ToolStripButton nextButton = new ToolStripButton("下一页");
|
||||
nextButton.Click += OnNextClick;
|
||||
ToolStripButton lastButton = new ToolStripButton("末页");
|
||||
lastButton.Click += OnLastClick;
|
||||
ToolStripButton zoomOutButton = new ToolStripButton("缩小");
|
||||
zoomOutButton.Click += OnZoomOutClick;
|
||||
ToolStripButton zoomInButton = new ToolStripButton("放大");
|
||||
zoomInButton.Click += OnZoomInClick;
|
||||
|
||||
toolStrip.Items.Add(printButton);
|
||||
toolStrip.Items.Add(new ToolStripSeparator());
|
||||
toolStrip.Items.Add(firstButton);
|
||||
toolStrip.Items.Add(prevButton);
|
||||
toolStrip.Items.Add(nextButton);
|
||||
toolStrip.Items.Add(lastButton);
|
||||
toolStrip.Items.Add(new ToolStripSeparator());
|
||||
toolStrip.Items.Add(zoomOutButton);
|
||||
toolStrip.Items.Add(zoomInButton);
|
||||
toolStrip.Items.Add(new ToolStripSeparator());
|
||||
toolStrip.Items.Add(_pageLabel);
|
||||
|
||||
_document.PageLayout = PDFPageLayout.SinglePage;
|
||||
_document.PageMode = PDFPageMode.UseNone;
|
||||
|
||||
_pageView.Dock = DockStyle.Fill;
|
||||
_pageView.Document = _document;
|
||||
_pageView.PageDisplayLayout = PDFPageDisplayLayout.OneColumn;
|
||||
_pageView.ZoomMode = PDFZoomMode.FitWidth;
|
||||
_pageView.WorkMode = UserInteractiveWorkMode.None;
|
||||
_pageView.BackColor = Color.White;
|
||||
|
||||
Controls.Add(_pageView);
|
||||
Controls.Add(toolStrip);
|
||||
}
|
||||
|
||||
private void OnFormLoad(object sender, EventArgs e)
|
||||
{
|
||||
_document.Load(_pdfFile);
|
||||
_pageView.PageNumber = 0;
|
||||
UpdatePageLabel();
|
||||
}
|
||||
|
||||
private void OnFormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_document.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPrintClick(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (PrintDialog printDialog = new PrintDialog())
|
||||
{
|
||||
printDialog.AllowSomePages = true;
|
||||
printDialog.UseEXDialog = true;
|
||||
printDialog.PrinterSettings = new PrinterSettings();
|
||||
|
||||
if (printDialog.ShowDialog(this) != DialogResult.OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PDFPrintSettings settings = new PDFPrintSettings(printDialog.PrinterSettings);
|
||||
settings.DocumentName = Path.GetFileName(_pdfFile);
|
||||
settings.AutoRotate = true;
|
||||
settings.PageScaling = PageScaling.FitToPrinterMarginsProportional;
|
||||
|
||||
PDFPrintContent content = PDFPrintContent.Page | PDFPrintContent.Annotations | PDFPrintContent.FormFields;
|
||||
_document.Print(settings, content);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageUtil.Show("签章PDF打印失败", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFirstClick(object sender, EventArgs e)
|
||||
{
|
||||
_pageView.GoToFirstPage();
|
||||
UpdatePageLabel();
|
||||
}
|
||||
|
||||
private void OnPrevClick(object sender, EventArgs e)
|
||||
{
|
||||
_pageView.GoToPrevPage();
|
||||
UpdatePageLabel();
|
||||
}
|
||||
|
||||
private void OnNextClick(object sender, EventArgs e)
|
||||
{
|
||||
_pageView.GoToNextPage();
|
||||
UpdatePageLabel();
|
||||
}
|
||||
|
||||
private void OnLastClick(object sender, EventArgs e)
|
||||
{
|
||||
_pageView.GoToLastPage();
|
||||
UpdatePageLabel();
|
||||
}
|
||||
|
||||
private void OnZoomOutClick(object sender, EventArgs e)
|
||||
{
|
||||
_pageView.ZoomMode = PDFZoomMode.Custom;
|
||||
_pageView.Zoom = Math.Max(0.25d, _pageView.Zoom - 0.1d);
|
||||
}
|
||||
|
||||
private void OnZoomInClick(object sender, EventArgs e)
|
||||
{
|
||||
_pageView.ZoomMode = PDFZoomMode.Custom;
|
||||
_pageView.Zoom = Math.Min(5d, _pageView.Zoom + 0.1d);
|
||||
}
|
||||
|
||||
private void UpdatePageLabel()
|
||||
{
|
||||
int pageCount = _document.PageCount;
|
||||
int pageNumber = pageCount == 0 ? 0 : _pageView.PageNumber + 1;
|
||||
_pageLabel.Text = "第 " + pageNumber + " / " + pageCount + " 页";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user