升级XCode和NewLife.Core,使用全新的IModel来拷贝接口入参

This commit is contained in:
大石头 2023-03-25 10:19:03 +08:00
parent 922229e780
commit 1519c0774a
19 changed files with 536 additions and 534 deletions

View File

@ -1,39 +1,36 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel;
using Microsoft.AspNetCore.Mvc;
using NewLife.Cube;
using NewLife.School.Entity;
using NewLife.Web;
namespace CubeDemo.Areas.School.Controllers
namespace CubeDemo.Areas.School.Controllers;
[SchoolArea]
[DisplayName("学生")]
public class StudentController : EntityController<Student>
{
[SchoolArea]
[DisplayName("学生")]
public class StudentController : EntityController<Student>
static StudentController()
{
static StudentController()
{
ListFields.RemoveField("CreateUserID");
ListFields.RemoveField("UpdateUserID");
//FormFields
}
ListFields.RemoveField("CreateUserID");
ListFields.RemoveField("UpdateUserID");
//FormFields
}
protected override Student Find(Object key)
{
return base.Find(key);
}
protected override Student Find(Object key)
{
return base.Find(key);
}
protected override IEnumerable<Student> Search(Pager p)
{
return base.Search(p);
var classid = p["classid"].ToInt();
return Student.Search(null,p);
}
protected override IEnumerable<Student> Search(Pager p)
{
return base.Search(p);
//var classid = p["classid"].ToInt();
//return Student.Search(null,p);
}
public override ActionResult Index(Pager p = null)
{
return base.Index(p);
}
public override ActionResult Index(Pager p = null)
{
return base.Index(p);
}
}

View File

@ -23,7 +23,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NewLife.Core" Version="10.2.2023.322-beta0150" />
<PackageReference Include="NewLife.Core" Version="10.2.2023.323-beta1548" />
<PackageReference Include="NewLife.Stardust.Extensions" Version="2.8.2023.318-beta0213" />
</ItemGroup>

View File

@ -1,7 +1,4 @@
@*
用户信息
*@
@model ChangePasswordModel
@model ChangePasswordModel
@using Microsoft.AspNetCore.Http
@using NewLife;
@using NewLife.Cube
@ -10,21 +7,12 @@
@using XCode;
@using XCode.Configuration
@using XCode.Membership;
@using System.Linq;
@using System.Reflection;
@{
var requireOldPass = Model.SsoName.IsNullOrEmpty();
var user = ManageProvider.User;
}
@using System.Linq;
@using System.Reflection;
@using NewLife.Cube
@using NewLife.Cube.Areas.Admin.Models
@using XCode;
@using XCode.Configuration
@using NewLife.Cube.Entity;
@using XCode.Membership;
@using NewLife;
<div class="">
<div class="card">
<div class="card-body pt-9 pb-0">

View File

@ -1,5 +1,4 @@
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using NewLife.Cube.Entity;
using NewLife.Data;
@ -118,11 +117,16 @@ public class EntityController<TEntity, TModel> : ReadOnlyEntityController<TEntit
if (model is not TEntity entity)
{
entity = Factory.Create(false) as TEntity;
entity.Copy(model);
if (model is TEntity src)
entity.CopyFrom(src, true);
else
entity.Copy(model);
}
// 检测避免乱用Add/id
if (Factory.Unique.IsIdentity && entity[Factory.Unique.Name].ToInt() != 0) throw new Exception("我们约定添加数据时路由id部分默认没有数据以免模型绑定器错误识别");
if (Factory.Unique.IsIdentity && entity[Factory.Unique.Name].ToInt() != 0)
throw new Exception("我们约定添加数据时路由id部分默认没有数据以免模型绑定器错误识别");
var rs = false;
var err = "";
@ -212,11 +216,15 @@ public class EntityController<TEntity, TModel> : ReadOnlyEntityController<TEntit
if (model is not TEntity entity)
{
var uk = Factory.Unique;
var key = model is IExtend ext ? ext[uk.Name] : model.GetValue(uk.Name);
var key = model is IModel ext ? ext[uk.Name] : model.GetValue(uk.Name);
// 先查出来,再拷贝。这里没有考虑脏数据的问题,有可能拷贝后并没有脏数据
entity = FindData(key);
entity.Copy(model, false, uk.Name);
if (model is TEntity src)
entity.CopyFrom(src, true);
else
entity.Copy(model, false, uk.Name);
}
var rs = false;

View File

@ -148,7 +148,7 @@ public class ReadOnlyEntityController<TEntity> : ControllerBaseX where TEntity :
var builder = CreateWhere();
if (builder != null)
{
builder.Data2 ??= p;
builder.Data2 ??= p.Items;
p.State = builder;
}
@ -224,7 +224,8 @@ public class ReadOnlyEntityController<TEntity> : ControllerBaseX where TEntity :
//Data = Session,
};
builder.SetData(Session);
builder.Data2 = new ItemsExtend { Items = HttpContext.Items };
//builder.Data2 = new ItemsExtend { Items = HttpContext.Items };
builder.Data2 = HttpContext.Items.ToDictionary(e => e.Key + "", e => e.Value);
return builder;
}

View File

@ -9,7 +9,7 @@ using NewLife.Data;
namespace NewLife.Web;
/// <summary>分页器。包含分页排序参数支持构造Url的功能</summary>
public class Pager : PageParameter, IExtend3
public class Pager : PageParameter, IExtend
{
#region
/// <summary>名称类。用户可根据需要修改Url参数名</summary>

View File

@ -47,6 +47,10 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Remove="Extensions\ItemsExtend.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\NewLife.CubeNC\Modules\IModule.cs" Link="Modules\IModule.cs" />
<Compile Include="..\NewLife.CubeNC\Modules\ModuleAttribute.cs" Link="Modules\ModuleAttribute.cs" />
@ -70,10 +74,10 @@
<Compile Include="..\NewLife.CubeNC\ViewModels\SelectUserModel.cs" Link="ViewModels\SelectUserModel.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NewLife.Core" Version="10.2.2023.322-beta0150" />
<PackageReference Include="NewLife.Core" Version="10.2.2023.323-beta1548" />
<PackageReference Include="NewLife.IP" Version="2.0.2023.203" />
<PackageReference Include="NewLife.Stardust" Version="2.8.2023.318-beta0213" />
<PackageReference Include="NewLife.XCode" Version="11.7.2023.322-beta1520" />
<PackageReference Include="NewLife.XCode" Version="11.7.2023.324-beta1635" />
</ItemGroup>
<ItemGroup>

View File

@ -187,7 +187,7 @@ namespace NewLife.Cube.Web
if (user is IEntity entity) entity.Update();
// 用户角色可能有更新需要清空扩展属性避免Roles保留脏数据导致用户首次访问显示无权限
(user as EntityBase).Extends = null;
(user as IEntity).Extends.Clear();
// 写日志
var log = LogProvider.Provider;

View File

@ -1,116 +1,113 @@
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Web.Script.Serialization;
using NewLife.Collections;
using NewLife.Data;
namespace NewLife.Cube.Charts
namespace NewLife.Cube.Charts;
/// <summary>标题,主副标题</summary>
public class ChartTitle : IExtend
{
/// <summary>标题,主副标题</summary>
public class ChartTitle : IExtend3
{
#region
/// <summary>显示</summary>
public Boolean Show { get; set; }
#region
/// <summary>显示</summary>
public Boolean Show { get; set; }
/// <summary>一级层叠控制</summary>
/// <remarks>
/// 每一个不同的zlevel将产生一个独立的canvas相同zlevel的组件或图标将在同一个canvas上渲染。
/// zlevel越高越靠顶层canvas对象增多会消耗更多的内存和性能并不建议设置过多的zlevel大部分情况可以通过二级层叠控制z实现层叠控制。
/// </remarks>
public Int32 ZLevel { get; set; }
/// <summary>一级层叠控制</summary>
/// <remarks>
/// 每一个不同的zlevel将产生一个独立的canvas相同zlevel的组件或图标将在同一个canvas上渲染。
/// zlevel越高越靠顶层canvas对象增多会消耗更多的内存和性能并不建议设置过多的zlevel大部分情况可以通过二级层叠控制z实现层叠控制。
/// </remarks>
public Int32 ZLevel { get; set; }
/// <summary>二级层叠控制</summary>
/// <remarks>同一个canvas相同zlevel上z越高约靠顶层。</remarks>
public Int32 Z { get; set; }
/// <summary>二级层叠控制</summary>
/// <remarks>同一个canvas相同zlevel上z越高约靠顶层。</remarks>
public Int32 Z { get; set; }
/// <summary>主标题文本,'\n'指定换行</summary>
public String Text { get; set; }
/// <summary>主标题文本,'\n'指定换行</summary>
public String Text { get; set; }
/// <summary>主标题文本超链接</summary>
public String Link { get; set; }
/// <summary>主标题文本超链接</summary>
public String Link { get; set; }
/// <summary>主标题超链接,'blank' | 'self'</summary>
public String Target { get; set; }
/// <summary>主标题超链接,'blank' | 'self'</summary>
public String Target { get; set; }
/// <summary>副标题文本,'\n'指定换行</summary>
public String SubText { get; set; }
/// <summary>副标题文本,'\n'指定换行</summary>
public String SubText { get; set; }
/// <summary>副标题文本超链接</summary>
public String SubLink { get; set; }
/// <summary>副标题文本超链接</summary>
public String SubLink { get; set; }
/// <summary>副标题超链接,'blank' | 'self'</summary>
public String SubTarget { get; set; }
/// <summary>副标题超链接,'blank' | 'self'</summary>
public String SubTarget { get; set; }
/// <summary>
/// 默认值:'left'
/// 水平安放位置,默认为左侧,可选为:'center' | 'left' | 'right' | {number}x坐标单位px
/// </summary>
public String X { get; set; }
/// <summary>
/// 默认值:'left'
/// 水平安放位置,默认为左侧,可选为:'center' | 'left' | 'right' | {number}x坐标单位px
/// </summary>
public String X { get; set; }
/// <summary>
/// 默认值:'top'
/// 垂直安放位置,默认为全图顶端,可选为:'top' | 'bottom' | 'center' | {number}y坐标单位px
/// </summary>
public String Y { get; set; }
/// <summary>
/// 默认值:'top'
/// 垂直安放位置,默认为全图顶端,可选为:'top' | 'bottom' | 'center' | {number}y坐标单位px
/// </summary>
public String Y { get; set; }
/// <summary>
/// 水平对齐方式默认根据x设置自动调整可选为 left' | 'right' | 'center
/// </summary>
public String TextAlign { get; set; }
/// <summary>
/// 水平对齐方式默认根据x设置自动调整可选为 left' | 'right' | 'center
/// </summary>
public String TextAlign { get; set; }
/// <summary>
/// 默认值:'rgba(0,0,0,0)'
/// 标题背景颜色,默认透明
/// </summary>
public String BackgroundColor { get; set; }
/// <summary>
/// 默认值:'rgba(0,0,0,0)'
/// 标题背景颜色,默认透明
/// </summary>
public String BackgroundColor { get; set; }
/// <summary>
/// 默认值:'#ccc'
/// 标题边框颜色
/// </summary>
public String BorderColor { get; set; }
/// <summary>
/// 默认值:'#ccc'
/// 标题边框颜色
/// </summary>
public String BorderColor { get; set; }
/// <summary>
/// 标题边框线宽单位px默认为0无边框
/// </summary>
public Int32 BorderWidth { get; set; }
/// <summary>
/// 标题边框线宽单位px默认为0无边框
/// </summary>
public Int32 BorderWidth { get; set; }
/// <summary>
/// 默认值5
/// 标题内边距单位px默认各方向内边距为5接受数组分别设定上右下左边距同css见下图
/// </summary>
public Int32 Padding { get; set; }
/// <summary>
/// 默认值5
/// 标题内边距单位px默认各方向内边距为5接受数组分别设定上右下左边距同css见下图
/// </summary>
public Int32 Padding { get; set; }
/// <summary>
/// 默认值5
/// 主副标题纵向间隔单位px默认为5
/// </summary>
public Int32 ItemGap { get; set; }
/// <summary>
/// 默认值5
/// 主副标题纵向间隔单位px默认为5
/// </summary>
public Int32 ItemGap { get; set; }
/// <summary>
/// 主标题文本样式
/// </summary>
public TextStyle TextStyle { get; set; }
/// <summary>
/// 主标题文本样式
/// </summary>
public TextStyle TextStyle { get; set; }
/// <summary>
/// 副标题文本样式
/// </summary>
public TextStyle SubTextStyle { get; set; }
/// <summary>
/// 副标题文本样式
/// </summary>
public TextStyle SubTextStyle { get; set; }
/// <summary>
/// 用于标题定位,数组为横纵相对仪表盘圆心坐标偏移,支持百分比(相对外半径)
/// </summary>
public Object OffsetCenter { get; set; }
/// <summary>
/// 用于标题定位,数组为横纵相对仪表盘圆心坐标偏移,支持百分比(相对外半径)
/// </summary>
public Object OffsetCenter { get; set; }
/// <summary>扩展字典</summary>
[ScriptIgnore]
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>(StringComparer.OrdinalIgnoreCase);
/// <summary>扩展字典</summary>
[ScriptIgnore]
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>(StringComparer.OrdinalIgnoreCase);
/// <summary>扩展数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public Object this[String key] { get => Items[key]; set => Items[key] = value; }
#endregion
}
/// <summary>扩展数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public Object this[String key] { get => Items[key]; set => Items[key] = value; }
#endregion
}

View File

@ -6,314 +6,313 @@ using NewLife.Serialization;
using XCode;
using XCode.Configuration;
namespace NewLife.Cube.Charts
namespace NewLife.Cube.Charts;
/// <summary>ECharts实例</summary>
public class ECharts : IExtend
{
/// <summary>ECharts实例</summary>
public class ECharts : IExtend3
#region
/// <summary>名称</summary>
public String Name { get; set; } = Rand.NextString(8);
/// <summary>宽度。单位px负数表示百分比默认-100</summary>
public Int32 Width { get; set; } = -100;
/// <summary>高度。单位px负数表示百分比默认300px</summary>
public Int32 Height { get; set; } = 300;
/// <summary>CSS样式</summary>
public String Style { get; set; }
/// <summary>CSS类</summary>
public String Class { get; set; }
/// <summary>标题。字符串或匿名对象</summary>
public ChartTitle Title { get; set; }
/// <summary>提示</summary>
public Object Tooltip { get; set; } = new Object();
/// <summary>提示</summary>
public Object Legend { get; set; }
/// <summary>X轴</summary>
public Object XAxis { get; set; }
/// <summary>Y轴</summary>
public Object YAxis { get; set; }
/// <summary>数据缩放</summary>
public DataZoom[] DataZoom { get; set; }
/// <summary>系列数据</summary>
public IList<Series> Series { get; set; }
/// <summary>标记的图形。设置后添加的图形都使用该值</summary>
[ScriptIgnore]
public String Symbol { get; set; }
/// <summary>扩展字典</summary>
[ScriptIgnore]
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>(StringComparer.OrdinalIgnoreCase);
/// <summary>扩展数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public Object this[String key] { get => Items[key]; set => Items[key] = value; }
FieldItem _timeX;
#endregion
#region
/// <summary>添加系列数据</summary>
/// <param name="series"></param>
public void Add(Series series)
{
#region
/// <summary>名称</summary>
public String Name { get; set; } = Rand.NextString(8);
Series ??= new List<Series>();
/// <summary>宽度。单位px负数表示百分比默认-100</summary>
public Int32 Width { get; set; } = -100;
/// <summary>高度。单位px负数表示百分比默认300px</summary>
public Int32 Height { get; set; } = 300;
/// <summary>CSS样式</summary>
public String Style { get; set; }
/// <summary>CSS类</summary>
public String Class { get; set; }
/// <summary>标题。字符串或匿名对象</summary>
public ChartTitle Title { get; set; }
/// <summary>提示</summary>
public Object Tooltip { get; set; } = new Object();
/// <summary>提示</summary>
public Object Legend { get; set; }
/// <summary>X轴</summary>
public Object XAxis { get; set; }
/// <summary>Y轴</summary>
public Object YAxis { get; set; }
/// <summary>数据缩放</summary>
public DataZoom[] DataZoom { get; set; }
/// <summary>系列数据</summary>
public IList<Series> Series { get; set; }
/// <summary>标记的图形。设置后添加的图形都使用该值</summary>
[ScriptIgnore]
public String Symbol { get; set; }
/// <summary>扩展字典</summary>
[ScriptIgnore]
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>(StringComparer.OrdinalIgnoreCase);
/// <summary>扩展数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public Object this[String key] { get => Items[key]; set => Items[key] = value; }
FieldItem _timeX;
#endregion
#region
/// <summary>添加系列数据</summary>
/// <param name="series"></param>
public void Add(Series series)
{
Series ??= new List<Series>();
Series.Add(series);
}
/// <summary>添加系列数据</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="type">图表类型默认折线图line</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <returns></returns>
public Series Add<T>(IList<T> list, FieldItem field, String type = "line", Func<T, Object> selector = null) where T : IEntity
{
if (type.IsNullOrEmpty()) type = "line";
var data = _timeX != null ?
list.Select(e => new Object[] { e[_timeX.Name], selector == null ? e[field.Name] : selector(e) }).ToArray() :
list.Select(e => selector == null ? e[field.Name] : selector(e)).ToArray();
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = type,
Data = data,
};
if (!Symbol.IsNullOrEmpty()) sr.Symbol = Symbol;
Add(sr);
return sr;
}
/// <summary>添加曲线系列数据</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <param name="smooth">折线光滑</param>
/// <returns></returns>
public Series AddLine<T>(IList<T> list, FieldItem field, Func<T, Object> selector = null, Boolean smooth = false) where T : IEntity
{
var data = _timeX != null ?
list.Select(e => new Object[] { e[_timeX.Name], selector == null ? e[field.Name] : selector(e) }).ToArray() :
list.Select(e => selector == null ? e[field.Name] : selector(e)).ToArray();
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = "line",
Data = data,
Smooth = smooth,
};
if (!Symbol.IsNullOrEmpty()) sr.Symbol = Symbol;
Add(sr);
return sr;
}
/// <summary>添加饼图</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <returns></returns>
public Series AddBar<T>(IList<T> list, FieldItem field, Func<T, Object> selector = null) where T : IEntity
{
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = "bar",
Data = list.Select(e => selector == null ? e[field.Name] : selector(e)).ToArray(),
};
Add(sr);
return sr;
}
/// <summary>添加曲线系列数据</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <returns></returns>
public Series AddPie<T>(IList<T> list, FieldItem field, Func<T, NameValue> selector = null) where T : IEntity
{
var nameKey = field.Table.Master?.Name ?? field.Table.PrimaryKeys.FirstOrDefault()?.Name;
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = "pie",
Data = list.Select(e => selector == null ? new NameValue(e[nameKey] + "", e[field.Name]) : selector(e)).ToArray(),
};
Add(sr);
return sr;
}
/// <summary>设置X轴</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">数据列表从中选择数据构建X轴</param>
/// <param name="field">作为X轴的字段支持time时间轴</param>
/// <param name="selector">构建X轴的委托使用时间轴时该参数无效</param>
public void SetX<T>(IList<T> list, FieldItem field, Func<T, String> selector = null) where T : IEntity
{
if (field != null && field.Type == typeof(DateTime))
{
XAxis = new
{
type = "time",
};
_timeX = field;
if (Symbol.IsNullOrEmpty() && list.Count > 100) Symbol = "none";
}
else
{
XAxis = new
{
data = list.Select(e => selector == null ? e[field.Name] + "" : selector(e)).ToArray()
};
}
}
/// <summary>设置Y轴</summary>
/// <param name="name"></param>
/// <param name="type">
/// 坐标轴类型。
/// value 数值轴,适用于连续数据。
/// category 类目轴,适用于离散的类目数据,为该类型时必须通过 data 设置类目数据。
/// time 时间轴,适用于连续的时序数据,与数值轴相比时间轴带有时间的格式化,在刻度计算上也有所不同,例如会根据跨度的范围来决定使用月,星期,日还是小时范围的刻度。
/// log 对数轴。适用于对数数据。
/// </param>
public void SetY(String name, String type = "value") => YAxis = new { name, type };
/// <summary>设置工具栏</summary>
/// <param name="trigger">
/// 触发类型。
/// item, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
/// axis, 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。
/// none, 什么都不触发。
/// </param>
/// <param name="axisPointerType">坐标轴指示器配置项。cross坐标系会自动选择显示哪个轴的 axisPointer</param>
/// <param name="backgroundColor"></param>
public void SetTooltip(String trigger = "axis", String axisPointerType = "cross", String backgroundColor = "#6a7985")
{
Tooltip = new
{
trigger = trigger,
axisPointer = new
{
type = axisPointerType,
label = new
{
backgroundColor = backgroundColor
}
},
};
}
/// <summary>设置提示</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="field"></param>
/// <param name="selector"></param>
public void SetLegend<T>(IList<T> list, FieldItem field, Func<T, String> selector = null) where T : IEntity => Legend = list.Select(e => selector == null ? e[field.Name] + "" : selector(e)).ToArray();
/// <summary>添加缩放。默认X0轴其它设置可直接修改返回对象</summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <returns></returns>
public DataZoom AddDataZoom(Int32 start = 0, Int32 end = 100)
{
var dz = new DataZoom
{
XAxiaIndex = new[] { 0 },
Start = start,
End = end,
};
var list = DataZoom?.ToList() ?? new List<DataZoom>();
list.Add(dz);
DataZoom = list.ToArray();
return dz;
}
/// <summary>构建选项Json</summary>
/// <returns></returns>
public String Build()
{
var dic = new Dictionary<String, Object>();
// 标题
var title = Title;
if (title != null) dic[nameof(title)] = title;
// 提示
var tooltip = Tooltip;
if (tooltip != null) dic[nameof(tooltip)] = tooltip;
// 提示
var legend = Legend;
legend ??= Series.Select(e => e.Name).ToArray();
if (legend != null)
{
if (legend is String str)
legend = new { data = new[] { str } };
else if (legend is String[] ss)
legend = new { data = ss };
dic[nameof(legend)] = legend;
}
// X轴
var xAxis = XAxis;
if (xAxis != null)
{
if (xAxis is String str)
xAxis = new { data = new[] { str } };
else if (xAxis is String[] ss)
xAxis = new { data = ss };
dic[nameof(xAxis)] = xAxis;
}
// Y轴
var yAxis = YAxis;
if (yAxis != null) dic[nameof(yAxis)] = yAxis;
var dataZoom = DataZoom;
if (dataZoom != null) dic[nameof(dataZoom)] = dataZoom;
// 系列数据
var series = Series;
if (series != null) dic[nameof(series)] = series;
// 合并Items
foreach (var item in Items)
{
dic[item.Key] = item.Value;
}
return dic.ToJson(true, false, true);
}
#endregion
Series.Add(series);
}
/// <summary>添加系列数据</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="type">图表类型默认折线图line</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <returns></returns>
public Series Add<T>(IList<T> list, FieldItem field, String type = "line", Func<T, Object> selector = null) where T : IEntity
{
if (type.IsNullOrEmpty()) type = "line";
var data = _timeX != null ?
list.Select(e => new Object[] { e[_timeX.Name], selector == null ? e[field.Name] : selector(e) }).ToArray() :
list.Select(e => selector == null ? e[field.Name] : selector(e)).ToArray();
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = type,
Data = data,
};
if (!Symbol.IsNullOrEmpty()) sr.Symbol = Symbol;
Add(sr);
return sr;
}
/// <summary>添加曲线系列数据</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <param name="smooth">折线光滑</param>
/// <returns></returns>
public Series AddLine<T>(IList<T> list, FieldItem field, Func<T, Object> selector = null, Boolean smooth = false) where T : IEntity
{
var data = _timeX != null ?
list.Select(e => new Object[] { e[_timeX.Name], selector == null ? e[field.Name] : selector(e) }).ToArray() :
list.Select(e => selector == null ? e[field.Name] : selector(e)).ToArray();
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = "line",
Data = data,
Smooth = smooth,
};
if (!Symbol.IsNullOrEmpty()) sr.Symbol = Symbol;
Add(sr);
return sr;
}
/// <summary>添加饼图</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <returns></returns>
public Series AddBar<T>(IList<T> list, FieldItem field, Func<T, Object> selector = null) where T : IEntity
{
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = "bar",
Data = list.Select(e => selector == null ? e[field.Name] : selector(e)).ToArray(),
};
Add(sr);
return sr;
}
/// <summary>添加曲线系列数据</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">实体列表</param>
/// <param name="field">要使用数据的字段</param>
/// <param name="selector">数据选择器默认null时直接使用字段数据</param>
/// <returns></returns>
public Series AddPie<T>(IList<T> list, FieldItem field, Func<T, NameValue> selector = null) where T : IEntity
{
var nameKey = field.Table.Master?.Name ?? field.Table.PrimaryKeys.FirstOrDefault()?.Name;
var sr = new Series
{
Name = field?.DisplayName ?? field.Name,
Type = "pie",
Data = list.Select(e => selector == null ? new NameValue(e[nameKey] + "", e[field.Name]) : selector(e)).ToArray(),
};
Add(sr);
return sr;
}
/// <summary>设置X轴</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">数据列表从中选择数据构建X轴</param>
/// <param name="field">作为X轴的字段支持time时间轴</param>
/// <param name="selector">构建X轴的委托使用时间轴时该参数无效</param>
public void SetX<T>(IList<T> list, FieldItem field, Func<T, String> selector = null) where T : IEntity
{
if (field != null && field.Type == typeof(DateTime))
{
XAxis = new
{
type = "time",
};
_timeX = field;
if (Symbol.IsNullOrEmpty() && list.Count > 100) Symbol = "none";
}
else
{
XAxis = new
{
data = list.Select(e => selector == null ? e[field.Name] + "" : selector(e)).ToArray()
};
}
}
/// <summary>设置Y轴</summary>
/// <param name="name"></param>
/// <param name="type">
/// 坐标轴类型。
/// value 数值轴,适用于连续数据。
/// category 类目轴,适用于离散的类目数据,为该类型时必须通过 data 设置类目数据。
/// time 时间轴,适用于连续的时序数据,与数值轴相比时间轴带有时间的格式化,在刻度计算上也有所不同,例如会根据跨度的范围来决定使用月,星期,日还是小时范围的刻度。
/// log 对数轴。适用于对数数据。
/// </param>
public void SetY(String name, String type = "value") => YAxis = new { name, type };
/// <summary>设置工具栏</summary>
/// <param name="trigger">
/// 触发类型。
/// item, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
/// axis, 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。
/// none, 什么都不触发。
/// </param>
/// <param name="axisPointerType">坐标轴指示器配置项。cross坐标系会自动选择显示哪个轴的 axisPointer</param>
/// <param name="backgroundColor"></param>
public void SetTooltip(String trigger = "axis", String axisPointerType = "cross", String backgroundColor = "#6a7985")
{
Tooltip = new
{
trigger = trigger,
axisPointer = new
{
type = axisPointerType,
label = new
{
backgroundColor = backgroundColor
}
},
};
}
/// <summary>设置提示</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="field"></param>
/// <param name="selector"></param>
public void SetLegend<T>(IList<T> list, FieldItem field, Func<T, String> selector = null) where T : IEntity => Legend = list.Select(e => selector == null ? e[field.Name] + "" : selector(e)).ToArray();
/// <summary>添加缩放。默认X0轴其它设置可直接修改返回对象</summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <returns></returns>
public DataZoom AddDataZoom(Int32 start = 0, Int32 end = 100)
{
var dz = new DataZoom
{
XAxiaIndex = new[] { 0 },
Start = start,
End = end,
};
var list = DataZoom?.ToList() ?? new List<DataZoom>();
list.Add(dz);
DataZoom = list.ToArray();
return dz;
}
/// <summary>构建选项Json</summary>
/// <returns></returns>
public String Build()
{
var dic = new Dictionary<String, Object>();
// 标题
var title = Title;
if (title != null) dic[nameof(title)] = title;
// 提示
var tooltip = Tooltip;
if (tooltip != null) dic[nameof(tooltip)] = tooltip;
// 提示
var legend = Legend;
legend ??= Series.Select(e => e.Name).ToArray();
if (legend != null)
{
if (legend is String str)
legend = new { data = new[] { str } };
else if (legend is String[] ss)
legend = new { data = ss };
dic[nameof(legend)] = legend;
}
// X轴
var xAxis = XAxis;
if (xAxis != null)
{
if (xAxis is String str)
xAxis = new { data = new[] { str } };
else if (xAxis is String[] ss)
xAxis = new { data = ss };
dic[nameof(xAxis)] = xAxis;
}
// Y轴
var yAxis = YAxis;
if (yAxis != null) dic[nameof(yAxis)] = yAxis;
var dataZoom = DataZoom;
if (dataZoom != null) dic[nameof(dataZoom)] = dataZoom;
// 系列数据
var series = Series;
if (series != null) dic[nameof(series)] = series;
// 合并Items
foreach (var item in Items)
{
dic[item.Key] = item.Value;
}
return dic.ToJson(true, false, true);
}
#endregion
}

View File

@ -5,7 +5,7 @@ using NewLife.Data;
namespace NewLife.Cube.Charts;
/// <summary>系列。一组数值以及他们映射成的图</summary>
public class Series : IExtend3
public class Series : IExtend
{
#region
/// <summary>图表类型</summary>

View File

@ -1,66 +1,63 @@
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Web.Script.Serialization;
using NewLife.Collections;
using NewLife.Data;
namespace NewLife.Cube.Charts
namespace NewLife.Cube.Charts;
/// <summary>文字样式</summary>
public class TextStyle : IExtend
{
/// <summary>文字样式</summary>
public class TextStyle : IExtend3
{
/// <summary>
/// 颜色
/// </summary>
public String Color { get; set; }
/// <summary>
/// 颜色
/// </summary>
public String Color { get; set; }
/// <summary>
/// 默认值:'none'
/// 修饰仅对tooltip.textStyle生效
/// </summary>
public String Decoration { get; set; }
/// <summary>
/// 默认值:'none'
/// 修饰仅对tooltip.textStyle生效
/// </summary>
public String Decoration { get; set; }
/// <summary>
/// 默认值:各异
/// 水平对齐方式,可选为:'left' | 'right' | 'center'
/// </summary>
public String Align { get; set; }
/// <summary>
/// 默认值:各异
/// 水平对齐方式,可选为:'left' | 'right' | 'center'
/// </summary>
public String Align { get; set; }
/// <summary>
/// 默认值:各异
/// 垂直对齐方式,可选为:'top' | 'bottom' | 'middle'
/// </summary>
public String Baseline { get; set; }
/// <summary>
/// 默认值:各异
/// 垂直对齐方式,可选为:'top' | 'bottom' | 'middle'
/// </summary>
public String Baseline { get; set; }
/// <summary>
/// 默认值:'Arial, Verdana, sans-serif'
/// 字体系列
/// </summary>
public String FontFamily { get; set; }
/// <summary>
/// 默认值:'Arial, Verdana, sans-serif'
/// 字体系列
/// </summary>
public String FontFamily { get; set; }
/// <summary>
/// 默认值12
/// 字号单位px
/// </summary>
public Int32 FontSize { get; set; }
/// <summary>
/// 默认值12
/// 字号单位px
/// </summary>
public Int32 FontSize { get; set; }
/// <summary>
/// 字体系列
/// </summary>
public String FontStyle { get; set; }
/// <summary>
/// 字体系列
/// </summary>
public String FontStyle { get; set; }
/// <summary>
/// 粗细,可选为:'normal' | 'bold' | 'bolder' | 'lighter' | 100 | 200 |... | 900
/// </summary>
public String FontWeight { get; set; }
/// <summary>
/// 粗细,可选为:'normal' | 'bold' | 'bolder' | 'lighter' | 100 | 200 |... | 900
/// </summary>
public String FontWeight { get; set; }
/// <summary>扩展字典</summary>
[ScriptIgnore]
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>(StringComparer.OrdinalIgnoreCase);
/// <summary>扩展字典</summary>
[ScriptIgnore]
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>(StringComparer.OrdinalIgnoreCase);
/// <summary>扩展数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public Object this[String key] { get => Items[key]; set => Items[key] = value; }
}
/// <summary>扩展数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public Object this[String key] { get => Items[key]; set => Items[key] = value; }
}

View File

@ -127,11 +127,16 @@ public class EntityController<TEntity, TModel> : ReadOnlyEntityController<TEntit
if (model is not TEntity entity)
{
entity = Factory.Create(true) as TEntity;
entity.Copy(model);
if (model is TEntity src)
entity.CopyFrom(src, true);
else
entity.Copy(model);
}
// 检测避免乱用Add/id
if (Factory.Unique.IsIdentity && entity[Factory.Unique.Name].ToInt() != 0) throw new Exception("我们约定添加数据时路由id部分默认没有数据以免模型绑定器错误识别");
if (Factory.Unique.IsIdentity && entity[Factory.Unique.Name].ToInt() != 0)
throw new Exception("我们约定添加数据时路由id部分默认没有数据以免模型绑定器错误识别");
var rs = false;
var err = "";
@ -181,11 +186,10 @@ public class EntityController<TEntity, TModel> : ReadOnlyEntityController<TEntit
var key = $"Cube_Add_{typeof(TEntity).FullName}";
var url = Session[key] as String;
if (!url.IsNullOrEmpty())
return Redirect(url);
else
// 新增完成跳到列表页,更新完成保持本页
return RedirectToAction("Index");
if (!url.IsNullOrEmpty()) return Redirect(url);
// 新增完成跳到列表页,更新完成保持本页
return RedirectToAction("Index");
}
/// <summary>表单,添加/修改</summary>
@ -233,11 +237,15 @@ public class EntityController<TEntity, TModel> : ReadOnlyEntityController<TEntit
if (model is not TEntity entity)
{
var uk = Factory.Unique;
var key = model is IExtend ext ? ext[uk.Name] : model.GetValue(uk.Name);
var key = model is IModel ext ? ext[uk.Name] : model.GetValue(uk.Name);
// 先查出来,再拷贝。这里没有考虑脏数据的问题,有可能拷贝后并没有脏数据
entity = FindData(key);
entity.Copy(model, false, uk.Name);
if (model is TEntity src)
entity.CopyFrom(src, true);
else
entity.Copy(model, false, uk.Name);
}
var rs = false;

View File

@ -13,7 +13,6 @@ using NewLife.Cube.Common;
using NewLife.Cube.Entity;
using NewLife.Cube.Extensions;
using NewLife.Cube.ViewModels;
using NewLife.Data;
using NewLife.IO;
using NewLife.Log;
using NewLife.Reflection;
@ -164,7 +163,7 @@ public class ReadOnlyEntityController<TEntity> : ControllerBaseX where TEntity :
var builder = CreateWhere();
if (builder != null)
{
builder.Data2 ??= p;
builder.Data2 ??= p.Items;
p.State = builder;
}
@ -240,7 +239,8 @@ public class ReadOnlyEntityController<TEntity> : ControllerBaseX where TEntity :
//Data = Session,
};
builder.SetData(Session);
builder.Data2 = new ItemsExtend { Items = HttpContext.Items };
//builder.Data2 = new ItemsExtend { Items = HttpContext.Items };
builder.Data2 = HttpContext.Items.ToDictionary(e => e.Key + "", e => e.Value);
return builder;
}

View File

@ -65,6 +65,6 @@ public static class StarHelper
/// <param name="field"></param>
/// <param name="data"></param>
/// <returns></returns>
public String Resolve(DataField field, IExtend data) => BuildUrl(data[field.Name] as String);
public String Resolve(DataField field, IModel data) => BuildUrl(data[field.Name] as String);
}
}

View File

@ -49,10 +49,10 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="NewLife.Core" Version="10.2.2023.322-beta0150" />
<PackageReference Include="NewLife.Core" Version="10.2.2023.323-beta1548" />
<PackageReference Include="NewLife.IP" Version="2.0.2023.203" />
<PackageReference Include="NewLife.Stardust" Version="2.8.2023.318-beta0213" />
<PackageReference Include="NewLife.XCode" Version="11.7.2023.322-beta1520" />
<PackageReference Include="NewLife.XCode" Version="11.7.2023.324-beta1635" />
</ItemGroup>
<ItemGroup>
@ -129,6 +129,10 @@
<EmbeddedResource Include="wwwroot\**\*" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Extensions\ItemsExtend.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\Doc\leaf.png" Link="leaf.png" PackagePath="\" />
</ItemGroup>

View File

@ -1,15 +1,14 @@
using System;
using NewLife.Data;
namespace NewLife.Cube.ViewModels
namespace NewLife.Cube.ViewModels;
/// <summary>Url扩展</summary>
public interface IUrlExtend
{
/// <summary>Url扩展</summary>
public interface IUrlExtend
{
/// <summary>解析Url地址</summary>
/// <param name="field"></param>
/// <param name="data"></param>
/// <returns></returns>
String Resolve(DataField field, IExtend data);
}
/// <summary>解析Url地址</summary>
/// <param name="field"></param>
/// <param name="data"></param>
/// <returns></returns>
String Resolve(DataField field, IModel data);
}

View File

@ -82,7 +82,7 @@ public class ListField : DataField
#region
private static readonly Regex _reg = new(@"{(\w+)}", RegexOptions.Compiled);
private static String Replace(String input, IExtend data)
private static String Replace(String input, IModel data)
{
return _reg.Replace(input, m =>
{
@ -98,7 +98,7 @@ public class ListField : DataField
/// <summary>针对指定实体对象计算DisplayName替换其中变量</summary>
/// <param name="data"></param>
/// <returns></returns>
public virtual String GetDisplayName(IExtend data)
public virtual String GetDisplayName(IModel data)
{
if (DisplayName.IsNullOrEmpty()) return null;
@ -108,7 +108,7 @@ public class ListField : DataField
/// <summary>针对指定实体对象计算链接名,替换其中变量</summary>
/// <param name="data"></param>
/// <returns></returns>
public virtual String GetLinkName(IExtend data)
public virtual String GetLinkName(IModel data)
{
// 如果设置了单元格文字则优先使用。Text>Entity[name]>DisplayName
var txt = Text;
@ -129,7 +129,7 @@ public class ListField : DataField
/// <summary>针对指定实体对象计算url替换其中变量</summary>
/// <param name="data"></param>
/// <returns></returns>
public virtual String GetUrl(IExtend data)
public virtual String GetUrl(IModel data)
{
var svc = GetService<IUrlExtend>();
if (svc != null) return svc.Resolve(this, data);
@ -143,7 +143,7 @@ public class ListField : DataField
/// <summary>针对指定实体对象计算title替换其中变量</summary>
/// <param name="data"></param>
/// <returns></returns>
public virtual String GetTitle(IExtend data)
public virtual String GetTitle(IModel data)
{
if (Title.IsNullOrEmpty()) return null;

View File

@ -17,6 +17,6 @@
<None Remove="Entity\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NewLife.XCode" Version="11.7.2023.322-beta1520" />
<PackageReference Include="NewLife.XCode" Version="11.7.2023.324-beta1635" />
</ItemGroup>
</Project>