增强可扩展字段的功能,支持把单个字段的Json/Xml映射到目标类,呈现到表单页并支持编辑保存

This commit is contained in:
智能大石头 2025-07-16 00:44:39 +08:00
parent ec70e12618
commit d1c9e5aaae
9 changed files with 737 additions and 665 deletions

View File

@ -240,15 +240,16 @@ public partial class EntityController<TEntity, TModel> : ReadOnlyEntityControlle
// 遍历表单字段,部分字段可能有扩展
foreach (var item in EditFormFields)
{
if (item is FormField ef && ef.GetExpand != null)
var field = (item as FormField)?.Expand;
if (field?.Decode != null && !(entity as IEntity).Dirtys[item.Name])
{
// 获取参数对象,展开参数,从表单字段接收参数
var p = ef.GetExpand(entity);
if (p != null && p is not String && !(entity as IEntity).Dirtys[ef.Name])
var p = field.Decode(entity);
if (p != null && p is not String)
{
// 保存参数对象
if (FieldCollection.ReadForm(p, Request.Form, ef.Name + "_"))
entity.SetItem(ef.Name, p.ToJson(true));
if (field.ReadForm(p, Request.Form))
entity.SetItem(item.Name, field.Encode?.Invoke(p) ?? p.ToJson(true));
}
}
}

View File

@ -481,19 +481,25 @@ public partial class ReadOnlyEntityController<TEntity>
fields = fields.Clone();
// 表单嵌入配置字段
if (kind == ViewKinds.EditForm && model is TEntity entity)
if ((kind == ViewKinds.EditForm || kind == ViewKinds.Detail) && model is TEntity entity)
{
// 获取参数对象,展开参数,作为表单字段
foreach (var item in fields.ToArray())
{
if (item is FormField ef && ef.GetExpand != null)
var field = (item as FormField)?.Expand;
var p = field?.Decode?.Invoke(entity);
if (p != null && p is not String)
{
var p = ef.GetExpand(entity);
if (p != null && p is not String)
{
if (!ef.RetainExpand) fields.Remove(ef);
if (field.Name.IsNullOrEmpty()) field.Name = item.Name;
if (field.Category.IsNullOrEmpty()) field.Category = item.Category;
if (field.Prefix.IsNullOrEmpty()) field.Prefix = item.Name + "_";
fields.Expand(entity, p, ef.Name + "_");
var fs = OnExpandFields(field, entity, p);
if (fs != null && fs.Count > 0)
{
fields.AddRange(fs);
if (!field.Retain) fields.Remove(item);
}
}
}
@ -501,5 +507,8 @@ public partial class ReadOnlyEntityController<TEntity>
return fields;
}
/// <summary>展开字段</summary>
protected virtual FieldCollection OnExpandFields(ExpandField field, TEntity entity, Object parameter) => field.Expand(entity, parameter);
#endregion
}

View File

@ -82,6 +82,7 @@
<Compile Include="..\NewLife.CubeNC\Session\SessionProvider.cs" Link="Session\SessionProvider.cs" />
<Compile Include="..\NewLife.CubeNC\ViewModels\DataField.cs" Link="ViewModels\DataField.cs" />
<Compile Include="..\NewLife.CubeNC\ViewModels\ErrorModel.cs" Link="ViewModels\ErrorModel.cs" />
<Compile Include="..\NewLife.CubeNC\ViewModels\ExpandField.cs" Link="ViewModels\ExpandField.cs" />
<Compile Include="..\NewLife.CubeNC\ViewModels\FieldCollection.cs" Link="ViewModels\FieldCollection.cs" />
<Compile Include="..\NewLife.CubeNC\ViewModels\FormField.cs" Link="ViewModels\FormField.cs" />
<Compile Include="..\NewLife.CubeNC\ViewModels\ILinkExtend.cs" Link="ViewModels\ILinkExtend.cs" />

View File

@ -46,8 +46,13 @@ public class CronJobController : EntityController<CronJob, CronJobModel>
// 扩展Argument字段
{
var ef = EditFormFields.GetField("Argument") as FormField;
ef.GetExpand = e => (e as CronJob)?.GetArgument();
ef.RetainExpand = false;
//ef.GetExpand = e => (e as CronJob)?.GetArgument();
//ef.RetainExpand = false;
ef.Expand = new ExpandField
{
Decode = e => (e as CronJob)?.GetArgument(),
Retain = false,
};
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
using System.Security.Cryptography;
/// <summary>RSA工具类</summary>
public static class RSTool
{
/// <summary>生成 PEM 格式的 RSA 密钥对</summary>

View File

@ -0,0 +1,106 @@
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using NewLife.Reflection;
using NewLife.Serialization;
using XCode;
namespace NewLife.Cube.ViewModels;
/// <summary>扩展字段。在表单页中把一个Json/Xml字段扩展为多个字段进行展示和编辑</summary>
public class ExpandField
{
#region
/// <summary>名称</summary>
public String Name { get; set; }
/// <summary>获取扩展字段委托。当前字段所表示的对象,各属性作为表单字段展开</summary>
public Func<Object, Object> Decode { get; set; }
/// <summary>编码扩展字段。一般是ToJson/ToXml</summary>
public Func<Object, Object> Encode { get; set; }
/// <summary>保留扩展字段。默认false字段被扩展以后表单上就不再出现原字段</summary>
public Boolean Retain { get; set; }
/// <summary>前缀</summary>
public String Prefix { get; set; }
/// <summary>分类</summary>
public String Category { get; set; }
#endregion
#region
/// <summary>当前字段集合加入目标对象作为扩展字段,用于动态表单</summary>
/// <param name="entity"></param>
/// <param name="parameter"></param>
public FieldCollection Expand(IEntity entity, Object parameter)
{
var fields = new FieldCollection(ViewKinds.EditForm);
foreach (var pi in parameter.GetType().GetProperties(true))
{
// 添加字段,加个前缀,避免与实体字段冲突
var ff = fields.Add(pi);
ff.Name = Prefix + ff.Name;
ff.Category = Category;
if (ff.Category.IsNullOrEmpty()) ff.Category = pi.GetCustomAttribute<CategoryAttribute>()?.Category;
if (ff.Category.IsNullOrEmpty()) ff.Category = "参数";
// 数组转为字符串
var v = pi.GetValue(parameter);
if (v is IList list)
{
v = list.Join(",");
ff.Type = v.GetType();
}
// 把参数值设置到实体对象的扩展属性里面
entity.SetItem(ff.Name, v);
}
return fields;
}
/// <summary>从表单读取数据到扩展字段的目标对象,稍候序列化并写入扩展字段</summary>
/// <param name="parameter"></param>
/// <param name="form"></param>
/// <returns></returns>
public Boolean ReadForm(Object parameter, IFormCollection form)
{
var flag = false;
foreach (var pi in parameter.GetType().GetProperties(true))
{
// 从Request里面获取参数值
var name = Prefix + pi.Name;
if (!form.ContainsKey(name)) continue;
var value = form[name].FirstOrDefault();
flag = true;
Object v = null;
if (pi.PropertyType.As<IList>())
{
var elmType = pi.PropertyType.GetElementTypeEx();
var ss = value.Split(",");
var arr = Array.CreateInstance(elmType, ss.Length);
for (var i = 0; i < arr.Length; i++)
{
arr.SetValue(ss[i].ChangeType(elmType), i);
}
v = arr;
}
else
{
v = value.ChangeType(pi.PropertyType);
}
// 设置到参数对象里面
parameter.SetValue(pi, v);
}
return flag;
}
#endregion
}

View File

@ -10,7 +10,6 @@ using NewLife.Reflection;
using XCode;
using XCode.Code;
using XCode.Configuration;
using XCode.DataAccessLayer;
namespace NewLife.Cube;
@ -389,79 +388,6 @@ public class FieldCollection : List<DataField>
public DataField GetField(String name) => this.FirstOrDefault(e => name.EqualIgnoreCase(e.Name, e.MapField));
#endregion
#region
/// <summary>当前字段集合加入目标对象作为扩展字段,用于动态表单</summary>
/// <param name="entity"></param>
/// <param name="parameter"></param>
/// <param name="prefix"></param>
public void Expand(IEntity entity, Object parameter, String prefix)
{
var fields = this;
//fields.RemoveField("Argument");
foreach (var pi in parameter.GetType().GetProperties(true))
{
// 添加字段,加个前缀,避免与实体字段冲突
var ff = fields.Add(pi);
ff.Name = prefix + ff.Name;
ff.Category = pi.GetCustomAttribute<CategoryAttribute>()?.Category ?? "参数";
// 数组转为字符串
var v = pi.GetValue(parameter);
if (v is IList list)
{
v = list.Join(",");
ff.Type = v.GetType();
}
// 把参数值设置到实体对象的扩展属性里面
entity.SetItem(ff.Name, v);
}
}
/// <summary>从表单读取数据到扩展字段的目标对象,稍候序列化并写入扩展字段</summary>
/// <param name="parameter"></param>
/// <param name="form"></param>
/// <param name="prefix"></param>
/// <returns></returns>
public static Boolean ReadForm(Object parameter, IFormCollection form, String prefix)
{
var flag = false;
foreach (var pi in parameter.GetType().GetProperties(true))
{
// 从Request里面获取参数值
var name = prefix + pi.Name;
if (!form.ContainsKey(name)) continue;
var value = form[name].FirstOrDefault();
flag = true;
Object v = null;
if (pi.PropertyType.As<IList>())
{
var elmType = pi.PropertyType.GetElementTypeEx();
var ss = value.Split(",");
var arr = Array.CreateInstance(elmType, ss.Length);
for (var i = 0; i < arr.Length; i++)
{
arr.SetValue(ss[i].ChangeType(elmType), i);
}
v = arr;
}
else
{
v = value.ChangeType(pi.PropertyType);
}
// 设置到参数对象里面
parameter.SetValue(pi, v);
}
return flag;
}
#endregion
#region
/// <summary>按类别分组获取字段列表</summary>
/// <param name="entity">实体对象</param>

View File

@ -17,8 +17,37 @@ public class FormField : DataField
#endif
/// <summary>获取扩展字段委托。当前字段所表示的对象,各属性作为表单字段展开</summary>
public GetExpandDelegate GetExpand { get; set; }
[Obsolete("=>Expand")]
public GetExpandDelegate GetExpand
{
get => Expand?.Decode == null ? null : e => Expand.Decode?.Invoke(e);
set
{
if (value == null)
{
if (Expand != null)
Expand.Decode = null;
}
else
{
var exp = Expand ??= new ExpandField();
exp.Decode = e => value(e);
}
}
}
/// <summary>保留扩展字段。默认false字段被扩展以后表单上就不再出现原字段</summary>
public Boolean RetainExpand { get; set; }
[Obsolete("=>Expand")]
public Boolean RetainExpand
{
get => Expand?.Retain ?? false;
set
{
if (Expand != null)
Expand.Retain = value;
}
}
/// <summary>扩展字段</summary>
public ExpandField Expand { get; set; }
}