feat(control): add module-backed extended return search

This commit is contained in:
2026-07-29 16:47:42 +08:00
parent 1bbe9c9a4c
commit 9c0fdac9ba
6 changed files with 118 additions and 109 deletions
@@ -0,0 +1,49 @@
using Lskj.Control.MultiModelLookUp;
using System;
using System.Collections.Generic;
namespace Lskj.Control
{
/// <summary>
/// 按模块编号延迟读取模块数据源 SQL。只缓存 SQL 文本,不加载业务数据。
/// </summary>
internal sealed class ExtendedReturnModuleSourceResolver
{
private readonly object syncRoot = new object();
private readonly Dictionary<string, string> sourceSqlByModule =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public string Resolve(string moduleCode)
{
moduleCode = (moduleCode ?? string.Empty).Trim();
if (moduleCode.Length == 0)
{
throw new InvalidOperationException("扩展模块搜索的模块编号不能为空。");
}
lock (syncRoot)
{
string cachedSql;
if (sourceSqlByModule.TryGetValue(moduleCode, out cachedSql))
{
return cachedSql;
}
using (FrmModelLookUp lookup = new FrmModelLookUp(moduleCode, true))
{
string sourceSql = lookup.SysModel == null
? string.Empty
: lookup.SysModel.MenuSql;
if (string.IsNullOrWhiteSpace(sourceSql))
{
throw new InvalidOperationException(
string.Format("模块“{0}”未配置数据源 SQL。", moduleCode));
}
sourceSqlByModule.Add(moduleCode, sourceSql);
return sourceSql;
}
}
}
}
}
@@ -18,7 +18,7 @@ using System.Windows.Forms;
namespace Lskj.Control
{
/// <summary>
/// MyControl 中的 181 扩展搜索控件。业务实际值与界面显示文本相互独立,
/// MyControl 中的 173/174 扩展搜索控件。业务实际值与界面显示文本相互独立,
/// 数据源仅在弹出框打开或用户执行查询时按需访问。
/// </summary>
public sealed class LabelExtendedReturnSearchEdit : BaseUserControl
@@ -152,7 +152,7 @@ namespace Lskj.Control
/// <summary>
/// BaseUserControl 的 EditText 仍用于常规赋值入口;读取时返回界面显示文本,
/// MyControl.GetControlValue 对 181 会显式读取 EditValue。
/// MyControl.GetControlValue 对 173/174 会显式读取 EditValue。
/// </summary>
public override string EditText
{
@@ -472,7 +472,14 @@ namespace Lskj.Control
{
if (Model == null) throw new InvalidOperationException("扩展返回控件配置不存在。");
if (ControlObj == null) throw new InvalidOperationException("扩展返回控件未关联 MyControl。");
if (string.IsNullOrWhiteSpace(Model.SourceSql))
if (Model.FieldType == ControlType.LabModuleSelectReturnIdExtended)
{
if (string.IsNullOrWhiteSpace(Model.AddModuleId))
{
throw new InvalidOperationException("扩展模块搜索的模块编号不能为空。");
}
}
else if (string.IsNullOrWhiteSpace(Model.SourceSql))
{
throw new InvalidOperationException("搜索数据源 SQL 不能为空。");
}
@@ -576,7 +583,7 @@ namespace Lskj.Control
private string BuildSourceSql()
{
string sourceSql = Model.SourceSql;
string sourceSql = GetBaseSourceSql();
if (ControlObj != null)
{
sourceSql = ControlObj.ReplaceControlValue(sourceSql);
@@ -585,6 +592,27 @@ namespace Lskj.Control
return ReplaceHelper.ReplaceParam(sourceSql);
}
private string GetBaseSourceSql()
{
if (Model == null)
{
throw new InvalidOperationException("扩展返回控件配置不存在。");
}
if (Model.FieldType == ControlType.LabModuleSelectReturnIdExtended)
{
if (ControlObj == null)
{
throw new InvalidOperationException("扩展返回控件未关联 MyControl。");
}
return ControlObj.ResolveExtendedReturnModuleSourceSql(Model.AddModuleId);
}
if (string.IsNullOrWhiteSpace(Model.SourceSql))
{
throw new InvalidOperationException("搜索数据源 SQL 不能为空。");
}
return Model.SourceSql;
}
private void StartSearch(string keyword)
{
SearchRequest request = new SearchRequest();
@@ -8,7 +8,6 @@ using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using Lskj.Business.Impl;
using Lskj.Control.Model;
using Lskj.Control.MultiModelLookUp;
using Lskj.Core;
using Lskj.Util;
using System;
@@ -31,6 +30,8 @@ namespace Lskj.Control
private const int ExtendedLookupMinimumPopupWidth = 360;
private readonly object mExtendedReturnSyncRoot = new object();
private readonly ExtendedReturnModuleSourceResolver mExtendedReturnModuleSourceResolver =
new ExtendedReturnModuleSourceResolver();
private readonly Dictionary<string, RepositoryItemPopupContainerEdit> mExtendedReturnSearchEditors =
new Dictionary<string, RepositoryItemPopupContainerEdit>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, ExtendedReturnPopupContext> mExtendedReturnPopupContexts =
@@ -84,7 +85,7 @@ namespace Lskj.Control
}
/// <summary>
/// 初始化扩展返回类型。180 仅创建模块选择按钮,181 仅创建空搜索编辑器,
/// 初始化扩展返回类型。173、174 共用空搜索编辑器,
/// 两种类型均不在表格初始化时访问业务数据源。
/// </summary>
private void InitExtendedReturn(GridColumn column, GridColumnModel model)
@@ -94,11 +95,7 @@ namespace Lskj.Control
CacheExtendedReturnDisplayField(model);
AttachExtendedReturnDisplayEvent();
AttachExtendedReturnDisposeEvent();
if (model.FieldType == ControlType.LabModuleSelectReturnIdExtended)
{
InitExtendedModuleReturn(column, model);
}
else if (model.FieldType == ControlType.LabSearchReturnIdExtended)
if (IsExtendedReturnType(model))
{
InitExtendedSearchReturn(column, model);
}
@@ -125,25 +122,6 @@ namespace Lskj.Control
DisposeExtendedReturnRequestTimers();
}
private void InitExtendedModuleReturn(GridColumn column, GridColumnModel model)
{
RepositoryItemButtonEdit buttonEdit = new RepositoryItemButtonEdit();
buttonEdit.NullText = string.Empty;
buttonEdit.AllowNullInput = DefaultBoolean.True;
buttonEdit.TextEditStyle = TextEditStyles.DisableTextEditor;
buttonEdit.Tag = model;
buttonEdit.Buttons.Clear();
buttonEdit.Buttons.Add(new EditorButton(ButtonPredefines.Ellipsis));
buttonEdit.ButtonClick += ExtendedModuleReturn_ButtonClick;
buttonEdit.CustomDisplayText += ExtendedModuleReturn_CustomDisplayText;
this.gridControl.RepositoryItems.Add(buttonEdit);
column.ColumnEdit = buttonEdit;
column.OptionsColumn.ReadOnly = true;
column.FilterMode = ColumnFilterMode.DisplayText;
this.mControlList.Add(model);
}
private void InitExtendedSearchReturn(GridColumn column, GridColumnModel model)
{
RepositoryItemPopupContainerEdit searchEdit = CreateExtendedReturnSearchEdit(model);
@@ -245,23 +223,6 @@ namespace Lskj.Control
}
}
private void ExtendedModuleReturn_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
{
try
{
RepositoryItemButtonEdit editor = sender as RepositoryItemButtonEdit;
GridColumnModel model = editor == null ? null : editor.Tag as GridColumnModel;
DataRow row = this.GridView.GetFocusedDataRow();
string displayField = GetExtendedReturnDisplayField(model);
if (row == null || string.IsNullOrWhiteSpace(displayField) || !row.Table.Columns.Contains(displayField)) return;
e.DisplayText = row[displayField] == DBNull.Value ? string.Empty : row[displayField] + string.Empty;
}
catch
{
}
}
private static bool IsExtendedReturnType(GridColumnModel model)
{
return model != null &&
@@ -297,7 +258,7 @@ namespace Lskj.Control
private void GridView_CustomRowCellEditForEditing_ExtendedReturn(object sender, CustomRowCellEditEventArgs e)
{
GridColumnModel model = e.Column == null ? null : e.Column.Tag as GridColumnModel;
if (model == null || model.FieldType != ControlType.LabSearchReturnIdExtended) return;
if (!IsExtendedReturnType(model)) return;
RepositoryItemPopupContainerEdit searchEdit;
if (!mExtendedReturnSearchEditors.TryGetValue(model.FieldName, out searchEdit)) return;
@@ -331,8 +292,7 @@ namespace Lskj.Control
private void GridView_RowCellClick_ExtendedReturn(object sender, RowCellClickEventArgs e)
{
GridColumnModel model = e.Column == null ? null : e.Column.Tag as GridColumnModel;
if (e.Button != MouseButtons.Left || model == null ||
model.FieldType != ControlType.LabSearchReturnIdExtended ||
if (e.Button != MouseButtons.Left || !IsExtendedReturnType(model) ||
!e.Column.OptionsColumn.AllowEdit) return;
this.GridView.FocusedRowHandle = e.RowHandle;
@@ -531,7 +491,7 @@ namespace Lskj.Control
private string ResolveExtendedReturnSourceSql(GridColumnModel model, DataRow row)
{
string sqlValue = model == null ? string.Empty : model.SqlSource;
string sqlValue = GetExtendedReturnBaseSourceSql(model);
if (this.ParentControl != null)
{
sqlValue = this.ParentControl.ReplaceParentControlValue(sqlValue);
@@ -546,6 +506,23 @@ namespace Lskj.Control
return ReplaceHelper.ReplaceParam(sqlValue);
}
private string GetExtendedReturnBaseSourceSql(GridColumnModel model)
{
if (model == null)
{
throw new InvalidOperationException("扩展返回列配置不存在。");
}
if (model.FieldType == ControlType.LabModuleSelectReturnIdExtended)
{
return mExtendedReturnModuleSourceResolver.Resolve(model.addModuleld);
}
if (string.IsNullOrWhiteSpace(model.SqlSource))
{
throw new InvalidOperationException("扩展搜索数据源 SQL 不能为空。");
}
return model.SqlSource;
}
private static void ValidateExtendedReturnMembers(GridColumnModel model)
{
if (model == null) throw new InvalidOperationException("扩展返回列配置不存在。");
@@ -1158,61 +1135,6 @@ namespace Lskj.Control
return TryCommitExtendedReturnValues(businessRow, stagedValues, out error);
}
private void ExtendedModuleReturn_ButtonClick(object sender, ButtonPressedEventArgs e)
{
ButtonEdit buttonEdit = sender as ButtonEdit;
GridColumnModel model = buttonEdit == null ? null : buttonEdit.Properties.Tag as GridColumnModel;
if (model == null) return;
try
{
DataRow businessRow = this.GridView.GetFocusedDataRow();
IList<ExtendedReturnFieldMapping> mappings = ValidateExtendedReturnBusinessConfiguration(model, businessRow);
using (FrmModelLookUp2 modelLookUp = new FrmModelLookUp2(model.addModuleld, true))
{
modelLookUp.ConfigureColumnMode = model.ConfigureColumnMode;
modelLookUp.ValueField = model.ValueMember;
modelLookUp.TextField = model.TextMember;
modelLookUp.SourceSQL = model.SqlSource;
modelLookUp.IsType = ControlType.LabSelectReturnIdNew;
modelLookUp.ValueMember = model.ValueMember;
modelLookUp.Tag = model;
modelLookUp.EditText = buttonEdit.Text;
modelLookUp.EditValue = buttonEdit.EditValue + string.Empty;
modelLookUp.CurrentOperColumnKey = Model.ModuleCode + "_" + model.FieldName;
string sourceSql = modelLookUp.SysModel.MenuSql.Replace("#", string.Empty) + model.SplicingConditions;
if (this.ParentControl != null)
{
sourceSql = this.ParentControl.ReplaceControlValue(sourceSql);
}
sourceSql = ReplaceHelper.ReplaceRowParam(this.GridView.GetFocusedDataRow(), sourceSql);
modelLookUp.NewSourceSQL = sourceSql;
modelLookUp.InitControls(modelLookUp.UnionModuleCodel);
ValidateExtendedReturnSourceColumns(modelLookUp.DataSource.Columns, model, mappings);
if (modelLookUp.ShowDialog() != DialogResult.OK) return;
string error;
if (!TryApplyExtendedReturnMappings(businessRow, modelLookUp.GetSelectedResultRow(), model, out error))
{
MessageUtil.Show("扩展返回字段配置错误:" + error);
return;
}
buttonEdit.EditValue = businessRow[model.FieldName];
this.GridView.PostEditor();
this.GridView.UpdateCurrentRow();
this.GridView.RefreshRow(this.GridView.FocusedRowHandle);
}
}
catch (Exception ex)
{
MessageUtil.Show("扩展模块选择失败:" + ex.Message);
}
}
/// <summary>
/// 先在同结构的脱离行上完成全部类型转换,所有值都合法后再写入真实业务行。
/// </summary>
+2 -1
View File
@@ -711,6 +711,7 @@
<Compile Include="AutoGridLookUp\ExtendedReturnSearchPopup.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="AutoGridLookUp\ExtendedReturnModuleSourceResolver.cs" />
<Compile Include="AutoGridLookUp\LabelExtendedReturnSearchEdit.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -1891,4 +1892,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
+2 -2
View File
@@ -495,11 +495,11 @@ namespace Lskj.Control.Model
/// <summary>
/// 模块选择返回ID-扩展
/// </summary>
public const int LabModuleSelectReturnIdExtended = 180;
public const int LabModuleSelectReturnIdExtended = 173;
/// <summary>
/// 搜索返回ID-扩展
/// </summary>
public const int LabSearchReturnIdExtended = 181;
public const int LabSearchReturnIdExtended = 174;
/// <summary>
/// <para>说明:是否为Value类型</para>
@@ -140,6 +140,8 @@ namespace Lskj.Control.Model
new List<LabelExtendedReturnSearchEdit>();
private readonly List<KeyValuePair<object, EventArgs>> mExtendedReturnPendingChanges =
new List<KeyValuePair<object, EventArgs>>();
private readonly ExtendedReturnModuleSourceResolver mExtendedReturnModuleSourceResolver =
new ExtendedReturnModuleSourceResolver();
private int mExtendedReturnBatchDepth;
/// <summary>
/// 数据源任务对象
@@ -2258,6 +2260,7 @@ namespace Lskj.Control.Model
LabelMultiAutoTextEdit4 moduleReturnsIdNew = ctr as LabelMultiAutoTextEdit4;
value = ControlType.LabSelectReturnIdNew == model.FieldType ? moduleReturnsIdNew.EditValue : moduleReturnsIdNew.EditText;
break;
case ControlType.LabModuleSelectReturnIdExtended:
case ControlType.LabSearchReturnIdExtended:
LabelExtendedReturnSearchEdit extendedReturnSearch = ctr as LabelExtendedReturnSearchEdit;
value = extendedReturnSearch == null ? string.Empty : extendedReturnSearch.EditValue;
@@ -3877,6 +3880,11 @@ namespace Lskj.Control.Model
}
}
public string ResolveExtendedReturnModuleSourceSql(string moduleCode)
{
return mExtendedReturnModuleSourceResolver.Resolve(moduleCode);
}
/// <summary>
/// <para>说明:设置搜索框数据源</para>
/// <para>创建人:曹屹峰</para>
@@ -4934,6 +4942,7 @@ namespace Lskj.Control.Model
if (!isLoadBorder) moduleReturnsIdNew.TextEdit.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
baseControl = moduleReturnsIdNew;
break;
case ControlType.LabModuleSelectReturnIdExtended:
case ControlType.LabSearchReturnIdExtended:
LabelExtendedReturnSearchEdit extendedReturnSearch = new LabelExtendedReturnSearchEdit();
extendedReturnSearch.ControlObj = this;