
以下文章来源于CodeSpirit-码灵,作者magiccodes
CrudDialogOperationAttribute 是 CodeSpirit.Amis 框架中用于在弹窗中显示列表数据的操作特性。它封装了常见的"点击按钮 → 弹出对话框 → 显示列表数据"的使用模式,简化了开发流程。

CrudDialogOperationAttribute 继承自 OperationAttribute,因此可以使用所有 OperationAttribute 的基础属性(如 Icon、DialogSize、VisibleOn 等)。
属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
DataApi | string | 是 | - | 数据API路由(支持模板变量,如 ${id}) |
DataType | Type | 是 | - | 要显示的数据类型(DTO) |
EnablePagination | bool | 否 | true | 是否启用分页 |
PerPage | int | 否 | 10 | 每页数量 |
PerPageOptions | int[] | 否 | [10, 20, 50, 100] | 每页选项 |
EnableSearch | bool | 否 | false | 是否启用搜索 |
EnableExport | bool | 否 | false | 是否启用导出 |
EnableRefresh | bool | 否 | true | 是否启用刷新 |
RowActions | string | 否 | - | 行操作按钮配置(JSON格式) |
CustomColumns | string | 否 | - | 自定义列配置(JSON格式,可选) |
最简单的使用方式,只需要指定数据 API 和数据类型:
[HttpGet("{id}/executions")]
[CrudDialogOperation("执行历史",
DataApi = "/api/web/ScheduledTasks/${id}/executions/data",
DataType = typeof(TaskExecution))]
[DisplayName("获取执行历史")]
public ActionResult<ApiResponse> GetTaskExecutions(string id)
{
return GenerateCrudDialogSchema(new Dictionary<string, string> { { "id", id } });
}
/// <summary>
/// 获取任务执行历史数据
/// </summary>
[HttpGet("{id}/executions/data")]
[DisplayName("获取执行历史数据")]
publicasync Task<ActionResult<ApiResponse>> GetTaskExecutionsData(string id, [FromQuery] QueryDtoBase queryDto)
{
var result = await _queryService.GetExecutionHistoryAsync(id, queryDto);
return Ok(ApiResponse<object>.Success(result));
}包含所有配置选项的完整示例:
[HttpGet("{id}/executions")]
[CrudDialogOperation("执行历史",
DataApi = "/api/web/ScheduledTasks/${id}/executions/data",
DataType = typeof(TaskExecution),
Icon = "fa-solid fa-clock-rotate-left",
DialogSize = DialogSize.XL,
EnablePagination = true,
PerPage = 20,
PerPageOptions = new[] { 10, 20, 50, 100 },
EnableSearch = true,
EnableExport = true,
EnableRefresh = true,
RowActions = """[
{
"type": "button",
"label": "详情",
"level": "link",
"actionType": "dialog",
"dialog": {
"title": "执行详情",
"size": "lg",
"body": {
"type": "form",
"wrapWithPanel": false,
"controls": [
{"type": "static", "name": "taskName", "label": "任务名称"},
{"type": "static", "name": "startTime", "label": "开始时间", "format": "YYYY-MM-DD HH:mm:ss"},
{"type": "static", "name": "status", "label": "执行状态"}
]
}
}
}
]""")]
[DisplayName("获取执行历史")]
public ActionResult<ApiResponse> GetTaskExecutions(string id)
{
return GenerateCrudDialogSchema(new Dictionary<string, string> { { "id", id } });
}注意:当前为简单实现,后续会继续优化RowActions,实现基于Dto的方法自动生成,而不是在此定义UI结构。

如果自动生成的列不满足需求,可以使用 CustomColumns 属性自定义列:
[HttpGet("{id}/orders")]
[CrudDialogOperation("订单列表",
DataApi = "/api/web/Orders/${id}/items",
DataType = typeof(OrderItemDto),
CustomColumns = """[
{
"name": "productName",
"label": "产品名称",
"type": "text"
},
{
"name": "quantity",
"label": "数量",
"type": "text"
},
{
"name": "price",
"label": "单价",
"type": "text",
"tpl": "${price} 元"
},
{
"name": "total",
"label": "总价",
"type": "text",
"tpl": "${quantity * price} 元"
}
]""")]
[DisplayName("查看订单")]
public ActionResult<ApiResponse> GetOrderItems(string id)
{
return GenerateCrudDialogSchema(new Dictionary<string, string> { { "id", id } });
}CrudDialogHandler 会根据 DataType 指定的类型自动生成列配置:
CustomColumns,直接使用自定义配置AmisColumnAttribute 特性DisplayNameAttribute 自动生成为了与 API 返回的 JSON 数据匹配,列名会自动转换为 camelCase:
TaskId → taskIdTaskName → taskNameStartTime → startTime如果属性上有 JsonPropertyAttribute,则优先使用其 PropertyName。
根据属性类型自动推断列类型:
DateTime / DateTimeOffset → datetime 类型,格式为 YYYY-MM-DD HH:mm:ssbool → switch 类型int / long / decimal → text 类型text 类型AmisApiControllerBase 提供了 GenerateCrudDialogSchema 方法,简化了 schema 生成:
protected ActionResult<ApiResponse> GenerateCrudDialogSchema(Dictionary<string, string> templateVariables = null)参数说明:
templateVariables:模板变量字典,用于替换 DataApi 中的变量(如 ${id})使用示例:
public ActionResult<ApiResponse> GetTaskExecutions(string id)
{
// 替换 DataApi 中的 ${id} 变量
return GenerateCrudDialogSchema(new Dictionary<string, string> { { "id", id } });
}数据 API 必须返回标准的 ApiResponse<PageList<T>> 格式:
public async Task<ActionResult<ApiResponse>> GetTaskExecutionsData(string id, [FromQuery] QueryDtoBase queryDto)
{
var result = await _queryService.GetExecutionHistoryAsync(id, queryDto);
return Ok(ApiResponse<object>.Success(result));
}数据 API 会自动接收以下查询参数(由 AMIS CRUD 组件传递):
page:当前页码perPage:每页数量orderBy:排序字段orderDir:排序方向(asc/desc)DataApi 支持模板变量,可以在运行时动态替换:
DataApi = "/api/web/ScheduledTasks/${id}/executions/data"在控制器方法中通过 GenerateCrudDialogSchema 传递变量值:
return GenerateCrudDialogSchema(new Dictionary<string, string> { { "id", id } });EnablePagination = true, // 启用分页
PerPage = 20, // 每页显示20条
PerPageOptions = new[] { 10, 20, 50, 100 } // 每页选项EnableRefresh = true, // 显示刷新按钮
EnableSearch = true, // 显示搜索按钮
EnableExport = true, // 显示导出按钮RowActions 是一个 JSON 格式的字符串数组,配置每行的操作按钮:
RowActions = """[
{
"type": "button",
"label": "详情",
"level": "link",
"actionType": "dialog",
"dialog": {
"title": "详情",
"body": { /* AMIS schema */ }
}
},
{
"type": "button",
"label": "删除",
"level": "danger",
"actionType": "ajax",
"api": "/api/web/Items/${id}",
"confirmText": "确定要删除吗?"
}
]"""优先使用 AmisApiControllerBase.GenerateCrudDialogSchema 方法,而不是手动生成 schema:
// ✅ 推荐
public ActionResult<ApiResponse> GetTaskExecutions(string id)
{
return GenerateCrudDialogSchema(new Dictionary<string, string> { { "id", id } });
}
// ❌ 不推荐:手动生成 schema
public ActionResult<ApiResponse> GetTaskExecutions(string id)
{
// 大量手动代码...
}将 schema 生成接口和数据接口分离:
// Schema 接口(用于生成弹窗配置)
[HttpGet("{id}/executions")]
[CrudDialogOperation(...)]
public ActionResult<ApiResponse> GetTaskExecutions(string id) { ... }
// 数据接口(用于获取实际数据)
[HttpGet("{id}/executions/data")]
public async Task<ActionResult<ApiResponse>> GetTaskExecutionsData(string id, [FromQuery] QueryDtoBase queryDto) { ... }为列表数据定义专门的 DTO 类型,而不是直接使用实体类型:
// ✅ 推荐:使用 DTO
[CrudDialogOperation(..., DataType = typeof(TaskExecutionDto))]
// ❌ 不推荐:直接使用实体
[CrudDialogOperation(..., DataType = typeof(TaskExecution))]只有在自动生成的列不满足需求时才使用 CustomColumns:
// ✅ 优先使用自动生成
[CrudDialogOperation(..., DataType = typeof(TaskExecution))]
// ✅ 必要时使用自定义列
[CrudDialogOperation(..., CustomColumns = "...")]配置 JSON 字符串时,使用原始字符串字面量(""")避免转义:
// ✅ 推荐
RowActions = """[{"type": "button", "label": "详情"}]"""
// ❌ 不推荐:需要转义
RowActions = "[{\"type\": \"button\", \"label\": \"详情\"}]"确保生成的列名与 API 返回的 JSON 字段名匹配。框架会自动将属性名转换为 camelCase,但如果 API 返回的字段名不同,需要使用 CustomColumns 或 JsonPropertyAttribute。
在生成 schema 时不会进行权限检查,权限检查应该在数据 API 中进行。
DataApi 中的模板变量(如 ${id})需要在调用 GenerateCrudDialogSchema 时提供对应的值。
数据 API 必须返回 PageList<T> 格式的数据,包含 items 和 total 字段。
A: 检查 API 返回的 JSON 字段名是否为 camelCase。如果属性名是 PascalCase,框架会自动转换为 camelCase。如果仍然不匹配,可以使用 CustomColumns 或 JsonPropertyAttribute。
A: 有两种方式:
AmisColumnAttribute 特性CustomColumns 属性提供完整的列配置A: 使用 RowActions 属性,提供 JSON 格式的按钮配置数组。
A: 在 DTO 属性上使用 IgnoreColumnAttribute 特性,或在 CustomColumns 中不包含该列。
A: 列默认支持排序(sortable: true),数据 API 需要处理 orderBy 和 orderDir 参数。
CrudDialogOperationAttribute 特性AmisApiControllerBase 中提供 GenerateCrudDialogSchema 方法本文分享自 CodeSpirit-码灵 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!