mirror of https://github.com/EasyAbp/EShop.git
92 changed files with 2524 additions and 73 deletions
@ -0,0 +1,223 @@ |
|||||
|
# Remove the line below if you want to inherit .editorconfig settings from higher directories |
||||
|
root = true |
||||
|
|
||||
|
# C# files |
||||
|
[*.cs] |
||||
|
|
||||
|
#### Core EditorConfig Options #### |
||||
|
|
||||
|
# Indentation and spacing |
||||
|
indent_size = 4 |
||||
|
indent_style = space |
||||
|
tab_width = 4 |
||||
|
|
||||
|
# New line preferences |
||||
|
end_of_line = crlf |
||||
|
insert_final_newline = false |
||||
|
|
||||
|
#### .NET Coding Conventions #### |
||||
|
|
||||
|
# Organize usings |
||||
|
dotnet_separate_import_directive_groups = false |
||||
|
dotnet_sort_system_directives_first = true |
||||
|
file_header_template = unset |
||||
|
|
||||
|
# this. and Me. preferences |
||||
|
dotnet_style_qualification_for_event = false |
||||
|
dotnet_style_qualification_for_field = false |
||||
|
dotnet_style_qualification_for_method = false |
||||
|
dotnet_style_qualification_for_property = false |
||||
|
|
||||
|
# Language keywords vs BCL types preferences |
||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true |
||||
|
dotnet_style_predefined_type_for_member_access = true |
||||
|
|
||||
|
# Parentheses preferences |
||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity |
||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity |
||||
|
dotnet_style_parentheses_in_other_operators = never_if_unnecessary |
||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity |
||||
|
|
||||
|
# Modifier preferences |
||||
|
dotnet_style_require_accessibility_modifiers = omit_if_default |
||||
|
|
||||
|
# Expression-level preferences |
||||
|
dotnet_style_coalesce_expression = true |
||||
|
dotnet_style_collection_initializer = true |
||||
|
dotnet_style_explicit_tuple_names = true |
||||
|
dotnet_style_namespace_match_folder = true |
||||
|
dotnet_style_null_propagation = true |
||||
|
dotnet_style_object_initializer = true |
||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line |
||||
|
dotnet_style_prefer_auto_properties = true |
||||
|
dotnet_style_prefer_compound_assignment = true |
||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true |
||||
|
dotnet_style_prefer_conditional_expression_over_return = true |
||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true |
||||
|
dotnet_style_prefer_inferred_tuple_names = true |
||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true |
||||
|
dotnet_style_prefer_simplified_boolean_expressions = true |
||||
|
dotnet_style_prefer_simplified_interpolation = true |
||||
|
|
||||
|
# Field preferences |
||||
|
dotnet_style_readonly_field = true |
||||
|
|
||||
|
# Parameter preferences |
||||
|
dotnet_code_quality_unused_parameters = all |
||||
|
|
||||
|
# Suppression preferences |
||||
|
dotnet_remove_unnecessary_suppression_exclusions = 0 |
||||
|
|
||||
|
# New line preferences |
||||
|
dotnet_style_allow_multiple_blank_lines_experimental = false |
||||
|
dotnet_style_allow_statement_immediately_after_block_experimental = false |
||||
|
|
||||
|
#### C# Coding Conventions #### |
||||
|
|
||||
|
# var preferences |
||||
|
csharp_style_var_elsewhere = false |
||||
|
csharp_style_var_for_built_in_types = false |
||||
|
csharp_style_var_when_type_is_apparent = false |
||||
|
|
||||
|
# Expression-bodied members |
||||
|
csharp_style_expression_bodied_accessors = true |
||||
|
csharp_style_expression_bodied_constructors = false |
||||
|
csharp_style_expression_bodied_indexers = true |
||||
|
csharp_style_expression_bodied_lambdas = true |
||||
|
csharp_style_expression_bodied_local_functions = false |
||||
|
csharp_style_expression_bodied_methods = false |
||||
|
csharp_style_expression_bodied_operators = false |
||||
|
csharp_style_expression_bodied_properties = true |
||||
|
|
||||
|
# Pattern matching preferences |
||||
|
csharp_style_pattern_matching_over_as_with_null_check = true |
||||
|
csharp_style_pattern_matching_over_is_with_cast_check = true |
||||
|
csharp_style_prefer_extended_property_pattern = true |
||||
|
csharp_style_prefer_not_pattern = true |
||||
|
csharp_style_prefer_pattern_matching = true |
||||
|
csharp_style_prefer_switch_expression = true |
||||
|
|
||||
|
# Null-checking preferences |
||||
|
csharp_style_conditional_delegate_call = true |
||||
|
csharp_style_prefer_parameter_null_checking = true |
||||
|
|
||||
|
# Modifier preferences |
||||
|
csharp_prefer_static_local_function = true |
||||
|
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async |
||||
|
|
||||
|
# Code-block preferences |
||||
|
csharp_prefer_braces = true |
||||
|
csharp_prefer_simple_using_statement = true |
||||
|
csharp_style_namespace_declarations = file_scoped |
||||
|
csharp_style_prefer_method_group_conversion = true |
||||
|
|
||||
|
# Expression-level preferences |
||||
|
csharp_prefer_simple_default_expression = true |
||||
|
csharp_style_deconstructed_variable_declaration = true |
||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = true |
||||
|
csharp_style_inlined_variable_declaration = true |
||||
|
csharp_style_prefer_index_operator = true |
||||
|
csharp_style_prefer_local_over_anonymous_function = true |
||||
|
csharp_style_prefer_null_check_over_type_check = true |
||||
|
csharp_style_prefer_range_operator = true |
||||
|
csharp_style_prefer_tuple_swap = true |
||||
|
csharp_style_throw_expression = true |
||||
|
csharp_style_unused_value_assignment_preference = discard_variable |
||||
|
csharp_style_unused_value_expression_statement_preference = discard_variable |
||||
|
|
||||
|
# 'using' directive preferences |
||||
|
csharp_using_directive_placement = outside_namespace:suggestion |
||||
|
|
||||
|
# New line preferences |
||||
|
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true |
||||
|
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false |
||||
|
csharp_style_allow_embedded_statements_on_same_line_experimental = true |
||||
|
|
||||
|
#### C# Formatting Rules #### |
||||
|
|
||||
|
# New line preferences |
||||
|
csharp_new_line_before_catch = true |
||||
|
csharp_new_line_before_else = true |
||||
|
csharp_new_line_before_finally = true |
||||
|
csharp_new_line_before_members_in_anonymous_types = true |
||||
|
csharp_new_line_before_members_in_object_initializers = true |
||||
|
csharp_new_line_before_open_brace = all |
||||
|
csharp_new_line_between_query_expression_clauses = true |
||||
|
|
||||
|
# Indentation preferences |
||||
|
csharp_indent_block_contents = true |
||||
|
csharp_indent_braces = false |
||||
|
csharp_indent_case_contents = true |
||||
|
csharp_indent_case_contents_when_block = true |
||||
|
csharp_indent_labels = one_less_than_current |
||||
|
csharp_indent_switch_labels = true |
||||
|
|
||||
|
# Space preferences |
||||
|
csharp_space_after_cast = false |
||||
|
csharp_space_after_colon_in_inheritance_clause = true |
||||
|
csharp_space_after_comma = true |
||||
|
csharp_space_after_dot = false |
||||
|
csharp_space_after_keywords_in_control_flow_statements = true |
||||
|
csharp_space_after_semicolon_in_for_statement = true |
||||
|
csharp_space_around_binary_operators = before_and_after |
||||
|
csharp_space_around_declaration_statements = false |
||||
|
csharp_space_before_colon_in_inheritance_clause = true |
||||
|
csharp_space_before_comma = false |
||||
|
csharp_space_before_dot = false |
||||
|
csharp_space_before_open_square_brackets = false |
||||
|
csharp_space_before_semicolon_in_for_statement = false |
||||
|
csharp_space_between_empty_square_brackets = false |
||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false |
||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false |
||||
|
csharp_space_between_method_call_parameter_list_parentheses = false |
||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false |
||||
|
csharp_space_between_method_declaration_name_and_open_parenthesis = false |
||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false |
||||
|
csharp_space_between_parentheses = false |
||||
|
csharp_space_between_square_brackets = false |
||||
|
|
||||
|
# Wrapping preferences |
||||
|
csharp_preserve_single_line_blocks = true |
||||
|
csharp_preserve_single_line_statements = true |
||||
|
|
||||
|
#### Naming styles #### |
||||
|
|
||||
|
# Naming rules |
||||
|
|
||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion |
||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface |
||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i |
||||
|
|
||||
|
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion |
||||
|
dotnet_naming_rule.types_should_be_pascal_case.symbols = types |
||||
|
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case |
||||
|
|
||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion |
||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members |
||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case |
||||
|
|
||||
|
# Symbol specifications |
||||
|
|
||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface |
||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected |
||||
|
dotnet_naming_symbols.interface.required_modifiers = |
||||
|
|
||||
|
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum |
||||
|
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected |
||||
|
dotnet_naming_symbols.types.required_modifiers = |
||||
|
|
||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method |
||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected |
||||
|
dotnet_naming_symbols.non_field_members.required_modifiers = |
||||
|
|
||||
|
# Naming styles |
||||
|
|
||||
|
dotnet_naming_style.pascal_case.required_prefix = |
||||
|
dotnet_naming_style.pascal_case.required_suffix = |
||||
|
dotnet_naming_style.pascal_case.word_separator = |
||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case |
||||
|
|
||||
|
dotnet_naming_style.begins_with_i.required_prefix = I |
||||
|
dotnet_naming_style.begins_with_i.required_suffix = |
||||
|
dotnet_naming_style.begins_with_i.word_separator = |
||||
|
dotnet_naming_style.begins_with_i.capitalization = pascal_case |
||||
@ -0,0 +1,95 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Orders.Orders.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using EasyAbp.EShop.Products.ProductDetails.Dtos; |
||||
|
using EasyAbp.EShop.Products.Products.Dtos; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.ObjectMapping; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Orders; |
||||
|
|
||||
|
public class CreateFlashSalesOrderEventHandler : IDistributedEventHandler<CreateFlashSalesOrderEto>, ITransientDependency |
||||
|
{ |
||||
|
protected INewOrderGenerator NewOrderGenerator { get; } |
||||
|
|
||||
|
protected IObjectMapper ObjectMapper { get; } |
||||
|
|
||||
|
protected IEnumerable<IOrderDiscountProvider> OrderDiscountProviders { get; } |
||||
|
|
||||
|
protected IOrderRepository OrderRepository { get; } |
||||
|
|
||||
|
protected IDistributedEventBus DistributedEventBus { get; } |
||||
|
|
||||
|
public CreateFlashSalesOrderEventHandler( |
||||
|
INewOrderGenerator newOrderGenerator, |
||||
|
IObjectMapper objectMapper, |
||||
|
IEnumerable<IOrderDiscountProvider> orderDiscountProviders, |
||||
|
IOrderRepository orderRepository, |
||||
|
IDistributedEventBus distributedEventBus) |
||||
|
{ |
||||
|
NewOrderGenerator = newOrderGenerator; |
||||
|
ObjectMapper = objectMapper; |
||||
|
OrderDiscountProviders = orderDiscountProviders; |
||||
|
OrderRepository = orderRepository; |
||||
|
DistributedEventBus = distributedEventBus; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork(true)] |
||||
|
public virtual async Task HandleEventAsync(CreateFlashSalesOrderEto eventData) |
||||
|
{ |
||||
|
//How to check product is available?
|
||||
|
//How to reduce product stock?
|
||||
|
|
||||
|
var input = new CreateOrderDto() |
||||
|
{ |
||||
|
StoreId = eventData.StoreId, |
||||
|
CustomerRemark = eventData.CustomerRemark, |
||||
|
OrderLines = new List<CreateOrderLineDto>() |
||||
|
{ |
||||
|
new CreateOrderLineDto() |
||||
|
{ |
||||
|
ProductId = eventData.Plan.ProductId, |
||||
|
ProductSkuId = eventData.Plan.ProductSkuId, |
||||
|
Quantity = eventData.Quantity |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
var productDict = new Dictionary<Guid, ProductDto>() |
||||
|
{ |
||||
|
{eventData.Product.Id, ObjectMapper.Map<FlashSalesProductEto,ProductDto>(eventData.Product)} |
||||
|
}; |
||||
|
var productDetailDict = new Dictionary<Guid, ProductDetailDto>() |
||||
|
{ |
||||
|
{eventData.ProductDetail.Id, ObjectMapper.Map<FlashSalesProductDetailEto,ProductDetailDto>(eventData.ProductDetail)} |
||||
|
}; |
||||
|
|
||||
|
var order = await NewOrderGenerator.GenerateAsync(eventData.UserId, input, productDict, productDetailDict); |
||||
|
|
||||
|
await DiscountOrderAsync(order, productDict); |
||||
|
|
||||
|
await OrderRepository.InsertAsync(order, autoSave: true); |
||||
|
|
||||
|
await DistributedEventBus.PublishAsync(new CreateFlashSalesOrderCompleteEto() |
||||
|
{ |
||||
|
TenantId = eventData.TenantId, |
||||
|
PlanId = eventData.PlanId, |
||||
|
OrderId = order.Id, |
||||
|
UserId = eventData.UserId, |
||||
|
StoreId = eventData.StoreId, |
||||
|
PendingResultId = eventData.PendingResultId, |
||||
|
Success = true |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task DiscountOrderAsync(Order order, Dictionary<Guid, ProductDto> productDict) |
||||
|
{ |
||||
|
foreach (var provider in OrderDiscountProviders) |
||||
|
{ |
||||
|
await provider.DiscountAsync(order, productDict); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Orders; |
||||
|
|
||||
|
public class FlashSalesOrderCreationAuthorizationHandler : OrderCreationAuthorizationHandler |
||||
|
{ |
||||
|
protected IAbpLazyServiceProvider LazyServiceProvider { get; } |
||||
|
|
||||
|
public FlashSalesOrderCreationAuthorizationHandler(IAbpLazyServiceProvider lazyServiceProvider) |
||||
|
{ |
||||
|
LazyServiceProvider = lazyServiceProvider; |
||||
|
} |
||||
|
|
||||
|
protected override async Task HandleOrderCreationAsync(AuthorizationHandlerContext context, |
||||
|
OrderOperationAuthorizationRequirement requirement, OrderCreationResource resource) |
||||
|
{ |
||||
|
var flashSalesPlanAppService = LazyServiceProvider.LazyGetRequiredService<IFlashSalesPlanAppService>(); |
||||
|
foreach (var orderLine in resource.Input.OrderLines) |
||||
|
{ |
||||
|
var plans = await flashSalesPlanAppService.GetListAsync(new FlashSalesPlanGetListInput() |
||||
|
{ |
||||
|
StoreId = resource.Input.StoreId, |
||||
|
ProductId = orderLine.ProductId, |
||||
|
ProductSkuId = orderLine.ProductSkuId, |
||||
|
OnlyShowPublished = true |
||||
|
}); |
||||
|
if (plans.Items.Count > 0) |
||||
|
{ |
||||
|
context.Fail(); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
context.Succeed(requirement); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System; |
||||
|
using AutoMapper; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using EasyAbp.EShop.Products.ProductDetails.Dtos; |
||||
|
using EasyAbp.EShop.Products.Products; |
||||
|
using EasyAbp.EShop.Products.Products.Dtos; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Json; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders |
||||
|
{ |
||||
|
public class EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile : Profile, ISingletonDependency |
||||
|
{ |
||||
|
public EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile(IJsonSerializer jsonSerializer) |
||||
|
{ |
||||
|
/* You can configure your AutoMapper mapping configuration here. |
||||
|
* Alternatively, you can split your mapping configurations |
||||
|
* into multiple profile classes for a better organization. */ |
||||
|
CreateMap<FlashSalesProductEto, ProductDto>(MemberList.Source) |
||||
|
.ForSourceMember(x => x.TenantId, opt => opt.DoNotValidate()) |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<FlashSalesProductSkuEto, ProductSkuDto>(MemberList.Source) |
||||
|
.ForMember(x => x.AttributeOptionIds, opt => opt.Ignore()) |
||||
|
.AfterMap((src, dest) => dest.AttributeOptionIds = jsonSerializer.Deserialize<List<Guid>>(src.SerializedAttributeOptionIds)) |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<FlashSalesProductAttributeEto, ProductAttributeDto>(MemberList.Source) |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<FlashSalesProductAttributeOptionEto, ProductAttributeOptionDto>(MemberList.Source) |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<FlashSalesProductDetailEto, ProductDetailDto>(MemberList.Source) |
||||
|
.MapExtraProperties(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,12 +1,37 @@ |
|||||
using EasyAbp.EShop.Orders; |
using EasyAbp.EShop.Orders; |
||||
|
using EasyAbp.EShop.Orders.Orders; |
||||
|
using EasyAbp.EShop.Products; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AutoMapper; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.FlashSales; |
namespace EasyAbp.EShop.Plugins.FlashSales; |
||||
|
|
||||
[DependsOn( |
[DependsOn( |
||||
typeof(EShopOrdersApplicationModule), |
typeof(EShopOrdersApplicationModule), |
||||
|
typeof(EShopProductsApplicationContractsModule), |
||||
typeof(EShopPluginsFlashSalesApplicationContractsModule) |
typeof(EShopPluginsFlashSalesApplicationContractsModule) |
||||
)] |
)] |
||||
public class EShopOrdersPluginsFlashSalesApplicationModule : AbpModule |
public class EShopOrdersPluginsFlashSalesApplicationModule : AbpModule |
||||
{ |
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddSingleton<IAuthorizationHandler, FlashSalesOrderCreationAuthorizationHandler>(); |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAutoMapperObjectMapper<EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile>(); |
||||
|
Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.Configurators.Add(abpAutoMapperConfigurationContext => |
||||
|
{ |
||||
|
var profile = abpAutoMapperConfigurationContext.ServiceProvider |
||||
|
.GetRequiredService<EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile>(); |
||||
|
|
||||
|
abpAutoMapperConfigurationContext.MapperConfiguration.AddProfile(profile); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,9 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
|
||||
|
public class CreateOrderInput : ExtensibleEntityDto |
||||
|
{ |
||||
|
public string CustomerRemark { get; set; } |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
|
||||
|
[Serializable] |
||||
|
public class FlashSalesPlanCreateDto : ExtensibleEntityDto |
||||
|
{ |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public DateTime BeginTime { get; set; } |
||||
|
|
||||
|
public DateTime EndTime { get; set; } |
||||
|
|
||||
|
public Guid ProductId { get; set; } |
||||
|
|
||||
|
public Guid ProductSkuId { get; set; } |
||||
|
|
||||
|
public bool IsPublished { get; set; } |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
|
||||
|
[Serializable] |
||||
|
public class FlashSalesPlanDto : ExtensibleFullAuditedEntityDto<Guid>, IHasConcurrencyStamp |
||||
|
{ |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public DateTime BeginTime { get; set; } |
||||
|
|
||||
|
public DateTime EndTime { get; set; } |
||||
|
|
||||
|
public Guid ProductId { get; set; } |
||||
|
|
||||
|
public Guid ProductSkuId { get; set; } |
||||
|
|
||||
|
public bool IsPublished { get; set; } |
||||
|
|
||||
|
public string ConcurrencyStamp { get; set; } |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
|
||||
|
[Serializable] |
||||
|
public class FlashSalesPlanGetListInput : ExtensiblePagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public Guid? StoreId { get; set; } |
||||
|
|
||||
|
public Guid? ProductId { get; set; } |
||||
|
|
||||
|
public Guid? ProductSkuId { get; set; } |
||||
|
|
||||
|
public bool OnlyShowPublished { get; set; } |
||||
|
|
||||
|
public DateTime? Start { get; set; } |
||||
|
|
||||
|
public DateTime? End { get; set; } |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
|
||||
|
[Serializable] |
||||
|
public class FlashSalesPlanUpdateDto : ExtensibleEntityDto, IHasConcurrencyStamp |
||||
|
{ |
||||
|
public DateTime BeginTime { get; set; } |
||||
|
|
||||
|
public DateTime EndTime { get; set; } |
||||
|
|
||||
|
public Guid ProductId { get; set; } |
||||
|
|
||||
|
public Guid ProductSkuId { get; set; } |
||||
|
|
||||
|
public bool IsPublished { get; set; } |
||||
|
|
||||
|
public string ConcurrencyStamp { get; set; } |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public interface IFlashSalesPlanAppService : |
||||
|
ICrudAppService< |
||||
|
FlashSalesPlanDto, |
||||
|
Guid, |
||||
|
FlashSalesPlanGetListInput, |
||||
|
FlashSalesPlanCreateDto, |
||||
|
FlashSalesPlanUpdateDto> |
||||
|
{ |
||||
|
Task PreOrderAsync(Guid id); |
||||
|
|
||||
|
Task CheckPreOrderAsync(Guid id); |
||||
|
|
||||
|
Task CreateOrderAsync(Guid id, CreateOrderInput input); |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos; |
||||
|
|
||||
|
public class FlashSalesResultDto : ExtensibleFullAuditedEntityDto<Guid> |
||||
|
{ |
||||
|
public virtual Guid StoreId { get; set; } |
||||
|
|
||||
|
public virtual Guid PlanId { get; set; } |
||||
|
|
||||
|
public virtual FlashSalesResultStatus Status { get; set; } |
||||
|
|
||||
|
public virtual string Reason { get; set; } |
||||
|
|
||||
|
public virtual Guid UserId { get; set; } |
||||
|
|
||||
|
public virtual Guid? OrderId { get; set; } |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos; |
||||
|
|
||||
|
public class FlashSalesResultGetListInput : ExtensiblePagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public virtual Guid? StoreId { get; set; } |
||||
|
|
||||
|
public virtual Guid? PlanId { get; set; } |
||||
|
|
||||
|
public virtual FlashSalesResultStatus? Status { get; set; } |
||||
|
|
||||
|
public virtual Guid? UserId { get; set; } |
||||
|
|
||||
|
public virtual Guid? OrderId { get; set; } |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public interface IFlashSalesResultAppService : |
||||
|
IReadOnlyAppService< |
||||
|
FlashSalesResultDto, |
||||
|
Guid, |
||||
|
FlashSalesResultGetListInput> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -1,13 +1,28 @@ |
|||||
using Volo.Abp.Reflection; |
using Volo.Abp.Reflection; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.FlashSales.Permissions; |
namespace EasyAbp.EShop.Plugins.FlashSales.Permissions; |
||||
|
|
||||
public class FlashSalesPermissions |
public class FlashSalesPermissions |
||||
{ |
{ |
||||
public const string GroupName = "FlashSales"; |
public const string GroupName = "EasyAbp.EShop.Plugins.FlashSales"; |
||||
|
|
||||
public static string[] GetAll() |
public static string[] GetAll() |
||||
{ |
{ |
||||
return ReflectionHelper.GetPublicConstantsRecursively(typeof(FlashSalesPermissions)); |
return ReflectionHelper.GetPublicConstantsRecursively(typeof(FlashSalesPermissions)); |
||||
} |
} |
||||
|
|
||||
|
public class FlashSalesPlan |
||||
|
{ |
||||
|
public const string Default = GroupName + ".FlashSalesPlan"; |
||||
|
public const string Manage = Default + ".Manage"; |
||||
|
public const string Update = Default + ".Update"; |
||||
|
public const string Create = Default + ".Create"; |
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
} |
||||
|
|
||||
|
public class FlashSalesResult |
||||
|
{ |
||||
|
public const string Default = GroupName + ".FlashSalesResult"; |
||||
|
public const string Manage = Default + ".Manage"; |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -1,13 +1,48 @@ |
|||||
using AutoMapper; |
using System.Linq; |
||||
|
using AutoMapper; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos; |
||||
|
using EasyAbp.EShop.Products.ProductDetails.Dtos; |
||||
|
using EasyAbp.EShop.Products.Products.Dtos; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Json; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.FlashSales; |
namespace EasyAbp.EShop.Plugins.FlashSales; |
||||
|
|
||||
public class FlashSalesApplicationAutoMapperProfile : Profile |
public class FlashSalesApplicationAutoMapperProfile : Profile, ISingletonDependency |
||||
{ |
{ |
||||
public FlashSalesApplicationAutoMapperProfile() |
public FlashSalesApplicationAutoMapperProfile(IJsonSerializer jsonSerializer) |
||||
{ |
{ |
||||
/* You can configure your AutoMapper mapping configuration here. |
/* You can configure your AutoMapper mapping configuration here. |
||||
* Alternatively, you can split your mapping configurations |
* Alternatively, you can split your mapping configurations |
||||
* into multiple profile classes for a better organization. */ |
* into multiple profile classes for a better organization. */ |
||||
|
CreateMap<FlashSalesPlan, FlashSalesPlanDto>() |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<FlashSalesPlanDto, FlashSalesPlanEto>() |
||||
|
.ForMember(x => x.TenantId, opt => opt.Ignore()) |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<FlashSalesPlanCreateDto, FlashSalesPlan>(MemberList.Source); |
||||
|
CreateMap<FlashSalesPlanUpdateDto, FlashSalesPlan>(MemberList.Source); |
||||
|
CreateMap<FlashSalesPlan, FlashSalesPlanCacheItem>() |
||||
|
.MapExtraProperties(); |
||||
|
|
||||
|
CreateMap<FlashSalesResult, FlashSalesResultDto>() |
||||
|
.MapExtraProperties(); |
||||
|
|
||||
|
CreateMap<ProductDto, FlashSalesProductEto>() |
||||
|
.ForMember(x => x.TenantId, opt => opt.Ignore()) |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<ProductSkuDto, FlashSalesProductSkuEto>() |
||||
|
.ForMember(x => x.SerializedAttributeOptionIds, opt => opt.Ignore()) |
||||
|
.AfterMap((src, dest) => dest.SerializedAttributeOptionIds = jsonSerializer.Serialize(src.AttributeOptionIds.OrderBy(x => x))) |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<ProductAttributeDto, FlashSalesProductAttributeEto>() |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<ProductAttributeOptionDto, FlashSalesProductAttributeOptionEto>() |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<ProductDetailDto, FlashSalesProductDetailEto>() |
||||
|
.MapExtraProperties(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,362 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Numerics; |
||||
|
using System.Security.Cryptography; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.Permissions; |
||||
|
using EasyAbp.EShop.Products.ProductDetails; |
||||
|
using EasyAbp.EShop.Products.ProductDetails.Dtos; |
||||
|
using EasyAbp.EShop.Products.Products; |
||||
|
using EasyAbp.EShop.Products.Products.Dtos; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.Extensions.Caching.Distributed; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.DistributedLocking; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.Users; |
||||
|
using static EasyAbp.EShop.Products.Permissions.ProductsPermissions; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
[Authorize] |
||||
|
public class FlashSalesPlanAppService : |
||||
|
CrudAppService<FlashSalesPlan, FlashSalesPlanDto, Guid, FlashSalesPlanGetListInput, FlashSalesPlanCreateDto, FlashSalesPlanUpdateDto>, |
||||
|
IFlashSalesPlanAppService |
||||
|
{ |
||||
|
protected override string GetPolicyName { get; set; } |
||||
|
protected override string GetListPolicyName { get; set; } |
||||
|
protected override string CreatePolicyName { get; set; } = FlashSalesPermissions.FlashSalesPlan.Create; |
||||
|
protected override string UpdatePolicyName { get; set; } = FlashSalesPermissions.FlashSalesPlan.Update; |
||||
|
protected override string DeletePolicyName { get; set; } = FlashSalesPermissions.FlashSalesPlan.Delete; |
||||
|
|
||||
|
protected IFlashSalesPlanRepository FlashSalesPlanRepository { get; } |
||||
|
protected IProductAppService ProductAppService { get; } |
||||
|
protected IProductDetailAppService ProductDetailAppService { get; } |
||||
|
protected IDistributedCache TokenDistributedCache { get; } |
||||
|
protected IDistributedCache<FlashSalesPlanCacheItem, Guid> DistributedCache { get; } |
||||
|
protected IDistributedEventBus DistributedEventBus { get; } |
||||
|
protected FlashSalesPlanManager FlashSalesPlanManager { get; } |
||||
|
protected IFlashSalesResultRepository FlashSalesResultRepository { get; } |
||||
|
protected IAbpDistributedLock DistributedLock { get; } |
||||
|
|
||||
|
public FlashSalesPlanAppService( |
||||
|
IFlashSalesPlanRepository flashSalesPlanRepository, |
||||
|
IProductAppService productAppService, |
||||
|
IProductDetailAppService productDetailAppService, |
||||
|
IDistributedCache tokenDistributedCache, |
||||
|
IDistributedCache<FlashSalesPlanCacheItem, Guid> distributedCache, |
||||
|
IDistributedEventBus distributedEventBus, |
||||
|
FlashSalesPlanManager flashSalesPlanManager, |
||||
|
IFlashSalesResultRepository flashSalesResultRepository, |
||||
|
IAbpDistributedLock distributedLock) |
||||
|
: base(flashSalesPlanRepository) |
||||
|
{ |
||||
|
FlashSalesPlanRepository = flashSalesPlanRepository; |
||||
|
ProductAppService = productAppService; |
||||
|
ProductDetailAppService = productDetailAppService; |
||||
|
TokenDistributedCache = tokenDistributedCache; |
||||
|
DistributedCache = distributedCache; |
||||
|
DistributedEventBus = distributedEventBus; |
||||
|
FlashSalesPlanManager = flashSalesPlanManager; |
||||
|
FlashSalesResultRepository = flashSalesResultRepository; |
||||
|
DistributedLock = distributedLock; |
||||
|
} |
||||
|
|
||||
|
public override async Task<FlashSalesPlanDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
await CheckGetPolicyAsync(); |
||||
|
|
||||
|
var flashSalesPlan = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
if (!flashSalesPlan.IsPublished) |
||||
|
{ |
||||
|
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesPlan.Manage); |
||||
|
} |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(flashSalesPlan); |
||||
|
} |
||||
|
|
||||
|
public override async Task<FlashSalesPlanDto> CreateAsync(FlashSalesPlanCreateDto input) |
||||
|
{ |
||||
|
await CheckCreatePolicyAsync(); |
||||
|
|
||||
|
var flashSalesPlan = await FlashSalesPlanManager.CreateAsync( |
||||
|
input.StoreId, |
||||
|
input.BeginTime, |
||||
|
input.EndTime, |
||||
|
input.ProductId, |
||||
|
input.ProductSkuId, |
||||
|
input.IsPublished |
||||
|
); |
||||
|
|
||||
|
await FlashSalesPlanRepository.InsertAsync(flashSalesPlan, autoSave: true); |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(flashSalesPlan); |
||||
|
} |
||||
|
|
||||
|
public override async Task<FlashSalesPlanDto> UpdateAsync(Guid id, FlashSalesPlanUpdateDto input) |
||||
|
{ |
||||
|
await CheckUpdatePolicyAsync(); |
||||
|
|
||||
|
var flashSalesPlan = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
await FlashSalesPlanManager.UpdateAsync( |
||||
|
flashSalesPlan, |
||||
|
input.BeginTime, |
||||
|
input.EndTime, |
||||
|
input.ProductId, |
||||
|
input.ProductSkuId, |
||||
|
input.IsPublished |
||||
|
); |
||||
|
|
||||
|
flashSalesPlan.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp); |
||||
|
|
||||
|
await FlashSalesPlanRepository.UpdateAsync(flashSalesPlan, autoSave: true); |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(flashSalesPlan); |
||||
|
} |
||||
|
|
||||
|
protected override async Task<IQueryable<FlashSalesPlan>> CreateFilteredQueryAsync(FlashSalesPlanGetListInput input) |
||||
|
{ |
||||
|
if (!input.OnlyShowPublished) |
||||
|
{ |
||||
|
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesPlan.Manage); |
||||
|
} |
||||
|
|
||||
|
return (await base.CreateFilteredQueryAsync(input)) |
||||
|
.WhereIf(input.StoreId.HasValue, x => x.StoreId == input.StoreId.Value) |
||||
|
.WhereIf(input.ProductId.HasValue, x => x.ProductId == input.ProductId.Value) |
||||
|
.WhereIf(input.ProductSkuId.HasValue, x => x.ProductSkuId == input.ProductSkuId.Value) |
||||
|
.WhereIf(input.OnlyShowPublished, x => x.IsPublished) |
||||
|
.WhereIf(input.Start.HasValue, x => x.BeginTime >= input.Start.Value) |
||||
|
.WhereIf(input.End.HasValue, x => x.BeginTime <= input.End.Value); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task PreOrderAsync(Guid id) |
||||
|
{ |
||||
|
var plan = await GetFlashSalesPlanCacheAsync(id); |
||||
|
var product = await ProductAppService.GetAsync(plan.ProductId); |
||||
|
var productSku = product.GetSkuById(plan.ProductSkuId); |
||||
|
|
||||
|
if (!product.IsPublished) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.ProductIsNotPublished); |
||||
|
} |
||||
|
|
||||
|
if (product.InventoryStrategy != InventoryStrategy.FlashSales) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.IsNotFlashSalesProduct); |
||||
|
} |
||||
|
|
||||
|
if (!plan.IsPublished) |
||||
|
{ |
||||
|
throw new EntityNotFoundException(typeof(FlashSalesPlan), id); |
||||
|
} |
||||
|
|
||||
|
if (Clock.Now > plan.EndTime) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.FlashSalesPlanIsExpired); |
||||
|
} |
||||
|
|
||||
|
await SetCacheHashTokenAsync(plan, product, productSku); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task CheckPreOrderAsync(Guid id) |
||||
|
{ |
||||
|
var plan = await GetFlashSalesPlanCacheAsync(id); |
||||
|
if (Clock.Now > plan.EndTime) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.FlashSalesPlanIsExpired); |
||||
|
} |
||||
|
|
||||
|
var cacheHashToken = await GetCacheHashTokenAsync(plan); |
||||
|
if (cacheHashToken.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred); |
||||
|
} |
||||
|
|
||||
|
var product = await ProductAppService.GetAsync(plan.ProductId); |
||||
|
var productSku = product.GetSkuById(plan.ProductSkuId); |
||||
|
|
||||
|
if (!await ComparekHashTokenAsync(cacheHashToken, plan, product, productSku)) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task CreateOrderAsync(Guid id, CreateOrderInput input) |
||||
|
{ |
||||
|
var plan = await GetFlashSalesPlanCacheAsync(id); |
||||
|
var now = Clock.Now; |
||||
|
if (plan.BeginTime > now) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.ProductIsNotPublished); |
||||
|
} |
||||
|
|
||||
|
if (now > plan.EndTime) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.FlashSalesPlanIsExpired); |
||||
|
} |
||||
|
|
||||
|
var cacheHashToken = await GetCacheHashTokenAsync(plan); |
||||
|
if (cacheHashToken.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred); |
||||
|
} |
||||
|
|
||||
|
var product = await ProductAppService.GetAsync(plan.ProductId); |
||||
|
var productSku = product.GetSkuById(plan.ProductSkuId); |
||||
|
|
||||
|
if (!await ComparekHashTokenAsync(cacheHashToken, plan, product, productSku)) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.PreOrderExipred); |
||||
|
} |
||||
|
|
||||
|
await RemoveCacheHashTokenAsync(plan); |
||||
|
|
||||
|
var userId = CurrentUser.GetId(); |
||||
|
|
||||
|
var result = await CreatePendingFlashSalesResultAsync(plan, userId); |
||||
|
|
||||
|
var CreateFlashSalesOrderEto = await PrepareCreateFlashSalesOrderEtoAsync(plan, product, productSku, result, input, userId, now); |
||||
|
|
||||
|
await DistributedEventBus.PublishAsync(CreateFlashSalesOrderEto); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<CreateFlashSalesOrderEto> PrepareCreateFlashSalesOrderEtoAsync( |
||||
|
FlashSalesPlanDto plan, |
||||
|
ProductDto product, |
||||
|
ProductSkuDto productSku, |
||||
|
FlashSalesResult result, |
||||
|
CreateOrderInput input, |
||||
|
Guid userId, |
||||
|
DateTime now) |
||||
|
{ |
||||
|
FlashSalesProductDetailEto productDetail = null; |
||||
|
var productDetailId = productSku.ProductDetailId ?? product.ProductDetailId; |
||||
|
if (productDetailId.HasValue) |
||||
|
{ |
||||
|
productDetail = ObjectMapper.Map<ProductDetailDto, FlashSalesProductDetailEto>(await ProductDetailAppService.GetAsync(productDetailId.Value)); |
||||
|
} |
||||
|
var productEto = ObjectMapper.Map<ProductDto, FlashSalesProductEto>(product); |
||||
|
productEto.TenantId = CurrentTenant.Id; |
||||
|
var planEto = ObjectMapper.Map<FlashSalesPlanDto, FlashSalesPlanEto>(plan); |
||||
|
planEto.TenantId = CurrentTenant.Id; |
||||
|
|
||||
|
var eto = new CreateFlashSalesOrderEto() |
||||
|
{ |
||||
|
TenantId = CurrentTenant.Id, |
||||
|
PlanId = plan.Id, |
||||
|
UserId = userId, |
||||
|
PendingResultId = result.Id, |
||||
|
StoreId = plan.StoreId, |
||||
|
CreateTime = now, |
||||
|
CustomerRemark = input.CustomerRemark, |
||||
|
Quantity = 1,//should configure
|
||||
|
Product = productEto, |
||||
|
ProductDetail = productDetail, |
||||
|
Plan = planEto |
||||
|
}; |
||||
|
|
||||
|
foreach (var item in input.ExtraProperties) |
||||
|
{ |
||||
|
eto.ExtraProperties.Add(item.Key, item.Value); |
||||
|
} |
||||
|
|
||||
|
return eto; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<FlashSalesPlanCacheItem> GetFlashSalesPlanCacheAsync(Guid id) |
||||
|
{ |
||||
|
return await DistributedCache.GetOrAddAsync(id, async () => |
||||
|
{ |
||||
|
var flashSalesPlan = await FlashSalesPlanRepository.GetAsync(id); |
||||
|
return ObjectMapper.Map<FlashSalesPlan, FlashSalesPlanCacheItem>(flashSalesPlan); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected virtual Task<string> GetCacheKeyAsync(FlashSalesPlanDto plan) |
||||
|
{ |
||||
|
return Task.FromResult($"eshopflashsales_{CurrentUser.Id}_{plan.ProductSkuId}"); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> GetCacheHashTokenAsync(FlashSalesPlanDto plan) |
||||
|
{ |
||||
|
return await TokenDistributedCache.GetStringAsync(await GetCacheKeyAsync(plan)); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task RemoveCacheHashTokenAsync(FlashSalesPlanDto plan) |
||||
|
{ |
||||
|
await TokenDistributedCache.RemoveAsync(await GetCacheKeyAsync(plan)); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task SetCacheHashTokenAsync(FlashSalesPlanDto plan, ProductDto product, ProductSkuDto productSku) |
||||
|
{ |
||||
|
await TokenDistributedCache.SetStringAsync(await GetCacheKeyAsync(plan), await GetHashTokenAsync(plan, product, productSku), new DistributedCacheEntryOptions() |
||||
|
{ |
||||
|
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(3) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected virtual Task<string> GetHashTokenAsync(FlashSalesPlanDto plan, ProductDto product, ProductSkuDto productSku) |
||||
|
{ |
||||
|
using var md5 = MD5.Create(); |
||||
|
var inputBytes = Encoding.UTF8.GetBytes($"{plan.LastModificationTime}|{product.LastModificationTime}|{productSku.LastModificationTime}"); |
||||
|
var sb = new StringBuilder(); |
||||
|
foreach (var t in md5.ComputeHash(inputBytes)) |
||||
|
{ |
||||
|
sb.Append(t.ToString("X2")); |
||||
|
} |
||||
|
return Task.FromResult(sb.ToString()); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<bool> ComparekHashTokenAsync(string cacheHashToken, FlashSalesPlanDto plan, ProductDto product, ProductSkuDto productSku) |
||||
|
{ |
||||
|
if (cacheHashToken.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
var hashToken = await GetHashTokenAsync(plan, product, productSku); |
||||
|
|
||||
|
return cacheHashToken == hashToken; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<FlashSalesResult> CreatePendingFlashSalesResultAsync(FlashSalesPlanDto plan, Guid userId) |
||||
|
{ |
||||
|
var lockKey = $"create-flash-sales-order-{plan.Id}-{userId}"; |
||||
|
|
||||
|
await using var handle = await DistributedLock.TryAcquireAsync(lockKey); |
||||
|
|
||||
|
if (handle == null) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.CreateFlashSalesOrderBusy); |
||||
|
} |
||||
|
|
||||
|
// Prevent repeat submit
|
||||
|
if (await FlashSalesResultRepository.AnyAsync(x => x.PlanId == plan.Id && x.UserId == userId)) |
||||
|
{ |
||||
|
throw new BusinessException(FlashSalesErrorCodes.AlreadySubmitCreateFlashSalesOrder); |
||||
|
} |
||||
|
|
||||
|
var result = new FlashSalesResult( |
||||
|
id: GuidGenerator.Create(), |
||||
|
tenantId: CurrentTenant.Id, |
||||
|
storeId: plan.StoreId, |
||||
|
planId: plan.Id, |
||||
|
status: FlashSalesResultStatus.Pending, |
||||
|
reason: null, |
||||
|
userId: userId, |
||||
|
orderId: null |
||||
|
); |
||||
|
return await FlashSalesResultRepository.InsertAsync(result, autoSave: true); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.Domain.Entities.Events; |
||||
|
using Volo.Abp.EventBus; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesPlanCacheInvalidator : ILocalEventHandler<EntityChangedEventData<FlashSalesPlan>> |
||||
|
{ |
||||
|
protected IDistributedCache<FlashSalesPlanCacheItem, Guid> DistributedCache { get; } |
||||
|
|
||||
|
public virtual async Task HandleEventAsync(EntityChangedEventData<FlashSalesPlan> eventData) |
||||
|
{ |
||||
|
await DistributedCache.RemoveAsync(eventData.Entity.Id); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
[Serializable] |
||||
|
public class FlashSalesPlanCacheItem : FlashSalesPlanDto |
||||
|
{ |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.Permissions; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public class FlashSalesResultAppService : |
||||
|
ReadOnlyAppService<FlashSalesResult, FlashSalesResultDto, Guid, FlashSalesResultGetListInput>, |
||||
|
IFlashSalesResultAppService |
||||
|
{ |
||||
|
protected override string GetPolicyName { get; set; } |
||||
|
protected override string GetListPolicyName { get; set; } |
||||
|
|
||||
|
protected IFlashSalesResultRepository FlashSalesResultRepository { get; } |
||||
|
|
||||
|
public FlashSalesResultAppService(IFlashSalesResultRepository flashSalesResultRepository) : base(flashSalesResultRepository) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override async Task<FlashSalesResultDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
await CheckGetPolicyAsync(); |
||||
|
|
||||
|
var flashSalesPlan = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
if (flashSalesPlan.UserId != CurrentUser.Id) |
||||
|
{ |
||||
|
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesResult.Manage); |
||||
|
} |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(flashSalesPlan); |
||||
|
} |
||||
|
|
||||
|
protected override async Task<IQueryable<FlashSalesResult>> CreateFilteredQueryAsync(FlashSalesResultGetListInput input) |
||||
|
{ |
||||
|
if (input.UserId != CurrentUser.Id) |
||||
|
{ |
||||
|
await CheckPolicyAsync(FlashSalesPermissions.FlashSalesResult.Manage); |
||||
|
} |
||||
|
|
||||
|
return (await base.CreateFilteredQueryAsync(input)) |
||||
|
.WhereIf(input.StoreId.HasValue, x => x.StoreId == input.StoreId.Value) |
||||
|
.WhereIf(input.PlanId.HasValue, x => x.PlanId == input.PlanId.Value) |
||||
|
.WhereIf(input.Status.HasValue, x => x.Status == input.Status.Value) |
||||
|
.WhereIf(input.UserId.HasValue, x => x.UserId == input.UserId.Value) |
||||
|
.WhereIf(input.OrderId.HasValue, x => x.OrderId == input.OrderId.Value); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class CreateFlashSalesOrderCompleteEto : ExtensibleObject, IMultiTenant |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid PendingResultId { get; set; } |
||||
|
|
||||
|
public bool Success { get; set; } |
||||
|
|
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public Guid PlanId { get; set; } |
||||
|
|
||||
|
public string Reason { get; set; } |
||||
|
|
||||
|
public Guid UserId { get; set; } |
||||
|
|
||||
|
public Guid? OrderId { get; set; } |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Products.Products; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
[Serializable] |
||||
|
public class CreateFlashSalesOrderEto : ExtensibleObject, IMultiTenant |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public Guid PlanId { get; set; } |
||||
|
|
||||
|
public Guid UserId { get; set; } |
||||
|
|
||||
|
public Guid PendingResultId { get; set; } |
||||
|
|
||||
|
public DateTime CreateTime { get; set; } |
||||
|
|
||||
|
public string CustomerRemark { get; set; } |
||||
|
|
||||
|
public int Quantity { get; set; } |
||||
|
|
||||
|
public FlashSalesProductEto Product { get; set; } |
||||
|
|
||||
|
public FlashSalesProductDetailEto ProductDetail { get; set; } |
||||
|
|
||||
|
public FlashSalesPlanEto Plan { get; set; } |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesPlanEto : FullAuditedEntityEto<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public DateTime BeginTime { get; set; } |
||||
|
|
||||
|
public DateTime EndTime { get; set; } |
||||
|
|
||||
|
public Guid ProductId { get; set; } |
||||
|
|
||||
|
public Guid ProductSkuId { get; set; } |
||||
|
|
||||
|
public bool IsPublished { get; set; } |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using EasyAbp.EShop.Products.Products; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesProductAttributeEto : FullAuditedEntityEto<Guid>, IProductAttribute |
||||
|
{ |
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public int DisplayOrder { get; set; } |
||||
|
|
||||
|
public List<FlashSalesProductAttributeOptionEto> ProductAttributeOptions { get; set; } |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Products.Products; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesProductAttributeOptionEto : FullAuditedEntityEto<Guid>, IProductAttributeOption |
||||
|
{ |
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public int DisplayOrder { get; set; } |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using EasyAbp.EShop.Products.Products; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesProductEto : FullAuditedEntityEto<Guid>, IProduct, IMultiTenant |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public string ProductGroupName { get; set; } |
||||
|
|
||||
|
public Guid? ProductDetailId { get; set; } |
||||
|
|
||||
|
public string UniqueName { get; set; } |
||||
|
|
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public InventoryStrategy InventoryStrategy { get; set; } |
||||
|
|
||||
|
public string InventoryProviderName { get; set; } |
||||
|
|
||||
|
public string MediaResources { get; set; } |
||||
|
|
||||
|
public int DisplayOrder { get; set; } |
||||
|
|
||||
|
public bool IsPublished { get; set; } |
||||
|
|
||||
|
public bool IsStatic { get; set; } |
||||
|
|
||||
|
public bool IsHidden { get; set; } |
||||
|
|
||||
|
public List<FlashSalesProductAttributeEto> ProductAttributes { get; set; } |
||||
|
|
||||
|
public List<FlashSalesProductSkuEto> ProductSkus { get; set; } |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Products.Products; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesProductSkuEto : FullAuditedEntityEto<Guid>, IProductSku |
||||
|
{ |
||||
|
public string SerializedAttributeOptionIds { get; set; } |
||||
|
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public string Currency { get; set; } |
||||
|
|
||||
|
public decimal? OriginalPrice { get; set; } |
||||
|
|
||||
|
public decimal Price { get; set; } |
||||
|
|
||||
|
public int OrderMinQuantity { get; set; } |
||||
|
|
||||
|
public int OrderMaxQuantity { get; set; } |
||||
|
|
||||
|
public string MediaResources { get; set; } |
||||
|
|
||||
|
public Guid? ProductDetailId { get; set; } |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesProductDetailEto : FullAuditedEntityEto<Guid> |
||||
|
{ |
||||
|
public Guid? StoreId { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public enum FlashSalesResultStatus |
||||
|
{ |
||||
|
Pending, |
||||
|
Successful, |
||||
|
Failed |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales; |
||||
|
|
||||
|
public class FullAuditedEntityEto<TPrimaryKey> : ExtensibleObject |
||||
|
{ |
||||
|
public TPrimaryKey Id { get; set; } |
||||
|
|
||||
|
public DateTime CreationTime { get; set; } |
||||
|
|
||||
|
public Guid? CreatorId { get; set; } |
||||
|
|
||||
|
public DateTime? LastModificationTime { get; set; } |
||||
|
|
||||
|
public Guid? LastModifierId { get; set; } |
||||
|
|
||||
|
public bool IsDeleted { get; set; } |
||||
|
|
||||
|
public Guid? DeleterId { get; set; } |
||||
|
|
||||
|
public DateTime? DeletionTime { get; set; } |
||||
|
} |
||||
@ -1,5 +1,34 @@ |
|||||
{ |
{ |
||||
"culture": "en", |
"culture": "en", |
||||
"texts": { |
"texts": { |
||||
|
"EasyAbp.EShop.Plugins.FlashSales:EndTimeMustBeLaterThanBeginTime": "End time must be later than start time", |
||||
|
"Menu:FlashSalesManagement": "FlashSalesManagement", |
||||
|
"Permission:FlashSalesPlan": "FlashSalesPlan", |
||||
|
"Permission:Manage": "Manage", |
||||
|
"Permission:Create": "Create", |
||||
|
"Permission:Update": "Update", |
||||
|
"Permission:Delete": "Delete", |
||||
|
"Menu:FlashSalesPlan": "FlashSalesPlan", |
||||
|
"FlashSalesPlan": "FlashSalesPlan", |
||||
|
"FlashSalesPlanStoreId": "Store ID", |
||||
|
"FlashSalesPlanBeginTime": "Begin Time", |
||||
|
"FlashSalesPlanEndTime": "End Time", |
||||
|
"FlashSalesPlanProductId": "Product ID", |
||||
|
"FlashSalesPlanProductSkuId": "Product SKU ID", |
||||
|
"FlashSalesPlanIsPublished": "Is Published", |
||||
|
"CreateFlashSalesPlan": "Create", |
||||
|
"EditFlashSalesPlan": "Edit", |
||||
|
"FlashSalesPlanDeletionConfirmationMessage": "Are you sure to delete the flashSalesPlan {0}?", |
||||
|
"SuccessfullyDeleted": "Successfully deleted", |
||||
|
"Permission:FlashSalesResult": "FlashSalesResult", |
||||
|
"Menu:FlashSalesResult": "FlashSalesResult", |
||||
|
"FlashSalesResult": "FlashSalesResult", |
||||
|
"FlashSalesResultStoreId": "Store ID", |
||||
|
"FlashSalesResultPlanId": "Plan ID", |
||||
|
"FlashSalesResultStatus": "Status", |
||||
|
"FlashSalesResultUserId": "User ID", |
||||
|
"FlashSalesResultOrderId": "Order ID", |
||||
|
"FlashSalesResultCreationTime": "Creation Time", |
||||
|
"ViewFlashSalesPlan": "View" |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,5 +1,34 @@ |
|||||
{ |
{ |
||||
"culture": "zh-Hans", |
"culture": "zh-Hans", |
||||
"texts": { |
"texts": { |
||||
|
"EasyAbp.EShop.Plugins.FlashSales:EndTimeMustBeLaterThanBeginTime": "结束时间必须晚于开始时间", |
||||
|
"Menu:FlashSalesManagement": "闪购", |
||||
|
"Permission:FlashSalesPlan": "闪购计划", |
||||
|
"Permission:Manage": "管理", |
||||
|
"Permission:Create": "新建", |
||||
|
"Permission:Update": "更新", |
||||
|
"Permission:Delete": "删除", |
||||
|
"Menu:FlashSalesPlan": "闪购计划", |
||||
|
"FlashSalesPlan": "闪购计划", |
||||
|
"FlashSalesPlanStoreId": "店铺 ID", |
||||
|
"FlashSalesPlanBeginTime": "开始时间", |
||||
|
"FlashSalesPlanEndTime": "结束时间", |
||||
|
"FlashSalesPlanProductId": "产品 ID", |
||||
|
"FlashSalesPlanProductSkuId": "产品SKU ID", |
||||
|
"FlashSalesPlanIsPublished": "发布", |
||||
|
"CreateFlashSalesPlan": "新建", |
||||
|
"EditFlashSalesPlan": "编辑", |
||||
|
"FlashSalesPlanDeletionConfirmationMessage": "确认删除闪购计划 {0}?", |
||||
|
"SuccessfullyDeleted": "删除成功", |
||||
|
"Permission:FlashSalesResult": "闪购结果", |
||||
|
"Menu:FlashSalesResult": "闪购结果", |
||||
|
"FlashSalesResult": "闪购结果", |
||||
|
"FlashSalesResultStoreId": "店铺 ID", |
||||
|
"FlashSalesResultPlanId": "计划 ID", |
||||
|
"FlashSalesResultStatus": "状态", |
||||
|
"FlashSalesResultUserId": "用户 ID", |
||||
|
"FlashSalesResultOrderId": "订单 ID", |
||||
|
"FlashSalesResultCreationTime": "创建时间", |
||||
|
"ViewFlashSalesPlan": "查看" |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,5 +1,34 @@ |
|||||
{ |
{ |
||||
"culture": "zh-Hant", |
"culture": "zh-Hant", |
||||
"texts": { |
"texts": { |
||||
|
"EasyAbp.EShop.Plugins.FlashSales:EndTimeMustBeLaterThanBeginTime": "結束時間必須晚於開始時間", |
||||
|
"Menu:FlashSalesManagement": "FlashSalesManagement", |
||||
|
"Permission:FlashSalesPlan": "FlashSalesPlan", |
||||
|
"Permission:Manage": "Manage", |
||||
|
"Permission:Create": "Create", |
||||
|
"Permission:Update": "Update", |
||||
|
"Permission:Delete": "Delete", |
||||
|
"Menu:FlashSalesPlan": "FlashSalesPlan", |
||||
|
"FlashSalesPlan": "FlashSalesPlan", |
||||
|
"FlashSalesPlanStoreId": "FlashSalesPlanStoreId", |
||||
|
"FlashSalesPlanBeginTime": "FlashSalesPlanBeginTime", |
||||
|
"FlashSalesPlanEndTime": "FlashSalesPlanEndTime", |
||||
|
"FlashSalesPlanProductId": "FlashSalesPlanProductId", |
||||
|
"FlashSalesPlanProductSkuId": "FlashSalesPlanProductSkuId", |
||||
|
"FlashSalesPlanIsPublished": "FlashSalesPlanIsActive", |
||||
|
"CreateFlashSalesPlan": "CreateFlashSalesPlan", |
||||
|
"EditFlashSalesPlan": "EditFlashSalesPlan", |
||||
|
"FlashSalesPlanDeletionConfirmationMessage": "Are you sure to delete the flashSalesPlan {0}?", |
||||
|
"SuccessfullyDeleted": "Successfully deleted", |
||||
|
"Permission:FlashSalesResult": "闪购结果", |
||||
|
"Menu:FlashSalesResult": "闪购计划", |
||||
|
"FlashSalesResult": "闪购结果", |
||||
|
"FlashSalesResultStoreId": "店铺 ID", |
||||
|
"FlashSalesResultPlanId": "计划 ID", |
||||
|
"FlashSalesResultStatus": "状态", |
||||
|
"FlashSalesResultUserId": "用户 ID", |
||||
|
"FlashSalesResultOrderId": "订单 ID", |
||||
|
"FlashSalesResultCreationTime": "创建时间", |
||||
|
"ViewFlashSalesPlan": "查看" |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,16 @@ |
|||||
|
using AutoMapper; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales; |
||||
|
|
||||
|
public class EShopPluginsFlashSalesDomainAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public EShopPluginsFlashSalesDomainAutoMapperProfile() |
||||
|
{ |
||||
|
/* You can configure your AutoMapper mapping configuration here. |
||||
|
* Alternatively, you can split your mapping configurations |
||||
|
* into multiple profile classes for a better organization. */ |
||||
|
CreateMap<FlashSalesPlan, FlashSalesPlanEto>() |
||||
|
.MapExtraProperties(); |
||||
|
} |
||||
|
} |
||||
@ -1,13 +1,33 @@ |
|||||
using Volo.Abp.Domain; |
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AutoMapper; |
||||
|
using Volo.Abp.Domain; |
||||
|
using Volo.Abp.Domain.Entities.Events.Distributed; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.FlashSales; |
namespace EasyAbp.EShop.Plugins.FlashSales; |
||||
|
|
||||
[DependsOn( |
[DependsOn( |
||||
typeof(AbpDddDomainModule), |
typeof(AbpDddDomainModule), |
||||
|
typeof(AbpAutoMapperModule), |
||||
typeof(EShopPluginsFlashSalesDomainSharedModule) |
typeof(EShopPluginsFlashSalesDomainSharedModule) |
||||
)] |
)] |
||||
public class EShopPluginsFlashSalesDomainModule : AbpModule |
public class EShopPluginsFlashSalesDomainModule : AbpModule |
||||
{ |
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAutoMapperObjectMapper<EShopPluginsFlashSalesDomainModule>(); |
||||
|
|
||||
|
Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.AddProfile<EShopPluginsFlashSalesDomainAutoMapperProfile>(validate: true); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpDistributedEntityEventOptions>(options => |
||||
|
{ |
||||
|
options.EtoMappings.Add<FlashSalesPlan, FlashSalesPlanEto>(typeof(EShopPluginsFlashSalesDomainModule)); |
||||
|
|
||||
|
options.AutoEventSelectors.Add<FlashSalesPlan>(); |
||||
|
}); |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
internal class EndTimeMustBeLaterThanBeginTimeException : BusinessException |
||||
|
{ |
||||
|
public EndTimeMustBeLaterThanBeginTimeException() |
||||
|
: base(FlashSalesErrorCodes.EndTimeMustBeLaterThanBeginTime) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesPlan : FullAuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid StoreId { get; protected set; } |
||||
|
|
||||
|
public virtual DateTime BeginTime { get; set; } |
||||
|
|
||||
|
public virtual DateTime EndTime { get; set; } |
||||
|
|
||||
|
public virtual Guid ProductId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid ProductSkuId { get; protected set; } |
||||
|
|
||||
|
public virtual bool IsPublished { get; protected set; } |
||||
|
|
||||
|
protected FlashSalesPlan() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public FlashSalesPlan(Guid id, Guid? tenantId, Guid storeId, DateTime beginTime, DateTime endTime, Guid productId, Guid productSkuId, bool isPublished) |
||||
|
: base(id) |
||||
|
{ |
||||
|
TenantId = tenantId; |
||||
|
StoreId = storeId; |
||||
|
SetTimeRange(beginTime, endTime); |
||||
|
SetProduct(productId, productSkuId); |
||||
|
SetPublished(isPublished); |
||||
|
} |
||||
|
|
||||
|
public void SetTimeRange(DateTime beginTime, DateTime endTime) |
||||
|
{ |
||||
|
if (beginTime > endTime) |
||||
|
{ |
||||
|
throw new EndTimeMustBeLaterThanBeginTimeException(); |
||||
|
} |
||||
|
|
||||
|
BeginTime = beginTime; |
||||
|
EndTime = endTime; |
||||
|
} |
||||
|
|
||||
|
public void SetProduct(Guid productId, Guid productSkuId) |
||||
|
{ |
||||
|
ProductId = productId; |
||||
|
ProductSkuId = productSkuId; |
||||
|
} |
||||
|
|
||||
|
public void SetPublished(bool isPublished) |
||||
|
{ |
||||
|
IsPublished = isPublished; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class FlashSalesPlanManager : DomainService |
||||
|
{ |
||||
|
public virtual Task<FlashSalesPlan> CreateAsync( |
||||
|
Guid storeId, |
||||
|
DateTime beginTime, |
||||
|
DateTime endTime, |
||||
|
Guid productId, |
||||
|
Guid productSkuId, |
||||
|
bool isActive) |
||||
|
{ |
||||
|
var flashSalesPlan = new FlashSalesPlan( |
||||
|
GuidGenerator.Create(), |
||||
|
CurrentTenant.Id, |
||||
|
storeId, |
||||
|
beginTime, |
||||
|
endTime, |
||||
|
productId, |
||||
|
productSkuId, |
||||
|
isActive |
||||
|
); |
||||
|
return Task.FromResult(flashSalesPlan); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<FlashSalesPlan> UpdateAsync( |
||||
|
FlashSalesPlan flashSalesPlan, |
||||
|
DateTime beginTime, |
||||
|
DateTime endTime, |
||||
|
Guid productId, |
||||
|
Guid productSkuId, |
||||
|
bool isPublished) |
||||
|
{ |
||||
|
flashSalesPlan.SetTimeRange(beginTime, endTime); |
||||
|
flashSalesPlan.SetProduct(productId, productSkuId); |
||||
|
flashSalesPlan.SetPublished(isPublished); |
||||
|
|
||||
|
return Task.FromResult(flashSalesPlan); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public interface IFlashSalesPlanRepository : IRepository<FlashSalesPlan, Guid> |
||||
|
{ |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.Guids; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public class CreateFlashSalesOrderCompleteEventHandler : IDistributedEventHandler<CreateFlashSalesOrderCompleteEto>, ITransientDependency |
||||
|
{ |
||||
|
protected IFlashSalesResultRepository FlashSalesResultRepository { get; } |
||||
|
protected IGuidGenerator GuidGenerator { get; } |
||||
|
|
||||
|
public CreateFlashSalesOrderCompleteEventHandler(IFlashSalesResultRepository flashSalesResultRepository, IGuidGenerator guidGenerator) |
||||
|
{ |
||||
|
FlashSalesResultRepository = flashSalesResultRepository; |
||||
|
GuidGenerator = guidGenerator; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public virtual async Task HandleEventAsync(CreateFlashSalesOrderCompleteEto eventData) |
||||
|
{ |
||||
|
var flashSalesResult = await FlashSalesResultRepository.GetAsync(eventData.PendingResultId); |
||||
|
|
||||
|
if (eventData.Success) |
||||
|
{ |
||||
|
flashSalesResult.MarkAsSuccessful(eventData.OrderId.Value); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
flashSalesResult.MarkAsFailed(eventData.Reason); |
||||
|
} |
||||
|
|
||||
|
await FlashSalesResultRepository.UpdateAsync(flashSalesResult, autoSave: true); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public class FlashSalesResult : FullAuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid StoreId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid PlanId { get; protected set; } |
||||
|
|
||||
|
public virtual FlashSalesResultStatus Status { get; protected set; } |
||||
|
|
||||
|
public virtual string Reason { get; protected set; } |
||||
|
|
||||
|
public virtual Guid UserId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid? OrderId { get; protected set; } |
||||
|
|
||||
|
protected FlashSalesResult() { } |
||||
|
|
||||
|
public FlashSalesResult(Guid id, Guid? tenantId, Guid storeId, Guid planId, FlashSalesResultStatus status, string reason, Guid userId, Guid? orderId) |
||||
|
: base(id) |
||||
|
{ |
||||
|
TenantId = tenantId; |
||||
|
StoreId = storeId; |
||||
|
PlanId = planId; |
||||
|
Status = status; |
||||
|
Reason = reason; |
||||
|
UserId = userId; |
||||
|
OrderId = orderId; |
||||
|
} |
||||
|
|
||||
|
public void MarkAsSuccessful(Guid orderId) |
||||
|
{ |
||||
|
Status = FlashSalesResultStatus.Successful; |
||||
|
OrderId = orderId; |
||||
|
} |
||||
|
|
||||
|
public void MarkAsFailed(string reason) |
||||
|
{ |
||||
|
Status = FlashSalesResultStatus.Failed; |
||||
|
Reason = Check.NotNullOrEmpty(reason, nameof(reason)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public interface IFlashSalesResultRepository : IRepository<FlashSalesResult, Guid> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -1,33 +1,32 @@ |
|||||
using Microsoft.EntityFrameworkCore; |
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
using Volo.Abp; |
using Volo.Abp; |
||||
|
using Volo.Abp.EntityFrameworkCore.Modeling; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore; |
namespace EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore; |
||||
|
|
||||
public static class FlashSalesDbContextModelCreatingExtensions |
public static class FlashSalesDbContextModelCreatingExtensions |
||||
{ |
{ |
||||
public static void ConfigureFlashSales( |
public static void ConfigureEShopPluginsFlashSales( |
||||
this ModelBuilder builder) |
this ModelBuilder builder) |
||||
{ |
{ |
||||
Check.NotNull(builder, nameof(builder)); |
Check.NotNull(builder, nameof(builder)); |
||||
|
|
||||
/* Configure all entities here. Example: |
builder.Entity<FlashSalesPlan>(b => |
||||
|
|
||||
builder.Entity<Question>(b => |
|
||||
{ |
{ |
||||
//Configure table & schema name
|
b.ToTable(FlashSalesDbProperties.DbTablePrefix + "Plans", FlashSalesDbProperties.DbSchema); |
||||
b.ToTable(FlashSalesDbProperties.DbTablePrefix + "Questions", FlashSalesDbProperties.DbSchema); |
|
||||
|
|
||||
b.ConfigureByConvention(); |
b.ConfigureByConvention(); |
||||
|
|
||||
//Properties
|
/* Configure more properties here */ |
||||
b.Property(q => q.Title).IsRequired().HasMaxLength(QuestionConsts.MaxTitleLength); |
}); |
||||
|
|
||||
//Relations
|
builder.Entity<FlashSalesResult>(b => |
||||
b.HasMany(question => question.Tags).WithOne().HasForeignKey(qt => qt.QuestionId); |
{ |
||||
|
b.ToTable(FlashSalesDbProperties.DbTablePrefix + "Results", FlashSalesDbProperties.DbSchema); |
||||
|
b.ConfigureByConvention(); |
||||
|
|
||||
//Indexes
|
/* Configure more properties here */ |
||||
b.HasIndex(q => q.CreationTime); |
|
||||
}); |
}); |
||||
*/ |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans |
||||
|
{ |
||||
|
public class EfCoreFlashSalesPlanRepository : EfCoreRepository<IFlashSalesDbContext, FlashSalesPlan, Guid>, IFlashSalesPlanRepository |
||||
|
{ |
||||
|
public EfCoreFlashSalesPlanRepository(IDbContextProvider<IFlashSalesDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override async Task<IQueryable<FlashSalesPlan>> WithDetailsAsync() |
||||
|
{ |
||||
|
return (await GetQueryableAsync()).IncludeDetails(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System.Linq; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public static class FlashSalesPlanEfCoreQueryableExtensions |
||||
|
{ |
||||
|
public static IQueryable<FlashSalesPlan> IncludeDetails(this IQueryable<FlashSalesPlan> queryable, bool include = true) |
||||
|
{ |
||||
|
if (!include) |
||||
|
{ |
||||
|
return queryable; |
||||
|
} |
||||
|
|
||||
|
return queryable |
||||
|
// .Include(x => x.xxx) // TODO: AbpHelper generated
|
||||
|
; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public class EfCoreFlashSalesResultRepository : EfCoreRepository<IFlashSalesDbContext, FlashSalesResult, Guid>, IFlashSalesResultRepository |
||||
|
{ |
||||
|
public EfCoreFlashSalesResultRepository(IDbContextProvider<IFlashSalesDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override async Task<IQueryable<FlashSalesResult>> WithDetailsAsync() |
||||
|
{ |
||||
|
return (await GetQueryableAsync()).IncludeDetails(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System.Linq; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public static class FlashSalesResultEfCoreQuerableExtensions |
||||
|
{ |
||||
|
public static IQueryable<FlashSalesResult> IncludeDetails(this IQueryable<FlashSalesResult> queryable, bool include = true) |
||||
|
{ |
||||
|
if (!include) |
||||
|
{ |
||||
|
return queryable; |
||||
|
} |
||||
|
|
||||
|
return queryable; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
[Area(EShopPluginsFlashSalesRemoteServiceConsts.ModuleName)] |
||||
|
[RemoteService(Name = EShopPluginsFlashSalesRemoteServiceConsts.RemoteServiceName)] |
||||
|
[Route("/api/e-shop/plugins/flash-sales/flash-sales-plan")] |
||||
|
public class FlashSalesPlanController : |
||||
|
FlashSalesController, |
||||
|
IFlashSalesPlanAppService |
||||
|
{ |
||||
|
protected IFlashSalesPlanAppService Service { get; } |
||||
|
|
||||
|
public FlashSalesPlanController(IFlashSalesPlanAppService flashSalesPlanAppService) |
||||
|
{ |
||||
|
Service = flashSalesPlanAppService; |
||||
|
} |
||||
|
|
||||
|
[HttpGet("{id}")] |
||||
|
public virtual Task<FlashSalesPlanDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
return Service.GetAsync(id); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
public virtual Task<PagedResultDto<FlashSalesPlanDto>> GetListAsync(FlashSalesPlanGetListInput input) |
||||
|
{ |
||||
|
return Service.GetListAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpPost("{id}")] |
||||
|
public virtual Task<FlashSalesPlanDto> CreateAsync(FlashSalesPlanCreateDto input) |
||||
|
{ |
||||
|
return Service.CreateAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpPut("{id}")] |
||||
|
public virtual Task<FlashSalesPlanDto> UpdateAsync(Guid id, FlashSalesPlanUpdateDto input) |
||||
|
{ |
||||
|
return Service.UpdateAsync(id, input); |
||||
|
} |
||||
|
|
||||
|
[HttpDelete("{id}")] |
||||
|
public virtual Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
return Service.DeleteAsync(id); |
||||
|
} |
||||
|
|
||||
|
[HttpPost("{id}/pre-order")] |
||||
|
public virtual Task PreOrderAsync(Guid id) |
||||
|
{ |
||||
|
return Service.PreOrderAsync(id); |
||||
|
} |
||||
|
|
||||
|
[HttpGet("{id}/check-pre-order")] |
||||
|
public virtual Task CheckPreOrderAsync(Guid id) |
||||
|
{ |
||||
|
return Service.CheckPreOrderAsync(id); |
||||
|
} |
||||
|
|
||||
|
[HttpPost("{id}/order")] |
||||
|
public virtual Task CreateOrderAsync(Guid id, CreateOrderInput input) |
||||
|
{ |
||||
|
return Service.CreateOrderAsync(id, input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
[Area(EShopPluginsFlashSalesRemoteServiceConsts.ModuleName)] |
||||
|
[RemoteService(Name = EShopPluginsFlashSalesRemoteServiceConsts.RemoteServiceName)] |
||||
|
[Route("/api/e-shop/plugins/flash-sales/flash-sales-result")] |
||||
|
public class FlashSalesResultController : FlashSalesController, IFlashSalesResultAppService |
||||
|
{ |
||||
|
protected IFlashSalesResultAppService Service { get; } |
||||
|
|
||||
|
public FlashSalesResultController(IFlashSalesResultAppService service) |
||||
|
{ |
||||
|
Service = service; |
||||
|
} |
||||
|
|
||||
|
[HttpGet("{id}")] |
||||
|
public virtual Task<FlashSalesResultDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
return Service.GetAsync(id); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
public virtual Task<PagedResultDto<FlashSalesResultDto>> GetListAsync(FlashSalesResultGetListInput input) |
||||
|
{ |
||||
|
return Service.GetListAsync(input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.MongoDB; |
||||
|
using Volo.Abp.Domain.Repositories.MongoDB; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
|
||||
|
public class MongoFlashSalesPlanRepository : MongoDbRepository<IFlashSalesMongoDbContext, FlashSalesPlan, Guid>, IFlashSalesPlanRepository |
||||
|
{ |
||||
|
public MongoFlashSalesPlanRepository(IMongoDbContextProvider<IFlashSalesMongoDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.MongoDB; |
||||
|
using Volo.Abp.Domain.Repositories.MongoDB; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
public class MongoFlashSalesResultRepository : MongoDbRepository<IFlashSalesMongoDbContext, FlashSalesResult, Guid>, IFlashSalesResultRepository |
||||
|
{ |
||||
|
public MongoFlashSalesResultRepository(IMongoDbContextProvider<IFlashSalesMongoDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -1,10 +1,12 @@ |
|||||
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Menus; |
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Menus; |
||||
|
|
||||
public class FlashSalesMenus |
public static class FlashSalesMenus |
||||
{ |
{ |
||||
public const string Prefix = "FlashSales"; |
public const string ModuleGroupPrefix = "EasyAbp.EShop"; |
||||
|
|
||||
//Add your menu items here...
|
public const string Prefix = ModuleGroupPrefix + ".Plugins.FlashSales"; |
||||
//public const string Home = Prefix + ".MyNewMenuItem";
|
|
||||
|
|
||||
|
public const string FlashSalesPlan = Prefix + ".FlashSalesPlan"; |
||||
|
|
||||
|
public const string FlashSalesResult = Prefix + ".FlashSalesResult"; |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,21 @@ |
|||||
|
@page |
||||
|
@using Microsoft.AspNetCore.Mvc.Localization |
||||
|
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Localization |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan |
||||
|
|
||||
|
@inject IHtmlLocalizer<FlashSalesResource> L |
||||
|
@model CreateModalModel |
||||
|
@{ |
||||
|
Layout = null; |
||||
|
} |
||||
|
|
||||
|
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="CreateModal"> |
||||
|
<abp-modal> |
||||
|
<abp-modal-header title="@L["CreateFlashSalesPlan"].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,27 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan; |
||||
|
|
||||
|
public class CreateModalModel : FlashSalesPageModel |
||||
|
{ |
||||
|
[BindProperty] |
||||
|
public CreateFlashSalesPlanViewModel ViewModel { get; set; } |
||||
|
|
||||
|
protected IFlashSalesPlanAppService Service { get; } |
||||
|
|
||||
|
public CreateModalModel(IFlashSalesPlanAppService service) |
||||
|
{ |
||||
|
Service = service; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IActionResult> OnPostAsync() |
||||
|
{ |
||||
|
var dto = ObjectMapper.Map<CreateFlashSalesPlanViewModel, FlashSalesPlanCreateDto>(ViewModel); |
||||
|
await Service.CreateAsync(dto); |
||||
|
return NoContent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
@page |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Localization |
||||
|
@using Microsoft.AspNetCore.Mvc.Localization |
||||
|
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan |
||||
|
|
||||
|
@inject IHtmlLocalizer<FlashSalesResource> L |
||||
|
@model EditModalModel |
||||
|
@{ |
||||
|
Layout = null; |
||||
|
} |
||||
|
|
||||
|
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="EditModal"> |
||||
|
<abp-modal> |
||||
|
<abp-modal-header title="@L["EditFlashSalesPlan"].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,38 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlans.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan; |
||||
|
|
||||
|
public class EditModalModel : FlashSalesPageModel |
||||
|
{ |
||||
|
[HiddenInput] |
||||
|
[BindProperty(SupportsGet = true)] |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
[BindProperty] |
||||
|
public EditFlashSalesPlanViewModel ViewModel { get; set; } |
||||
|
|
||||
|
protected IFlashSalesPlanAppService Service { get; } |
||||
|
|
||||
|
public EditModalModel(IFlashSalesPlanAppService service) |
||||
|
{ |
||||
|
Service = service; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task OnGetAsync() |
||||
|
{ |
||||
|
var dto = await Service.GetAsync(Id); |
||||
|
ViewModel = ObjectMapper.Map<FlashSalesPlanDto, EditFlashSalesPlanViewModel>(dto); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IActionResult> OnPostAsync() |
||||
|
{ |
||||
|
var dto = ObjectMapper.Map<EditFlashSalesPlanViewModel, FlashSalesPlanUpdateDto>(ViewModel); |
||||
|
await Service.UpdateAsync(Id, dto); |
||||
|
return NoContent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
@page |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Permissions |
||||
|
@using Microsoft.AspNetCore.Authorization |
||||
|
@using Microsoft.AspNetCore.Mvc.Localization |
||||
|
@using Volo.Abp.AspNetCore.Mvc.UI.Layout |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Localization |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Web.Menus |
||||
|
|
||||
|
@model IndexModel |
||||
|
|
||||
|
@inject IPageLayout PageLayout |
||||
|
@inject IHtmlLocalizer<FlashSalesResource> L |
||||
|
@inject IAuthorizationService Authorization |
||||
|
@{ |
||||
|
PageLayout.Content.Title = L["FlashSalesPlan"].Value; |
||||
|
PageLayout.Content.BreadCrumb.Add(L["Menu:FlashSalesPlan"].Value); |
||||
|
PageLayout.Content.MenuItemName = FlashSalesMenus.FlashSalesPlan; |
||||
|
} |
||||
|
|
||||
|
@section scripts |
||||
|
{ |
||||
|
<abp-script src="/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.js" /> |
||||
|
} |
||||
|
@section styles |
||||
|
{ |
||||
|
<abp-style src="/Pages/EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/index.css" /> |
||||
|
} |
||||
|
|
||||
|
<abp-card> |
||||
|
<abp-card-header> |
||||
|
<abp-row> |
||||
|
<abp-column size-md="_6"> |
||||
|
<abp-card-title>@L["FlashSalesPlan"]</abp-card-title> |
||||
|
</abp-column> |
||||
|
<abp-column size-md="_6" class="text-end"> |
||||
|
@if (await Authorization.IsGrantedAsync(FlashSalesPermissions.FlashSalesPlan.Create)) |
||||
|
{ |
||||
|
<abp-button id="NewFlashSalesPlanButton" |
||||
|
text="@L["CreateFlashSalesPlan"].Value" |
||||
|
icon="plus" |
||||
|
button-type="Primary" /> |
||||
|
} |
||||
|
</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-table striped-rows="true" id="FlashSalesPlanTable" class="nowrap" /> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan; |
||||
|
|
||||
|
public class IndexModel : FlashSalesPageModel |
||||
|
{ |
||||
|
public virtual async Task OnGetAsync() |
||||
|
{ |
||||
|
await Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels; |
||||
|
|
||||
|
public class CreateFlashSalesPlanViewModel |
||||
|
{ |
||||
|
[Display(Name = "FlashSalesPlanStoreId")] |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanBeginTime")] |
||||
|
public DateTime BeginTime { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanEndTime")] |
||||
|
public DateTime EndTime { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanProductId")] |
||||
|
public Guid ProductId { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanProductSkuId")] |
||||
|
public Guid ProductSkuId { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanIsPublished")] |
||||
|
public bool IsPublished { get; set; } |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesPlans.FlashSalesPlan.ViewModels; |
||||
|
|
||||
|
public class EditFlashSalesPlanViewModel : IHasConcurrencyStamp |
||||
|
{ |
||||
|
[DisabledInput] |
||||
|
[ReadOnlyInput] |
||||
|
[Display(Name = "FlashSalesPlanStoreId")] |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanBeginTime")] |
||||
|
public DateTime BeginTime { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanEndTime")] |
||||
|
public DateTime EndTime { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanProductId")] |
||||
|
public Guid ProductId { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanProductSkuId")] |
||||
|
public Guid ProductSkuId { get; set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesPlanIsPublished")] |
||||
|
public bool IsPublished { get; set; } |
||||
|
|
||||
|
[HiddenInput] |
||||
|
public string ConcurrencyStamp { get; set; } |
||||
|
} |
||||
@ -0,0 +1,87 @@ |
|||||
|
$(function () { |
||||
|
|
||||
|
var l = abp.localization.getResource('EasyAbpEShopPluginsFlashSales'); |
||||
|
|
||||
|
var service = easyAbp.eShop.plugins.flashSales.flashSalesPlans.flashSalesPlan; |
||||
|
var createModal = new abp.ModalManager(abp.appPath + 'EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/CreateModal'); |
||||
|
var editModal = new abp.ModalManager(abp.appPath + 'EShop/Plugins/FlashSales/FlashSalesPlans/FlashSalesPlan/EditModal'); |
||||
|
|
||||
|
var dataTable = $('#FlashSalesPlanTable').DataTable(abp.libs.datatables.normalizeConfiguration({ |
||||
|
processing: true, |
||||
|
serverSide: true, |
||||
|
paging: true, |
||||
|
searching: false, |
||||
|
autoWidth: false, |
||||
|
scrollCollapse: true, |
||||
|
order: [[2, "asc"]], |
||||
|
ajax: abp.libs.datatables.createAjax(service.getList), |
||||
|
columnDefs: [ |
||||
|
{ |
||||
|
rowAction: { |
||||
|
items: |
||||
|
[ |
||||
|
{ |
||||
|
text: l('Edit'), |
||||
|
visible: abp.auth.isGranted('EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlan.Update'), |
||||
|
action: function (data) { |
||||
|
editModal.open({ id: data.record.id }); |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
text: l('Delete'), |
||||
|
visible: abp.auth.isGranted('EasyAbp.EShop.Plugins.FlashSales.FlashSalesPlan.Delete'), |
||||
|
confirmMessage: function (data) { |
||||
|
return l('FlashSalesPlanDeletionConfirmationMessage', data.record.id); |
||||
|
}, |
||||
|
action: function (data) { |
||||
|
service.delete(data.record.id) |
||||
|
.then(function () { |
||||
|
abp.notify.info(l('SuccessfullyDeleted')); |
||||
|
dataTable.ajax.reload(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesPlanStoreId'), |
||||
|
data: "storeId" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesPlanBeginTime'), |
||||
|
data: "beginTime" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesPlanEndTime'), |
||||
|
data: "endTime" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesPlanProductId'), |
||||
|
data: "productId" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesPlanProductSkuId'), |
||||
|
data: "productSkuId" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesPlanIsPublished'), |
||||
|
data: "isPublished", |
||||
|
dataFormat: 'boolean' |
||||
|
}, |
||||
|
] |
||||
|
})); |
||||
|
|
||||
|
createModal.onResult(function () { |
||||
|
dataTable.ajax.reload(); |
||||
|
}); |
||||
|
|
||||
|
editModal.onResult(function () { |
||||
|
dataTable.ajax.reload(); |
||||
|
}); |
||||
|
|
||||
|
$('#NewFlashSalesPlanButton').click(function (e) { |
||||
|
e.preventDefault(); |
||||
|
createModal.open(); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,41 @@ |
|||||
|
@page |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Permissions |
||||
|
@using Microsoft.AspNetCore.Authorization |
||||
|
@using Microsoft.AspNetCore.Mvc.Localization |
||||
|
@using Volo.Abp.AspNetCore.Mvc.UI.Layout |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Localization |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Web.Menus |
||||
|
|
||||
|
@model IndexModel |
||||
|
|
||||
|
@inject IPageLayout PageLayout |
||||
|
@inject IHtmlLocalizer<FlashSalesResource> L |
||||
|
@inject IAuthorizationService Authorization |
||||
|
@{ |
||||
|
PageLayout.Content.Title = L["FlashSalesResult"].Value; |
||||
|
PageLayout.Content.BreadCrumb.Add(L["Menu:FlashSalesResult"].Value); |
||||
|
PageLayout.Content.MenuItemName = FlashSalesMenus.FlashSalesResult; |
||||
|
} |
||||
|
|
||||
|
@section scripts |
||||
|
{ |
||||
|
<abp-script src="/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.js" /> |
||||
|
} |
||||
|
@section styles |
||||
|
{ |
||||
|
<abp-style src="/Pages/EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/index.css" /> |
||||
|
} |
||||
|
|
||||
|
<abp-card> |
||||
|
<abp-card-header> |
||||
|
<abp-row> |
||||
|
<abp-column size-md="_6"> |
||||
|
<abp-card-title>@L["FlashSalesResult"]</abp-card-title> |
||||
|
</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-table striped-rows="true" id="FlashSalesResultTable" class="nowrap" /> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult; |
||||
|
|
||||
|
public class IndexModel : PageModel |
||||
|
{ |
||||
|
public void OnGet() |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
@page |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Localization |
||||
|
@using Microsoft.AspNetCore.Mvc.Localization |
||||
|
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
||||
|
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult |
||||
|
|
||||
|
@inject IHtmlLocalizer<FlashSalesResource> L |
||||
|
@model ViewModalModel |
||||
|
@{ |
||||
|
Layout = null; |
||||
|
} |
||||
|
|
||||
|
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="ViewModal"> |
||||
|
<abp-modal> |
||||
|
<abp-modal-header title="@L["ViewFlashSalesResult"].Value"></abp-modal-header> |
||||
|
<abp-modal-body> |
||||
|
<abp-input asp-for="Id" /> |
||||
|
<abp-form-content /> |
||||
|
</abp-modal-body> |
||||
|
<abp-modal-footer buttons="@(AbpModalButtons.Close)"></abp-modal-footer> |
||||
|
</abp-modal> |
||||
|
</abp-dynamic-form> |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults.Dtos; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult.ViewModels; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult; |
||||
|
|
||||
|
public class ViewModalModel : FlashSalesPageModel |
||||
|
{ |
||||
|
[HiddenInput] |
||||
|
[BindProperty(SupportsGet = true)] |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
[BindProperty] |
||||
|
public ViewFlashSalesResultViewModel ViewModel { get; set; } |
||||
|
|
||||
|
protected IFlashSalesResultAppService Service { get; } |
||||
|
|
||||
|
public ViewModalModel(IFlashSalesResultAppService service) |
||||
|
{ |
||||
|
Service = service; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task OnGetAsync() |
||||
|
{ |
||||
|
var dto = await Service.GetAsync(Id); |
||||
|
ViewModel = ObjectMapper.Map<FlashSalesResultDto, ViewFlashSalesResultViewModel>(dto); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using EasyAbp.EShop.Plugins.FlashSales.FlashSalesResults; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales.FlashSalesResults.FlashSalesResult.ViewModels; |
||||
|
|
||||
|
public class ViewFlashSalesResultViewModel |
||||
|
{ |
||||
|
[Display(Name = "FlashSalesResultStoreId")] |
||||
|
public virtual Guid StoreId { get; protected set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesResultPlanId")] |
||||
|
public virtual Guid PlanId { get; protected set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesResultStatus")] |
||||
|
public virtual FlashSalesResultStatus Status { get; protected set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesResultUserId")] |
||||
|
public virtual Guid UserId { get; protected set; } |
||||
|
|
||||
|
[Display(Name = "FlashSalesResultOrderId")] |
||||
|
public virtual Guid? OrderId { get; protected set; } |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
$(function () { |
||||
|
|
||||
|
var l = abp.localization.getResource('EasyAbpEShopPluginsFlashSales'); |
||||
|
|
||||
|
var service = easyAbp.eShop.plugins.flashSales.flashSalesPlans.flashSalesPlan; |
||||
|
var viewModal = new abp.ModalManager(abp.appPath + 'EShop/Plugins/FlashSales/FlashSalesResults/FlashSalesResult/ViewModal'); |
||||
|
|
||||
|
var dataTable = $('#FlashSalesResultTable').DataTable(abp.libs.datatables.normalizeConfiguration({ |
||||
|
processing: true, |
||||
|
serverSide: true, |
||||
|
paging: true, |
||||
|
searching: false, |
||||
|
autoWidth: false, |
||||
|
scrollCollapse: true, |
||||
|
order: [[6, "desc"]], |
||||
|
ajax: abp.libs.datatables.createAjax(service.getList), |
||||
|
columnDefs: [ |
||||
|
{ |
||||
|
rowAction: { |
||||
|
items: |
||||
|
[ |
||||
|
{ |
||||
|
text: l('ViewFlashSalesPlan'), |
||||
|
action: function (data) { |
||||
|
viewModal.open({ id: data.record.id }); |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesResultStoreId'), |
||||
|
data: "storeId" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesResultPlanId'), |
||||
|
data: "planId" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesResultStatus'), |
||||
|
data: "status" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesResultUserId'), |
||||
|
data: "userId" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesResultOrderId'), |
||||
|
data: "orderId" |
||||
|
}, |
||||
|
{ |
||||
|
title: l('FlashSalesResultCreationTime'), |
||||
|
data: "creationTime", |
||||
|
dataFormat: 'datetime' |
||||
|
}, |
||||
|
] |
||||
|
})); |
||||
|
|
||||
|
viewModal.onResult(function () { |
||||
|
dataTable.ajax.reload(); |
||||
|
}); |
||||
|
}); |
||||
@ -1,11 +1,12 @@ |
|||||
@page |
@page |
||||
@using Microsoft.Extensions.Localization |
@using Microsoft.Extensions.Localization |
||||
@using EasyAbp.EShop.Plugins.FlashSales.Localization |
@using EasyAbp.EShop.Plugins.FlashSales.Localization |
||||
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EasyAbp.EShop.Plugins.FlashSales |
@using EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales |
||||
|
|
||||
@model IndexModel |
@model IndexModel |
||||
@inject IStringLocalizer<FlashSalesResource> L |
@inject IStringLocalizer<FlashSalesResource> L |
||||
|
|
||||
@{ |
@{ |
||||
} |
} |
||||
|
|
||||
<h1>FlashSales</h1> |
<h1>FlashSales</h1> |
||||
<p>@L["SamplePageMessage"]</p> |
<p>@L["SamplePageMessage"]</p> |
||||
@ -1,4 +1,4 @@ |
|||||
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EasyAbp.EShop.Plugins.FlashSales; |
namespace EasyAbp.EShop.Plugins.FlashSales.Web.Pages.EShop.Plugins.FlashSales; |
||||
|
|
||||
public class IndexModel : FlashSalesPageModel |
public class IndexModel : FlashSalesPageModel |
||||
{ |
{ |
||||
Loading…
Reference in new issue