240 lines
9.4 KiB
C#
240 lines
9.4 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using StopShopping.EF;
|
|
using StopShopping.Services.Models.Req;
|
|
using StopShopping.Services.Models.Resp;
|
|
using O = StopShopping.OpenPlatform;
|
|
|
|
namespace StopShopping.Services.Implementions;
|
|
|
|
public class DistrictService : IDistrictService
|
|
{
|
|
public DistrictService(
|
|
StopShoppingContext dbContext,
|
|
O.IDistrictService districtService,
|
|
ILogger<DistrictService> logger)
|
|
{
|
|
_dbContext = dbContext;
|
|
_oDistrictService = districtService;
|
|
_logger = logger;
|
|
}
|
|
|
|
private readonly StopShoppingContext _dbContext;
|
|
private readonly O.IDistrictService _oDistrictService;
|
|
private readonly ILogger<DistrictService> _logger;
|
|
|
|
public async Task InitialDatabaseAsync(CancellationToken cancellationToken)
|
|
{
|
|
_logger.LogInformation("开始初始化行政区划");
|
|
|
|
if (await _dbContext.Districts.AnyAsync(cancellationToken))
|
|
{
|
|
_logger.LogInformation("已经存在数据,无需初始化");
|
|
}
|
|
else
|
|
{
|
|
var districtsResp = await _oDistrictService.GetTop3LevelDistrictsAsync(cancellationToken);
|
|
if (districtsResp?.IsSucced ?? false)
|
|
{
|
|
if (null != districtsResp?.Districts)
|
|
{
|
|
using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);
|
|
|
|
short order = 1;
|
|
int parentId = 0;
|
|
var districtsProvince = districtsResp.Districts
|
|
.Select(d => Cast(d, parentId, order++))
|
|
.ToList();
|
|
await _dbContext.Districts.AddRangeAsync(districtsProvince, cancellationToken);
|
|
await _dbContext.SaveChangesAsync(cancellationToken);
|
|
|
|
foreach (var province in districtsResp.Districts)
|
|
{
|
|
parentId = districtsProvince.First(p => p.Code == province.Code).Id;
|
|
order = 1;
|
|
|
|
var citys = province.Districts;
|
|
|
|
if (null == citys)
|
|
{
|
|
await transaction.RollbackAsync(cancellationToken);
|
|
_logger.LogError("行政区划下级数据不完整:{Name}", province.Name);
|
|
return;
|
|
}
|
|
|
|
var districtsCity = citys
|
|
.Select(d => Cast(d, parentId, order++))
|
|
.ToList();
|
|
await _dbContext.Districts.AddRangeAsync(districtsCity, cancellationToken);
|
|
await _dbContext.SaveChangesAsync(cancellationToken);
|
|
|
|
// 直辖市下属区
|
|
// var directlyCitysDistrict = citys
|
|
// .Where(d => d.Districts?.Count == 0)
|
|
// .ToList();
|
|
// if (0 == directlyCitysDistrict.Count)
|
|
// {
|
|
// await transaction.RollbackAsync(cancellationToken);
|
|
// _logger.LogError("行政区划数据不完整,缺少直辖市数据");
|
|
// return;
|
|
// }
|
|
|
|
var semaphoreSlim = new SemaphoreSlim(50);
|
|
//(parent id, district response)
|
|
List<Task<(int, O.DistrictResponse?)>> districtTasks = [];
|
|
|
|
foreach (var city in citys)
|
|
{
|
|
parentId = districtsCity.First(c => c.Code == city.Code).Id;
|
|
order = 1;
|
|
if (city.Districts == null || city.Districts.Count == 0)//直辖市
|
|
{
|
|
try
|
|
{
|
|
await semaphoreSlim.WaitAsync(cancellationToken);
|
|
districtTasks.Add(
|
|
Task.FromResult((
|
|
parentId
|
|
, await _oDistrictService.GetChildrenAsync(city.Code, cancellationToken)))
|
|
);
|
|
}
|
|
finally
|
|
{
|
|
semaphoreSlim.Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var districtsDistrict = city.Districts
|
|
.Select(d => Cast(d, parentId, order++))
|
|
.ToList();
|
|
await _dbContext.Districts.AddRangeAsync(districtsDistrict, cancellationToken);
|
|
await _dbContext.SaveChangesAsync(cancellationToken);
|
|
|
|
var districtTask = city.Districts!.Select(async (d) =>
|
|
{
|
|
try
|
|
{
|
|
await semaphoreSlim.WaitAsync();
|
|
|
|
return (
|
|
districtsDistrict.First(dd => dd.Code == d.Code).Id
|
|
, await _oDistrictService.GetChildrenAsync(d.Code, cancellationToken)
|
|
);
|
|
}
|
|
finally
|
|
{
|
|
semaphoreSlim.Release();
|
|
}
|
|
});
|
|
|
|
districtTasks.AddRange(districtTask);
|
|
}
|
|
}
|
|
|
|
var streets = await Task.WhenAll(districtTasks);
|
|
foreach (var s in streets)
|
|
{
|
|
order = 1;
|
|
parentId = s.Item1;
|
|
if (s.Item2?.IsSucced ?? false)
|
|
{
|
|
var districtsStreet = s.Item2.Districts
|
|
?.Select(ds => Cast(ds, parentId, order++))
|
|
.ToList();
|
|
|
|
if (null != districtsStreet)
|
|
{
|
|
await _dbContext.Districts.AddRangeAsync(districtsStreet, cancellationToken);
|
|
await _dbContext.SaveChangesAsync(cancellationToken);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await transaction.RollbackAsync(cancellationToken);
|
|
_logger.LogError("街道数据请求失败:{Message}", s.Item2?.Message);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
await transaction.CommitAsync(cancellationToken);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_logger.LogError("行政区划接口错误:{Message}", districtsResp?.Message);
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation("结束初始化行政区划");
|
|
}
|
|
|
|
public async Task<ApiResponse<List<District>>> GetTop3LevelDistrictsAsync()
|
|
{
|
|
List<District> districts = [];
|
|
|
|
var top3Districts = await _dbContext.Districts
|
|
.Where(d => d.Level <= 3)
|
|
.AsNoTracking()
|
|
.ToListAsync();
|
|
|
|
if (0 != top3Districts.Count)
|
|
{
|
|
Dictionary<int, District> idDicts = [];
|
|
foreach (var dbDistrict in top3Districts)
|
|
{
|
|
idDicts.Add(dbDistrict.Id, Cast(dbDistrict));
|
|
}
|
|
foreach (var kv in idDicts)
|
|
{
|
|
if (kv.Value.ParentId > 0)
|
|
idDicts[kv.Value.ParentId].Children.Add(kv.Value);
|
|
else
|
|
districts.Add(kv.Value);
|
|
}
|
|
}
|
|
|
|
var result = new ApiResponse<List<District>>(districts);
|
|
|
|
return result;
|
|
}
|
|
|
|
public ApiResponse<List<District>> GetChildren(DistrictParentIdParams model)
|
|
{
|
|
var children = _dbContext.Districts
|
|
.Where(d => d.ParentId == model.ParentId)
|
|
.AsNoTracking()
|
|
.Select(Cast)
|
|
.ToList();
|
|
|
|
return new ApiResponse<List<District>>(children);
|
|
}
|
|
|
|
private District Cast(EF.Models.District district)
|
|
{
|
|
return new District
|
|
{
|
|
Children = [],
|
|
FullName = district.FullName,
|
|
Id = district.Id,
|
|
Level = district.Level,
|
|
ParentId = district.ParentId
|
|
};
|
|
}
|
|
|
|
private EF.Models.District Cast(O.DistrictResponse.District district, int parentId, short order)
|
|
{
|
|
return new EF.Models.District
|
|
{
|
|
Code = district.Code,
|
|
FullName = district.FullName,
|
|
Latitude = district.Latitude.ToString(),
|
|
Level = (short)(district.Level ?? 0),
|
|
Longitude = district.Longitude.ToString(),
|
|
Name = district.Name,
|
|
Order = order,
|
|
ParentId = parentId,
|
|
Pinyin = district.PinYin ?? ""
|
|
};
|
|
}
|
|
} |