SVN r1211

SVN-Revision: r1211
This commit is contained in:
cyf
2026-06-18 01:43:59 +00:00
parent 253cb869bb
commit f6192b8086
59 changed files with 2910 additions and 657 deletions
@@ -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>
/// 创
+542 -16
View File
@@ -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
{
+118 -12
View File
@@ -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
+103 -15
View File
@@ -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 + " 页";
}
}
}
}