ABP 開發(fā)手記(Begin 2018-7-25)
7.25開始,啟用5.4版本asp net zero,做一個最簡單的分類管理和上傳圖片這兩個功能,看從學(xué)習(xí)到完成需要多久的時(shí)間
因?yàn)楣ぷ魈Γ阈浅闀r(shí)間弄了一下,最后做完這個功能,居然已經(jīng)是9.25,整整兩個月。
=============================================================================================
按照官方教程建好項(xiàng)目后,假定項(xiàng)目名稱為Relyto.CoreERP
文章內(nèi)容我按照正常的步驟完整做完一個mvc頁面。初用這個框架的時(shí)候,由于我沒有完整的閱讀官方文檔,拿著就開整 ,對整體架構(gòu)不熟悉,做每一個步驟需要在不同的項(xiàng)目文件夾切換來切換去,經(jīng)常找不到需要添加的內(nèi)容在哪里。所以這個文檔我描述了在做的過程中,每一步在哪個項(xiàng)目或者文件進(jìn)行操作,大家在做的時(shí)候注意后面的項(xiàng)目后綴,對應(yīng)原先的項(xiàng)目結(jié)構(gòu)。
#2018-7-25
#1、建實(shí)體
--Namespace
Relyto.CoreERP.Core項(xiàng)目下,新建文件夾Channel,然后建實(shí)體
需要添加以下命名空間:
using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
更改類對應(yīng)的表名,是在class類前加上以下注解:
[Table("cmn_channelinfo")]
示例:
[Table("cmn_channelinfo")]
? ? public class ChannelInfo:FullAuditedEntity ,IMustHaveTenant
{}
對于多租戶,實(shí)現(xiàn) IMustHaveTenant,并添加以下語句
public int TenantId { get; set; }
#2、添加到DbContext
Relyto.CoreERP.EntityFrameworkCore項(xiàng)目下\EntityFrameworkCore文件夾
修改:AbpZeroTemplateDbContext.cs
Add Namespace:using Relyto.CoreERP.Channel;
在下面添加一行代碼,用于下面命令行把這張表結(jié)構(gòu)生成到數(shù)據(jù)庫中去:
public virtual DbSet<ChannelInfo> ChannelInfos { get; set; }
在程序包管理器控制臺,先選擇項(xiàng)目為Relyto.CoreERP.EntityFrameworkCore,然后在下面執(zhí)行以下命令:
Add-Migration "Add Channel Info"
Update-Database
,然后檢查一下數(shù)據(jù)庫,請應(yīng)該是生成了
#3.APPlication 層
Relyto.CoreERP.Application項(xiàng)目下新建ChannelInfo文件夾
3.1 IChannelInfoAppService
using Abp.Application.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Relyto.CoreERP.Channel;
using Relyto.CoreERP.Channel.Dtos;
using Abp.Application.Services.Dto;
namespace Relyto.CoreERP.Channel
{
? ? public interface IChannelInfoAppService: IApplicationService
? ? {
? ? ? ? Task<ListResultDto<ChannelInfoListDto>> GetAll(GetAllChannelInfoInput input);
? ? ? ? System.Threading.Tasks.Task Create(CreateChannelInfoInput input);
? ? }
}
建立Dtos文件夾,生成Get,Create的方法的參數(shù)類
3.2? ChannelInfoListDto
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Relyto.CoreERP.Channel;
using Relyto.CoreERP.SharedEnum;
namespace Relyto.CoreERP.Channel.Dtos
{
? ? [AutoMapFrom(typeof(ChannelInfo))]
? ? public class ChannelInfoListDto:FullAuditedEntityDto
? ? {
? ? ? ? public string Title { get; set; }? ? ? ?
? ? ? ? public string Description { get; set; }? ? ? ?
? ? ? ? public string SubTitle { get; set; }? ? ? ?
? ? ? ? public string ChannelCode { get; set; }
? ? ? ? public string EnglishName { get; set; }? ? ? ?
? ? ? ? public string ImageUrl { get; set; }? ? ? ?
? ? ? ? public short ChannelIndex { get; set; }? ? ? ?
? ? ? ? public int ParentID { get; set; }? ? ? ?
? ? ? ? public EnumState State { get; set; }? ? ? ?
? ? ? ? public bool IsLastNode { get; set; }
? ? }
}
3.3 GetAllChannelInfoInput
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Relyto.CoreERP.Channel.Dtos
{
? ? public class GetAllChannelInfoInput
? ? {
? ? ? ? public int ParentID { get; set; }
? ? }
}
3.4 CreateChannelInfoInput
using Abp.AutoMapper;
using Relyto.CoreERP.SharedEnum;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Relyto.CoreERP.Channel.Dtos
{
? ? [AutoMapTo(typeof(ChannelInfo))]
? ? public class CreateChannelInfoInput
? ? {
? ? ? ? public const int MaxTitleLength = 20;
? ? ? ? public const int MaxDescriptionLength = 100; //64KB
? ? ? ? /// <summary>
? ? ? ? /// 標(biāo)題
? ? ? ? /// </summary>
? ? ? ? [Required]
? ? ? ? [MaxLength(MaxTitleLength)]
? ? ? ? public string Title { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 描述
? ? ? ? /// </summary>
? ? ? ? [MaxLength(MaxDescriptionLength)]
? ? ? ? public string Description { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 子標(biāo)題
? ? ? ? /// </summary>
? ? ? ? [MaxLength(MaxTitleLength)]
? ? ? ? public string SubTitle { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// channel Code附加
? ? ? ? /// </summary>
? ? ? ? [MaxLength(MaxTitleLength)]
? ? ? ? public string ChannelCode { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 英文名
? ? ? ? /// </summary>
? ? ? ? [MaxLength(MaxTitleLength)]
? ? ? ? public string EnglishName { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// channel 附加的圖片地址
? ? ? ? /// </summary>
? ? ? ? public string ImageUrl { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 顯示順序
? ? ? ? /// </summary>
? ? ? ? public short ChannelIndex { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 上級ID
? ? ? ? /// </summary>
? ? ? ? [Required]
? ? ? ? public int ParentID { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 狀態(tài)
? ? ? ? /// </summary>
? ? ? ? public EnumState State { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 是否末級
? ? ? ? /// </summary>
? ? ? ? public bool IsLastNode { get; set; }
? ? }
}
#4.實(shí)現(xiàn)IChannelInfoAppService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Relyto.CoreERP;
using Relyto.CoreERP.Channel;
using Relyto.CoreERP.Channel.Dtos;
using Abp.Application.Services.Dto;
using Microsoft.EntityFrameworkCore;
namespace Relyto.CoreERP.Channel
{
? ? public class ChannelInfoAppService:AbpZeroTemplateAppServiceBase,IChannelInfoAppService
? ? {
? ? ? ? private readonly IRepository<ChannelInfo> _channelInfoRepository;
? ? ? ? public ChannelInfoAppService(IRepository<ChannelInfo> channelRepository)
? ? ? ? {
? ? ? ? ? ? _channelInfoRepository = channelRepository;
? ? ? ? }
? ? ? ? public async System.Threading.Tasks.Task Create(CreateChannelInfoInput input)
? ? ? ? {
? ? ? ? ? ? var channelInfo = ObjectMapper.Map<ChannelInfo>(input);
? ? ? ? ? ? await _channelInfoRepository.InsertAsync(channelInfo);
? ? ? ? }
? ? ? ? public async Task<ListResultDto<ChannelInfoListDto>> GetAll(GetAllChannelInfoInput input)
? ? ? ? {
? ? ? ? ? ? var channelInfos = await _channelInfoRepository
? ? ? ? ? ? ? ? .GetAll()? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? .Where(m=>m.ParentID==input.ParentID)
? ? ? ? ? ? ? ? .OrderByDescending(t => t.CreationTime)
? ? ? ? ? ? ? ? .ToListAsync();
? ? ? ? ? ? return new ListResultDto<ChannelInfoListDto>(
? ? ? ? ? ? ? ? ObjectMapper.Map<List<ChannelInfoListDto>>(channelInfos)
? ? ? ? ? ? );
? ? ? ? }
? ? }
}
#5.添加測試
跳過了
#6.Adding a New Menu Item,添加新菜單
找到
Relyto.CoreERP.Web.Mvc項(xiàng)目下AppAreaName\Startup\找到AppAreaNameNavigationProvider
類似這樣:
.AddItem(new MenuItemDefinition(
? ? ? ? ? ? ? ? ? ? ? ? AppAreaNamePageNames.Common.DemoUiComponents,
? ? ? ? ? ? ? ? ? ? ? ? L("圖片上傳"),
? ? ? ? ? ? ? ? ? ? ? ? url: "AppAreaName/ImageManager",
? ? ? ? ? ? ? ? ? ? ? ? icon: "flaticon-shapes"
? ? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? );
或者需要權(quán)限:
.AddItem(new MenuItemDefinition(
? ? ? ? ? ? ? ? ? ? ? ? AppAreaNamePageNames.Common.DemoUiComponents,
? ? ? ? ? ? ? ? ? ? ? ? L("DemoUiComponents"),
? ? ? ? ? ? ? ? ? ? ? ? url: "AppAreaName/DemoUiComponents",
? ? ? ? ? ? ? ? ? ? ? ? icon: "flaticon-shapes",
? ? ? ? ? ? ? ? ? ? ? ? requiredPermissionName: AppPermissions.Pages_DemoUiComponents
? ? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? )
6.1 AppAreaNamePageNames 添加幾個常量,用于菜單等需要的時(shí)候使用
? ? public static class Channel
? ? ? ? {
? ? ? ? ? ? public const string NewChannel = "Channel.New";
? ? ? ? ? ? public const string ViewAll = "Channel.ViewAll";
? ? ? ? ? ? public const string EditChannel = "Channel.Edit";
? ? ? ? }
6.2添加權(quán)限名稱,這些名稱在后面對應(yīng)的JS中也要用到
Relyto.CoreERP.Authorization.AppPermissions
? public const string Pages_Administration_ChannelManager = "Pages.Administration.Pages_Administration_ChannelManager";
6.3在Relyto.CoreERP.Core項(xiàng)目Localization\AbpZeroTemplate下添加語言詞條,這個地方要記到,以后要添加詞條資源都在這里添加
比如在代碼里使用到 L("ChannelManager"),需要在對應(yīng)的zh文件里面添加:
? <text name="ChannelManager">分類管理</text>
6.3 創(chuàng)建權(quán)限點(diǎn)
Relyto.CoreERP.Core\Authorization\AppAuthorizationProvider下
? ? ? ? administration.CreateChildPermission(AppPermissions.Pages_Administration_ChannelManager, L("ChannelManager"));
#7.創(chuàng)建MVC
Relyto.CoreERP.Web.Mvc\Areas\AppAreaName\Controllers\ChannelInfoController
創(chuàng)建control.直接添加control.Relyto.CoreERP.Web.Mvc\Areas\AppAreaName\Controllers 繼承的是 AbpZeroTemplateControllerBase
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.AspNetCore.Mvc.Authorization;
using Abp.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Relyto.CoreERP.Authorization;
using Relyto.CoreERP.Web.Controllers;
namespace Relyto.CoreERP.Web.Mvc.Areas.AppAreaName.Controllers
{
? ? [Area("AppAreaName")]
? ? [AbpMvcAuthorize(AppPermissions.Pages_Administration_ChannelManager)]
? ? public class ChannelInfoController : AbpZeroTemplateControllerBase
#8.復(fù)雜的客戶端腳本,以樹形為例,分類信息
在\Relyto.CoreERP.Web.Mvc\Areas\AppAreaName\Views\ChannelInfo
而對應(yīng)的腳本信息,css信息,確放在:
Relyto.CoreERP.Web.Mvc\wwwroot\view-resources\Areas\AppAreaName\Views\ChannelInfo
目錄,使用時(shí)注意對照
另外,在View頁面里,涉及的字符串,我們一般直接寫,但是在這里一般用L("Key")的方式,要對照
Relyto.CoreERP.Core\Localization\AbpZeroTemplate
里面的模板文件添加
前期比如我只添加中文:AbpZeroTemplate-zh-CN.xml里對照添加
舉例:
<div id="ChannelInfoEmptyInfo" ng-if="!vm.organizationTree.unitCount" class="text-muted">
? ? ? ? ? ? ? ? ? ? ? ? @L("ChannelNoInfoYet")
? ? ? ? </div>
大量的這種。是很不習(xí)慣的
研究JS,還沒明白tree是怎么生成的,噢。原來是用的JStree,以前沒有用過,難怪不懂,NND前端不懂的東西太多了,一入前端深似海。
學(xué)習(xí)地方:https://www.jstree.com/
JS Tree: Create an instance
Once the DOM is ready you can start creating jstree instances.
$(function () { $('#jstree_demo_div').jstree(); });
--------------------------------------------------------------------
讀代碼 :在 里面給了一個div? ChannelInfoEditTree
在js里面,調(diào)用了
channelinfoTree.init();
這個方法代碼:
init: function () {
? ? ? ? ? ? ? ? channelinfoTree.getTreeDataFromServer(function (treeData) {
? ? ? ? ? ? ? ? ? ? channelinfoTree.setUnitCount(treeData.length);
? ? ? ? ? ? ? ? ? ? channelinfoTree.$tree
? ? ? ? ? ? ? ? ? ? ? ? .on('changed.jstree', function (e, data) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (data.selected.length != 1) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? channelinfoTree.selectedOu.set(null);
? ? ? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? var selectedNode = data.instance.get_node(data.selected[0]);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? channelinfoTree.selectedOu.set(selectedNode);
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? ? ? ? ? .on('move_node.jstree', function (e, data) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? var parentNodeName = (!data.parent || data.parent == '#')
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? app.localize('Root')
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? : channelinfoTree.$tree.jstree('get_node', data.parent).original.displayName;
? ? ? ? ? ? ? ? ? ? ? ? ? ? abp.message.confirm(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? app.localize('OrganizationUnitMoveConfirmMessage', data.node.original.displayName, parentNodeName),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? function (isConfirmed) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (isConfirmed) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? _channelinfoService.moveOrganizationUnit({
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id: data.node.id,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? newParentId: data.parent
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }).done(function () {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? abp.notify.success(app.localize('SuccessfullyMoved'));
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? channelinfoTree.reload();
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }).fail(function (err) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? channelinfoTree.$tree.jstree('refresh'); //rollback
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? setTimeout(function () { abp.message.error(err.message); }, 500);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? channelinfoTree.$tree.jstree('refresh'); //rollback
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? );
? ? ? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? ? ? ? ? .jstree({
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'core': {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? data: treeData,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? multiple: false,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check_callback: function (operation, node, node_parent, node_position, more) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? types: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "default": {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "icon": "fa fa-folder m--font-warning"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "file": {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "icon": "fa fa-file? m--font-warning"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? contextmenu: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? items: channelinfoTree.contextMenu
? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? sort: function (node1, node2) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (this.get_node(node2).original.displayName < this.get_node(node1).original.displayName) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return 1;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return -1;
? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? plugins: [
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'types',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'contextmenu',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'wholerow',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'sort',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'dnd'
? ? ? ? ? ? ? ? ? ? ? ? ? ? ]
? ? ? ? ? ? ? ? ? ? ? ? });
#9.改好了客戶端展示頁面,要實(shí)現(xiàn)功能,先從createmodal開始吧
9.1 在Relyto.CoreERP.Web.Mvc\Areas\AppAreaName\Models\Channel
新建了CreateChannelInfoModalViewModel類,里面就實(shí)現(xiàn)了個parentid,現(xiàn)在還不知道怎么用
9.2更改View,添加了Relyto.CoreERP.Web.Mvc\Areas\AppAreaName\Views\ChannelInfo\_CreateModal.cshtml
里面好像頭部和尾部都是現(xiàn)成的。
遇的到,半天不能彈出modal框,原來是JS路徑寫錯了,下次記得檢查這個:
一開始我沒有在控制文件創(chuàng)建creeateModal這個方法,所以直接報(bào)錯。
控制文件創(chuàng)建了以后,因?yàn)閖s不對一直沒打開
? ? ? ? var _createModal = new app.ModalManager({
? ? ? ? ? ? viewUrl: abp.appPath + 'AppAreaName/ChannelInfo/CreateModal',
? ? ? ? ? ? scriptUrl: abp.appPath + 'view-resources/Areas/AppAreaName/Views/ChannelInfo/_CreateModal.js',? =》剛才就是這個路徑寫錯了,所以就不彈出圣誕框 。
? ? ? ? ? ? modalClass:'CreateChannelInfoModal'? =》這個類名,就是 _CreateModal里面開始那個類。如果對不上,則后來點(diǎn)保存沒有反應(yīng)。我找了半天才發(fā)現(xiàn)這個問題。
function() {
? ? app.modals.CreateChannelInfoModalViewModel = function () {
? ? 就是上面這個代碼
這個類里面就是通過var channelInfo = _$form.serializeFormToObject();
直接就把界面上的數(shù)據(jù),form里面的,序列化,然后就傳給后端,后端使用的是DtoInput,也不知道 怎么弄的,居然可以直接解析出來。
然后就去寫數(shù)據(jù)庫了。感覺客戶端主要是太不熟悉了。慢慢看代碼 還是看的懂。
套路就是
服務(wù)端App定義的服務(wù),客戶端可以直接變成js來用,這個真牛逼。當(dāng)然要注意把方法的第一個字母小寫了。
cshtml頁面里,直接用DtoInput的字段名來做數(shù)據(jù),自然就可以映射到服務(wù)端dto去,應(yīng)該還要整理一下文本框架,單選,多選,日期,圖片等各種類型的客戶端處理方法。
從user那個來看,還可以有更復(fù)雜的頁面方法來實(shí)現(xiàn) 。
這樣客戶端的邏輯代碼就相對多一些。
? ? ? ? });
9.3 在APPService 那個項(xiàng)目可以通過AbpSession.TenantId 來獲取當(dāng)前的TenantID.
9.4.已搞定添加到數(shù)據(jù)庫,但是現(xiàn)在顯示 還是undefind
#10.解決顯示問題
1.解決了分類顯示那里不能正確顯示的問題,搞明白了()里面是對子節(jié)點(diǎn)的統(tǒng)計(jì)
原來是這個在搞定節(jié)點(diǎn)顯示:
generateTextOnTree: function (ou) {
? ? ? ? ? ? ? ? var itemClass = ou.memberCount > 0 ? ' ou-text-has-members' : ' ou-text-no-members';
? ? ? ? ? ? ? ? return '<span title="' + ou.id + '" class="ou-text' + itemClass
? ? ? ? ? ? ? ? ? ? + '" data-ou-id="' + ou.id + '">'
? ? ? ? ? ? ? ? ? ? + app.htmlUtils.htmlEncodeText(ou.title)
? ? ? ? ? ? ? ? ? ? + ' (<span class="ou-text-member-count">'
? ? ? ? ? ? ? ? ? ? + ou.memberCount
? ? ? ? ? ? ? ? ? ? + '</span>) <i class="fa fa-caret-down text-muted"></i></span>';
? ? ? ? ? ? },
其中有幾個注意事項(xiàng):
a.title這種字段,在服務(wù)端是全大定,到了這里是首字母小寫才正常。
b.memberCount是服務(wù)端app層統(tǒng)計(jì)出來的,而organ那里有個方法,我還沒有寫過那種方法,待確定。他用了一個join+new就搞定了分類統(tǒng)計(jì)的問題。
#11 遇到本地在樹狀選擇里沒有復(fù)選框的問題
1.編輯頻道信息,結(jié)果發(fā)現(xiàn)做角色與權(quán)限管理那里,樹狀沒有復(fù)選框,不知道為什么在我的界面上沒有回來
最后我在
Relyto.CoreERP.Web.Mvc\wwwroot\view-resources\Areas\AppAreaName\Views\Common\PermissionTree.js
修改了一個變量:
'checkbox': {
? ? ? ? ? ? ? ? ? ? keep_selected_style: true,? --false =>true
? ? ? ? ? ? ? ? ? ? three_state: false,
? ? ? ? ? ? ? ? ? ? cascade: '',
? ? ? ? ? ? ? ? ? ? visible:true
? ? ? ? ? ? ? ? },
可以看到藍(lán)色背景的選擇結(jié)果,勉強(qiáng)可以,不曉得為哈我這個上面不出來復(fù)選框。
折騰了一晚上,只解決了這個問題。效率很低啊
還有就是把權(quán)限又搞懂了一點(diǎn)。 現(xiàn)在還建了子權(quán)限菜單。在數(shù)據(jù)庫里有個表,對應(yīng)createpermison那塊
https://blog.csdn.net/new0801/article/details/54766984這篇文章講的比較清楚,一步一步做就可以了
#還是前端工作
發(fā)現(xiàn)前端工作量真大啊。寫個修改,也要寫那么久
沒有解決到復(fù)選框的問題,現(xiàn)在發(fā)現(xiàn)abp前端這個好麻煩啊,每個controller對應(yīng)的方法都要有個Model類。
現(xiàn)在還全部是用的實(shí)體復(fù)制,沒有做變更,空了還要來整理。權(quán)限、實(shí)體內(nèi)容 這一塊,然后寫個文檔。
又是checkbox???,在編輯的時(shí)候,一選中chekcobx就valid error.搞了半天,要用這種style才能繼續(xù)的下去,原因嘛,我也不懂,看起來怪怪的
<label for="IsLastNode" class="m-checkbox">
? ? ? ? ? ? <input id="IsLastNode"? type="checkbox" name="IsLastNode" value="true" @(Model.IsLastNode ? "checked=\"checked\"" : "")>
? ? ? ? ? ? @L("IsLastNode")
? ? ? ? ? ? <span></span>
? ? ? ? </label>
我看很多地方都是這樣寫的,抄過來就可以用,但原因嘛,沒明白 。
現(xiàn)在基本完成添加和修改了。接下來,那就把展示那里,把點(diǎn)擊后,其附加信息顯示出來這塊做了嘛。
坑:juqery設(shè)置<input textbox 不是用text(),而是用val();
我最后又遇到checkbox,沒搞定用javascript更改期check值。最后換文本了。我這個版本跟checkbox有仇?怎么都不出來chekcbox
在Service Update那里,從DBRepority取出來的實(shí)體不能用object.Automapper去修改數(shù)據(jù)。必須用傳統(tǒng)的賦值方法修改過去。
#2018-8-6
1.查看信息做完后,考慮做添加下級,結(jié)果發(fā)現(xiàn)添加下級的時(shí)候,我沒有把parentid在controller那里添加進(jìn)去,修改后,數(shù)據(jù)到是對了
接下來就是不能分組顯示。查看organunit,使用了一種不太懂的語法完成。我修改了getall()以后,還是不分組,看代碼,似懂非懂
細(xì)致的觀察了一下js代碼,發(fā)現(xiàn)是把一個parentId寫成了parnetID。原來寫在了大寫。在js里面首字母小寫后,后面就不對了。
這種約定我沒有找到文檔,但在abp里面確實(shí)存在這種約定,可能大家都不用這種方式開發(fā),我也沒有看到相關(guān)的文檔。
更奇怪的是,我做了 按channelindex排序后發(fā)現(xiàn)是倒序的,后來查看了app service層確實(shí)是orderbydesending。所以不怪別個。
目前看來樹級的狀態(tài)基本正常了,接下來就刪除 了。
這玩意兒還缺一個刷新的按鈕,從服務(wù)器重新取數(shù)據(jù)來刷一下。
#2018-8-9
1.終于在今晚完成了刪除功能,現(xiàn)在除()里面顯示的總數(shù)據(jù)不對,缺權(quán)限完,其他功能基本完成,跌跌撞撞用了10多天,都還沒有完全搞完,前端真是坑啊。
還有圖片上傳的功能還沒有做呢。
2.JS端的權(quán)限搞懂了
var _permissions = {
? ? ? ? ? ? create: abp.auth.isGranted('Pages.Administration.ChannelManager.Create'),
? ? ? ? ? ? edit: abp.auth.isGranted('Pages.Administration.ChannelManager.Edit'),
? ? ? ? ? ? delete: abp.auth.isGranted('Pages.Administration.ChannelManager.Delete')
? ? ? ? };
這個就是創(chuàng)建權(quán)限點(diǎn)的,對應(yīng)D:\Project\2018\Relyto.CoreERP\aspnet-core\src\Relyto.CoreERP.Core\Authorization\AppAuthorizationProvider.cs
下的權(quán)限點(diǎn),注意里面的isGranted 我用了 這個,沒有用原來的haspermit那個方法。另外,后面的.是字條串常量。要去常量類里copy
接下來就是controll層和Application的Service要同樣加權(quán)限。
service層是:? ? ? ? [AbpAuthorize(AppPermissions.Pages_Administration_ChannelManager_Delete)]
controll層是:[AbpMvcAuthorize(AppPermissions.Pages_Administration_ChannelManager_Edit)]
有點(diǎn)區(qū)別的。
到此權(quán)限暫時(shí)可以用了哈。
現(xiàn)在主要就是圖片上傳的功能 了。
順便還添加了一個refresh方法。
#2018-8-22
1.搞清楚了圖像上傳后,是存了一個GUID,放在[AppBinaryObjects]中,目前只寫了數(shù)據(jù)庫保存,還沒有寫本地保存。
所以我把代碼全部改了一下,關(guān)聯(lián)表只存GUID,不存URL
因?yàn)槭菙?shù)據(jù)庫,我看JS中當(dāng)前圖像最大存放:9990000,實(shí)測小于1.2M,沒看懂這個單位。
不過折騰了一遍。完善了添加、修改刪除后刷新的問題,解決了添加、刪除、修改過程中圖片顯示、上傳的問題,以及服務(wù)端在編輯、刪除同步刪除相關(guān)圖片的問題。
#2018-9-14
1.找了個前端的上傳圖片的框架bootstrap-fileinput,好不容易搞定了前端,但是還沒有搞定后臺存儲的問題。
#2018-9-17
1.發(fā)現(xiàn)在cshtml端,必須通過
@section Styles
? ? {
? ? <link rel="stylesheet" abp-href="/view-resources/Areas/AppAreaName/Views/ImageManager/bootstrap-fileinput/css/fileinput.min.css" asp-append-version="true" />
}
@section Scripts
? ? {
? ? <script abp-src="/view-resources/Areas/AppAreaName/Views/ImageManager/bootstrap-fileinput/js/fileinput.min.js" asp-append-version="true"></script>
? ? <script abp-src="/view-resources/Areas/AppAreaName/Views/ImageManager/bootstrap-fileinput/js/locales/zh.js" asp-append-version="true"></script>
? ? <script abp-src="/view-resources/Areas/AppAreaName/Views/ImageManager/upload_fileinput.js" asp-append-version="true"></script>
}
這樣的方式引入樣式和js文件,才能正確解決跨域的問題。也解決了文件上傳不發(fā)送到controller端的問題
2.在文件保存時(shí),如果發(fā)現(xiàn)文件路徑所在的文件夾沒有創(chuàng)建,會報(bào)錯,比如uploadfile文件夾沒有創(chuàng)建,會報(bào)內(nèi)部錯誤。