mirror of https://github.com/EasyAbp/EShop.git
48 changed files with 662 additions and 239 deletions
@ -1,12 +1,15 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Stores.StoreOwners.Dtos |
|||
{ |
|||
public class StoreOwnerDto : AuditedEntityDto<Guid> |
|||
public class StoreOwnerDto : ExtensibleFullAuditedEntityDto<Guid> |
|||
{ |
|||
[Required] |
|||
public Guid StoreId { get; set; } |
|||
|
|||
[Required] |
|||
public Guid OwnerId { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Stores.StoreOwners |
|||
{ |
|||
public class StoreOwnerDuplicatedException : BusinessException |
|||
{ |
|||
public StoreOwnerDuplicatedException(Guid storeId, Guid ownerId) : base( |
|||
message: $"Owner {ownerId} is duplicate for the store {storeId}") |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,10 +1,12 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Stores.Stores.Dtos |
|||
{ |
|||
public class StoreDto : ExtensibleAuditedEntityDto<Guid> |
|||
{ |
|||
[Required] |
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace EasyAbp.EShop.Stores.StoreOwners |
|||
{ |
|||
public interface IStoreOwnerStore |
|||
{ |
|||
Task<bool> IsStoreOwnerAsync(Guid storeId, Guid userId); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using System; |
|||
|
|||
namespace EasyAbp.EShop.Stores.StoreOwners |
|||
{ |
|||
[Serializable] |
|||
public class StoreOwnerCacheItem |
|||
{ |
|||
public bool IsOwner { get; set; } |
|||
|
|||
public StoreOwnerCacheItem() |
|||
{ |
|||
} |
|||
|
|||
public StoreOwnerCacheItem(bool isOwner) |
|||
{ |
|||
IsOwner = isOwner; |
|||
} |
|||
|
|||
public static string CalculateCacheKey(Guid storeId, Guid userId) |
|||
{ |
|||
return "s:" + storeId.ToString("D") + ",u:" + userId.ToString("D"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Stores.StoreOwners |
|||
{ |
|||
public class StoreOwnerStore : IStoreOwnerStore, ITransientDependency |
|||
{ |
|||
protected ILogger<StoreOwnerStore> Logger { get; } |
|||
protected IStoreOwnerRepository StoreOwnerRepository { get; } |
|||
protected IDistributedCache<StoreOwnerCacheItem> Cache { get; } |
|||
|
|||
public StoreOwnerStore(ILogger<StoreOwnerStore> logger, |
|||
IStoreOwnerRepository storeOwnerRepository, |
|||
IDistributedCache<StoreOwnerCacheItem> cache) |
|||
{ |
|||
StoreOwnerRepository = storeOwnerRepository; |
|||
Cache = cache; |
|||
Logger = logger ?? NullLogger<StoreOwnerStore>.Instance; |
|||
} |
|||
|
|||
public async Task<bool> IsStoreOwnerAsync(Guid storeId, Guid userId) |
|||
{ |
|||
return (await GetCacheItemAsync(storeId, userId)).IsOwner; |
|||
} |
|||
|
|||
protected virtual async Task<StoreOwnerCacheItem> GetCacheItemAsync(Guid storeId, Guid userId) |
|||
{ |
|||
var cacheKey = CalculateCacheKey(storeId, userId); |
|||
Logger.LogDebug($"StoreOwnerStore.GetCacheItemAsync: {cacheKey}"); |
|||
|
|||
var cacheItem = await Cache.GetAsync(cacheKey); |
|||
if (cacheItem != null) |
|||
{ |
|||
Logger.LogDebug($"Found in the cache: {cacheKey}"); |
|||
return cacheItem; |
|||
} |
|||
|
|||
Logger.LogDebug($"Not found in the cache: {cacheKey}"); |
|||
cacheItem = new StoreOwnerCacheItem(false); |
|||
|
|||
await SetCacheItemsAsync(storeId, userId, cacheItem); |
|||
return cacheItem; |
|||
} |
|||
|
|||
protected virtual async Task SetCacheItemsAsync( |
|||
Guid storeId, Guid userId, |
|||
StoreOwnerCacheItem currentCacheItem) |
|||
{ |
|||
var storeOwners = await StoreOwnerRepository.GetListByStoreIdAsync(storeId); |
|||
Logger.LogDebug( |
|||
$"Getting all store owner in store: {storeId}"); |
|||
|
|||
Logger.LogDebug($"Setting the cache items. Count: {storeOwners.Count}"); |
|||
|
|||
var cacheItems = new Dictionary<string, StoreOwnerCacheItem>(); |
|||
foreach (var storeOwner in storeOwners) |
|||
{ |
|||
cacheItems.Add(CalculateCacheKey(storeOwner.StoreId, storeOwner.OwnerId), |
|||
new StoreOwnerCacheItem(true)); |
|||
|
|||
if (storeOwner.StoreId == storeId && storeOwner.OwnerId == userId) |
|||
{ |
|||
currentCacheItem.IsOwner = true; |
|||
} |
|||
} |
|||
|
|||
await Cache.SetManyAsync(cacheItems); |
|||
Logger.LogDebug($"Finished setting the cache items. Count: {storeOwners.Count}"); |
|||
} |
|||
|
|||
protected virtual string CalculateCacheKey(Guid storeId, Guid userId) |
|||
{ |
|||
return StoreOwnerCacheItem.CalculateCacheKey(storeId, userId); |
|||
} |
|||
} |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Services; |
|||
|
|||
namespace EasyAbp.EShop.Stores.Stores |
|||
{ |
|||
public interface IStoreManager : IDomainService |
|||
{ |
|||
Task<Store> CreateAsync(Store store, IEnumerable<Guid> ownerIds = null); |
|||
|
|||
Task<Store> UpdateAsync(Store store, IEnumerable<Guid> ownerIds = null); |
|||
} |
|||
} |
|||
@ -1,58 +0,0 @@ |
|||
using EasyAbp.EShop.Stores.StoreOwners; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Services; |
|||
|
|||
namespace EasyAbp.EShop.Stores.Stores |
|||
{ |
|||
public class StoreManager : DomainService, IStoreManager |
|||
{ |
|||
private readonly IStoreRepository _storeRepository; |
|||
private readonly IStoreOwnerRepository _storeOwnerRepository; |
|||
|
|||
public StoreManager(IStoreRepository storeRepository, |
|||
IStoreOwnerRepository storeOwnerRepository) |
|||
{ |
|||
_storeRepository = storeRepository; |
|||
_storeOwnerRepository = storeOwnerRepository; |
|||
} |
|||
|
|||
public async Task<Store> CreateAsync(Store store, IEnumerable<Guid> ownerIds = null) |
|||
{ |
|||
store = await _storeRepository.InsertAsync(store); |
|||
|
|||
await UpdateStoreOwnersAsync(store.Id, ownerIds); |
|||
|
|||
return store; |
|||
} |
|||
|
|||
public async Task<Store> UpdateAsync(Store store, IEnumerable<Guid> ownerIds = null) |
|||
{ |
|||
store = await _storeRepository.UpdateAsync(store); |
|||
|
|||
await UpdateStoreOwnersAsync(store.Id, ownerIds); |
|||
|
|||
return store; |
|||
} |
|||
|
|||
protected virtual async Task UpdateStoreOwnersAsync(Guid storeId, IEnumerable<Guid> ownerIds) |
|||
{ |
|||
ownerIds ??= new List<Guid>(); |
|||
|
|||
var storeOwners = await _storeOwnerRepository.GetListByStoreIdAsync(storeId); |
|||
|
|||
foreach (var storeOwner in storeOwners.Where(x => !ownerIds.Contains(x.OwnerId)).ToList()) |
|||
{ |
|||
await _storeOwnerRepository.DeleteAsync(storeOwner, true); |
|||
} |
|||
|
|||
foreach (var ownerId in ownerIds.Except(storeOwners.Select(x => x.OwnerId).ToList())) |
|||
{ |
|||
await _storeOwnerRepository.InsertAsync( |
|||
new StoreOwner(GuidGenerator.Create(), storeId, ownerId, CurrentTenant.Id), true); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
@page |
|||
@using EasyAbp.EShop.Stores.Localization |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
@inject IHtmlLocalizer<StoresResource> L |
|||
@model CreateModalModel |
|||
@{ |
|||
Layout = null; |
|||
} |
|||
<abp-dynamic-form abp-model="StoreOwner" data-ajaxForm="true" asp-page="CreateModal"> |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["CreateStoreOwner"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<abp-form-content /> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
</abp-dynamic-form> |
|||
@ -0,0 +1,46 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Stores.StoreOwners; |
|||
using EasyAbp.EShop.Stores.StoreOwners.Dtos; |
|||
using EasyAbp.EShop.Stores.Stores; |
|||
using EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner.ViewModels; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Identity; |
|||
|
|||
namespace EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner |
|||
{ |
|||
public class CreateModalModel : StoresPageModel |
|||
{ |
|||
[BindProperty] |
|||
public CreateEditStoreOwnerViewModel StoreOwner { get; set; } |
|||
|
|||
private readonly IStoreAppService _storeService; |
|||
private readonly IIdentityUserAppService _userAppService; |
|||
private readonly IStoreOwnerAppService _storeOwnerAppService; |
|||
|
|||
public CreateModalModel(IStoreAppService storeService, |
|||
IIdentityUserAppService userAppService, |
|||
IStoreOwnerAppService storeOwnerAppService) |
|||
{ |
|||
_storeService = storeService; |
|||
_userAppService = userAppService; |
|||
_storeOwnerAppService = storeOwnerAppService; |
|||
} |
|||
|
|||
public virtual Task OnGetAsync() |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var createDto = ObjectMapper.Map<CreateEditStoreOwnerViewModel, StoreOwnerDto>(StoreOwner); |
|||
var storeOwner = await _storeOwnerAppService.CreateAsync(createDto); |
|||
|
|||
return NoContent(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
@page |
|||
@using EasyAbp.EShop.Stores.Localization |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
@using EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner |
|||
@inject IHtmlLocalizer<StoresResource> L |
|||
@model EditModalModel |
|||
@{ |
|||
Layout = null; |
|||
} |
|||
<abp-dynamic-form abp-model="StoreOwner" data-ajaxForm="true" asp-page="EditModal"> |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["EditStore"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<abp-input asp-for="Id" /> |
|||
<abp-form-content /> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
</abp-dynamic-form> |
|||
@ -0,0 +1,53 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Stores.StoreOwners; |
|||
using EasyAbp.EShop.Stores.StoreOwners.Dtos; |
|||
using EasyAbp.EShop.Stores.Stores; |
|||
using EasyAbp.EShop.Stores.Stores.Dtos; |
|||
using EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner.ViewModels; |
|||
using EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.Stores.Store.ViewModels; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Identity; |
|||
|
|||
namespace EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner |
|||
{ |
|||
public class EditModalModel : StoresPageModel |
|||
{ |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid Id { get; set; } |
|||
|
|||
[BindProperty] public CreateEditStoreOwnerViewModel StoreOwner { get; set; } |
|||
|
|||
private readonly IStoreAppService _storeService; |
|||
private readonly IIdentityUserAppService _userAppService; |
|||
private readonly IStoreOwnerAppService _storeOwnerAppService; |
|||
|
|||
public EditModalModel(IStoreAppService storeService, |
|||
IIdentityUserAppService userAppService, |
|||
IStoreOwnerAppService storeOwnerAppService) |
|||
{ |
|||
_storeService = storeService; |
|||
_userAppService = userAppService; |
|||
_storeOwnerAppService = storeOwnerAppService; |
|||
} |
|||
|
|||
public async Task OnGetAsync() |
|||
{ |
|||
|
|||
var dto = await _storeOwnerAppService.GetAsync(Id); |
|||
StoreOwner = ObjectMapper.Map<StoreOwnerDto, CreateEditStoreOwnerViewModel>(dto); |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
await _storeOwnerAppService.UpdateAsync(Id, |
|||
ObjectMapper.Map<CreateEditStoreOwnerViewModel, StoreOwnerDto>( StoreOwner)); |
|||
return NoContent(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
@page |
|||
@using EasyAbp.EShop.Stores.Permissions |
|||
@using EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner |
|||
@using EasyAbp.EShop.Stores.Localization |
|||
@using EasyAbp.EShop.Stores.Web.Menus |
|||
@using Microsoft.AspNetCore.Authorization |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Layout |
|||
@model IndexModel |
|||
@inject IPageLayout PageLayout |
|||
@inject IHtmlLocalizer<StoresResource> L |
|||
@inject IAuthorizationService Authorization |
|||
@{ |
|||
PageLayout.Content.Title = L["StoreOwner"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:StoreOwner"].Value); |
|||
PageLayout.Content.MenuItemName = StoresMenus.StoreOwner; |
|||
} |
|||
|
|||
@section scripts |
|||
{ |
|||
<abp-script src="/Pages/EShop/Stores/StoreOwners/StoreOwner/index.js"/> |
|||
} |
|||
|
|||
@section styles |
|||
{ |
|||
<abp-style src="/Pages/EShop/Stores/StoreOwners/StoreOwner/index.css"/> |
|||
} |
|||
|
|||
<script> |
|||
let storeId = '@Model.StoreId'; |
|||
</script> |
|||
|
|||
<abp-card> |
|||
<abp-card-header> |
|||
<abp-row> |
|||
<abp-column size-md="_6"> |
|||
<abp-card-title>@L["StoreOwner"]</abp-card-title> |
|||
</abp-column> |
|||
<abp-column size-md="_6" class="text-right"> |
|||
@if (await Authorization.IsGrantedAsync(StoresPermissions.Stores.Manage)) |
|||
{ |
|||
<abp-button id="NewStoreOwnerButton" |
|||
text="@L["CreateStoreOwner"].Value" |
|||
icon="plus" |
|||
button-type="Primary"/> |
|||
} |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-header> |
|||
<abp-card-body> |
|||
<abp-table striped-rows="true" id="StoreOwnerTable"> |
|||
<thead> |
|||
<tr> |
|||
<th>@L["Actions"]</th> |
|||
<th>@L["StoreName"]</th> |
|||
<th>@L["OwnerName"]</th> |
|||
</tr> |
|||
</thead> |
|||
</abp-table> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
@ -0,0 +1,21 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
|
|||
namespace EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner |
|||
{ |
|||
public class IndexModel : StoresPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid? StoreId { get; set; } |
|||
|
|||
public IndexModel() |
|||
{ |
|||
} |
|||
|
|||
public Task OnGetAsync() |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
$(function () { |
|||
|
|||
var l = abp.localization.getResource('EasyAbpEShopStores'); |
|||
|
|||
var service = easyAbp.eShop.stores.storeOwners.storeOwner; |
|||
var storeService = easyAbp.eShop.stores.stores.store; |
|||
var userService = volo.abp.identity.identityUser; |
|||
var createModal = new abp.ModalManager(abp.appPath + 'EShop/Stores/StoreOwners/StoreOwner/CreateModal'); |
|||
var editModal = new abp.ModalManager(abp.appPath + 'EShop/Stores/StoreOwners/StoreOwner/EditModal'); |
|||
|
|||
var dataTable = $('#StoreOwnerTable').DataTable(abp.libs.datatables.normalizeConfiguration({ |
|||
processing: true, |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
autoWidth: false, |
|||
scrollCollapse: true, |
|||
order: [[1, "asc"]], |
|||
ajax: abp.libs.datatables.createAjax(service.getList, function () { |
|||
return {storeId: storeId} |
|||
}), |
|||
columnDefs: [ |
|||
{ |
|||
rowAction: { |
|||
items: |
|||
[ |
|||
{ |
|||
text: l('Edit'), |
|||
action: function (data) { |
|||
editModal.open({id: data.record.id}); |
|||
} |
|||
}, |
|||
{ |
|||
text: l('Delete'), |
|||
confirmMessage: function (data) { |
|||
return l('StoreDeletionConfirmationMessage', data.record.id); |
|||
}, |
|||
action: function (data) { |
|||
service.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info(l('SuccessfullyDeleted')); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
data: "storeId", |
|||
render: function (data, type, row, meta) { |
|||
var currentCell = $("#StoreOwnerTable").DataTable().cells({"row":meta.row, "column":meta.col}).nodes(0); |
|||
storeService.get(data).then( |
|||
x => { |
|||
$(currentCell).html(x.name); |
|||
}); |
|||
return '...'; |
|||
} |
|||
}, |
|||
{ |
|||
data: "ownerId", |
|||
render: function (data, type, row, meta) { |
|||
var currentCell = $("#StoreOwnerTable").DataTable().cells({"row":meta.row, "column":meta.col}).nodes(0); |
|||
userService.get(data).then( |
|||
x=>{ |
|||
$(currentCell).html(x.userName); |
|||
} |
|||
); |
|||
return '...'; |
|||
} |
|||
} |
|||
] |
|||
})); |
|||
|
|||
createModal.onResult(function () { |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
editModal.onResult(function () { |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
$('#NewStoreOwnerButton').click(function (e) { |
|||
e.preventDefault(); |
|||
createModal.open({storeId: storeId}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.ObjectExtending; |
|||
|
|||
namespace EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner.ViewModels |
|||
{ |
|||
public class CreateEditStoreOwnerViewModel : ExtensibleObject |
|||
{ |
|||
[Required] |
|||
public Guid StoreId { get; set; } |
|||
|
|||
|
|||
[Required] |
|||
public Guid OwnerId { get; set; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue