上一篇文章中介绍了如何下载、运行ABP Zero示例项目,这个示例项目可以直接作为模板进行二次开发,很适合做企业开发框架。
本未介绍基于ABP Zero示例项目,如何新建一个自定义的实体。
此处以EquipmentType(设备类型)为例,建立一个简单的实体。
以下是之前添加一个简单实体类的效果:
主页
公司列表
新建公司
编辑公司
删除公司
建立方法
按ABP的标准格式,完整建立一个实体,映射到数据库,作为一个基础资料,并通过前端进行增删查改功能,最小步骤如下:
- 新增实体类。
- 添加数据库映射。
- 同步到数据库。
- 新建Dto,建立Dto与实体类的映射。
- 建立实体类的功能接口(增删查改),并实现接口。
- 添加视图模型ViewModel。
- 添加控制器。
- 添加视图。
- 添加js脚本。
- 添加前端菜单(入口)。
- 添加权限管理。
1. 添加实体类
在core层添加实体类
1 namespace oMES_APServer.Equipments 2 { 3 public class EquipmentType : MESBase.MESBaseEntity 4 { 5 6 } 7 }
这里我把MES会用到的常规属性单独建了一个基类,并继承ABP全属性基类FullAuditedEntity
1 using Abp.Domain.Entities; 2 using Abp.Domain.Entities.Auditing; 3 using System.ComponentModel.DataAnnotations; 4 5 namespace oMES_APServer.MESBase 6 { 7 public class MESBaseEntity : FullAuditedEntity<int>, IPassivable 8 { 9 10 public const int MaxCodeLength = 64; 11 public const int MaxNameLength = 256; 12 public const int MaxBriefNameLength = 64; 13 public const int MaxRemarkLength = 64; 14 15 [Required] 16 [StringLength(MaxCodeLength)] 17 public string Code { get; set; } 18 19 [Required] 20 [StringLength(MaxNameLength)] 21 public string Name { get; set; } 22 23 [StringLength(64)] 24 public string BriefName { get; set; } 25 26 [StringLength(512)] 27 public string Remark { get; set; } 28 public bool IsActive { get; set; } 29 30 } 31 }
2. 添加数据库映射
在EFCore层添加以下代码:为了让EFCore能够自动生成数据库表结构。
public DbSet<EquipmentType> equipmentTypes { get; set; }
modelBuilder.Entity<EquipmentType>().ToTable("EquipmentType").HasAlternateKey(x => x.Code).HasName("UK_EquipmentType_Code");
其中.HasAlternateKey表示建立唯一键,.HasName表示键的名称。
1 using Microsoft.EntityFrameworkCore; 2 using Abp.Zero.EntityFrameworkCore; 3 using oMES_APServer.Authorization.Roles; 4 using oMES_APServer.Authorization.Users; 5 using oMES_APServer.MultiTenancy; 6 using oMES_APServer.Companies; 7 using oMES_APServer.Equipments; 8 9 namespace oMES_APServer.EntityFrameworkCore 10 { 11 public class oMES_APServerDbContext : AbpZeroDbContext<Tenant, Role, User, oMES_APServerDbContext> 12 { 13 /* Define a DbSet for each entity of the application */ 14 public oMES_APServerDbContext(DbContextOptions<oMES_APServerDbContext> options) 15 : base(options) 16 { 17 } 18 19 /*添加自定义实体类的数据库映射*/ 20 public DbSet<Company> companies { get; set; } 21 public DbSet<Department> departments { get; set; } 22 public DbSet<EquipmentType> equipmentTypes { get; set; } 23 24 protected override void OnModelCreating(ModelBuilder modelBuilder) 25 { 26 base.OnModelCreating(modelBuilder); 27 28 modelBuilder.Entity<Company>().ToTable("Company") 29 .HasAlternateKey(x=>x.Code).HasName("UK_Company_Code"); 30 modelBuilder.Entity<Department>().ToTable("Department") 31 .HasAlternateKey(x => x.Code).HasName("UK_Department_Code"); 32 modelBuilder.Entity<EquipmentType>().ToTable("EquipmentType") 33 .HasAlternateKey(x => x.Code).HasName("UK_EquipmentType_Code"); 34 } 35 36 } 37 }
3. 同步到数据库。
依次执行以下两条指令:
- add-migration add-EquipmentType
- update-database
第一条表示,新建同步映射,映射名称为add-EquipmentType。
第二条表示同步数据库。
执行时,出现上述报错,不要慌,重新生成一下项目,应该有报错,解决完项目报错再执行,就可以了。
执行时注意默认项目需要选择EFCore项目。
4. 新建Dto,建立Dto与实体类的映射
在Application层建立Dto
1 namespace oMES_APServer.Equipments.Dto 2 { 3 public class EquipmentTypeDto : MESBaseDto.MESBaseEntityDto 4 { 5 6 } 7 }
在Dtos同级目录下,建立实体类和Dto的映射 EquipmentTypeMapProfile
1 using AutoMapper; 2 3 namespace oMES_APServer.Equipments.Dto 4 { 5 public class EquipmentTypeMapProfile : Profile 6 { 7 public EquipmentTypeMapProfile() 8 { 9 CreateMap<EquipmentType, EquipmentTypeDto>(); 10 CreateMap<EquipmentTypeDto, EquipmentType>(); 11 CreateMap<EquipmentTypeDto, EquipmentType>() 12 .ForMember(x => x.CreationTime, opt => opt.Ignore()); 13 } 14 } 15 }
引申:
ABP Zero的Dto类文件夹中,会有一个 PagedxxxResultRequestDto.cs类,这个是用于按给定条件查找数据列表,并进行分页的类。目前还没有学习到,所以仅按照现有的实体类进行仿照编程,不做额外处理。
1 using Abp.Application.Services.Dto; 2 3 namespace oMES_APServer.Equipments.Dto 4 { 5 public class PagedEquipmentTypeResultRequestDto : PagedResultRequestDto 6 { 7 8 public string Code { get; set; } 9 10 public string Name { get; set; } 11 12 public bool? IsActive { get; set; } 13 14 } 15 }
5. 建立实体类的功能接口(增删查改),并实现接口。
在Application层中建立接口:因为ABP接口已经实现了基础功能(增删查改)的方法定义,所以直接继承IAsyncCrudAppService即可,写法参照已有的User相关类。
1 using Abp.Application.Services; 2 using oMES_APServer.Companies.Dto; 3 4 namespace oMES_APServer.Equipments 5 { 6 public interface IEquipmentTypesAppService : IAsyncCrudAppService<CompanyDto, int, PagedCompanyResultRequestDto, CompanyDto, CompanyDto> 7 { 8 9 } 10 }
自定义实现基础接口:
1 using System.Collections.Generic; 2 using System.Linq; 3 using System.Threading.Tasks; 4 using Abp.Application.Services; 5 using Abp.Application.Services.Dto; 6 using Abp.Domain.Repositories; 7 using Abp.Domain.Uow; 8 using Abp.Extensions; 9 using Abp.Linq.Extensions; 10 using Abp.UI; 11 using Microsoft.EntityFrameworkCore; 12 using oMES_APServer.Equipments.Dto; 13 14 namespace oMES_APServer.Equipments 15 { 16 public class EquipmentTypesAppService : AsyncCrudAppService<EquipmentType, EquipmentTypeDto, int, PagedEquipmentTypeResultRequestDto, EquipmentTypeDto, EquipmentTypeDto>, IEquipmentTypeAppService 17 { 18 private readonly IRepository<EquipmentType> _equipmentTypeRepository; 19 20 public EquipmentTypesAppService(IRepository<EquipmentType> equipmentTypeRepository) 21 : base(equipmentTypeRepository) 22 { 23 _equipmentTypeRepository = equipmentTypeRepository; 24 25 LocalizationSourceName = oMES_APServerConsts.LocalizationSourceName; 26 } 27 28 public override async Task<EquipmentTypeDto> Get(EntityDto<int> input) 29 { 30 var equipmentType = await _equipmentTypeRepository 31 .GetAsync(input.Id); 32 33 return ObjectMapper.Map<EquipmentTypeDto>(equipmentType); 34 } 35 36 public override async Task<PagedResultDto<EquipmentTypeDto>> GetAll(PagedEquipmentTypeResultRequestDto input) 37 { 38 var equipmentTypes = Repository.GetAll() 39 .WhereIf(!input.Name.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Name)) 40 .WhereIf(!input.Code.IsNullOrWhiteSpace(), x => x.Code.Contains(input.Code)) 41 .WhereIf(input.IsActive.HasValue, x => x.IsActive == input.IsActive) 42 .OrderBy(x => x.Code); 43 44 return await Task.FromResult(new PagedResultDto<EquipmentTypeDto>(equipmentTypes.CountAsync().Result, 45 ObjectMapper.Map<List<EquipmentTypeDto>>(equipmentTypes) 46 )); 47 } 48 49 public override async Task<EquipmentTypeDto> Create(EquipmentTypeDto input) 50 { 51 52 //判断CODE是否已存在 53 var model = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code); 54 if (model != null) 55 { 56 throw new UserFriendlyException(L("EquipmentType code already exists")); 57 } 58 59 //检查是否已被软删除,已经软删除的数据,无法通过 60 using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete)) 61 { 62 //判断CODE是否已存在 63 var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code); 64 if (model0 != null) 65 { 66 throw new UserFriendlyException(L("EquipmentType code is deleted")); 67 } 68 } 69 70 var entity = ObjectMapper.Map<EquipmentType>(input); 71 await _equipmentTypeRepository.InsertAsync(entity); 72 return MapToEntityDto(entity); 73 } 74 75 public override async Task<EquipmentTypeDto> Update(EquipmentTypeDto input) 76 { 77 var entity = await _equipmentTypeRepository.GetAsync(input.Id); 78 79 ObjectMapper.Map(input, entity); 80 81 await _equipmentTypeRepository.UpdateAsync(entity); 82 83 return MapToEntityDto(entity); 84 } 85 86 public override async Task Delete(EntityDto<int> input) 87 { 88 var entity = await _equipmentTypeRepository.GetAsync(input.Id); 89 await _equipmentTypeRepository.DeleteAsync(entity); 90 } 91 92 } 93 }
其中,创建的代码如下:在基类中,我们设置了Code字段为唯一键,所以需要先确定Code不存在
1 public override async Task<EquipmentTypeDto> Create(EquipmentTypeDto input) 2 { 3 4 //判断CODE是否已存在 5 var model = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code); 6 if (model != null) 7 { 8 throw new UserFriendlyException(L("EquipmentType code already exists")); 9 } 10 11 //检查是否已被软删除,已经软删除的数据,无法通过 12 using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete)) 13 { 14 //判断CODE是否已存在 15 var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code); 16 if (model0 != null) 17 { 18 throw new UserFriendlyException(L("EquipmentType code is deleted")); 19 } 20 } 21 22 var entity = ObjectMapper.Map<EquipmentType>(input); 23 await _equipmentTypeRepository.InsertAsync(entity); 24 return MapToEntityDto(entity); 25 }
ABP的全属性类FullAuditedEntity中,预置了软删除功能,如果一条数据被软删除了(IsDeleted字段为1),那么直接查找是招不到的。
需要临时关闭软删除的过滤器,才能找到:在using中,使用正常的查询代码,就能查到已被软删除的数据。
1 //检查是否已被软删除,已经软删除的数据,无法通过 2 using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete)) 3 { 4 //判断CODE是否已存在 5 var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code); 6 if (model0 != null) 7 { 8 throw new UserFriendlyException(L("EquipmentType code is deleted")); 9 } 10 }
6. 添加视图模型ViewModel。
在MVC层
添加查询视图模型,这里没有做特殊处理,直接使用Dto
1 using oMES_APServer.Equipments.Dto; 2 using System.Collections.Generic; 3 4 namespace oMES_APServer.Web.Models.EquipmentTypes 5 { 6 public class EquipmentTypeListViewModel 7 { 8 public IReadOnlyList<EquipmentTypeDto> EquipmentTypes { get; set; } 9 } 10 }
添加编辑视图模型
1 using oMES_APServer.Equipments.Dto; 2 3 namespace oMES_APServer.Web.Models.EquipmentTypes 4 { 5 public class EditEquipmentTypeModalViewModel 6 { 7 public EquipmentTypeDto EquipmentType { get; set; } 8 } 9 }
7. 添加控制器。
控制器中添加两个方法Index和Edit.
1 using System.Threading.Tasks; 2 using Abp.Application.Services.Dto; 3 using Microsoft.AspNetCore.Mvc; 4 using oMES_APServer.Controllers; 5 using oMES_APServer.Equipments; 6 using oMES_APServer.Equipments.Dto; 7 using oMES_APServer.Web.Models.EquipmentTypes; 8 9 namespace oMES_APServer.Web.Mvc.Controllers 10 { 11 public class EquipmentTypesController : oMES_APServerControllerBase 12 { 13 14 private readonly IEquipmentTypeAppService _equipmentTypeAppService; 15 16 public EquipmentTypesController(IEquipmentTypeAppService equipmentTypeAppService) 17 { 18 _equipmentTypeAppService = equipmentTypeAppService; 19 } 20 21 public async Task<IActionResult> Index() 22 { 23 var modelDto = (await _equipmentTypeAppService 24 .GetAll(new PagedEquipmentTypeResultRequestDto { MaxResultCount = int.MaxValue }) 25 ).Items; 26 var viewModel = new EquipmentTypeListViewModel 27 { 28 EquipmentTypeList = modelDto 29 }; 30 return View(viewModel); 31 } 32 33 public async Task<ActionResult> EditEquipmentTypeModal(int id) 34 { 35 var modelDto = await _equipmentTypeAppService.Get(new EntityDto(id)); 36 var editViewModel = new EditEquipmentTypeModalViewModel 37 { 38 EquipmentType = modelDto 39 }; 40 return View("_EditEquipmentTypeModal", editViewModel); 41 } 42 43 } 44 }
8. 添加视图。
视图由user中相关视图复制而来,将名称user更改为equipmentType相关即可使用。
查看&新建视图
1 @using oMES_APServer.Web.Startup 2 @using oMES_APServer.Equipments 3 @model oMES_APServer.Web.Models.EquipmentTypes.EquipmentTypeListViewModel 4 @{ 5 ViewBag.CurrentPageName = PageNames.EquipmentTypes; 6 } 7 @section scripts 8 { 9 <environment names="Development"> 10 <script src="~/view-resources/Views/EquipmentTypes/Index.js" asp-append-version="true"></script> 11 </environment> 12 13 <environment names="Staging,Production"> 14 <script src="~/view-resources/Views/EquipmentTypes/Index.js" asp-append-version="true"></script> 15 </environment> 16 } 17 <div class="row clearfix"> 18 <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> 19 <div class="card"> 20 <div class="header"> 21 <h2> 22 @L("EquipmentType") 23 </h2> 24 <ul class="header-dropdown m-r--5"> 25 <li class="dropdown"> 26 <a href="javascript:void(0);" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> 27 <i class="material-icons">more_vert</i> 28 </a> 29 <ul class="dropdown-menu pull-right"> 30 <li><a id="RefreshButton" href="javascript:void(0);" class="waves-effect waves-block"><i class="material-icons">refresh</i>@L("Refresh")</a></li> 31 </ul> 32 </li> 33 </ul> 34 </div> 35 <div class="body table-responsive"> 36 <table class="table"> 37 <thead> 38 <tr> 39 <th>@L("Code")</th> 40 <th>@L("Name")</th> 41 <th>@L("BriefName")</th> 42 <th>@L("Remark")</th> 43 <th>@L("CreationTime")</th> 44 <th>@L("CreatorUserId")</th> 45 <th>@L("LastModificationTime")</th> 46 <th>@L("LastModifierUserId")</th> 47 </tr> 48 </thead> 49 <tbody> 50 @foreach (var viewModel in Model.EquipmentTypeList) 51 { 52 <tr> 53 <td>@viewModel.Code</td> 54 <td>@viewModel.Name</td> 55 <td>@viewModel.BriefName</td> 56 <td>@viewModel.Remark</td> 57 <td>@viewModel.CreationTime</td> 58 <td>@viewModel.CreatorUserId</td> 59 <td>@viewModel.LastModificationTime</td> 60 <td>@viewModel.LastModifierUserId</td> 61 62 <td class="dropdown"> 63 <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> 64 <i class="material-icons">menu</i> 65 </a> 66 <ul class="dropdown-menu pull-right"> 67 <li><a href="#" class="waves-effect waves-block edit-equipmentType" data-equipmentType-id="@viewModel.Id" data-toggle="modal" data-target="#EquipmentTypeEditModal"><i class="material-icons">edit</i>@L("Edit")</a></li> 68 <li><a href="#" class="waves-effect waves-block delete-equipmentType" data-equipmentType-id="@viewModel.Id" data-equipmentType-name="@viewModel.Name"><i class="material-icons">delete_sweep</i>@L("Delete")</a></li> 69 </ul> 70 </td> 71 </tr> 72 } 73 </tbody> 74 </table> 75 <button type="button" class="btn btn-primary btn-circle waves-effect waves-circle waves-float pull-right" data-toggle="modal" data-target="#EquipmentTypeCreateModal"> 76 <i class="material-icons">add</i> 77 </button> 78 </div> 79 </div> 80 </div> 81 </div> 82 83 <div class="modal fade" id="EquipmentTypeCreateModal" tabindex="-1" role="dialog" aria-labelledby="EquipmentTypeCreateModalLabel" data-backdrop="static"> 84 <div class="modal-dialog" role="document"> 85 <div class="modal-content"> 86 <form name="equipmentTypeCreateForm" role="form" novalidate class="form-validation"> 87 <div class="modal-header"> 88 <h4 class="modal-title"> 89 <span>@L("CreateNewEquipmentType")</span> 90 </h4> 91 </div> 92 <div class="modal-body"> 93 <div class="form-group form-float"> 94 <div class="form-line"> 95 <input class="form-control" type="text" name="Code" required maxlength="@EquipmentType.MaxCodeLength"> 96 <label class="form-label">@L("Code")</label> 97 </div> 98 </div> 99 <div class="form-group form-float"> 100 <div class="form-line"> 101 <input class="form-control" type="text" name="Name" required maxlength="@EquipmentType.MaxNameLength"> 102 <label class="form-label">@L("Name")</label> 103 </div> 104 </div> 105 <div class="form-group form-float"> 106 <div class="form-line"> 107 <input class="form-control" type="text" name="BriefName" maxlength="@EquipmentType.MaxBriefNameLength"> 108 <label class="form-label">@L("BriefName")</label> 109 </div> 110 <div class="form-group form-float"> 111 <div class="form-line"> 112 <input class="form-control" type="text" name="Remark" maxlength="@EquipmentType.MaxRemarkLength"> 113 <label class="form-label">@L("Remark")</label> 114 </div> 115 </div> 116 </div> 117 <div class="modal-footer"> 118 <button type="button" class="btn btn-default waves-effect" data-dismiss="modal">@L("Cancel")</button> 119 <button type="submit" class="btn btn-primary waves-effect">@L("Save")</button> 120 </div> 121 </form> 122 </div> 123 </div> 124 </div> 125 126 <div class="modal fade" id="EquipmentTypeEditModal" tabindex="-1" role="dialog" aria-labelledby="EquipmentTypeEditModalLabel" data-backdrop="static"> 127 <div class="modal-dialog" role="document"> 128 <div class="modal-content"> 129 130 </div> 131 </div> 132 </div>
编辑视图
1 @using oMES_APServer.Web.Models.Common.Modals 2 @model oMES_APServer.Web.Models.EquipmentTypes.EditEquipmentTypeModalViewModel 3 @{ 4 Layout = null; 5 } 6 @Html.Partial("~/Views/Shared/Modals/_ModalHeader.cshtml", new ModalHeaderViewModel(L("EditEquipmentType"))) 7 8 <div class="modal-body"> 9 <form name="EquipmentTypeEditForm" role="form" novalidate class="form-validation"> 10 <input type="hidden" name="Id" value="@Model.EquipmentType.Id" /> 11 <ul class="nav nav-tabs tab-nav-right" role="tablist"> 12 <li role="presentation" class="active"><a href="#edit-equipmentType-details" data-toggle="tab">@L("EquipmentTypeDetails")</a></li> 13 </ul> 14 <div class="tab-content"> 15 <div role="tabpanel" class="tab-pane animated fadeIn active" id="edit-equipmentType-details"> 16 17 <div class="row clearfix" style="margin-top:10px;"> 18 <div class="col-sm-12"> 19 <div class="form-group form-float"> 20 <div class="form-line"> 21 <input id="code" type="text" name="Code" value="@Model.EquipmentType.Code" required maxlength="32" minlength="2" class="validate form-control"> 22 <label for="code" class="form-label">@L("Code")</label> 23 </div> 24 </div> 25 </div> 26 </div> 27 28 <div class="row clearfix" style="margin-top:10px;"> 29 <div class="col-sm-12"> 30 <div class="form-group form-float"> 31 <div class="form-line"> 32 <input id="name" type="text" name="Name" value="@Model.EquipmentType.Name" required maxlength="32" minlength="2" class="validate form-control"> 33 <label for="name" class="form-label">@L("Name")</label> 34 </div> 35 </div> 36 </div> 37 </div> 38 39 <div class="row clearfix" style="margin-top:10px;"> 40 <div class="col-sm-12"> 41 <div class="form-group form-float"> 42 <div class="form-line"> 43 <input id="briefname" type="text" name="BriefName" value="@Model.EquipmentType.BriefName" maxlength="32" minlength="2" class="validate form-control"> 44 <label for="briefname" class="form-label">@L("BriefName")</label> 45 </div> 46 </div> 47 </div> 48 </div> 49 50 <div class="row clearfix" style="margin-top:10px;"> 51 <div class="col-sm-12"> 52 <div class="form-group form-float"> 53 <div class="form-line"> 54 <input id="remark" type="text" name="Remark" value="@Model.EquipmentType.Remark" maxlength="32" minlength="2" class="validate form-control"> 55 <label for="remark" class="form-label">@L("Remark")</label> 56 </div> 57 </div> 58 </div> 59 </div> 60 61 </div> 62 </div> 63 </form> 64 </div> 65 66 @Html.Partial("~/Views/Shared/Modals/_ModalFooterWithSaveAndCancel.cshtml") 67 68 <script src="~/view-resources/Views/EquipmentTypes/_EditEquipmentTypeModal.js" asp-append-version="true"></script>
9. 添加js脚本。
视图中添加了js脚本,此处添加合适的js脚本,此脚本由user.js复制而来,更改为equipmentType即可使用。
添加的位置如上述视图中代码所示:"~/view-resources/Views/EquipmentTypes/_EditEquipmentTypeModal.js"
index.js如下
1 (function () { 2 $(function () { 3 4 var _equipmentTypeService = abp.services.app.equipmentTypes; 5 var _$modal = $('#EquipmentTypeCreateModal'); 6 var _$form = _$modal.find('form'); 7 8 _$form.validate(); 9 10 $('#RefreshButton').click(function () { 11 refreshequipmentTypeList(); 12 }); 13 14 //删除方法 15 $('.delete-equipmentType').click(function () { 16 var equipmentTypeId = $(this).attr("data-equipmentType-id"); 17 var tenancyName = $(this).attr('data-equipmentType-name'); 18 19 deleteequipmentType(equipmentTypeId, tenancyName); 20 }); 21 22 //编辑方法 23 $('.edit-equipmentType').click(function (e) { 24 var equipmentTypeId = $(this).attr("data-equipmentType-id"); 25 26 e.preventDefault(); 27 $.ajax({ 28 url: abp.appPath + 'equipmentTypes/EditEquipmentTypeModal?equipmentTypeId=' + equipmentTypeId, 29 type: 'POST', 30 contentType: 'application/html', 31 success: function (content) { 32 $('#EquipmentTypeEditModal div.modal-content').html(content); 33 }, 34 error: function (e) { } 35 }); 36 }); 37 38 //新增 39 _$form.find('button[type="submit"]').click(function (e) { 40 e.preventDefault(); 41 42 if (!_$form.valid()) { 43 return; 44 } 45 46 var equipmentType = _$form.serializeFormToObject(); //serializeFormToObject is defined in main.js 47 48 abp.ui.setBusy(_$modal); 49 _equipmentTypeService.create(equipmentType).done(function () { 50 _$modal.modal('hide'); 51 location.reload(true); //reload page to see new equipmentType! 52 }).always(function () { 53 abp.ui.clearBusy(_$modal); 54 }); 55 }); 56 57 _$modal.on('shown.bs.modal', function () { 58 _$modal.find('input:not([type=hidden]):first').focus(); 59 }); 60 61 function refreshequipmentTypeList() { 62 location.reload(true); //reload page to see new equipmentType! 63 } 64 65 function deleteequipmentType(equipmentTypeId, equipmentTypeName) { 66 abp.message.confirm( 67 abp.utils.formatString(abp.localization.localize('AreYouSureWantToDelete', 'oMES_APServer'), equipmentTypeName), 68 function (isConfirmed) { 69 if (isConfirmed) { 70 _equipmentTypeService.delete({ 71 id: equipmentTypeId 72 }).done(function () { 73 refreshequipmentTypeList(); 74 }); 75 } 76 } 77 ); 78 } 79 }); 80 })();
编辑模型的脚本_EditEquipmentTypeModal.js如下
1 (function ($) { 2 3 var _equipmentTypeService = abp.services.app.equipmentType; 4 var _$modal = $('#EquipmentTypeEditModal'); 5 var _$form = $('form[name=EquipmentTypeEditForm]'); 6 7 function save() { 8 9 if (!_$form.valid()) { 10 return; 11 } 12 13 var equipmentType = _$form.serializeFormToObject(); //serializeFormToObject is defined in main.js 14 15 16 abp.ui.setBusy(_$form); 17 _equipmentTypeService.update(equipmentType).done(function () { 18 _$modal.modal('hide'); 19 location.reload(true); //reload page to see edited equipmentType! 20 }).always(function () { 21 abp.ui.clearBusy(_$modal); 22 }); 23 } 24 25 //Handle save button click 26 _$form.closest('div.modal-content').find(".save-button").click(function (e) { 27 e.preventDefault(); 28 save(); 29 }); 30 31 //Handle enter key 32 _$form.find('input').on('keypress', function (e) { 33 if (e.which === 13) { 34 e.preventDefault(); 35 save(); 36 } 37 }); 38 39 $.AdminBSB.input.activate(_$form); 40 41 _$modal.on('shown.bs.modal', function () { 42 _$form.find('input[type=text]:first').focus(); 43 }); 44 })(jQuery);
10. 添加前端菜单(入口)。
菜单需在startup文件夹 xxxNavigationProvider类中,添加.AddItem代码。
.AddItem放置的顺序不同,界面中的显示顺序就不同。
1 using Abp.Application.Navigation; 2 using Abp.Localization; 3 using oMES_APServer.Authorization; 4 5 namespace oMES_APServer.Web.Startup 6 { 7 /// <summary> 8 /// This class defines menus for the application. 9 /// </summary> 10 public class oMES_APServerNavigationProvider : NavigationProvider 11 { 12 public override void SetNavigation(INavigationProviderContext context) 13 { 14 context.Manager.MainMenu 15 .AddItem( 16 new MenuItemDefinition( 17 PageNames.EquipmentTypes, 18 L("EquipmentTypes"), 19 url: "EquipmentTypes", 20 icon: "info" 21 ) 22 )
以下省略
MenuItemDefinition的各参数看名字就能理解,从上到下依次是:
菜单名称,
菜单显示名称,
url:链接,即控制器名称
icon:图标名称,会根据名称自动查找对应的图标文件。
11. 添加权限管理。
通常的权限管理方式为:人员->角色->权限。
即为人员分配角色,为角色分配权限,这样就避免了多人相同权限时,重复分配的工作。
此处将设备管理功能(菜单)分配给对应的角色。
需要添加如下代码:
1、添加权限名称
1 namespace oMES_APServer.Authorization 2 { 3 public static class PermissionNames 4 { 5 public const string Pages_Tenants = "Pages.Tenants"; 6 public const string Pages_Users = "Pages.Users"; 7 public const string Pages_Roles = "Pages.Roles"; 8 //添加自定义权限名称 9 public const string Pages_Companies = "Pages.Companies"; 10 public const string Pages_Departments = "Pages.Departments"; 11 12 public const string Pages_EquipmentTypes = "Pages.EquipmentTypes"; 13 } 14 }
2、系统权限列表中,添加该权限名称
1 using Abp.Authorization; 2 using Abp.Localization; 3 using Abp.MultiTenancy; 4 5 namespace oMES_APServer.Authorization 6 { 7 public class oMES_APServerAuthorizationProvider : AuthorizationProvider 8 { 9 public override void SetPermissions(IPermissionDefinitionContext context) 10 { 11 context.CreatePermission(PermissionNames.Pages_Users, L("Users")); 12 context.CreatePermission(PermissionNames.Pages_Roles, L("Roles")); 13 context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host); 14 15 //添加自定义权限 16 context.CreatePermission(PermissionNames.Pages_Companies, L("Companies")); 17 context.CreatePermission(PermissionNames.Pages_Departments, L("Departments")); 18 context.CreatePermission(PermissionNames.Pages_EquipmentTypes, L("EquipmentTypes")); 19 } 20 21 private static ILocalizableString L(string name) 22 { 23 return new LocalizableString(name, oMES_APServerConsts.LocalizationSourceName); 24 } 25 } 26 }
3、菜单中添加权限控制
requiredPermissionName: PermissionNames.Pages_Companies
4、控制器中添加权限控制
[AbpAuthorize(PermissionNames.Pages_EquipmentTypes)]
5、应用服务方法中添加权限控制
[AbpAuthorize(PermissionNames.Pages_EquipmentTypes)]
添加完成后,运行程序,角色管理中,就可以单独选择该功能的权限了。
12. 文本翻译。
ABP的翻译方法在xxx.Core项目Localization文件夹中
默认支持9种语言。
添加中文翻译,只需在xxx-zh-Hans.xml文件中添加相应字段即可。
这要注意一下:xml中的子项,如果name值相同的话,会报错。所以每次添加新翻译时,先检查一下name值是否重复。
如下添加即可:
到此,一个基础资料的基础功能就完成了。
之后会继续完善所有的基础功能,中间有对ABP功能的研究也会一点一点写出来。