添加项目文件。

This commit is contained in:
2025-12-02 13:10:10 +08:00
parent 93a2382a16
commit 289aa4cbe7
400 changed files with 91177 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AntDesign" Version="1.5.0" />
<PackageReference Include="AntDesign.ProLayout" Version="1.4.0" />
<PackageReference Include="Blazilla" Version="2.0.1" />
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Blazored.FluentValidation" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.15.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Atomx.Common\Atomx.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,60 @@
@using Microsoft.AspNetCore.Authorization
@inject IPermissionService PermissionService
@inject IAuthorizationService AuthorizationService
<CascadingAuthenticationState>
<AuthorizeView Context="authContext">
<Authorized>
@if (_hasPermission)
{
@ChildContent
}
else if (!string.IsNullOrEmpty(NotAuthorizedContent))
{
@NotAuthorizedContent
}
</Authorized>
<NotAuthorized>
@if (!string.IsNullOrEmpty(NotAuthenticatedContent))
{
@NotAuthenticatedContent
}
</NotAuthorized>
</AuthorizeView>
</CascadingAuthenticationState>
@code {
[Parameter] public RenderFragment? ChildContent { get; set; }
[Parameter] public string? Permission { get; set; }
[Parameter] public string[]? Permissions { get; set; }
[Parameter] public bool RequireAll { get; set; }
[Parameter] public string? Policy { get; set; }
[Parameter] public string? NotAuthorizedContent { get; set; }
[Parameter] public string? NotAuthenticatedContent { get; set; }
private bool _hasPermission;
protected override async Task OnParametersSetAsync()
{
if (!string.IsNullOrEmpty(Policy))
{
var authState = await AuthorizationService.AuthorizeAsync(null, Policy);
_hasPermission = authState.Succeeded;
}
else if (!string.IsNullOrEmpty(Permission))
{
_hasPermission = await PermissionService.HasPermissionAsync(Permission);
}
else if (Permissions != null && Permissions.Length > 0)
{
if (RequireAll)
{
_hasPermission = await PermissionService.HasAllPermissionsAsync(Permissions);
}
else
{
_hasPermission = await PermissionService.HasAnyPermissionAsync(Permissions);
}
}
}
}

View File

@@ -0,0 +1,29 @@
@inject IJSRuntime JSRuntime
@inject ILocalizationService LocalizationService
@inject NavigationManager Navigation
@* <select @bind="_selectedCulture" @onchange="OnCultureChanged">
<option value="en-US">English</option>
<option value="zh-CN">中文</option>
<option value="ja-JP">日本語</option>
</select> *@
@code {
private string _selectedCulture = "en-US";
protected override async Task OnInitializedAsync()
{
_selectedCulture = await JSRuntime.InvokeAsync<string>("blazorCulture.get") ?? "en-US";
}
private async Task OnCultureChanged(ChangeEventArgs e)
{
var culture = e.Value?.ToString();
if (!string.IsNullOrEmpty(culture))
{
await JSRuntime.InvokeVoidAsync("blazorCulture.set", culture);
await LocalizationService.LoadResourcesAsync(culture);
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
}
}
}

View File

@@ -0,0 +1,26 @@
@inject ILocalizationService LocalizationService
@Text
@code {
private string? _text;
[Parameter]
public string Key { get; set; } = string.Empty;
[Parameter]
public string? Culture { get; set; }
private string Text => _text ?? Key;
protected override async Task OnParametersSetAsync()
{
await LoadText();
}
private async Task LoadText()
{
_text = await LocalizationService.GetStringAsync(Key, Culture) ?? Key;
StateHasChanged();
}
}

View File

@@ -0,0 +1,9 @@
@inherits LayoutComponentBase
<div style="min-height:100vh">
@Body
</div>
@code {
}

View File

@@ -0,0 +1,122 @@
@inherits LayoutComponentBase
@inject ILogger<MainLayout> _logger
<ErrorBoundary>
<ChildContent>
<AntDesign.ProLayout.BasicLayout MenuData="MenuDatas" Title="Atomx" MenuAccordion @bind-Collapsed="_open">
<HeaderContentRender>
<Space Size="@("24")">
<SpaceItem>
<Icon Class="action" Type="@(_open ? "menu-unfold" : "menu-fold")" OnClick="ToggleDrawer" />
</SpaceItem>
</Space>
</HeaderContentRender>
<RightContentRender>
<Space Size="@("24")">
@* <SpaceItem>
<HeaderSearch Class="action search"
Placeholder="Site Search"
DefaultValue="umi ui"
Options="DefaultOptions" />
</SpaceItem> *@
<SpaceItem>
<AntDesign.Tooltip Title="@("Help")" Placement="@Placement.Bottom">
<Unbound>
<span @ref="@context.Current" class="action">
<Icon Type="question-circle" Theme="IconThemeType.Outline" />
</span>
</Unbound>
</AntDesign.Tooltip>
</SpaceItem>
<SpaceItem>
<AvatarDropdown Name="Test"
Avatar=""
MenuItems="@AvatarMenuItems"
OnItemSelected="HandleSelectUser" />
</SpaceItem>
@*<SpaceItem>
<SelectLang OnItemSelected="HandleSelectLang" />
</SpaceItem> *@
</Space>
</RightContentRender>
<ChildContent>
@Body
</ChildContent>
</AntDesign.ProLayout.BasicLayout>
</ChildContent>
<ErrorContent Context="ex">
<div class="pa-5" style="user-select: text;">
<div class="d-flex justify-space-between align-center">
<Alert Class="mr-2">程序遇到了未知错误!</Alert>
<Button Type="ButtonType.Link" OnClick="@(() => ResetError(ex))">确定</Button>
</div>
<div class="error-message mt-3">
@($"{ex.Message}{Environment.NewLine}{ex.StackTrace}")
</div>
</div>
</ErrorContent>
</ErrorBoundary>
@code {
private ErrorBoundary? _errorBoundary;
private void ResetError(Exception ex)
{
_logger.LogError(ex, "未处理的异常。");
_errorBoundary?.Recover();
}
private bool _open = true;
private void ToggleDrawer()
{
_open = !_open;
}
private MenuDataItem[] MenuDatas;
private AvatarMenuItem[] AvatarMenuItems =>
[
new() { Key = "center", IconType = "user", Option = "通知消息"},
new() { Key = "setting", IconType = "setting", Option ="修改资料" },
new() { IsDivider = true },
new() { Key = "logout", IconType = "logout", Option = "退出登录"}
];
public void HandleSelectUser(AntDesign.MenuItem item)
{
switch (item.Key)
{
case "center":
Navigation.NavigateTo("/account/center");
break;
case "setting":
Navigation.NavigateTo("/account/settings");
break;
case "logout":
Navigation.NavigateTo("/logout");
break;
}
}
protected async override Task OnInitializedAsync()
{
var url = "/api/menu/tree";
var apiResult = await HttpService.Get<ApiResult<List<MenuDataItem>>>(url);
if (apiResult.Success)
{
if (apiResult.Data != null)
{
MenuDatas = apiResult.Data.ToArray();
StateHasChanged();
}
}
}
}

View File

@@ -0,0 +1,98 @@
.page {
position: relative;
display: flex;
flex-direction: column;
}
main {
flex: 1;
}
.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}
.top-row {
background-color: #f7f7f7;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-end;
height: 3.5rem;
display: flex;
align-items: center;
}
.top-row ::deep a, .top-row ::deep .btn-link {
white-space: nowrap;
margin-left: 1.5rem;
text-decoration: none;
}
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
text-decoration: underline;
}
.top-row ::deep a:first-child {
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 640.98px) {
.top-row {
justify-content: space-between;
}
.top-row ::deep a, .top-row ::deep .btn-link {
margin-left: 0;
}
}
@media (min-width: 641px) {
.page {
flex-direction: row;
}
.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}
.top-row {
position: sticky;
top: 0;
z-index: 1;
}
.top-row.auth ::deep a:first-child {
flex: 1;
text-align: right;
width: 0;
}
.top-row, article {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}
}
#blazor-error-ui {
color-scheme: light only;
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
box-sizing: border-box;
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}

View File

@@ -0,0 +1,30 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">Atomx.Admin</a>
</div>
</div>
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
<nav class="nav flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="weather">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
</NavLink>
</div>
</nav>
</div>

View File

@@ -0,0 +1,105 @@
.navbar-toggler {
appearance: none;
cursor: pointer;
width: 3.5rem;
height: 2.5rem;
color: white;
position: absolute;
top: 0.5rem;
right: 1rem;
border: 1px solid rgba(255, 255, 255, 0.1);
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
}
.navbar-toggler:checked {
background-color: rgba(255, 255, 255, 0.5);
}
.top-row {
min-height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}
.navbar-brand {
font-size: 1.1rem;
}
.bi {
display: inline-block;
position: relative;
width: 1.25rem;
height: 1.25rem;
margin-right: 0.75rem;
top: -1px;
background-size: cover;
}
.bi-house-door-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}
.bi-plus-square-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
}
.bi-list-nested-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}
.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.nav-item:first-of-type {
padding-top: 1rem;
}
.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item ::deep .nav-link {
color: #d7d7d7;
background: none;
border: none;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
width: 100%;
}
.nav-item ::deep a.active {
background-color: rgba(255,255,255,0.37);
color: white;
}
.nav-item ::deep .nav-link:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}
.nav-scrollable {
display: none;
}
.navbar-toggler:checked ~ .nav-scrollable {
display: block;
}
@media (min-width: 641px) {
.navbar-toggler {
display: none;
}
.nav-scrollable {
/* Never collapse the sidebar for wide screens */
display: block;
/* Allow sidebar to scroll for tall menus */
height: calc(100vh - 3.5rem);
overflow-y: auto;
}
}

View File

@@ -0,0 +1,85 @@
namespace Atomx.Admin.Client.Models
{
public class AddressModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 添加地址用户
/// </summary>
public long UserId { get; set; }
/// <summary>
/// 收件人姓名
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 邮件地址
/// </summary>
public string Email { get; set; } = string.Empty;
/// <summary>
/// 电话号码
/// </summary>
public string Phone { get; set; } = string.Empty;
/// <summary>
/// 公司
/// </summary>
public string Company { get; set; } = string.Empty;
/// <summary>
/// 国家
/// </summary>
public long Country { get; set; }
/// <summary>
/// 省份
/// </summary>
public long Province { get; set; }
/// <summary>
/// 城市
/// </summary>
public long City { get; set; }
/// <summary>
/// 地区
/// </summary>
public long Region { get; set; }
/// <summary>
/// 邮政编码
/// </summary>
public string PostalCode { get; set; } = string.Empty;
/// <summary>
/// 详细地址
/// </summary>
public string FullAddress { get; set; } = string.Empty;
/// <summary>
/// 地址所在经度
/// </summary>
public decimal Longitude { get; set; }
/// <summary>
/// 地址所在纬度
/// </summary>
public decimal Latitude { get; set; }
/// <summary>
/// 是否是虚拟地址
/// </summary>
public bool IsVirtual { get; set; }
/// <summary>
/// 是否编辑
/// </summary>
public bool IsEdit { get; set; }
}
}

View File

@@ -0,0 +1,50 @@
namespace Atomx.Admin.Client.Models
{
public class AdminModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 管理员用户名
/// </summary>
public string Username { get; set; } = string.Empty;
/// <summary>
/// 注册手机号
/// </summary>
public string Mobile { get; set; } = string.Empty;
/// <summary>
/// 注册邮箱
/// </summary>
public string Email { get; set; } = string.Empty;
/// <summary>
/// 登录密码
/// </summary>
public string Password { get; set; } = string.Empty;
/// <summary>
/// 新密码
/// </summary>
public string NewPassword { get; set; } = string.Empty;
/// <summary>
/// 确认密码
/// </summary>
public string RePassword { get; set; } = string.Empty;
/// <summary>
/// 是否设置密码
/// </summary>
public bool SetPassword { get; set; }
/// <summary>
/// 状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
namespace Atomx.Admin.Client.Models
{
public class AdminSearch : BaseSearch
{
/// <summary>
/// 用户名或昵称
/// </summary>
public string? Username { get; set; }
/// <summary>
/// 邮件地址
/// </summary>
public string? Email { get; set; }
/// <summary>
/// 手机号码
/// </summary>
public string? Mobile { get; set; }
/// <summary>
/// 真实姓名
/// </summary>
public string? RealName { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime?[] RangeTime { get; set; } = new DateTime?[] { null, null };
/// <summary>
/// 状态
/// </summary>
public string? Status { get; set; }
}
}

View File

@@ -0,0 +1,78 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Atomx.Admin.Client.Models
{
public class AppVersionModel
{
/// <summary>
/// 数据ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public long Id { get; set; }
/// <summary>
/// 运行平台
/// </summary>
public int Platform { get; set; }
/// <summary>
/// 应用名称KEY
/// </summary>
[Column(TypeName = "varchar(64)")]
public string AppName { get; set; } = string.Empty;
/// <summary>
/// 版本标题
/// </summary>
[Column(TypeName = "varchar(64)")]
public string Title { get; set; } = string.Empty;
/// <summary>
/// 版本
/// </summary>
[Column(TypeName = "varchar(64)")]
public string Version { get; set; } = string.Empty;
/// <summary>
/// 主版本号(major)无法向下兼容时,需要递增
/// </summary>
[Column(TypeName = "varchar(64)")]
public int VersionX { get; set; }
/// <summary>
/// 次版本号(minor)新增新的特性时,需要递增
/// </summary>
[Column(TypeName = "varchar(64)")]
public int VersionY { get; set; }
/// <summary>
/// 修订版本号(patch)修复问题时,需要递增
/// </summary>
[Column(TypeName = "varchar(64)")]
public int VersionZ { get; set; }
/// <summary>
/// 版本日期
/// </summary>
[Column(TypeName = "varchar(64)")]
public int VersionDate { get; set; }
/// <summary>
/// 版本状态 例如b 表示bate版即测试版
/// </summary>
public int VersionState { get; set; }
/// <summary>
/// 更新内容说明
/// </summary>
[Column(TypeName = "text")]
public string Content { get; set; } = string.Empty;
/// <summary>
/// 版本状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
namespace Atomx.Admin.Client.Models
{
public class AppVersionSearch : BaseSearch
{
/// <summary>
/// 名称
/// </summary>
public string? Name { get; set; }
/// <summary>
/// 状态
/// </summary>
public string Status { get; set; } = string.Empty;
/// <summary>
/// 开始时间
/// </summary>
public DateTime?[] RangeTime { get; set; } = new DateTime?[] { null, null };
}
}

View File

@@ -0,0 +1,15 @@
namespace Atomx.Admin.Client.Models
{
public class BaseSearch
{
/// <summary>
/// 查询开始时间
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// 查询结束时间
/// </summary>
public DateTime? EndTime { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class CategoryItem : Category
{
public List<CategoryItem> Children { get; set; } = new List<CategoryItem>();
public bool IsLast { get; set; }
}
}

View File

@@ -0,0 +1,83 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Atomx.Admin.Client.Models
{
public class CategoryModel
{
/// <summary>
/// 分类ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public long Id { get; set; }
/// <summary>
/// 分类类型,1内容2产品3社区
/// </summary>
public int Type { get; set; }
/// <summary>
/// 上级分类ID
/// </summary>
public long ParentId { get; set; }
/// <summary>
/// 分类名称
/// </summary>
[Column(TypeName = "varchar(25)")]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 分类URL缩略名
/// </summary>
[Column(TypeName = "varchar(50)")]
public string Slug { get; set; } = string.Empty;
/// <summary>
/// Meta描述介绍
/// </summary>
[Column(TypeName = "varchar(255)")]
public string MetaDescription { get; set; } = string.Empty;
/// <summary>
/// Meta关键词
/// </summary>
[Column(TypeName = "varchar(255)")]
public string MetaKeywords { get; set; } = string.Empty;
/// <summary>
/// 过滤属性IDs
/// </summary>
[Column(TypeName = "varchar(255)")]
public string FilterAttributes { get; set; } = string.Empty;
/// <summary>
/// 分类图片
/// </summary>
[Column(TypeName = "varchar(255)")]
public string Image { get; set; } = string.Empty;
/// <summary>
/// 分类页 banner
/// </summary>
[Column(TypeName = "varchar(255)")]
public string Banner { get; set; } = string.Empty;
/// <summary>
/// 只是一个节点
/// </summary>
public bool IsNode { get; set; }
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 排序
/// </summary>
public int DisplayOrder { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Atomx.Admin.Client.Models
{
public class CategorySearch : BaseSearch
{
/// <summary>
/// 分类名称
/// </summary>
public string? Name { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
namespace Atomx.Admin.Client.Models
{
public class CorporationModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 公司名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 数据状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class CorporationSearch : BaseSearch
{
/// <summary>
/// 名称
/// </summary>
public string? Name { get; set; }
}
}

View File

@@ -0,0 +1,55 @@
namespace Atomx.Admin.Client.Models
{
public class CorporationStaffModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 管理员用户名
/// </summary>
public string Username { get; set; } = string.Empty;
/// <summary>
/// 注册手机号
/// </summary>
public string Mobile { get; set; } = string.Empty;
/// <summary>
/// 注册邮箱
/// </summary>
public string Email { get; set; } = string.Empty;
/// <summary>
/// 登录密码
/// </summary>
public string Password { get; set; } = string.Empty;
/// <summary>
/// 新密码
/// </summary>
public string NewPassword { get; set; } = string.Empty;
/// <summary>
/// 确认密码
/// </summary>
public string RePassword { get; set; } = string.Empty;
/// <summary>
/// 是否设置密码
/// </summary>
public bool SetPassword { get; set; }
/// <summary>
/// 状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,40 @@
namespace Atomx.Admin.Client.Models
{
public class CorporationStaffSearch : BaseSearch
{
/// <summary>
/// 公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 用户名或昵称
/// </summary>
public string? Username { get; set; }
/// <summary>
/// 邮件地址
/// </summary>
public string? Email { get; set; }
/// <summary>
/// 手机号码
/// </summary>
public string? Mobile { get; set; }
/// <summary>
/// 真实姓名
/// </summary>
public string? RealName { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime?[] RangeTime { get; set; } = new DateTime?[] { null, null };
/// <summary>
/// 状态
/// </summary>
public string? Status { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class CorporationUserModel:User
{
/// <summary>
/// 公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 用户ID
/// </summary>
public long UserId { get; set; }
/// <summary>
/// 是否是管理员
/// </summary>
public bool IsAdmin { get; set; }
/// <summary>
/// 数据状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,7 @@
namespace Atomx.Admin.Client.Models
{
public class CorporationUserSearch : BaseSearch
{
public string Name { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,56 @@
namespace Atomx.Admin.Client.Models
{
public class CurrencyModel
{
/// <summary>
/// 数据ID
/// </summary>
public int Id { get; set; }
/// <summary>
/// 语言
/// </summary>
public string Language { get; set; } = string.Empty;
/// <summary>
/// 货币名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 货币单位代码
/// </summary>
public string CurrencyCode { get; set; } = string.Empty;
/// <summary>
/// 本地显示
/// </summary>
public string DisplayLocale { get; set; } = string.Empty;
/// <summary>
/// 数字自定义格式化
/// </summary>
public string CustomFormatting { get; set; } = string.Empty;
/// <summary>
/// 兑换汇率
/// </summary>
public double Rate { get; set; }
/// <summary>
/// 排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 是否编辑
/// </summary>
public bool IsEdit { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Atomx.Admin.Client.Models
{
public class CurrentUser
{
public string Name { get; set; } = string.Empty;
public string Avatar { get; set; } = string.Empty;
public string UserId { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,55 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Atomx.Admin.Client.Models
{
public class LanguageModel
{
/// <summary>
/// 数据ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
/// <summary>
/// 语言名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 语言标题
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 语言名称
/// </summary>
public string Culture { get; set; } = string.Empty;
/// <summary>
/// 国旗
/// </summary>
public string FlagImage { get; set; } = string.Empty;
/// <summary>
/// 排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 是否可用,系统面
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 多语言资源的版本,可以是时间戳或哈希
/// </summary>
public string ResourceVersion { get; set; } = string.Empty;
/// <summary>
/// 是否编辑
/// </summary>
public bool IsEdit { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Atomx.Admin.Client.Models
{
public class LanguageSearch : BaseSearch
{
/// <summary>
/// 语言名称
/// </summary>
public string Name { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,35 @@
namespace Atomx.Common.Models
{
public class LinkItem
{
/// <summary>
/// 链接标识
/// </summary>
public string Key { get; set; } = string.Empty;
/// <summary>
/// 链接名字
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 图标
/// </summary>
public string Image { get; set; } = string.Empty;
/// <summary>
/// 链接URL
/// </summary>
public string Url { get; set; } = string.Empty;
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
namespace Atomx.Admin.Client.Models
{
public class LocaleResourceModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 语言编码
/// </summary>
public int LanguageId { get; set; }
/// <summary>
/// 语言名称
/// </summary>
public string Culture { get; set; } = string.Empty;
/// <summary>
/// 资源名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 资源内容值
/// </summary>
public string Value { get; set; } = string.Empty;
/// <summary>
/// 是否编辑
/// </summary>
public bool IsEdit { get; set; }
}
}

View File

@@ -0,0 +1,25 @@
namespace Atomx.Admin.Client.Models
{
public class LoginModel
{
/// <summary>
/// 登录账号
/// </summary>
public string Account { get; set; } = string.Empty;
/// <summary>
/// 登录密码
/// </summary>
public string Password { get; set; } = string.Empty;
/// <summary>
/// 地区代码,同时用来识别是否手机登录
/// </summary>
public string AreaCode { get; set; } = string.Empty;
/// <summary>
/// 是否记住我
/// </summary>
public bool SaveMe { get; set; }
}
}

View File

@@ -0,0 +1,58 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Atomx.Admin.Client.Models
{
public class ManufacturerModel
{
/// <summary>
/// 制造商ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 制造商名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 是否是供应商
/// </summary>
public bool IsVendor { get; set; }
/// <summary>
/// 品牌LOGO
/// </summary>
public string Logo { get; set; } = string.Empty;
/// <summary>
/// 品牌制造商描述
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// Meta标题
/// </summary>
public string MetaTitle { get; set; } = string.Empty;
/// <summary>
/// Meta标题
/// </summary>
public string MetaKeywords { get; set; } = string.Empty;
/// <summary>
/// Meta标题
/// </summary>
public string MetaDescription { get; set; } = string.Empty;
/// <summary>
/// 是否启用
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 显示排序
/// </summary>
public int DisplayOrder { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class ManufacturerProductItemSearch : BaseSearch
{
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class ManufacturerSearch:BaseSearch
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }=string.Empty;
}
}

View File

@@ -0,0 +1,20 @@
namespace Atomx.Admin.Client.Models
{
public class MaterialSearch : BaseSearch
{
/// <summary>
/// 类型
/// </summary>
public int? Type { get; set; }
/// <summary>
/// 原料归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 原料归属店铺网点ID
/// </summary>
public long StoreId { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class MenuItem : Menu
{
public List<MenuItem>? Children { get; set; }
}
}

View File

@@ -0,0 +1,70 @@
namespace Atomx.Admin.Client.Models
{
public class MenuModel
{
/// <summary>
/// 分类ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 分类类型,1-管理后台系统
/// </summary>
public int Type { get; set; }
/// <summary>
/// 上级分类ID
/// </summary>
public long ParentId { get; set; }
/// <summary>
/// 分类名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 分类图片
/// </summary>
public string Icon { get; set; } = string.Empty;
/// <summary>
/// 菜单分组,针对折叠菜单效果
/// </summary>
public string Key { get; set; } = string.Empty;
/// <summary>
/// 菜单链接的URL
/// </summary>
public string Url { get; set; } = string.Empty;
/// <summary>
/// 权限代码
/// </summary>
public string Code { get; set; } = string.Empty;
/// <summary>
/// 是否外链接
/// </summary>
public bool IsLink { get; set; }
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 层级深度
/// </summary>
public int Depth { get; set; }
/// <summary>
/// 层级路径
/// </summary>
public string Path { get; set; } = string.Empty;
/// <summary>
/// 排序
/// </summary>
public int DisplayOrder { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Atomx.Admin.Client.Models
{
public class MenuSearch
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,19 @@
namespace Atomx.Admin.Client.Models
{
public class MenuTreeItem
{
public string Icon { get; set; } = string.Empty;
public string IconFont { get; set; } = string.Empty;
public string Locale { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Key { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public List<MenuTreeItem> Children { get; set; } = new List<MenuTreeItem>();
}
}

View File

@@ -0,0 +1,40 @@
namespace Atomx.Admin.Client.Models
{
public class MessageTemplateModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 消息模板类型
/// </summary>
public string Type { get; set; } = string.Empty;
/// <summary>
/// 信息模板KEY
/// </summary>
public string Key { get; set; } = string.Empty;
/// <summary>
/// 消息模板名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 消息标题
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 消息内容
/// </summary>
public string Body { get; set; } = string.Empty;
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Atomx.Admin.Client.Models
{
public class MessageTemplateSearch : BaseSearch
{
public int? Type { get; set; }
public string Key { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class OrderSearch : BaseSearch
{
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class PriceTrendSearch : BaseSearch
{
}
}

View File

@@ -0,0 +1,50 @@
namespace Atomx.Admin.Client.Models
{
public class ProductAddStockModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 产品ID
/// </summary>
public long ProductId { get; set; }
/// <summary>
/// 产品标题
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 产品属性
/// </summary>
public List<ProductStockAttributeModel> ProductStockAttributes { get; set; } = new();
/// <summary>
/// SKU信息
/// </summary>
public ProductAttributeCombinationModel ProductAttributeCombination { get; set; } = new();
/// <summary>
/// 归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 仓库ID
/// </summary>
public string WarehouseId { get; set; } = string.Empty;
/// <summary>
/// 是否新增属性
/// </summary>
public bool AddAttribute { get; set; }
/// <summary>
/// 添加库存
/// </summary>
public int AddStockQuantity { get; set; }
}
}

View File

@@ -0,0 +1,89 @@
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// 产品SKU属性组合模型
/// </summary>
public class ProductAttributeCombinationModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 产品ID
/// </summary>
public long ProductId { get; set; }
/// <summary>
/// 供应制造商ID
/// </summary>
public long ManufacturerId { get; set; }
/// <summary>
/// 属性JSON
/// </summary>
public List<ProductSkuModel> SkuAttributes { get; set; } = new List<ProductSkuModel>();
/// <summary>
/// 库存数量
/// </summary>
public int StockQuantity { get; set; }
/// <summary>
/// 销售数量
/// </summary>
public int SalesQuantity { get; set; }
/// <summary>
/// SKU编码
/// </summary>
public string SkuNumber { get; set; } = string.Empty;
/// <summary>
/// 销售加工费
/// </summary>
public decimal ProcessCharge { get; set; }
/// <summary>
/// 加工费成本
/// </summary>
public decimal ProcessCost { get; set; }
/// <summary>
/// 销售附加费
/// </summary>
public decimal Surcharge { get; set; }
/// <summary>
/// 附加费成本
/// </summary>
public decimal SurchargeCost { get; set; }
/// <summary>
/// SKU的市场价划线价
/// </summary>
public decimal MarketPrice { get; set; }
/// <summary>
/// SKU的销售价格
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// 重量
/// </summary>
public decimal Weight { get; set; }
/// <summary>
/// 重量单位1克2千克3磅4盎司
/// </summary>
public int WeightUnit { get; set; }
/// <summary>
/// 是否上架销售
/// </summary>
public bool Enabled { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class ProductAttributeItemModel : ProductAttribute
{
public string CategoryName { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,50 @@
namespace Atomx.Admin.Client.Models
{
public class ProductAttributeModel
{
/// <summary>
/// 属性ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 上级属性,用于规格属性做分组
/// </summary>
public long ParentId { get; set; }
/// <summary>
/// 分类ID
/// </summary>
public long CategoryId { get; set; }
/// <summary>
/// 属性名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 属性控件类型1选项0文本
/// </summary>
public int ControlType { get; set; }
/// <summary>
/// 必须填写重量
/// </summary>
public bool WeightIsRequired { get; set; }
/// <summary>
/// 是否是必须的属性
/// </summary>
public bool IsRequired { get; set; }
/// <summary>
/// 展示排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 数据状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,40 @@
namespace Atomx.Admin.Client.Models
{
public class ProductAttributeOptionModel
{
/// <summary>
/// 预设值ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 供应商自定义值
/// </summary>
public long VendorId { get; set; }
/// <summary>
/// 产品属性ID
/// </summary>
public long AttributeId { get; set; }
/// <summary>
/// 预设值名称
/// </summary>
public string Value { get; set; } = string.Empty;
/// <summary>
/// 展示排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 是否通用的
/// </summary>
public bool Standard { get; set; }
/// <summary>
/// 数据状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
namespace Atomx.Admin.Client.Models
{
public class ProductAttributeOptionSearch : BaseSearch
{
/// <summary>
/// 值
/// </summary>
public string? Value { get; set; }
public long AttributeId { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Atomx.Admin.Client.Models
{
public class ProductAttributeSearch : BaseSearch
{
public string Name { get; set; }=string.Empty;
public long CategoryId { get; set; }
}
}

View File

@@ -0,0 +1,63 @@
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// 产品属性值模型
/// </summary>
public class ProductAttributeValueModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 产品ID
/// </summary>
public long ProductId { get; set; }
/// <summary>
/// 预设值ID
/// </summary>
public long OptionId { get; set; }
/// <summary>
/// 产品属性关系数据ID
/// </summary>
public long ProductAttributeRelationId { get; set; }
/// <summary>
/// 属性值名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 属性图片
/// </summary>
public string Image { get; set; } = string.Empty;
/// <summary>
/// 重量
/// </summary>
public decimal Weight { get; set; }
/// <summary>
/// 重量单位1克2千克3磅4盎司
/// </summary>
public int WeightUnit { get; set; }
/// <summary>
/// 是否是加重的
/// </summary>
public bool IsAddWeight { get; set; } = false;
/// <summary>
/// 展示排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 是否在编辑
/// </summary>
public bool IsEdit { get; set; }
}
}

View File

@@ -0,0 +1,6 @@
namespace Atomx.Admin.Client.Models
{
public class ProductDetailModel
{
}
}

View File

@@ -0,0 +1,241 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class ProductModel
{
/// <summary>
/// 产品ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 父产品ID
/// </summary>
public long ParentProductId { get; set; }
/// <summary>
/// 发布用户ID
/// </summary>
public long UserId { get; set; }
/// <summary>
/// 归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 卖家店铺ID
/// </summary>
public long StoreId { get; set; }
/// <summary>
/// 产品类型ID
/// </summary>
public long ProductTypeId { get; set; }
/// <summary>
/// 分类路径
/// </summary>
public string? CategoryPath { get; set; } = string.Empty;
/// <summary>
/// 分类ID
/// </summary>
public long CategoryId { get; set; }
/// <summary>
/// 制造商ID
/// </summary>
public long ManufacturerId { get; set; }
/// <summary>
/// SEO Title
/// </summary>
public string MetaTitle { get; set; } = string.Empty;
/// <summary>
/// SEO Description
/// </summary>
public string MetaDescription { get; set; } = string.Empty;
/// <summary>
/// 产品Slug
/// </summary>
public string Slug { get; set; } = string.Empty;
/// <summary>
/// 产品名称
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 产品唯一编码
/// </summary>
public string? SIN { get; set; } = string.Empty;
/// <summary>
/// 封面图片
/// </summary>
public string? Image { get; set; } = string.Empty;
/// <summary>
/// 产品图片JSON
/// </summary>
public string? Photos { get; set; } = string.Empty;
/// <summary>
/// 产品卖点
/// </summary>
public string? Feature { get; set; } = string.Empty;
/// <summary>
/// 产品简介
/// </summary>
public string? Description { get; set; } = string.Empty;
/// <summary>
/// 产品特点标签
/// </summary>
public string? Tags { get; set; } = string.Empty;
/// <summary>
/// 产品详细介绍
/// </summary>
public string Body { get; set; } = string.Empty;
/// <summary>
/// 规格信息Json
/// </summary>
public string? Specification { get; set; } = string.Empty;
/// <summary>
/// 商品库存
/// </summary>
public int StockQuantity { get; set; }
/// <summary>
/// 重量
/// </summary>
public decimal? Weight { get; set; }
/// <summary>
/// 市场价,划线价
/// </summary>
public decimal MarketPrice { get; set; }
/// <summary>
/// 销售标价
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// SKU组合的产品价格信息
/// </summary>
public string? SkuPrices { get; set; } = string.Empty;
/// <summary>
/// 商品扩展信息
/// </summary>
public string Extended { get; set; } = string.Empty;
/// <summary>
/// 订单最小数量
/// </summary>
public int OrderMinimumQuantity { get; set; }
/// <summary>
/// 订单最多数量
/// </summary>
public int OrderMaximumQuantity { get; set; }
/// <summary>
/// 是否允许退货
/// </summary>
public bool AllowReturn { get; set; }
/// <summary>
/// 是否允许换货
/// </summary>
public bool AllowExchange { get; set; }
/// <summary>
/// 是否独立发货
/// </summary>
public bool SingleShip { get; set; }
/// <summary>
/// 预计运输天数
/// </summary>
public int ShippingDays { get; set; }
/// <summary>
/// 运费模板ID
/// </summary>
public long ShippingId { get; set; }
/// <summary>
/// 精选
/// </summary>
public bool IsFeatured { get; set; }
/// <summary>
/// 是否 best
/// </summary>
public bool IsBest { get; set; }
/// <summary>
/// 是否标注新品
/// </summary>
public bool IsNew { get; set; }
/// <summary>
/// 排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 暂停销售,前台处理成已售罄
/// </summary>
public bool StopSales { get; set; }
/// <summary>
/// 产品状态0未上架1上架
/// </summary>
public int Status { get; set; }
/// <summary>
/// 产品信息审核状态
/// </summary>
public int ReviewStatus { get; set; }
/// <summary>
/// 禁用优惠券
/// </summary>
public bool DisableCoupons { get; set; }
/// <summary>
/// 产品属性
/// </summary>
public List<ProductSaleAttributeModel> ProductSaleAttributes { get; set; } = new();
/// <summary>
/// 产品属性组合信息
/// </summary>
public List<ProductAttributeCombinationModel> ProductAttributeCombinations { get; set; } = new();
/// <summary>
/// 用来设置SKU属性图片的数据源
/// </summary>
public List<ProductAttribute> PhotoSalesAttribute { get; set; } = new();
/// <summary>
/// 是否编辑
/// </summary>
public bool IsEdit { get; set; } = false;
}
}

View File

@@ -0,0 +1,23 @@
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// SKU价格
/// </summary>
public class ProductSKUPricesModel
{
/// <summary>
/// SKU组合ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 市场价
/// </summary>
public decimal? MarketPrice { get; set; }
/// <summary>
/// 销售价
/// </summary>
public decimal? Price { get; set; }
}
}

View File

@@ -0,0 +1,68 @@
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// 产品销售属性模型
/// </summary>
public class ProductSaleAttributeModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 属性ID
/// </summary>
public long AttributeId { get; set; }
/// <summary>
/// 控件的类型
/// </summary>
public int ControlType { get; set; }
/// <summary>
/// 必须填重量
/// </summary>
public bool WeightIsRequired { get; set; }
/// <summary>
/// 属性名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 是否拥有规格图片
/// </summary>
public bool Image { get; set; }
/// <summary>
/// 属性排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 产品属性值
/// </summary>
public List<ProductAttributeValueModel> ProductAttributeValues { get; set; } = new List<ProductAttributeValueModel>();
/// <summary>
///
/// </summary>
public string SelectOption { get; set; } = string.Empty;
/// <summary>
/// 输入的新属性值
/// </summary>
public string InputText { get; set; } = string.Empty;
/// <summary>
/// 是否编辑状态
/// </summary>
public bool AddAttribute { get; set; }
/// <summary>
/// 是否是必须的属性
/// </summary>
public bool IsRequired { get; set; }
}
}

View File

@@ -0,0 +1,6 @@
namespace Atomx.Admin.Client.Models
{
public class ProductSaleSpecificationAttributeModel
{
}
}

View File

@@ -0,0 +1,25 @@
namespace Atomx.Admin.Client.Models
{
public class ProductSearch : BaseSearch
{
/// <summary>
/// 产品标题
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 分类ID
/// </summary>
public string CategoryId { get; set; } = string.Empty;
/// <summary>
/// 产品状态
/// </summary>
public string Status { get; set; } = string.Empty;
/// <summary>
/// 开始时间
/// </summary>
public DateTime?[] RangeTime { get; set; } = new DateTime?[] { null, null };
}
}

View File

@@ -0,0 +1,77 @@
using Atomx.Utils.Extension;
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// 产品SKU信息模型
/// </summary>
public class ProductSkuModel : IEquatable<ProductSkuModel>
{
/// <summary>
/// 属性ID
/// </summary>
public long AttributeId { get; set; }
/// <summary>
/// 属性名称
/// </summary>
public string AttributeName { get; set; } = string.Empty;
/// <summary>
/// 属性值ID
/// </summary>
public long ValueId { get; set; }
/// <summary>
/// 属性值 Name
/// </summary>
public string ValueName { get; set; } = string.Empty;
/// <summary>
/// 重量
/// </summary>
public decimal Weight { get; set; }
/// <summary>
/// 重量单位,1毫克mg2克g,3千克kg,4吨t5磅lb6盎司oz
/// </summary>
public int WeightUnit { get; set; }
public bool Equals(ProductSkuModel? other)
{
if (other is null) return false;
if (ValueId != other.ValueId)
{
return AttributeId == other.AttributeId &&
ValueId == other.ValueId &&
Weight.RemoveTrailingZeros() == other.Weight.RemoveTrailingZeros() &&
WeightUnit == other.WeightUnit &&
AttributeName == other.AttributeName &&
ValueName == other.ValueName;
}
else
{
return AttributeId == other.AttributeId &&
ValueId == other.ValueId &&
AttributeName == other.AttributeName;
}
}
public override bool Equals(object obj) => Equals(obj as ProductSkuModel);
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + AttributeId.GetHashCode();
hash = hash * 23 + ValueId.GetHashCode();
hash = hash * 23 + Weight.GetHashCode();
hash = hash * 23 + WeightUnit.GetHashCode();
hash = hash * 23 + (AttributeName?.GetHashCode() ?? 0);
hash = hash * 23 + (ValueName?.GetHashCode() ?? 0);
return hash;
}
}
}
}

View File

@@ -0,0 +1,75 @@
namespace Atomx.Admin.Client.Models
{
public class ProductStockAttributeModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 属性ID
/// </summary>
public long AttributeId { get; set; }
/// <summary>
/// 控件的类型
/// </summary>
public int ControlType { get; set; }
/// <summary>
/// 必须填重量
/// </summary>
public bool WeightIsRequired { get; set; }
/// <summary>
/// 重量单位,1毫克mg2克g,3千克kg,4吨t5磅lb6盎司oz
/// </summary>
public int WeightUnit { get; set; }
/// <summary>
/// 属性名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 是否拥有规格图片
/// </summary>
public bool Image { get; set; }
/// <summary>
/// 属性排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 产品属性值
/// </summary>
public List<ProductAttributeValueModel> ProductAttributeValues { get; set; } = new List<ProductAttributeValueModel>();
/// <summary>
/// 新产品属性值
/// </summary>
public ProductAttributeValueModel AttributeValue { get; set; } = new ProductAttributeValueModel();
/// <summary>
///
/// </summary>
public string SelectOption { get; set; } = string.Empty;
/// <summary>
/// 输入的新属性值
/// </summary>
public string InputText { get; set; } = string.Empty;
/// <summary>
/// 是否编辑状态
/// </summary>
public bool AddAttribute { get; set; }
/// <summary>
/// 是否是必须的属性
/// </summary>
public bool IsRequired { get; set; }
}
}

View File

@@ -0,0 +1,32 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class ProductStockModel: ProductAttributeCombination
{
/// <summary>
/// 产品名称
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 封面图片
/// </summary>
public string? Image { get; set; } = string.Empty;
/// <summary>
/// 产品SKU信息
/// </summary>
public List<ProductSkuModel> Sku { get; set; } = new();
/// <summary>
/// 仓库ID
/// </summary>
public long WarehouseId { get; set; }
/// <summary>
/// 添加库存
/// </summary>
public int AddStockQuantity { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// 产品SKU库存量模型
/// </summary>
public class ProductStockUnitModel : ProductAttributeCombination
{
/// <summary>
/// 产品名称
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 封面图片
/// </summary>
public string? Image { get; set; } = string.Empty;
public List<ProductSkuModel> Sku { get; set; } = new();
}
}

View File

@@ -0,0 +1,23 @@
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// 产品SKU库存量搜索模型
/// </summary>
public class ProductStockUnitSearch : BaseSearch
{
/// <summary>
/// 产品ID
/// </summary>
public int Type { get; set; }
/// <summary>
/// 产品名称
/// </summary>
public string Key { get; set; } = string.Empty;
/// <summary>
/// 重量
/// </summary>
public decimal Weight { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class ProductTransferSearch : BaseSearch
{
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class RawMaterialBatchSearch : BaseSearch
{
/// <summary>
/// 原料类型ID
/// </summary>
public long MaterialId { get; set; }
/// <summary>
/// 原料归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 原料归属店铺网点ID
/// </summary>
public long StoreId { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
namespace Atomx.Admin.Client.Models
{
public class RawMaterialRecordSearch : BaseSearch
{
/// <summary>
/// 原料类型ID
/// </summary>
public long MaterialId { get; set; }
/// <summary>
/// 原料归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 原料归属店铺网点ID
/// </summary>
public long StoreId { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
namespace Atomx.Admin.Client.Models
{
public class RawMaterialSearch : BaseSearch
{
/// <summary>
/// 原料类型ID
/// </summary>
public long MaterialId { get; set; }
/// <summary>
/// 原料归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 原料归属店铺网点ID
/// </summary>
public long StoreId { get; set; }
}
}

View File

@@ -0,0 +1,25 @@
namespace Atomx.Admin.Client.Models
{
public class RawMaterialTransferSearch : BaseSearch
{
/// <summary>
/// 原料类型ID
/// </summary>
public long MaterialId { get; set; }
/// <summary>
/// 原料归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 原料归属店铺网点ID
/// </summary>
public long FromStoreId { get; set; }
/// <summary>
/// 原料归属店铺网点ID
/// </summary>
public long ToStoreId { get; set; }
}
}

View File

@@ -0,0 +1,47 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Atomx.Admin.Client.Models
{
public class RoleModel
{
/// <summary>
/// 数据ID
/// </summary>
public int Id { get; set; }
/// <summary>
/// 角色类型
/// </summary>
public int Type { get; set; }
/// <summary>
/// 角色名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 说明
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// 权限
/// </summary>
public string Permission { get; set; } = string.Empty;
/// <summary>
/// 是否系统角色
/// </summary>
public bool IsSystemRole { get; set; }
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 是否是编辑
/// </summary>
public bool IsEdit { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace Atomx.Admin.Client.Models
{
public class RolePermissionGroup
{
public string Category { get; set; }
public string CategoryName { get; set; }
public List<RolePermissionItem> PermissionItems { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Atomx.Admin.Client.Models
{
public class RolePermissionItem
{
public string Name { get; set; }
public string Description { get; set; }
public bool IsSelected { get; set; }
}
}

View File

@@ -0,0 +1,7 @@
namespace Atomx.Admin.Client.Models
{
public class RoleSearch
{
public string? Name { get; set; }
}
}

View File

@@ -0,0 +1,26 @@
namespace Atomx.Admin.Client.Models
{
public class SiteAppModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 网站应用类型
/// </summary>
public int Type { get; set; }
/// <summary>
/// 网站应用名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Atomx.Admin.Client.Models
{
public class SiteAppSearch : BaseSearch
{
public int? Type { get; set; }
public string Name { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,9 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class SpecificationAttributeItemModel:SpecificationAttribute
{
public string CategoryName { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,47 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Atomx.Admin.Client.Models
{
public class SpecificationAttributeModel
{
/// <summary>
/// 属性ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public long Id { get; set; }
/// <summary>
/// 上级属性,用于规格属性做分组
/// </summary>
public long ParentId { get; set; }
/// <summary>
/// 分类ID
/// </summary>
public long CategoryId { get; set; }
/// <summary>
/// 属性名称
/// </summary>
[Column(TypeName = "varchar(50)")]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 属性控件类型1选项2文本
/// </summary>
public int ControlType { get; set; }
/// <summary>
/// 展示排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 数据状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,47 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Atomx.Admin.Client.Models
{
public class SpecificationAttributeOptionModel
{
/// <summary>
/// 预设值ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public long Id { get; set; }
/// <summary>
/// 供应商自定义值
/// </summary>
public long VendorId { get; set; }
/// <summary>
/// 产品属性ID
/// </summary>
public long SpecificationId { get; set; }
/// <summary>
/// 预设值名称
/// </summary>
[Column(TypeName = "varchar(50)")]
public string Value { get; set; } = string.Empty;
/// <summary>
/// 展示排序
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// 是否通用的
/// </summary>
public bool Standard { get; set; }
/// <summary>
/// 数据状态
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
namespace Atomx.Admin.Client.Models
{
public class SpecificationAttributeOptionSearch:BaseSearch
{
/// <summary>
/// 值
/// </summary>
public string? Value { get; set; }
/// <summary>
/// 规格ID
/// </summary>
public long SpecificationId { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
namespace Atomx.Admin.Client.Models
{
public class SpecificationAttributeSearch : BaseSearch
{
/// <summary>
/// 名称
/// </summary>
public string? Name { get; set; }
public long CategoryId { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class StoreProductItemSearch
{
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class StoreSearch : BaseSearch
{
}
}

View File

@@ -0,0 +1,42 @@
namespace Atomx.Admin.Client.Models
{
public class UploadFileModel
{
public long Id { get; set; }
/// <summary>
/// 文件类型
/// </summary>
public int Type { get; set; }
/// <summary>
/// 文件名
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 存放路径
/// </summary>
public string Path { get; set; } = string.Empty;
/// <summary>
/// 文件扩展
/// </summary>
public string Extension { get; set; } = string.Empty;
/// <summary>
/// 文件扩展
/// </summary>
public string ContentType { get; set; } = string.Empty;
/// <summary>
/// 创建用户ID
/// </summary>
public long CreateUid { get; set; }
/// <summary>
/// 创建用户名
/// </summary>
public string CreateBy { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,20 @@
namespace Atomx.Admin.Client.Models
{
public class UploadFileSearch : BaseSearch
{
/// <summary>
/// 文件类型
/// </summary>
public int? Type { get; set; }
/// <summary>
/// 名称
/// </summary>
public string? Name { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime?[] RangeTime { get; set; } = new DateTime?[] { null, null };
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Atomx.Admin.Client.Models
{
public class UserSearch : BaseSearch
{
/// <summary>
/// 用户名或昵称
/// </summary>
public string? Username { get; set; }
/// <summary>
/// 邮件地址
/// </summary>
public string? Email { get; set; }
/// <summary>
/// 手机号码
/// </summary>
public string? Mobile { get; set; }
/// <summary>
/// 真实姓名
/// </summary>
public string? RealName { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime?[] RangeTime { get; set; } = new DateTime?[] { null, null };
/// <summary>
/// 状态
/// </summary>
public string? Status { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using Atomx.Common.Entities;
namespace Atomx.Admin.Client.Models
{
public class WarehouseItemModel:Warehouse
{
/// <summary>
/// 公司名称
/// </summary>
public string CorporationName { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,28 @@
namespace Atomx.Admin.Client.Models
{
/// <summary>
/// 仓库模型
/// </summary>
public class WarehouseModel
{
/// <summary>
/// 数据ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 归属公司ID
/// </summary>
public long CorporationId { get; set; }
/// <summary>
/// 分类名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 是否可用
/// </summary>
public bool Enabled { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
namespace Atomx.Admin.Client.Models
{
public class WarehouseSearch : BaseSearch
{
/// <summary>
/// 仓库名称
/// </summary>
public string? Name { get; set; } = string.Empty;
/// <summary>
/// 企业ID
/// </summary>
public long CorporationId { get; set; } = 0;
/// <summary>
/// 企业名称
/// </summary>
public string CorporationName { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,5 @@
<h3>ContentEdit</h3>
@code {
}

View File

@@ -0,0 +1,7 @@
@page "/content/list"
<h3>ContentList</h3>
@code {
}

View File

@@ -0,0 +1,5 @@
<h3>PageEdit</h3>
@code {
}

View File

@@ -0,0 +1,8 @@
@page "/content/page/list"
<h3>PageList</h3>
@code {
}

View File

@@ -0,0 +1,18 @@
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}

View File

@@ -0,0 +1,24 @@
@page "/"
@attribute [Authorize]
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<li>
<a href="/category/list">产品分类</a>
</li>
<li>
<a href="/product/category/edit">产品分类编辑</a>
</li>
<li>
<a href="/system/language/list">多语言设置</a>
</li>
<li>
<a href="/system/locale/resource/list">多语言资源设置</a>
</li>
<li>
<a href="/system/role/list">角色管理</a>
</li>

View File

@@ -0,0 +1,140 @@
@page "/account/login"
@layout EmptyLayout
@inject ILogger<Login> Logger
<PageTitle>登录</PageTitle>
@if (!dataLoaded)
{
<Spin Spinning="_isLoading" />
}
else
{
<Flex Style="height:100vh" Justify="FlexJustify.Center" Align="FlexAlign.Center" Direction="FlexDirection.Vertical">
<GridRow Justify="RowJustify.Center" Class="">
<GridCol>
<Card>
<Form @ref="form" Model="@login" OnFinish="LoginAsync">
<FluentValidationValidator />
<FormItem>
<AntDesign.Input Placeholder="登录账号" Size="InputSize.Large" @bind-Value="@login.Account">
<Prefix><Icon Type="user" /></Prefix>
</AntDesign.Input>
</FormItem>
<FormItem>
<AntDesign.Input Placeholder="登录密码" Size="InputSize.Large" @bind-Value="@login.Password" Type="InputType.Password">
<Prefix><Icon Type="lock" /></Prefix>
</AntDesign.Input>
</FormItem>
<FormItem>
<a style="float: left;">
忘记密码
</a>
<a style="float: right;">
<NavLink href="/register">马上注册</NavLink>
</a>
</FormItem>
<FormItem>
<Button Type="ButtonType.Primary" HtmlType="submit" Class="submit" Size="ButtonSize.Large" Block>登录</Button>
</FormItem>
</Form>
</Card>
</GridCol>
</GridRow>
<GridRow Style="padding-top:40px">
<span style="font-size:12px;padding-right:3px;">Copyright © 2025-@DateTime.Now.Year Atomx.cn All rights reserved.</span>
<span style="font-size:12px">runing as @handler</span>
</GridRow>
</Flex>
}
@code {
string handler = "Server";
[Parameter]
[SupplyParameterFromQuery(Name = "ReturnUrl")]
public string? ReturnUrl { get; set; }
[SupplyParameterFromForm]
public LoginModel login { get; set; } = new();
private Form<LoginModel> form = null!;
bool dataLoaded = false;
string message { get; set; } = string.Empty;
private bool _isLoading = false;
protected override void OnInitialized()
{
if (OperatingSystem.IsBrowser())
{
handler = "Wasm";
}
else
{
handler = "Server";
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
if (authState.User.Identity != null)
{
if (authState.User.Identity.IsAuthenticated)
{
Navigation.NavigateTo(ReturnUrl ?? "/");
}
}
}
if (!dataLoaded)
{
dataLoaded = true;
StateHasChanged();
}
}
private async Task LoginAsync()
{
if (form.Validate())
{
var api = "/api/sign/in";
var result = await HttpService.Post<ApiResult<string>>(api, login);
if (result.Success)
{
Console.WriteLine("请求api成功");
if (!string.IsNullOrEmpty(result.Data))
{
await localStorage.SetItemAsStringAsync(StorageKeys.JWTTokenKeyName, result.Data);
await localStorage.SetItemAsStringAsync("refreshToken", result.Data);
var authState = (AuthStateProvider as PersistentAuthenticationStateProvider);
if (authState != null)
{
authState.UpdateAuthenticationState(result.Data);
}
Logger.LogInformation($"登录成功跳转目标,{ReturnUrl}");
Navigation.NavigateTo(ReturnUrl ?? "/");
}
}
else
{
ModalService.Error(new ConfirmOptions() { Title = "提示", Content = result.Message });
}
}
}
private async Task OnPasswordKeyDown(KeyboardEventArgs value)
{
if (value.Key == "Enter")
{
await LoginAsync();
}
}
}

View File

@@ -0,0 +1,11 @@
@page "/logout"
@layout EmptyLayout
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await ((PersistentAuthenticationStateProvider)AuthStateProvider).MarkUserAsLoggedOut();
Navigation.NavigateTo("/account/login");
await base.OnAfterRenderAsync(firstRender);
}
}

View File

@@ -0,0 +1,5 @@
<h3>OrderList</h3>
@code {
}

View File

@@ -0,0 +1,7 @@
@page "/orders/view/{OrderId:long}"
<h3>OrderView</h3>
@code {
}

View File

@@ -0,0 +1,137 @@
@page "/product/category/edit"
@page "/product/category/edit/{Id:long?}"
@inject ILogger<CategoryEdit> Logger
@* @attribute [Authorize] *@
<PageTitle>分类编辑</PageTitle>
<Title Level="4">分类信息</Title>
<Spin Spinning="pageLoading">
<Card Title="" Class="hideborder"
Style="margin-top: 24px;"
BodyStyle="padding: 0 32px 40px 32px">
<Form @ref="editform" Model="@model" LabelColSpan="5" WrapperColSpan="19" OnFinish="OnFormFinishAsync">
@* @if (languages.Count > 1 && Id > 0)
{
<Tabs ActiveKey="@context.Language" OnTabClick="OnLanguageTabChange">
<TabPane Key="0">
<TabTemplate>
<span>标准</span>
</TabTemplate>
</TabPane>
@foreach (var item in languages)
{
<TabPane Key="@item.Id.ToString()">
<TabTemplate>
<span>@item.Name @item.Id.ToString()</span>
</TabTemplate>
</TabPane>
}
</Tabs>
}
<FormItem Label="上级菜单">
<SimpleSelect DefaultValue="" Style="width:300px;" @bind-Value="@context.ParentId">
<SelectOptions>
<SimpleSelectOption Value="0" Label="无上级"></SimpleSelectOption>
@foreach (var item in categories)
{
<SimpleSelectOption Value="@item.Id.ToString()" Label="@item.Name"></SimpleSelectOption>
}
</SelectOptions>
</SimpleSelect>
</FormItem>
<FormItem Label="分类名称" Required>
<Input @bind-Value="@context.Name" Placeholder="分类名称" />
</FormItem>
<FormItem Label="URL缩略名" Required>
<Input @bind-Value="@context.Slug" Placeholder="URL缩略名" />
</FormItem>
<FormItem Label="图标">
<Button OnClick="HandleSetIcon">
@if (string.IsNullOrEmpty(formModel.Image))
{
<span>选择图标</span>
}
else
{
<span>已选图标:</span>
}
</Button> <Button Size="@ButtonSize.Large" Type="@ButtonType.Text" Icon="@formModel.Image"></Button>
</FormItem> *@
<FormItem Label="Meta描述">
<Input @bind-Value="@context.MetaDescription" Placeholder="Meta描述" />
</FormItem>
<FormItem Label="Meta关键词">
<Input @bind-Value="@context.MetaKeywords" Placeholder="Meta关键词" />
</FormItem>
<FormItem Label="显示排序">
<Input @bind-Value="@context.DisplayOrder" Placeholder="显示排序" />
</FormItem>
<FormItem Label="状态">
<Checkbox @bind-Checked="@context.Enabled">启用</Checkbox>
</FormItem>
<FormItem WrapperCol="new ColLayoutParam { Span = 24, Offset = 5 }">
<Button Type="@ButtonType.Primary" HtmlType="submit">
提交保存
</Button>
</FormItem>
</Form>
</Card>
</Spin>
@code {
[SupplyParameterFromQuery]
int? Lang { get; set; }
[Parameter]
public long? Id { get; set; }
[SupplyParameterFromForm]
CategoryModel model { get; set; } = new();
Form<CategoryModel> editform = null!;
bool pageLoading = true;
List<CategoryItem> Categories = new();
protected override void OnInitialized()
{
base.OnInitialized();
}
protected override async Task OnParametersSetAsync()
{
pageLoading = true;
// await LoadCategories();
// if (Id > 0)
// {
// await LoadData();
// await SearchAttribute(string.Empty);
// }
// else
// {
// editCategory = true;
// CategoryPath = string.Empty;
// }
// if (Categories.Any())
// {
// BindCategory();
// }
pageLoading = false;
base.OnParametersSet();
}
async Task LoadCategories()
{
var url = $"/api/category/items";
var apiResult = await HttpService.Get<ApiResult<List<CategoryItem>>>(url);
if (apiResult.Success)
{
Categories = apiResult.Data ?? new();
}
}
async void OnFormFinishAsync()
{
}
}

View File

@@ -0,0 +1,336 @@
@page "/category/list"
@inject ILogger<CategoryList> Logger
@attribute [Authorize]
<PageTitle>分类管理</PageTitle>
<Title Level="4">菜单管理</Title>
<Card>
<Form @ref="searchForm" Model="search" Layout="FormLayout.Inline" Class="search-form" OnFinish="OnSearchFinish">
<Row Justify="RowJustify.Start" Gutter="16">
<Col>
<FormItem Label="名称">
<Input @bind-Value="search.Name" Placeholder="名称" AllowClear />
</FormItem>
</Col>
<Col>
<div class="ant-form-item" style="width:200px;display:flex;">
<Button Type="ButtonType.Primary" HtmlType="submit">查询</Button>
<Button Style="margin: 0 8px;" OnClick="OnSearchReset">重置</Button>
</div>
</Col>
</Row>
</Form>
</Card>
<Card Class="mt-3">
<Table DataSource="categories" PageSize="100" HidePagination="true" Resizable>
<TitleTemplate>
<Flex Justify="FlexJustify.SpaceBetween">
菜单列表
<div>
<Button Class="me-3" OnClick="OnCreateClick" Type="ButtonType.Primary">新增</Button>
</div>
</Flex>
</TitleTemplate>
<ColumnDefinitions>
<PropertyColumn Property="c=>c.Name" Title="名称">
<AntDesign.Text>@GetName(context)</AntDesign.Text>
</PropertyColumn>
<PropertyColumn Property="c=>c.Slug" Title="缩略名" Width="80px" Align="ColumnAlign.Center">
</PropertyColumn>
<PropertyColumn Property="c=>c.DisplayOrder" Title="排序" Width="100px" />
<PropertyColumn Property="c=>c.Enabled" Title="状态" Width="80px" Align="ColumnAlign.Center">
@if (context.Enabled)
{
<AntDesign.Text Type="TextElementType.Success"><Icon Type="check" Theme=" IconThemeType.Outline" Width="1.3em" Height="1.3em" /></AntDesign.Text>
}
else
{
<Icon Type="close" Theme="IconThemeType.Outline" Width="1.3em" Height="1.3em" />
}
</PropertyColumn>
<PropertyColumn Property="c=>c.CreateTime" Title="时间" Width="190px" />
<ActionColumn Title="操作" Align="ColumnAlign.Right" Width="160px">
<Space>
@if (context.IsLast)
{
<SpaceItem>
<a Href="@($"/attribute/list?categoryid={context.Id}")">属性</a>
</SpaceItem>
<SpaceItem>
<a Href="@($"/specification/list?categoryid={context.Id}")">规格</a>
</SpaceItem>
}
<SpaceItem>
<Dropdown Trigger="@(new Trigger[] { Trigger.Click })">
<Overlay>
<Menu>
<MenuItem>
<a @onclick="(e)=>OnEditClick(context)"> <Icon Type="@IconType.Outline.Edit" /> 编辑</a>
</MenuItem>
<MenuDivider />
<MenuItem>
<Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")"
OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))"
OkText="确定"
CancelText="取消">
<a> <Icon Type="@IconType.Outline.Delete" /> 删除</a>
</Popconfirm>
</MenuItem>
</Menu>
</Overlay>
<ChildContent>
<a class="ant-dropdown-link" @onclick:preventDefault>
<Icon Type="@IconType.Outline.Menu" />
</a>
</ChildContent>
</Dropdown>
</SpaceItem>
</Space>
</ActionColumn>
</ColumnDefinitions>
</Table>
</Card>
<Drawer Closable="true" Width="520" Visible="drawerVisible" Title='("设置菜单")' OnClose="_=>CloseDrawer()">
<Form LabelColSpan="5" @ref="@editform" Model="@model" OnFinish="OnFormFinish">
<FluentValidationValidator />
<FormItem Label="名称">
<Input @bind-Value="model.Name" For="(()=>model.Name)" />
</FormItem>
<FormItem Label="缩略名">
<Input @bind-Value="model.Slug" For="(()=>model.Slug)" />
</FormItem>
<FormItem Label="上级分类">
<Select @bind-Value="@model.ParentId" TItemValue="long" TItem="string" Placeholder="请选择上级分类">
<SelectOptions>
<SelectOption Value="0L" Label="无" />
@foreach (var item in categories)
{
<SelectOption Value="@item.Id" Label="@GetName(item)" />
}
</SelectOptions>
</Select>
</FormItem>
<FormItem Label="排序">
<Input @bind-Value="model.DisplayOrder" For="(()=>model.DisplayOrder)" />
</FormItem>
<FormItem Label="状态">
<Checkbox @bind-Value="model.Enabled" For="(()=>model.Enabled)">启用</Checkbox>
</FormItem>
<FormItem WrapperColOffset="4">
<Button Type="ButtonType.Primary" HtmlType="submit" Style="width: 100%;">保存</Button>
</FormItem>
</Form>
</Drawer>
@code {
[SupplyParameterFromQuery]
int? Page { get; set; }
[SupplyParameterFromForm]
CategorySearch search { get; set; } = new();
Form<CategorySearch> searchForm = null!;
[SupplyParameterFromForm]
CategoryModel model { get; set; } = new();
Form<CategoryModel> editform = null!;
List<CategoryItem> categories = new();
bool drawerVisible;
protected override void OnParametersSet()
{
loadQueryString();
LoadList();
base.OnParametersSet();
}
void loadQueryString()
{
var uri = new Uri(Navigation.Uri);
var query = uri.Query;
search.Name = query.GetQueryString("Name");
}
private async void LoadList()
{
var url = "/api/category/list";
var apiResult = await HttpService.Get<ApiResult<List<CategoryItem>>>(url);
if (apiResult.Success)
{
if (apiResult.Data != null)
{
categories = apiResult.Data;
StateHasChanged();
}
}
}
void OnSearchFinish()
{
Page = Page.GetValueOrDefault(1) - 1;
OnSearch(Page.Value);
}
void OnSearchReset()
{
search = new();
searchForm?.Reset();
OnSearchFinish();
}
private void OnReset()
{
search = new();
LoadList();
}
private void OnSearch(int page)
{
var queryString = search.BuildQueryString();
if (string.IsNullOrEmpty(queryString))
{
if (page > 1)
{
Navigation.NavigateTo($"/category/list?page={page}");
}
else
{
Navigation.NavigateTo($"/category/list");
}
}
else
{
if (page > 1)
{
Navigation.NavigateTo($"/category/list?page={page}&{queryString}");
}
else
{
Navigation.NavigateTo($"/category/list?{queryString}");
}
}
LoadList();
}
async Task HandleDeleteConfirmAsync(MouseEventArgs e, long id)
{
var url = $"/api/category/delete/{id}";
var apiResult = await HttpService.Post<ApiResult<string>>(url, new());
if (apiResult.Success)
{
LoadList();
await ModalService.InfoAsync(new ConfirmOptions() { Title = "操作提示", Content = "删除数据成功" });
}
else
{
await ModalService.ErrorAsync(new ConfirmOptions() { Title = "操作提示", Content = $"数据删除失败.{apiResult.Message}" });
}
}
void OnEditClick(CategoryItem item)
{
this.model = item.Adapt<CategoryModel>();
drawerVisible = true;
}
async Task OnFormFinish()
{
if (editform.Validate())
{
var result = new ApiResult<string>();
var data = model.Adapt<CategoryModel>();
if (model.Id > 0)
{
var url = $"api/category/edit";
result = await HttpService.Post<ApiResult<string>>(url, data);
}
else
{
var url = $"api/category/add";
result = await HttpService.Post<ApiResult<string>>(url, data);
}
if (result.Code == (int)ResultCode.Success)
{
CloseDrawer();
LoadList();
await ModalService.InfoAsync(new ConfirmOptions() { Title = "提示", Content = "数据提交成功!" });
}
else
{
await ModalService.ErrorAsync(new ConfirmOptions() { Title = "服务异常", Content = result.Message });
}
}
}
private string GetPath(string path)
{
var array = path.Split(",").ToList();
var pathText = string.Empty;
foreach (var item in array)
{
var name = categories.Where(p => p.Id == item.ToLong()).Select(p => p.Name).SingleOrDefault();
if (string.IsNullOrEmpty(pathText))
{
pathText = name;
}
else
{
pathText = $"{pathText}>{name}";
}
}
return pathText;
}
private string GetName(CategoryItem menu)
{
string name = string.Empty;
if (menu.Depth > 0)
{
var symbol = " ";
for (var i = 0; i < menu.Depth; i++)
{
symbol = $"{symbol}{symbol}";
}
name = $"{symbol}├ {menu.Name}";
}
else
{
name = menu.Name;
}
return name;
}
void OnCreateClick()
{
model = new CategoryModel();
drawerVisible = true;
}
void CloseDrawer()
{
drawerVisible = false;
editform.Reset();
}
}

View File

@@ -0,0 +1,5 @@
<h3>GoodsList</h3>
@code {
}

View File

@@ -0,0 +1,290 @@
@page "/attribute/predefined/list/{AttributeId:long}"
@inject ILogger<PredefinedAttributeList> Logger
@attribute [Authorize]
<PageTitle>产品属性管理</PageTitle>
<Title Level="4">属性列表</Title>
<Card>
<Form @ref="searchForm" Model="search" Layout="FormLayout.Inline" Class="search-form" OnFinish="OnSearchFinish">
<Row Justify="RowJustify.Start" Gutter="16">
<Col>
<FormItem Label="名称">
<Input @bind-Value="search.Value" Placeholder="名称" AllowClear />
</FormItem>
</Col>
<Col>
<div class="ant-form-item" style="width:200px;display:flex;">
<Button Type="ButtonType.Primary" HtmlType="submit">查询</Button>
<Button Style="margin: 0 8px;" OnClick="OnSearchReset">重置</Button>
</div>
</Col>
</Row>
</Form>
</Card>
<Card Class="mt-3">
<Table DataSource="PagingList.Items" PageSize="100" HidePagination="true" Resizable>
<TitleTemplate>
<Flex Justify="FlexJustify.SpaceBetween">
@productAttribute.Name 属性预设值列表
<div>
<Button Class="me-3" OnClick="OnCreateClick" Type="ButtonType.Primary">新增</Button>
</div>
</Flex>
</TitleTemplate>
<ColumnDefinitions>
<PropertyColumn Property="c=>c.Value" Title="名称"></PropertyColumn>
<PropertyColumn Property="c=>c.DisplayOrder" Title="排序" Width="150px" Align="ColumnAlign.Center" />
<PropertyColumn Property="c=>c.Status" Title="状态" Width="80px" Align="ColumnAlign.Center">
@if (context.Status == 1)
{
<AntDesign.Text Type="TextElementType.Success"><Icon Type="check" Theme=" IconThemeType.Outline" Width="1.3em" Height="1.3em" /></AntDesign.Text>
}
else
{
<Icon Type="close" Theme="IconThemeType.Outline" Width="1.3em" Height="1.3em" />
}
</PropertyColumn>
<PropertyColumn Property="c=>c.CreateTime" Title="时间" Width="200px" />
<ActionColumn Title="操作" Align="ColumnAlign.Right" Width="180px">
<Space>
<SpaceItem>
<a @onclick="(e)=>OnEditClick(context)">编辑</a>
</SpaceItem>
<SpaceItem>
<Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")"
OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))"
OkText="确定"
CancelText="取消">
<a>删除</a>
</Popconfirm>
</SpaceItem>
</Space>
</ActionColumn>
</ColumnDefinitions>
</Table>
<br />
<Row Justify="RowJustify.End">
<Pagination Current="PagingList.Index" Total="PagingList.Count" PageSize="PagingList.Size" ShowSizeChanger="false" OnChange="OnPageChanged"></Pagination>
</Row>
</Card>
<Drawer Closable="true" Width="520" Visible="drawerVisible" Title='($"设置{productAttribute.Name}属性预设值")' OnClose="_=>CloseDrawer()">
<Form LabelColSpan="4" @ref="@editform" Model="@model" OnFinish="OnFormFinish">
<FluentValidationValidator />
<FormItem Label="名称">
<Input @bind-Value="model.Value" For="(()=>model.Value)" />
</FormItem>
<FormItem Label="排序">
<Input @bind-Value="model.DisplayOrder" For="(()=>model.DisplayOrder)" />
</FormItem>
<FormItem Label="状态">
<RadioGroup @bind-Value="@model.Status" ButtonStyle="RadioButtonStyle.Solid">
<Radio RadioButton Value="1">启用</Radio>
<Radio RadioButton Value="2">禁用</Radio>
</RadioGroup>
</FormItem>
<FormItem WrapperColOffset="4">
<Button Type="ButtonType.Primary" HtmlType="submit" Style="width: 100%;">保存</Button>
</FormItem>
</Form>
</Drawer>
@code {
[Parameter]
public long AttributeId { get; set; }
[SupplyParameterFromQuery]
int? Page { get; set; }
[SupplyParameterFromQuery(Name = "size")]
int? PageSize { get; set; }
[SupplyParameterFromForm]
ProductAttributeOptionSearch search { get; set; } = new();
Form<ProductAttributeOptionSearch> searchForm = null!;
[SupplyParameterFromForm]
ProductAttributeOptionModel model { get; set; } = new();
Form<ProductAttributeOptionModel> editform = null!;
ProductAttribute productAttribute = new();
PagingList<ProductAttributeOption> PagingList = new();
bool loading { get; set; } = true;
bool searchExpand { get; set; } = false;
bool drawerVisible;
protected override void OnInitialized()
{
base.OnInitialized();
}
protected override void OnParametersSet()
{
loadQueryString();
LoadList();
LoadAttribute();
base.OnParametersSet();
}
void loadQueryString()
{
var uri = new Uri(Navigation.Uri);
var query = uri.Query;
search.Value = query.GetQueryString("Value");
}
private async void LoadAttribute()
{
var url = $"/api/productattribute/{AttributeId}";
var apiResult = await HttpService.Get<ApiResult<ProductAttribute>>(url);
if (apiResult.Success)
{
if (apiResult.Data != null)
{
productAttribute = apiResult.Data;
}
}
}
private async void LoadList()
{
loading = true;
var url = "/api/productattributeoption/search";
var apiResult = await HttpService.GetPagingList<ProductAttributeOption>(url, search, Page.GetValueOrDefault(1), PageSize.GetValueOrDefault(20));
if (apiResult.Success)
{
if (apiResult.Data != null)
{
PagingList = apiResult.Data;
}
}
loading = false;
StateHasChanged();
}
void OnSearchFinish()
{
Page = Page.GetValueOrDefault(1) - 1;
OnSearch(Page.Value);
}
private void OnSearchReset()
{
search = new();
LoadList();
}
private void OnSearch(int page)
{
var queryString = search.BuildQueryString();
if (string.IsNullOrEmpty(queryString))
{
if (page > 1)
{
Navigation.NavigateTo($"/attribute/predefined/list/{AttributeId}?page={page}");
}
else
{
Navigation.NavigateTo($"/attribute/predefined/list/{AttributeId}");
}
}
else
{
if (page > 1)
{
Navigation.NavigateTo($"/attribute/predefined/list/{AttributeId}?page={page}&{queryString}");
}
else
{
Navigation.NavigateTo($"/attribute/predefined/list/{AttributeId}?{queryString}");
}
}
}
void OnPageChanged(PaginationEventArgs args)
{
OnSearch(args.Page);
}
async Task HandleDeleteConfirmAsync(MouseEventArgs e, long id)
{
var url = $"/api/productattributeoption/delete/{model.Id}";
var apiResult = await HttpService.Post<ApiResult<string>>(url, new());
if (apiResult.Success)
{
LoadList();
await ModalService.InfoAsync(new ConfirmOptions() { Title = "操作提示", Content = "删除数据成功" });
}
else
{
await ModalService.ErrorAsync(new ConfirmOptions() { Title = "操作提示", Content = $"数据删除失败.{apiResult.Message}" });
}
}
async Task OnFormFinish()
{
if (editform.Validate())
{
var result = new ApiResult<string>();
if (model.Id > 0)
{
var url = $"api/productattributeoption/edit";
result = await HttpService.Post<ApiResult<string>>(url, model);
}
else
{
var url = $"api/productattributeoption/add";
result = await HttpService.Post<ApiResult<string>>(url, model);
}
if (result.Code == (int)ResultCode.Success)
{
CloseDrawer();
LoadList();
await ModalService.InfoAsync(new ConfirmOptions() { Title = "提示", Content = "数据提交成功!" });
}
else
{
await ModalService.ErrorAsync(new ConfirmOptions() { Title = "服务异常", Content = result.Message });
}
}
}
void OnEditClick(ProductAttributeOption option)
{
this.model = option.Adapt<ProductAttributeOptionModel>();
drawerVisible = true;
}
void OnCreateClick()
{
model = new();
drawerVisible = true;
}
private void CloseDrawer()
{
drawerVisible = false;
editform.Reset();
}
}

Some files were not shown because too many files have changed in this diff Show More