SVN r1104

SVN-Revision: r1104
This commit is contained in:
cyf
2026-01-30 07:48:24 +00:00
parent 5ccfe15fee
commit 47cf35aa28
45 changed files with 4096 additions and 449 deletions
@@ -282,7 +282,18 @@ namespace Lskj.Control.Model
/// 刷新明细的序号(排产模块)
/// </summary>
public string PlanLetfControl;
/// <summary>
/// 隐藏下方操作按钮
/// </summary>
public bool HideBottomPanel;
/// <summary>
/// 隐藏下方操作按钮
/// </summary>
public string ChartText;
/// <summary>
/// 隐藏下方操作按钮
/// </summary>
public string ChartTextColor;
/// <summary>
/// 主模块编号
@@ -342,4 +353,7 @@ namespace Lskj.Control.Model
this.DBClickEvent = item.Table.Columns.Contains("DBClickEvent") ? "1".Equals(item["DBClickEvent"] + "") : false;
this.ProhibitRefresh = item.Table.Columns.Contains("ProhibitRefresh") ? "1".Equals(item["ProhibitRefresh"] + "") : false;
this.DragExecuteSql = item.Table.Columns.Contains("DragExecuteSql") ? item["DragExecuteSql"] + "" : "";
this.QueryAgain = item.Table.Col
this.QueryAgain = item.Table.Columns.Contains("QueryAgain") ? "1".Equals(item["QueryAgain"] + "") : false;
this.BottomRefreshMain = item.Table.Columns.Contains("BottomRefreshMain") ? "1".Equals(item["BottomRefreshMain"] + "") : false;
this.LoadFilter = item.Table.Columns.Contains("LoadFilter") ? "1".Equals(item["LoadFilter"] + "") : false;
this.
@@ -42,6 +42,7 @@ public static class LabPicUrlPreview
// 唯一列名(保持你原逻辑)
gridColumn.FieldName = string.Format("{0}{1}", model.FieldName, Guid.NewGuid());
//gridColumn.FieldName = model.FieldName;
gridColumn.Tag = model; // 事件里取模型
RepositoryItemPictureEdit pictureEdit = new RepositoryItemPictureEdit();
@@ -167,7 +168,7 @@ public static class LabPicUrlPreview
int listIndex = view.GetDataSourceRowIndex(rowHandle);
try
{
object val2 = view.GetListSourceRowCellValue(listIndex, m.FieldName);
object val2 = view.GetListSourceRowCellValue(listIndex, m.FieldName);// "GM_leb_TuShi_ZS"
raw = val2 == null ? null : Convert.ToString(val2);
}
catch { }
@@ -0,0 +1,546 @@
// ============================================================================
// LabPicUrlPreview_TreeList.cs C# 7.3 / DevExpress 15.2 兼容)
// - 适配 TreeListInitPicColumn / Attach / AttachPreview
// - 复用原线程安全缓存:缩略图 & 原图分离缓存、并发限流 + LRU 清理
// - 同步阶段写 e.Value,异步完成后刷新 TreeList 单元格或预览窗体
// ============================================================================
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevExpress.Data;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using DevExpress.XtraTreeList.Nodes;
using DevExpress.XtraTreeList.ViewInfo;
using Lskj.Control.Model;
using Lskj.Control;
using Lskj.Business;
public static class LabPicUrlPreview_TreeList
{
// ====== 对外:初始化图片列(创建 RepositoryItemPictureEdit、设为 Unbound ======
public static void InitPicColumn(TreeList treeList, TreeListColumn treeListColumn, GridColumnModel model)
{
if (treeList == null || treeListColumn == null || model == null) return;
treeListColumn.AppearanceCell.Options.UseTextOptions = true;
treeListColumn.AppearanceCell.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center;
treeListColumn.OptionsColumn.AllowEdit = false;
// 唯一列名(保持原逻辑,避免列名重复)
treeListColumn.FieldName = string.Format("{0}{1}", model.FieldName, Guid.NewGuid());
treeListColumn.Tag = model; // 事件中获取列模型
RepositoryItemPictureEdit pictureEdit = new RepositoryItemPictureEdit();
pictureEdit.ShowMenu = false;
pictureEdit.NullText = " ";
pictureEdit.SizeMode = PictureSizeMode.Zoom;
treeList.RepositoryItems.Add(pictureEdit);
treeListColumn.UnboundType = DevExpress.XtraTreeList.Data.UnboundColumnType.Object;
treeListColumn.ColumnEdit = pictureEdit;
}
// ====== 对外:绑定“取缩略图”的事件(只需调用一次) ======
public static void Attach(TreeList treeList)
{
if (treeList == null) return;
treeList.CustomUnboundColumnData -= OnCustomUnboundColumnData;
treeList.CustomUnboundColumnData += OnCustomUnboundColumnData;
}
// ====== 对外:绑定“双击大图预览”的事件(只需调用一次) ======
public static void AttachPreview(TreeList treeList)
{
if (treeList == null) return;
treeList.DoubleClick -= OnTreeListDoubleClick;
treeList.DoubleClick += OnTreeListDoubleClick;
}
// ===================== 缩略图事件实现(核心改造) =====================
private static void OnCustomUnboundColumnData(object sender, TreeListCustomColumnDataEventArgs e)
{
TreeList treeList = sender as TreeList;
if (treeList == null) return;
GridColumnModel m = e.Column.Tag as GridColumnModel;
if (m == null || m.FieldType != ControlType.LabPicUrl || !e.IsGetData) return;
// 1) TreeList 用 Node 直接定位(替代 Grid 的 RowHandle/ListSourceRowIndex
TreeListNode node = e.Node;
if (node == null) return;
// 2) 读取原始 URL(优先 Node 数据,兜底数据源)
string raw = null;
try
{
// TreeList 直接从 Node 获取字段值(兼容绑定 DataTable/自定义对象)
object val = node.GetValue(m.FieldName);
raw = val == null ? null : Convert.ToString(val);
}
catch
{
// 兜底:从数据源(如 DataRow)获取
DataRow row = node.Tag as DataRow;
if (row != null && row.Table.Columns.Contains(m.FieldName))
raw = Convert.ToString(row[m.FieldName]);
}
if (string.IsNullOrWhiteSpace(raw)) return;
// 3) 拼接完整 URL(复用原逻辑)
string url = ResolveFullUrl(raw);
// 4) 目标高度(复用原逻辑)
int targetHeight = NormalizeHeight(m);
// 5) 缓存命中:同步赋值 e.Value
Image img;
if (ImageCache.TryGetThumb(url, targetHeight, out img))
{
e.Value = img;
return;
}
// 6) 未命中:异步下载,完成后刷新当前单元格(TreeList 刷新 API 改造)
System.Windows.Forms.Control invoker = treeList; // UI 回调对象
ImageCache.GetThumbAsync(url, targetHeight, invoker, delegate ()
{
RefreshCellCompat(treeList, node, e.Column);
});
}
// ===================== 双击预览(原图)(核心改造) =====================
private static void OnTreeListDoubleClick(object sender, EventArgs e)
{
TreeList treeList = sender as TreeList;
if (treeList == null) return;
// 1) TreeList 命中测试(替代 Grid 的 CalcHitInfo
TreeListHitInfo hitInfo = treeList.CalcHitInfo(treeList.PointToClient(Control.MousePosition));
//if (hitInfo == null || !hitInfo.InNodeCell || hitInfo.Column == null) return;
if (hitInfo == null || hitInfo.HitInfoType != HitInfoType.Cell || hitInfo.Node == null || hitInfo.Column == null) return;
TreeListNode hitNode = hitInfo.Node;
TreeListColumn hitColumn = hitInfo.Column;
// 2) 只处理 LabPicUrl 类型列
GridColumnModel m = hitColumn.Tag as GridColumnModel;
if (m == null || m.FieldType != ControlType.LabPicUrl) return;
// 3) 读取当前 Node 的 URLTreeList 专属取值逻辑)
string raw = null;
try
{
object val = hitNode.GetValue(m.FieldName);
raw = val == null ? null : Convert.ToString(val);
}
catch
{
// 兜底:从 Node.Tag(如 DataRow)获取
DataRow row = hitNode.Tag as DataRow;
if (row != null && row.Table.Columns.Contains(m.FieldName))
raw = Convert.ToString(row[m.FieldName]);
}
if (string.IsNullOrWhiteSpace(raw)) return;
string url = ResolveFullUrl(raw);
// 4) 打开预览窗体(复用原逻辑,适配 TreeList 数据)
Image thumb = null;
ImageCache.TryGetThumb(url, NormalizeHeight(m), out thumb);
FrmTreePicture frm = new FrmTreePicture();
try
{
// 适配 TreeList 列与节点数据(替换原 Grid 的 Column/Row
frm.PicUrlColumns = treeList.Columns.Where(c => c.Tag is GridColumnModel cm && cm.FieldType == ControlType.LabPicUrl).ToList(); // 兼容原窗体列集合类型
frm.FocusedRow = hitNode.Tag as DataRow; // 传递 Node 绑定的 DataRow
frm.FocusedColumn = hitColumn;
frm.Text = "预览";
frm.Picture = thumb;
frm.WindowState = FormWindowState.Maximized;
frm.StartPosition = FormStartPosition.CenterScreen;
// 异步拉取原图并更新(复用原缓存逻辑)
ImageCache.GetFullAsync(url, frm, delegate (Image full)
{
if (full == null) return;
try
{
if (!frm.IsDisposed) frm.Picture = full;
}
catch { }
});
frm.ShowDialog();
}
finally
{
if (frm != null && !frm.IsDisposed) frm.Dispose();
}
}
// ====== TreeList 单元格安全刷新(替代 Grid 的 RefreshRowCell ======
private static void RefreshCellCompat(TreeList treeList, TreeListNode node, TreeListColumn column)
{
try
{
if (treeList.IsDisposed || node == null || column == null) return;
// 整体刷新节点(避免单个单元格刷新失败)
if (!treeList.IsDisposed && node != null)
treeList.RefreshNode(node);
}
catch
{
try
{
// 刷新整个 TreeList(极端情况)
if (!treeList.IsDisposed)
treeList.RefreshDataSource();
}
catch
{
}
}
}
// ====== 以下方法完全复用原逻辑(无改造) ======
private static int NormalizeHeight(object model)
{
try
{
var t = model.GetType();
// 读取属性
var pi = t.GetProperty("LabPicUrlHeight");
if (pi != null)
{
int v = Convert.ToInt32(pi.GetValue(model, null));
return v <= 18 ? 30 : v;
}
// 读取无参方法
var mi = t.GetMethod("LabPicUrlHeight", Type.EmptyTypes);
if (mi != null)
{
int v = Convert.ToInt32(mi.Invoke(model, null));
return v <= 18 ? 30 : v;
}
}
catch { }
return 30;
}
private static string ResolveFullUrl(string raw)
{
if (string.IsNullOrEmpty(raw)) return raw;
if (raw.StartsWith("http", StringComparison.OrdinalIgnoreCase)) return raw;
try
{
string oa = SystemInfo.Instance.OAUrl;
if (string.IsNullOrEmpty(oa)) return raw.TrimStart('/');
if (!oa.EndsWith("/")) oa += "/";
return oa + raw.TrimStart('/');
}
catch
{
return raw.TrimStart('/');
}
}
// ====== 图片缓存(完全复用原逻辑,无任何改造) ======
private static class ImageCache
{
// —— 公共接口(缩略图) ——
public static bool TryGetThumb(string url, int targetHeight, out Image img)
{
return ThumbCache.TryGet(url, targetHeight, out img);
}
public static void GetThumbAsync(string url, int targetHeight, System.Windows.Forms.Control invoker, Action onReady)
{
ThumbCache.GetOrCreateAsync(url, targetHeight, invoker, onReady);
}
// —— 公共接口(原图) ——
public static bool TryGetFull(string url, out Image img)
{
return FullCache.TryGet(url, out img);
}
public static void GetFullAsync(string url, System.Windows.Forms.Control invoker, Action<Image> onReady)
{
FullCache.GetOrCreateAsync(url, invoker, onReady);
}
// ===== 缩略图缓存实现 =====
private static class ThumbCache
{
private class CacheEntry
{
public Image Image;
public DateTime LastHitUtc;
}
private static readonly object _lock = new object();
private static readonly Dictionary<string, CacheEntry> _cache =
new Dictionary<string, CacheEntry>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<string, Task<Image>> _tasks =
new Dictionary<string, Task<Image>>(StringComparer.OrdinalIgnoreCase);
private static readonly Semaphore _throttle = new Semaphore(4, 4); // 并发 4
private const int Capacity = 300;
static ThumbCache()
{
EnableTls12();
}
private static string MakeKey(string url, int h)
{
return url + "#h=" + h.ToString();
}
public static bool TryGet(string url, int targetHeight, out Image image)
{
string key = MakeKey(url, targetHeight);
lock (_lock)
{
CacheEntry e;
if (_cache.TryGetValue(key, out e) && e != null && e.Image != null)
{
e.LastHitUtc = DateTime.UtcNow;
_cache[key] = e;
image = e.Image;
return true;
}
}
image = null;
return false;
}
public static void GetOrCreateAsync(string url, int targetHeight, System.Windows.Forms.Control uiInvoker, Action onReady)
{
string key = MakeKey(url, targetHeight);
lock (_lock)
{
if (_cache.ContainsKey(key))
{
BeginInvokeSafe(uiInvoker, onReady);
return;
}
Task<Image> exist;
if (_tasks.TryGetValue(key, out exist))
{
exist.ContinueWith(delegate { BeginInvokeSafe(uiInvoker, onReady); }, TaskScheduler.Default);
return;
}
Task<Image> task = Task.Factory.StartNew<Image>(delegate
{
_throttle.WaitOne();
try
{
byte[] bytes = DownloadBytes(url);
if (bytes == null) return null;
using (Bitmap src = BytesToBitmap(bytes))
{
return ScaleBitmap(src, targetHeight);
}
}
catch { return null; }
finally { try { _throttle.Release(); } catch { } }
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).ContinueWith<Image>(delegate (Task<Image> t)
{
Image result = t.Result;
lock (_lock)
{
_tasks.Remove(key);
if (result != null)
{
_cache[key] = new CacheEntry { Image = result, LastHitUtc = DateTime.UtcNow };
TrimIfNeededUnsafe();
}
}
return result;
}, TaskScheduler.Default);
_tasks[key] = task;
task.ContinueWith(delegate { BeginInvokeSafe(uiInvoker, onReady); }, TaskScheduler.Default);
}
}
private static void TrimIfNeededUnsafe()
{
if (_cache.Count <= Capacity) return;
List<KeyValuePair<string, CacheEntry>> list = _cache.ToList();
list.Sort(delegate (KeyValuePair<string, CacheEntry> a, KeyValuePair<string, CacheEntry> b)
{
return a.Value.LastHitUtc.CompareTo(b.Value.LastHitUtc);
});
int removeCount = Math.Max(1, Capacity / 10);
for (int i = 0; i < removeCount && i < list.Count; i++)
{
string k = list[i].Key;
CacheEntry e;
if (_cache.TryGetValue(k, out e))
{
_cache.Remove(k);
try { if (e.Image != null) e.Image.Dispose(); } catch { }
}
}
}
}
// ===== 原图缓存实现(容量更小) =====
private static class FullCache
{
private class CacheEntry
{
public Image Image;
public DateTime LastHitUtc;
}
private static readonly object _lock = new object();
private static readonly Dictionary<string, CacheEntry> _cache =
new Dictionary<string, CacheEntry>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<string, Task<Image>> _tasks =
new Dictionary<string, Task<Image>>(StringComparer.OrdinalIgnoreCase);
private static readonly Semaphore _throttle = new Semaphore(2, 2); // 原图并发更小
private const int Capacity = 50;
static FullCache()
{
EnableTls12();
}
public static bool TryGet(string url, out Image image)
{
lock (_lock)
{
CacheEntry e;
if (_cache.TryGetValue(url, out e) && e != null && e.Image != null)
{
e.LastHitUtc = DateTime.UtcNow;
_cache[url] = e;
image = e.Image;
return true;
}
}
image = null;
return false;
}
public static void GetOrCreateAsync(string url, System.Windows.Forms.Control uiInvoker, Action<Image> onReady)
{
lock (_lock)
{
Image cached;
if (TryGet(url, out cached))
{
BeginInvokeSafe(uiInvoker, delegate { onReady(cached); });
return;
}
Task<Image> exist;
if (_tasks.TryGetValue(url, out exist))
{
exist.ContinueWith(t => BeginInvokeSafe(uiInvoker, delegate { onReady(t.Result); }), TaskScheduler.Default);
return;
}
Task<Image> task = Task.Factory.StartNew<Image>(delegate
{
_throttle.WaitOne();
try
{
byte[] bytes = DownloadBytes(url);
if (bytes == null) return null;
using (Bitmap bmp = BytesToBitmap(bytes))
{
return CopyBitmap(bmp);
}
}
catch { return null; }
finally { try { _throttle.Release(); } catch { } }
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).ContinueWith<Image>(delegate (Task<Image> t)
{
Image result = t.Result;
lock (_lock)
{
_tasks.Remove(url);
if (result != null)
{
_cache[url] = new CacheEntry { Image = result, LastHitUtc = DateTime.UtcNow };
TrimIfNeededUnsafe();
}
}
return result;
}, TaskScheduler.Default);
_tasks[url] = task;
task.ContinueWith(t => BeginInvokeSafe(uiInvoker, delegate { onReady(t.Result); }), TaskScheduler.Default);
}
}
private static void TrimIfNeededUnsafe()
{
if (_cache.Count <= Capacity) return;
List<KeyValuePair<string, CacheEntry>> list = _cache.ToList();
list.Sort(delegate (KeyValuePair<string, CacheEntry> a, KeyValuePair<string, CacheEntry> b)
{
return a.Value.LastHitUtc.CompareTo(b.Value.LastHitUtc);
});
int removeCount = Math.Max(1, Capacity / 10);
for (int i = 0; i < removeCount && i < list.Count; i++)
{
string k = list[i].Key;
CacheEntry e;
if (_cache.TryGetValue(k, out e))
{
_cache.Remove(k);
try { if (e.Image != null) e.Image.Dispose(); } catch { }
}
}
}
}
// ===== 共享底层工具 =====
private static void EnableTls12()
{
try
{
const System.Security.Authentication.SslProtocols _Tls12 =
(System.Security.Authentication.SslProtocols)0x00000C00;
ServicePointManager.SecurityProtocol |= (SecurityProtocolType)_Tls12;
}
catch { }
}
private static byte[] DownloadBytes(string url)
{
using (WebClient wc = new WebClient())
{
return wc.DownloadData(url);
}
}
private static Bitmap BytesToBitmap(byte[] bytes)
{
using (MemoryStream ms = new MemoryStream(bytes))
{
using (Image img = Image.FromStream(ms))
{
return new
@@ -34,6 +34,8 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Windows.Forms;
@@ -100,22 +102,22 @@ namespace Lskj.Control.Model
//判断是否存在网址框(需要绑定右键打开事件判断是否生成 网址框右键)
bool existLabWWW = false;
if (view is GridControlEx)
if (view is GridControlEx)
{
GridControlEx grid= view as GridControlEx;
foreach (GridColumn item in grid.GridView.Columns)
GridControlEx grid = view as GridControlEx;
foreach (GridColumn item in grid.GridView.Columns)
{
if (item.Tag is GridColumnModel)
if (item.Tag is GridColumnModel)
{
GridColumnModel gridColumnModel = item.Tag as GridColumnModel;
if (gridColumnModel.FieldType == ControlType.LabWWW) existLabWWW = true;
}
}
}
if (((table == null || table.Rows.Count == 0) && menu == null)&& !existLabWWW) return;
if (((table == null || table.Rows.Count == 0) && menu == null) && !existLabWWW) return;
ContextMenuStrip cmsMenu = new ContextMenuStrip();
cmsMenu.Opening += new CancelEventHandler(MenuStripOpening);
@@ -274,17 +276,20 @@ namespace Lskj.Control.Model
ToolStripMenuItem item = sender as ToolStripMenuItem;
DXMenuItem items = sender as DXMenuItem;
DataRow[] rowArray = GetSelectedRows();
GridRightMenuModel model = item == null ? items.Tag as GridRightMenuModel : item.Tag as GridRightMenuModel;
if (!model.Mergeexec && !model.MoreClick && rowArray.Length > 1)
{
MessageUtil.Show(string.Format(ResourceKeys.ExecRightMenuOnlyOne, model.MenuName));
return;
}
if (model.AllowNullExec && rowArray.Length == 0)
{
rowArray = new DataRow[] { new DataTable().NewRow() };
}
if (rowArray.Length == 0 && model.IsMustSelectRow())
{
MessageUtil.Show(ResourceKeys.SelectRowIsNull);
@@ -341,9 +346,9 @@ namespace Lskj.Control.Model
MessageUtil.Show(Message, ex.Message);
LogHelper.Instance.WriteError(ex);
}
finally
finally
{
if(!string.IsNullOrEmpty(model.UnionZTid))ToDBatching(AccountItem, AccountItem);
if (!string.IsNullOrEmpty(model.UnionZTid)) ToDBatching(AccountItem, AccountItem);
}
}
/// <summary>
@@ -449,7 +454,7 @@ namespace Lskj.Control.Model
string actionSql = string.Empty;
bool execOnlyOne = IsExecOnlyOne(model, paramListEx, rows, out actionSql);
bool tipOnlyOne = true; // 执行是否提示一次
bool allowBefore = ApiHelper.IsExecEventApi(Interface.Api.OperateEvent.BeforeModuleContextMenu, Model.ModuleCode, model.Id);
bool allowAfter = ApiHelper.IsExecEventApi(Interface.Api.OperateEvent.AfterModuleContextMenu, Model.ModuleCode, model.Id);
@@ -531,25 +536,74 @@ namespace Lskj.Control.Model
// 特殊处理程序
else if (dllName.Contains(".exe") && !model.WipeExes.Contains(dllName.ToString()) && (dllName.ToLower() != "lstest.exe"))
{
//删除选中行的json信息
if(!string.IsNullOrWhiteSpace(maintabFocusedRowJson))paramList.Remove(maintabFocusedRowJson);
// 创建进程启动信息对象
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = File.Exists(dllName) ? dllName : PubUtil.AbsolutelyLibPath + dllName; // 指定要启动的 EXE 路径
// 将参数数组拼接为命令行字符串(注意空格处理)
// 若参数包含空格,需要用双引号包裹,避免被解析为多个参数
startInfo.Arguments = string.Join(" ", paramList.Select(arg =>
arg.Contains(" ") ? $"\"{arg}\"" : arg
));
// 可选:设置进程启动选项
startInfo.UseShellExecute = false; // 不使用系统外壳程序(建议为 false,便于重定向输入输出)
startInfo.CreateNoWindow = false; // 是否在新窗口中启动(false 为显示窗口)
// 启动进程
Process process = Process.Start(startInfo);
// 执行exe程序
//WinHelper.WinExec(File.Exists(dllName) ? dllName : PubUtil.AbsolutelyLibPath + dllName, 1);
// WinHelper.WinExec(dllName);
string[] dllNameSplit = Regex.Split(dllName, ":args=");
string[] pmsSplit = dllNameSplit.Length > 1 ? (dllNameSplit[1] + "").Split(',') : null;
if (dllNameSplit.Length > 1 && pmsSplit != null && pmsSplit.Length > 0)//嵌入exe模块
{
string[] pmsArgs = pmsSplit.Select(pms => ReplaceHelper.ReplaceUserInfo(pms)).ToArray();
string guid = Guid.NewGuid().ToString();
Panel mainPanel = new Panel();
ProcessStartInfo processStartInfo = new ProcessStartInfo()
{
FileName = dllNameSplit[0],
Arguments = HandleHelper.CombineArgs(pmsArgs),
UseShellExecute = false,
RedirectStandardOutput = false,
RedirectStandardError = false,
CreateNoWindow = false
};
Process startedProcess = Process.Start(processStartInfo);
if (startedProcess == null)
{
MessageUtil.Show("进程启动失败");
return false;
}
startedProcess.WaitForInputIdle();
int retry = 0;
while (startedProcess.MainWindowHandle == IntPtr.Zero && retry < 500)
{
Thread.Sleep(100);
startedProcess.Refresh();
retry++;
}
IntPtr exeMainHandle = startedProcess.MainWindowHandle;
if (exeMainHandle == IntPtr.Zero)
{
MessageBox.Show("无法获取启动程序的主窗口句柄");
return false;
}
HandleHelper.SetFormNoneStyle(exeMainHandle, mainPanel);
mainPanel.Dock = DockStyle.Fill;
using (BaseForm baseForm = new BaseForm())
{
baseForm.WindowState = FormWindowState.Maximized;
baseForm.Controls.Add(mainPanel);
baseForm.ShowDialog();
}
}
else
{
//删除选中行的json信息
if (!string.IsNullOrWhiteSpace(maintabFocusedRowJson)) paramList.Remove(maintabFocusedRowJson);
// 创建进程启动信息对象
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = File.Exists(dllName) ? dllName : PubUtil.AbsolutelyLibPath + dllName; // 指定要启动的 EXE 路径
// 将参数数组拼接为命令行字符串(注意空格处理)
// 若参数包含空格,需要用双引号包裹,避免被解析为多个参数
startInfo.Arguments = string.Join(" ", paramList.Select(arg =>
arg.Contains(" ") ? $"\"{arg}\"" : arg
));
// 可选:设置进程启动选项
startInfo.UseShellExecute = false; // 不使用系统外壳程序(建议为 false,便于重定向输入输出)
startInfo.CreateNoWindow = false; // 是否在新窗口中启动(false 为显示窗口)
// 启动进程
Process process = Process.Start(startInfo);
// 执行exe程序
//WinHelper.WinExec(File.Exists(dllName) ? dllName : PubUtil.AbsolutelyLibPath + dllName, 1);
}
}
else if (dllName.StartsWith("www.") ||
dllName.StartsWith("http://") ||
@@ -580,7 +634,7 @@ namespace Lskj.Control.Model
switch (model.ActionType)
{
case 1: // 执行存储过程
if (i == rows.Length - 1 || execOnlyOne )
if (i == rows.Length - 1 || execOnlyOne)
{
//执行最后一条
FinallySucceeded = true;
@@ -633,8 +687,13 @@ namespace Lskj.Control.Model
return resultValue;
}
public bool OpenFrmcCover(GridRightMenuModel model, List<string> paramList)
/// <summary>
/// 导入数据或者反写到界面
/// </summary>
/// <param name="model"></param>
/// <param name="paramList"></param>
/// <returns></returns>
public bool OpenFrmcCover(GridRightMenuModel model, List<string> paramList)
{
bool importIntoDatabase = false;
@@ -647,32 +706,58 @@ namespace Lskj.Control.Model
return false;
}
}
else
else
{
//模式2,保存到数据库中,在执行保存后sql
importIntoDatabase = true;
if (string.IsNullOrWhiteSpace(paramList[1]) )
if (string.IsNullOrWhiteSpace(paramList[1]))
{
MessageUtil.Show("模块编号未配置");
return false;
}
}
string primaryKey = paramList[2];
FrmCover frmCover = new FrmCover(importIntoDatabase,paramList[1], paramList[2], paramList[3]);
if (frmCover.ShowDialog() == DialogResult.OK&& !importIntoDatabase)
FrmCover frmCover = new FrmCover(importIntoDatabase, paramList[1], paramList[2], paramList[3]);
if (frmCover.ShowDialog() == DialogResult.OK && !importIntoDatabase)
{
//反写数据源
DataTable ReverseData = frmCover.ReverseData;
//外部数据
DataTable table = GetDataTable();
// 2. 筛选出 ReverseData 和 table 中名称和数据类型都相同的列(排除主键列,避免重复赋值)
// 提取 ReverseData 中所有的主键值
HashSet<object> reversePrimaryKeys = new HashSet<object>(
ReverseData.AsEnumerable()
.Select(dr => dr[primaryKey])
.Where(val => val != DBNull.Value && val != null)
);
// 获取table中,没有更新的行(在ReverseData中没有对应主键)
IEnumerable<DataRow> noUpdateRows = table.AsEnumerable()
.Where(dr => dr[primaryKey] != DBNull.Value && dr[primaryKey] != null
&& !reversePrimaryKeys.Contains(dr[primaryKey]));
//提示存在没有更新的行
if (noUpdateRows.Any())
{
// 提示没有反写的数据
string noUpdateIds = string.Join("、", noUpdateRows.Select(dr => dr[primaryKey].ToString()));
string text = string.Format("有 {0} 条数据未更新,主键为:{1} \r\n请确认是否要继续", noUpdateRows.Count(), noUpdateIds);
DialogResult result = MessageUtil.Show(text, MessageBoxButtons.YesNo);
if (result != DialogResult.Yes)
{
return false;
}
}
//筛选出 ReverseData 和 table 中名称和数据类型都相同的列(排除主键列,避免重复赋值)
var commonColumns = ReverseData.Columns.Cast<DataColumn>()
.Where(col1 => col1.ColumnName != primaryKey // 跳过 id 列(无需更新)
&& table.Columns.Contains(col1.ColumnName) // 列名存在于 table2
)
)
.Select(col => col.ColumnName)
.ToList();
@@ -691,7 +776,7 @@ namespace Lskj.Control.Model
continue; // 跳过 id 为空的行
// 在 table2 中查找 id 匹配的行(使用 Select 方法快速定位)
DataRow[] matchedRows = table.Select($""+ primaryKey + " = '"+ idValue + "'");
DataRow[] matchedRows = table.Select($"" + primaryKey + " = '" + idValue + "'");
// 只处理找到唯一匹配行的情况
if (matchedRows.Length == 1)
@@ -855,9 +940,9 @@ namespace Lskj.Control.Model
catch (Exception)
{
result = 0;
if (result==0 )
if (result == 0)
{
SqlStoredProcedurepPrompt.GenerateProcedureExecutionScript(procName, paramList, isFirstFlag, comfirmFlag );
SqlStoredProcedurepPrompt.GenerateProcedureExecutionScript(procName, paramList, isFirstFlag, comfirmFlag);
}
}
finally
@@ -1011,7 +1096,7 @@ namespace Lskj.Control.Model
/// <para>版本:1.0</para>
/// </summary>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool ExecDynamicLinkLibary(GridRightMenuModel model, List<string> paramList, string dllName, bool isAddPage = false,DataRow rowData = null)
private bool ExecDynamicLinkLibary(GridRightMenuModel model, List<string> paramList, string dllName, bool isAddPage = false, DataRow rowData = null)
{
if (string.IsNullOrWhiteSpace(dllName))
{
@@ -1214,7 +1299,8 @@ namespace Lskj.Control.Model
{
form.SubForm.Show();
}
else {
else
{
form.SubForm.ShowDialog();
StaticControl.DogVerifyNoPageForms.Remove(form);
form.SubForm.Dispose();
@@ -1227,7 +1313,7 @@ namespace Lskj.Control.Model
XtraTabPage tp = new XtraTabPage();
tp.Text = model.MenuName;
if (!string.IsNullOrWhiteSpace(model.PageName))
if (!string.IsNullOrWhiteSpace(model.PageName))
{
tp.Text = ReplaceHelper.ReplaceRowParam(rowData, model.PageName).Trim();
}
@@ -1288,8 +1374,8 @@ namespace Lskj.Control.Model
int filequency = 0;
bool isOpenvisble = rows.Count() > 0;
string parmaryKey = BaseImpl.GetBasePrimaryKey(this.Model.ModuleCode);//获取主键
//string detailparmaryKey = parmaryKey;
List <GridDetailModel> details = GetDetails(Model.ModuleCode);//捕获所有明细 // 2. 筛选出 “关联下载” 的明细
//string detailparmaryKey = parmaryKey;
List<GridDetailModel> details = GetDetails(Model.ModuleCode);//捕获所有明细 // 2. 筛选出 “关联下载” 的明细
List<GridDetailModel> downloadRelated = details
.Where(d => d.IsDownloadRelated) // 只保留 IsDownloadRelated 为 true 的项
.ToList();
@@ -1308,7 +1394,7 @@ namespace Lskj.Control.Model
{
foreach (DataRow row in dataTable.Rows)
{
string url = row["webpath"] + "";
if (!string.IsNullOrEmpty(url))
{
@@ -1423,7 +1509,8 @@ namespace Lskj.Control.Model
MessageUtil.Show("未配置关联明细数据");
}
}
else {
else
{
MessageUtil.Show("没有需要下载的数据");
}
@@ -1446,7 +1533,7 @@ namespace Lskj.Control.Model
List<SqlParameter> sqlParamList = new List<SqlParameter>();
SqlParameter pMsg = new SqlParameter("@msg", SqlDbType.VarChar, 2000);
SqlParameter pComfirmFlag = new SqlParameter("@comfirmFlag", SqlDbType.Int);
paramList = model.Mergeexec? paramList:this.HandleRightMenuParams(model.ParamList,dataRow, null, model.ActionType);
paramList = model.Mergeexec ? paramList : this.HandleRightMenuParams(model.ParamList, dataRow, null, model.ActionType);
for (int i = 0; i < paramStr.Length; i++)
{
string item = paramStr[i];
@@ -1588,7 +1675,7 @@ namespace Lskj.Control.Model
/// <param name="model">The model.</param>
/// <param name="rowItem">The row item.</param>
/// <returns>System.String.</returns>
protected string GetSearchSql(GridDetailModel model, DataRow rowItem,string ParmaryKey)
protected string GetSearchSql(GridDetailModel model, DataRow rowItem, string ParmaryKey)
{
string fieldName = !string.IsNullOrEmpty(model.UnionParentField) && rowItem.Table.Columns.Contains(model.UnionParentField) ? model.UnionParentField : ParmaryKey;
string sqlValue = model.IsReadOnly || model.IsChart ? model.DetailSql : model.SystemModel.MenuSql;
@@ -1778,10 +1865,10 @@ namespace Lskj.Control.Model
return null;
}
/// <summary>
/// 获取外面的数据源
/// </summary>
/// <returns></returns>
/// <summary>
/// 获取外面的数据源
/// </summary>
/// <returns></returns>
protected virtual DataTable GetDataTable()
{
return null;
@@ -1972,28 +2059,4 @@ namespace Lskj.Control.Model
DataRow[] dataRows = columnsTab.Select().Where(n => (n["name"] + "").Equals(colunmField.Key)).ToArray();
if (dataRows.Length == 0)
{
string addColSql = string.Format("alter table P_PrivateDllTab add {0} {1}", colunmField.Key, colunmField.Value);
SqlHelper.ExecuteNonQuery(addColSql);//添加列
}
}
}
else
{
string createTabSql = "create table P_PrivateDllTab(id int IDENTITY(1,1) NOT NULL,{0})";
string createCol = string.Empty;
foreach (KeyValuePair<string, string> colunmField in colDic)
{
createCol += string.Format("{0} {1},", colunmField.Key, colunmField.Value);
}
createTabSql = string.Format(createTabSql, createCol.TrimEnd(','));
SqlHelper.ExecuteNonQuery(createTabSql);//创建表
}
return true;
}
catch (Exception)
{
return false;
}
}
}
}
string a
@@ -327,6 +327,12 @@ namespace Lskj.Control.Model
/// 页签名称(审核模块以页签形式打开,可以配置单据id)
/// </summary>
public string PageName;
/// <summary>
/// 右键菜单是否可用条件2(单据模块中使用。点击时实时判断主键控件是否满足条件,MenuCond之前写成了重置按钮时根据主表判断是否可以交互。)
/// </summary>
/// <value>The menu cond.</value>
public string ClickCond;
/// <summary>
/// 需要单独处理的exe程序
@@ -451,4 +457,5 @@ namespace Lskj.Control.Model
if (item.Table.Columns.Contains("DuringExecutionMinimize"))
this.DuringExecutionMinimize = string.IsNullOrWhiteSpace(item["DuringExecutionMinimize"] + "") ? false : "1".Equals(item["DuringExecutionMinimize"] + "");
if (item.Table.Columns.Contains("SqlDirectExecution"))
this.SqlDirectExecution = string.IsNullOrWhi
this.SqlDirectExecution = string.IsNullOrWhiteSpace(item["SqlDirectExecution"] + "") ? false : "1".Equals(item["SqlDirectExecution"] + "");
if (item
+49 -8
View File
@@ -156,7 +156,10 @@ namespace Lskj.Control.Model
///单据特殊模块id(单据来源控件)
/// </summary>
public string BillSourceControlId = string.Empty;
/// <summary>
///特殊左侧表
/// </summary>
public GridControlEx SpecialLeftTable;
/// <summary>
/// 执行查询之前验证
@@ -859,6 +862,10 @@ namespace Lskj.Control.Model
{
return BaseImpl.GetDefaultValue(item["defaultValue"] + "", ParentKey, OtherParams);
}));
Task<string> LookupSqlTask = cachesDic.AddTask(item, "LookupSql", new Task<string>(() =>
{
return BaseImpl.SpecialReplacement(item["lookupSql"] + "", OtherParams);
}));
Task<ControlModel> controlModelTask = cachesDic.AddTask(item, "ControlModel", new Task<ControlModel>(() =>
{
ControlModel controlModel = GetControlModel(item);//获取控件对象
@@ -1255,6 +1262,10 @@ namespace Lskj.Control.Model
{
return BaseImpl.GetDefaultValue(item["defaultValue"] + "", ParentKey, OtherParams);
}));
Task<string> LookupSqlTask = cachesDic.AddTask(item, "LookupSql", new Task<string>(() =>
{
return BaseImpl.SpecialReplacement(item["lookupSql"] + "", OtherParams);
}));
Task<ControlModel> controlModelTask = cachesDic.AddTask(item, "ControlModel", new Task<ControlModel>(() =>
{
ControlModel controlModel = GetControlModel(item);//获取控件对象
@@ -1693,7 +1704,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 refreshSearchSource = false)
public void CopyControlValue(bool Association = true,bool refreshSearchSource = false)
{
try
{
@@ -1759,15 +1770,19 @@ namespace Lskj.Control.Model
}
}
foreach (ControlModel model in this.ControlModels)
if (Association)
{
BaseUserControl control = FindControl(model);
// 树结构节点不清空数据
if (control != null && model.FieldType != ControlType.LabTreeType)
foreach (ControlModel model in this.ControlModels)
{
this.SetUnionAncCalcControl(control);
BaseUserControl control = FindControl(model);
// 树结构节点不清空数据
if (control != null && model.FieldType != ControlType.LabTreeType)
{
this.SetUnionAncCalcControl(control);
}
}
}
}
catch (Exception ex)
{
@@ -4018,7 +4033,14 @@ namespace Lskj.Control.Model
model.Sign = item.Table.Columns.Contains("TM_tagID") && !string.IsNullOrEmpty(item["TM_tagID"] + "") ? Convert.ToInt32(item["TM_tagID"] + "") : 0;
model.TextMember = item["lookupResult"] + "";
model.ValueMember = item["lookupKeyField"] + "";
model.SourceSql = item["lookupSql"] + "";
if (!dataCaches.GetValue(item, "LookupSql", out string lookupSql))
{
lookupSql=BaseImpl.SpecialReplacement(item["lookupSql"] + "",OtherParams);
}
//model.SourceSql = item["lookupSql"] + "";
model.SourceSql = lookupSql;
model.NullText = item.Table.Columns.Contains("InputHintText") ? item["InputHintText"] + "" : string.Empty;
model.TabOrder = item.Table.Columns.Contains("TabOrder") && !string.IsNullOrEmpty(item["TabOrder"] + "") ? Convert.ToInt32(item["TabOrder"] + "") : 0;
model.CalcExpr = item.Table.Columns.Contains("CalcExpr") ? item["CalcExpr"] + "" : string.Empty;
@@ -4186,6 +4208,7 @@ namespace Lskj.Control.Model
{
dateEdit.TextEdit.Properties.VistaCalendarViewStyle = DevExpress.XtraEditors.VistaCalendarViewStyle.YearView;
}
baseControl = dateEdit;
break;
case ControlType.LabComboxValue:
@@ -5459,6 +5482,24 @@ namespace Lskj.Control.Model
}
}
if (SpecialLeftTable != null)
{
GridView gridview = SpecialLeftTable.GridControl.DefaultView as GridView;
DataRow rowItem = gridview.GetFocusedDataRow();
if (rowItem != null)
{
sqlValue = ReplaceHelper.ReplaceRowParam(rowItem, sqlValue);
}
if (SpecialLeftTable is TreeGridControlEx)
{
rowItem = SpecialLeftTable.GetViewFocusedDataRow();
if (rowItem != null)
{
sqlValue = ReplaceHelper.ReplaceRowParam(rowItem, sqlValue);
}
}
}
return ReplaceHelper.ReplaceWhereCond(sqlValue) + WhereCond;
}
/// <summary>
@@ -49,4 +49,5 @@ namespace Lskj.Control.Model
public static KeyValuePair<string, GridControlEx> AddParentGrid = new KeyValuePair<string, GridControlEx>();
/// <summary>
/// 当前右键点击时的表格
/// </summa
/// </summary>
public static GridView _