This commit is contained in:
2026-01-05 12:44:01 +08:00
parent 41a939176e
commit ea541fb6e4
14 changed files with 171 additions and 467 deletions

View File

@@ -2,7 +2,7 @@
namespace Atomx.Admin.Client.Models
{
public class StateProvinceModel: StateProvince
public class StateProvinceModel: Area
{
}
}

View File

@@ -111,7 +111,7 @@
async Task LoadStateProvinceAndCities()
{
var url = $"/api/stateprovince/tree/{CountryId}";
var url = $"/api/area/tree/{CountryId}";
var apiResult = await HttpService.Get<ApiResult<List<KeyValueTree>>>(url);
if (apiResult.Success)
{
@@ -164,14 +164,14 @@
{
area = apiResult.Data;
model = apiResult.Data.Adapt<AreaModel>();
if (model.ParentId > 0)
{
cities = $"{model.StateProvinceId},{model.ParentId}";
}
else if (model.StateProvinceId > 0)
{
cities = $"{model.StateProvinceId}";
}
// if (model.ParentId > 0)
// {
// cities = $"{model.StateProvinceId},{model.ParentId}";
// }
// else if (model.StateProvinceId > 0)
// {
// cities = $"{model.StateProvinceId}";
// }
}
}
else
@@ -186,13 +186,7 @@
void OnCitiesChange(CascaderNode[] selectedNodes)
{
Console.WriteLine($"value: {cities} selected: {string.Join(",", selectedNodes.Select(x => x.Value))}");
model.StateProvinceId = long.Parse(selectedNodes.First().Value.ToString() ?? "0");
model.ParentId = long.Parse(selectedNodes.Last().Value.ToString() ?? "0");
if (model.StateProvinceId == model.ParentId)
{
model.ParentId = 0;
}
}
async void OnFormFinishAsync()

View File

@@ -57,11 +57,11 @@
public long Id { get; set; }
[SupplyParameterFromForm]
StateProvinceModel model { get; set; } = new();
Form<StateProvinceModel> editform = null!;
AreaModel model { get; set; } = new();
Form<AreaModel> editform = null!;
List<KeyValue> languageList = new();
Country country = new();
StateProvinceLocalizedModel stateProvince = new();
AreaLocalizedModel stateProvince = new();
bool pageLoading = false;
bool saving = false;
@@ -125,8 +125,8 @@
async void LoadData()
{
pageLoading = true;
var url = $"/api/stateprovince/detail?id={Id}";
var apiResult = await HttpService.Get<ApiResult<StateProvinceLocalizedModel>>(url);
var url = $"/api/area/detail?id={Id}";
var apiResult = await HttpService.Get<ApiResult<AreaLocalizedModel>>(url);
if (apiResult.Success)
{
if (apiResult.Data == null)
@@ -136,7 +136,7 @@
else
{
stateProvince = apiResult.Data;
model = apiResult.Data.Adapt<StateProvinceModel>();
model = apiResult.Data.Adapt<AreaModel>();
}
}
else
@@ -153,7 +153,7 @@
if (editform.Validate())
{
saving = true;
var url = $"api/stateprovince/save";
var url = $"api/area/save";
var result = new ApiResult<string>();
result = await HttpService.Post<ApiResult<string>>(url, model);

View File

@@ -108,7 +108,7 @@
Form<StateProvinceSearch> searchForm = new();
StateProvinceSearch search = new();
PagingList<StateProvince> PagingList = new() { Size = 20 };
PagingList<Area> PagingList = new() { Size = 20 };
protected override async Task OnInitializedAsync()
@@ -136,8 +136,8 @@
try
{
pageLoading = true;
var url = "/api/stateprovince/search";
var apiResult = await HttpService.GetPagingList<StateProvince>(url, search, Page.GetValueOrDefault(1), PageSize.GetValueOrDefault(20));
var url = "/api/area/stateprovince/search";
var apiResult = await HttpService.GetPagingList<Area>(url, search, Page.GetValueOrDefault(1), PageSize.GetValueOrDefault(20));
if (apiResult.Success)
{
if (apiResult.Data != null)
@@ -209,12 +209,12 @@
}
void HandleEdit(StateProvince model)
void HandleEdit(Area model)
{
Navigation.NavigateTo($"/stateprovince/{CountryId}/edit/{model.Id}");
}
void GotoArea(StateProvince model)
void GotoArea(Area model)
{
Navigation.NavigateTo($"/area/list/{CountryId}/{model.Id}");
}

View File

@@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using System.Threading.Tasks;
namespace Atomx.Admin.Controllers
{
@@ -60,6 +61,21 @@ namespace Atomx.Admin.Controllers
_localizer = localizer;
}
/// <summary>
/// 获取省份-城市树形数据
/// </summary>
/// <param name="search"></param>
/// <param name="page"></param>
/// <param name="size"></param>
/// <returns></returns>
[HttpGet("tree/{countryId}")]
public async Task<IActionResult> GetAreatree(long countryId)
{
var result = new ApiResult<List<KeyValueTree>>();
var list = await _cacheService.GetAreaTree(countryId);
return new JsonResult(result.IsSuccess(list));
}
/// <summary>
/// 数据查询
/// </summary>
@@ -67,8 +83,8 @@ namespace Atomx.Admin.Controllers
/// <param name="page"></param>
/// <param name="size"></param>
/// <returns></returns>
[HttpPost("search")]
public IActionResult Search(AreaSearch search, int page, int size = 20)
[HttpPost("stateprovince/search")]
public async Task<IActionResult> StateProvinceSearch(AreaSearch search, int page, int size = 20)
{
if (page < 1)
{
@@ -77,9 +93,83 @@ namespace Atomx.Admin.Controllers
var result = new ApiResult<PagingList<AreaItem>>();
var list = new PagingList<AreaItem>() { Index = page, Size = size };
var countries = new List<Country>();
var stateProvices = new List<StateProvince>();
var query = from p in _dbContext.Areas
where p.StateProvinceId == 0
select p;
if (!string.IsNullOrEmpty(search.Name))
{
query = from p in query
where p.Name.Contains(search.Name)
select p;
}
if (search.CountryId > 0)
{
query = from p in query
where p.CountryId == search.CountryId
select p;
}
list.Count = query.Count();
var data = query.OrderByDescending(p => p.DisplayOrder).Skip((page - 1) * size).Take(size).ToList();
if (search.CountryId > 0)
{
var country = _dbContext.Countries.SingleOrDefault(p => p.Id == search.CountryId);
if (country != null)
{
countries.Add(country);
}
}
else
{
var countryIds = data.Select(p => p.CountryId).Distinct().ToList();
countries = _dbContext.Countries.Where(p => countryIds.Contains(p.Id)).ToList();
}
foreach (var item in data)
{
var model = _mapper.Map<AreaItem>(item);
var country = countries.SingleOrDefault(p => p.Id == item.CountryId);
if (country != null)
{
model.CountryName = country.Name;
}
var state = await _cacheService.GetStateProvince(item.CountryId, item.ParentId);
if (state != null)
{
model.StateProvinceName = state.Name;
}
list.Items.Add(model);
}
result = result.IsSuccess(list);
return new JsonResult(result);
}
/// <summary>
/// 数据查询
/// </summary>
/// <param name="search"></param>
/// <param name="page"></param>
/// <param name="size"></param>
/// <returns></returns>
[HttpPost("search")]
public async Task<IActionResult> SearchAsync(AreaSearch search, int page, int size = 20)
{
if (page < 1)
{
page = 1;
}
var result = new ApiResult<PagingList<AreaItem>>();
var list = new PagingList<AreaItem>() { Index = page, Size = size };
var countries = new List<Country>();
var query = from p in _dbContext.Areas
where p.StateProvinceId != 0
select p;
if (!string.IsNullOrEmpty(search.Name))
@@ -98,7 +188,7 @@ namespace Atomx.Admin.Controllers
if (search.StateProvinceId > 0)
{
query = from p in query
where p.StateProvinceId == search.StateProvinceId
where p.ParentId == search.StateProvinceId
select p;
}
list.Count = query.Count();
@@ -118,20 +208,6 @@ namespace Atomx.Admin.Controllers
countries = _dbContext.Countries.Where(p => countryIds.Contains(p.Id)).ToList();
}
if (search.StateProvinceId > 0)
{
var state = _dbContext.StateProvinces.SingleOrDefault(p => p.Id == search.StateProvinceId);
if (state != null)
{
stateProvices.Add(state);
}
}
else
{
var stateIds = data.Select(p => p.StateProvinceId).Distinct().ToList();
stateProvices = _dbContext.StateProvinces.Where(p => stateIds.Contains(p.Id)).ToList();
}
foreach (var item in data)
{
var model = _mapper.Map<AreaItem>(item);
@@ -140,7 +216,7 @@ namespace Atomx.Admin.Controllers
{
model.CountryName = country.Name;
}
var state = stateProvices.SingleOrDefault(p => p.Id == item.StateProvinceId);
var state = await _cacheService.GetStateProvince(item.CountryId, item.ParentId);
if (state != null)
{
model.StateProvinceName = state.Name;
@@ -196,14 +272,13 @@ namespace Atomx.Admin.Controllers
return new JsonResult(result);
}
/// <summary>
/// 新增编辑数据
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost("save")]
public IActionResult AddressEdit(AreaModel model)
public IActionResult Edit(AreaModel model)
{
var result = new ApiResult<bool>();
var validation = _validator.Validate(model);
@@ -212,15 +287,13 @@ namespace Atomx.Admin.Controllers
var message = validation.Errors.FirstOrDefault()?.ErrorMessage ?? string.Empty;
return new JsonResult(new ApiResult<string>().IsFail(message, null));
}
var data = _dbContext.Areas.SingleOrDefault(p => p.CountryId == model.CountryId && p.StateProvinceId == model.StateProvinceId && p.Name == model.Name && p.Id != model.Id);
var data = _dbContext.Areas.SingleOrDefault(p => p.CountryId == model.CountryId && p.ParentId == model.ParentId && p.Name == model.Name && p.Id != model.Id);
if (data != null)
{
return new JsonResult(new ApiResult<string>().IsFail("当前站点语言下已经存在这个配置,请认真检查", null));
}
if (model.Id > 0)
{
data = _dbContext.Areas.SingleOrDefault(p => p.Id == model.Id);
if (data == null)
{
@@ -229,7 +302,7 @@ namespace Atomx.Admin.Controllers
data = _mapper.Map(model, data);
var parent = _dbContext.Categories.Where(p => p.Id == model.ParentId).SingleOrDefault();
var parent = _dbContext.Areas.Where(p => p.Id == model.ParentId).SingleOrDefault();
if (parent == null)
{
data.Depth = 0;
@@ -237,6 +310,15 @@ namespace Atomx.Admin.Controllers
}
else
{
if (parent.StateProvinceId == 0)
{
data.StateProvinceId = parent.Id;
}
else
{
data.StateProvinceId = parent.StateProvinceId;
}
data.Depth = parent.Depth + 1;
data.Path = $"{parent.Path},{data.Id}";
}
@@ -249,7 +331,7 @@ namespace Atomx.Admin.Controllers
data = _mapper.Map<Area>(model);
data.Id = _idCreator.CreateId();
var parent = _dbContext.Categories.Where(p => p.Id == data.ParentId).SingleOrDefault();
var parent = _dbContext.Areas.Where(p => p.Id == data.ParentId).SingleOrDefault();
if (parent == null)
{
data.Depth = 0;
@@ -257,6 +339,14 @@ namespace Atomx.Admin.Controllers
}
else
{
if (parent.StateProvinceId == 0)
{
data.StateProvinceId = parent.Id;
}
else
{
data.StateProvinceId = parent.StateProvinceId;
}
data.Depth = parent.Depth + 1;
data.Path = $"{parent.Path},{data.Id}";
}

View File

@@ -1,246 +0,0 @@
using Atomx.Admin.Client.Models;
using Atomx.Admin.Services;
using Atomx.Common.Constants;
using Atomx.Common.Entities;
using Atomx.Common.Models;
using Atomx.Core.Jos;
using Atomx.Data;
using Atomx.Data.CacheServices;
using Atomx.Data.Services;
using FluentValidation;
using MapsterMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using System.Threading.Tasks;
namespace Atomx.Admin.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class StateProvinceController : ControllerBase
{
private readonly ILogger<StateProvinceController> _logger;
private readonly DataContext _dbContext;
private readonly IIdCreatorService _idCreator;
private readonly IIdentityService _identityService;
private readonly IMapper _mapper;
private readonly ICacheService _cacheService;
private readonly IBackgroundJobService _backgroundService;
readonly IValidator<StateProvinceModel> _validator;
readonly IStringLocalizer<StateProvinceController> _localizer;
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
/// <param name="idCreator"></param>
/// <param name="identityService"></param>
/// <param name="dbContext"></param>
/// <param name="mapper"></param>
/// <param name="jwtSettings"></param>
/// <param name="cacheService"></param>
public StateProvinceController(ILogger<StateProvinceController> logger, IIdCreatorService idCreator, IIdentityService identityService, DataContext dbContext, IMapper mapper,
ICacheService cacheService, IBackgroundJobService backgroundJobService, IValidator<StateProvinceModel> validator, IStringLocalizer<StateProvinceController> localizer)
{
_logger = logger;
_idCreator = idCreator;
_identityService = identityService;
_dbContext = dbContext;
_mapper = mapper;
_cacheService = cacheService;
_backgroundService = backgroundJobService;
_validator = validator;
_localizer = localizer;
}
/// <summary>
/// 数据查询
/// </summary>
/// <param name="search"></param>
/// <param name="page"></param>
/// <param name="size"></param>
/// <returns></returns>
[HttpGet("tree/{countryId:long}")]
public async Task<IActionResult> GetTree(long countryId, int page, int size = 20)
{
var list = await _cacheService.GetAreaTree(countryId);
return new JsonResult(new ApiResult<List<KeyValueTree>>().IsSuccess(list));
}
/// <summary>
/// 数据查询
/// </summary>
/// <param name="search"></param>
/// <param name="page"></param>
/// <param name="size"></param>
/// <returns></returns>
[HttpGet("select/{countryId:long}")]
public IActionResult Select(long countryId, int page, int size = 20)
{
var list = new List<KeyValue>();
var query = from p in _dbContext.StateProvinces
where p.CountryId == countryId && p.Enabled
select p;
list = query.OrderByDescending(p => p.DisplayOrder).Select(p => new KeyValue() { Label = p.Id.ToString(), Value = p.Name }).ToList();
return new JsonResult(new ApiResult<List<KeyValue>>().IsSuccess(list));
}
/// <summary>
/// 数据查询
/// </summary>
/// <param name="search"></param>
/// <param name="page"></param>
/// <param name="size"></param>
/// <returns></returns>
[HttpPost("search")]
public IActionResult Search(StateProvinceSearch search, int page, int size = 20)
{
if (page < 1)
{
page = 1;
}
var result = new ApiResult<PagingList<StateProvince>>();
var list = new PagingList<StateProvince>() { Index = page, Size = size };
var query = from p in _dbContext.StateProvinces
select p;
if (!string.IsNullOrEmpty(search.Name))
{
query = from p in query
where p.Name.Contains(search.Name)
select p;
}
if (search.CountryId > 0)
{
query = from p in query
where p.CountryId == search.CountryId
select p;
}
list.Count = query.Count();
list.Items = query.OrderByDescending(p => p.DisplayOrder).Skip((page - 1) * size).Take(size).ToList();
result = result.IsSuccess(list);
return new JsonResult(result);
}
/// <summary>
/// 通过ID获取数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id:long}")]
public IActionResult Get(long id)
{
var result = new ApiResult<StateProvince>();
var data = _dbContext.StateProvinces.SingleOrDefault(p => p.Id == id);
if (data == null)
{
return new JsonResult(new ApiResult<string>().IsFail("数据不存在", null));
}
result = result.IsSuccess(data);
return new JsonResult(result);
}
/// <summary>
/// 通过ID获取详情,含多语言
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("detail")]
public IActionResult Detail(long id)
{
var result = new ApiResult<StateProvinceLocalizedModel>();
var data = _dbContext.StateProvinces.SingleOrDefault(p => p.Id == id);
if (data == null)
{
return new JsonResult(new ApiResult<string>().IsFail("数据不存在", null));
}
var localizedList = _dbContext.LocalizedProperties.Where(p => p.EntityId == id).ToList();
var model = _mapper.Map<StateProvinceLocalizedModel>(data);
model.Locales = localizedList;
result = result.IsSuccess(model);
return new JsonResult(result);
}
/// <summary>
/// 新增编辑数据
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost("save")]
public IActionResult AddressEdit(StateProvinceModel model)
{
var result = new ApiResult<bool>();
var validation = _validator.Validate(model);
if (!validation.IsValid)
{
var message = validation.Errors.FirstOrDefault()?.ErrorMessage ?? string.Empty;
return new JsonResult(new ApiResult<string>().IsFail(message, null));
}
var data = _dbContext.StateProvinces.SingleOrDefault(p => p.CountryId == model.CountryId && p.Name == model.Name && p.Id != model.Id);
if (data != null)
{
return new JsonResult(new ApiResult<string>().IsFail("当前数据已经存在,请认真检查", null));
}
if (model.Id > 0)
{
data = _dbContext.StateProvinces.SingleOrDefault(p => p.Id == model.Id);
if (data == null)
{
return new JsonResult(new ApiResult<string>().IsFail("数据不存在", null));
}
data = _mapper.Map(model, data);
_dbContext.SaveChanges();
_backgroundService.ResetStateProvinceAndAreaTree(data.CountryId);
}
else
{
data = _mapper.Map<StateProvince>(model);
data.Id = _idCreator.CreateId();
_dbContext.StateProvinces.Add(data);
_dbContext.SaveChanges();
}
return new JsonResult(new ApiResult<string>().IsSuccess("操作成功"));
}
/// <summary>
/// 删除数据
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost("delete")]
public async Task<IActionResult> DeleteAsync(long id)
{
var result = new ApiResult<string>();
try
{
Console.WriteLine($"{id} deleted");
var count = _dbContext.StateProvinces.Where(p => p.Id == id).ExecuteDelete();
result = result.IsSuccess(count.ToString());
}
catch (Exception ex)
{
result = result.IsFail(ex.Message);
_logger.LogError(ex.Message);
}
return new JsonResult(result);
}
}
}