This commit is contained in:
yxw
2026-01-06 18:46:52 +08:00
parent 4eb09a79fc
commit b098b3f815
10 changed files with 225 additions and 18 deletions

View File

@@ -6,6 +6,6 @@ namespace Atomx.Admin.Client.Models
{ {
public string CountryName { get; set; } = string.Empty; public string CountryName { get; set; } = string.Empty;
public string StateProvinceName { get; set; } = string.Empty; public string StateProvinceName { get; set; } = string.Empty;
public string ParentName { get; set; } = string.Empty;
} }
} }

View File

@@ -66,14 +66,14 @@
<SpaceItem> <SpaceItem>
<a @onclick="(e) => HandleEdit(context)">编辑</a> <a @onclick="(e) => HandleEdit(context)">编辑</a>
</SpaceItem> </SpaceItem>
@*<SpaceItem> <SpaceItem>
<Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")" <Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")"
OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))" OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))"
OkText="确定" OkText="确定"
CancelText="取消"> CancelText="取消">
<a>删除</a> <a>删除</a>
</Popconfirm> </Popconfirm>
</SpaceItem>*@ </SpaceItem>
</Space> </Space>
</ActionColumn> </ActionColumn>
</Table> </Table>
@@ -218,7 +218,7 @@
{ {
Navigation.NavigateTo($"/area/list/{CountryId}?{queryString}"); Navigation.NavigateTo($"/area/list/{CountryId}?{queryString}");
} }
} }
} }
} }
@@ -245,7 +245,7 @@
{ {
Navigation.NavigateTo($"/area/create/{CountryId}"); Navigation.NavigateTo($"/area/create/{CountryId}");
} }
} }
@@ -254,4 +254,18 @@
Navigation.NavigateTo($"/area/edit/{model.CountryId}/{model.StateProvinceId}/{model.Id}"); Navigation.NavigateTo($"/area/edit/{model.CountryId}/{model.StateProvinceId}/{model.Id}");
} }
async Task HandleDeleteConfirmAsync(MouseEventArgs e, long id)
{
var url = $"/api/area/delete/{id}";
var apiResult = await HttpService.Post<ApiResult<string>>(url, new());
if (apiResult.Success)
{
await LoadListAsync();
await ModalService.InfoAsync(new ConfirmOptions() { Title = "操作提示", Content = "删除数据成功" });
}
else
{
await ModalService.ErrorAsync(new ConfirmOptions() { Title = "操作提示", Content = $"数据删除失败.{apiResult.Message}" });
}
}
} }

View File

@@ -60,22 +60,22 @@
<ActionColumn Title="操作" Align="ColumnAlign.Right"> <ActionColumn Title="操作" Align="ColumnAlign.Right">
<Space> <Space>
<SpaceItem> <SpaceItem>
<a @onclick="(e) => GotoStateProvince(context)">州省管理</a> <a @onclick="(e) => GotoStateProvince(context)">查看州/省</a>
</SpaceItem> </SpaceItem>
<SpaceItem> <SpaceItem>
<a @onclick="(e) => GotoArea(context)">城市管理</a> <a @onclick="(e) => GotoArea(context)">查看城市</a>
</SpaceItem> </SpaceItem>
<SpaceItem> <SpaceItem>
<a @onclick="(e)=>HandleEdit(context)">编辑</a> <a @onclick="(e)=>HandleEdit(context)">编辑</a>
</SpaceItem> </SpaceItem>
@*<SpaceItem> <SpaceItem>
<Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")" <Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")"
OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))" OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))"
OkText="确定" OkText="确定"
CancelText="取消"> CancelText="取消">
<a>删除</a> <a>删除</a>
</Popconfirm> </Popconfirm>
</SpaceItem>*@ </SpaceItem>
</Space> </Space>
</ActionColumn> </ActionColumn>
</Table> </Table>
@@ -221,4 +221,19 @@
{ {
Navigation.NavigateTo($"/area/list/{model.Id}"); Navigation.NavigateTo($"/area/list/{model.Id}");
} }
async Task HandleDeleteConfirmAsync(MouseEventArgs e, long id)
{
var url = $"/api/country/delete/{id}";
var apiResult = await HttpService.Post<ApiResult<string>>(url, new());
if (apiResult.Success)
{
await LoadListAsync();
await ModalService.InfoAsync(new ConfirmOptions() { Title = "操作提示", Content = "删除数据成功" });
}
else
{
await ModalService.ErrorAsync(new ConfirmOptions() { Title = "操作提示", Content = $"数据删除失败.{apiResult.Message}" });
}
}
} }

View File

@@ -62,19 +62,19 @@
<ActionColumn Title="操作" Align="ColumnAlign.Right"> <ActionColumn Title="操作" Align="ColumnAlign.Right">
<Space> <Space>
<SpaceItem> <SpaceItem>
<a @onclick="(e) => GotoArea(context)">城市管理</a> <a @onclick="(e) => GotoArea(context)">查看城市</a>
</SpaceItem> </SpaceItem>
<SpaceItem> <SpaceItem>
<a @onclick="(e) => HandleEdit(context)">编辑</a> <a @onclick="(e) => HandleEdit(context)">编辑</a>
</SpaceItem> </SpaceItem>
@*<SpaceItem> <SpaceItem>
<Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")" <Popconfirm Placement="@Placement.Left" Title="@("删除这条数据无法恢复,您确定要删除吗?")"
OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))" OnConfirm="@(e=>HandleDeleteConfirmAsync(e,context.Id))"
OkText="确定" OkText="确定"
CancelText="取消"> CancelText="取消">
<a>删除</a> <a>删除</a>
</Popconfirm> </Popconfirm>
</SpaceItem>*@ </SpaceItem>
</Space> </Space>
</ActionColumn> </ActionColumn>
</Table> </Table>
@@ -220,4 +220,18 @@
Navigation.NavigateTo($"/area/list/{CountryId}/{model.Id}"); Navigation.NavigateTo($"/area/list/{CountryId}/{model.Id}");
} }
async Task HandleDeleteConfirmAsync(MouseEventArgs e, long id)
{
var url = $"/api/area/delete/{id}";
var apiResult = await HttpService.Post<ApiResult<string>>(url, new());
if (apiResult.Success)
{
await LoadListAsync();
await ModalService.InfoAsync(new ConfirmOptions() { Title = "操作提示", Content = "删除数据成功" });
}
else
{
await ModalService.ErrorAsync(new ConfirmOptions() { Title = "操作提示", Content = $"数据删除失败.{apiResult.Message}" });
}
}
} }

View File

@@ -216,11 +216,17 @@ namespace Atomx.Admin.Controllers
{ {
model.CountryName = country.Name; model.CountryName = country.Name;
} }
var state = await _cacheService.GetStateProvince(item.CountryId, item.ParentId); var state = await _cacheService.GetStateProvince(item.CountryId, item.StateProvinceId);
if (state != null) if (state != null)
{ {
model.StateProvinceName = state.Name; model.StateProvinceName = state.Name;
} }
var parent = await _cacheService.GetArea(item.CountryId, item.ParentId);
if (parent != null)
{
model.ParentName = parent.Name;
}
list.Items.Add(model); list.Items.Add(model);
} }
@@ -435,14 +441,18 @@ namespace Atomx.Admin.Controllers
/// <param name="model"></param> /// <param name="model"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("delete")] [HttpPost("delete/{id:long}")]
public async Task<IActionResult> DeleteAsync(long id) public async Task<IActionResult> DeleteAsync(long id)
{ {
var result = new ApiResult<string>(); var result = new ApiResult<string>();
try try
{ {
Console.WriteLine($"{id} deleted"); var count = _dbContext.Areas.Count(p => p.ParentId == id || p.StateProvinceId == id);
var count = _dbContext.Areas.Where(p => p.Id == id).ExecuteDelete(); if (count > 0)
{
return new JsonResult(new ApiResult<string>().IsFail("请先删除下级数据", null));
}
count = _dbContext.Areas.Where(p => p.Id == id).ExecuteDelete();
result = result.IsSuccess(count.ToString()); result = result.IsSuccess(count.ToString());
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -259,14 +259,19 @@ namespace Atomx.Admin.Controllers
/// <param name="model"></param> /// <param name="model"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("delete")] [HttpPost("delete/{id:long}")]
public async Task<IActionResult> Delete(long id) public async Task<IActionResult> Delete(long id)
{ {
var result = new ApiResult<string>(); var result = new ApiResult<string>();
try try
{ {
var count = _dbContext.Areas.Count(p => p.CountryId == id);
if (count > 0)
{
return new JsonResult(new ApiResult<string>().IsFail("当前数据存在城市关联数据,不能删除", null));
}
Console.WriteLine($"{id} deleted"); Console.WriteLine($"{id} deleted");
var count = _dbContext.Countries.Where(p => p.Id == id).ExecuteDelete(); count = _dbContext.Countries.Where(p => p.Id == id).ExecuteDelete();
result = result.IsSuccess(count.ToString()); result = result.IsSuccess(count.ToString());
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -0,0 +1,60 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Atomx.Common.Entities
{
/// <summary>
/// 设备访问控制表
/// </summary>
[Table("DeviceAccessControls")]
public class DeviceAccessControl
{
/// <summary>
/// 数据ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public long Id { get; set; }
/// <summary>
/// 限制类型1黑名单2白名单
/// </summary>
public int Type { get; set; }
/// <summary>
/// 设备ID
/// </summary>
[Column(TypeName = "varchar(256)")]
public string DeviceId { get; set; } = string.Empty;
/// <summary>
/// 设备哈希值,用于唯一标识设备
/// </summary>
[Column(TypeName = "varchar(64)")]
public string DeviceHash { get; set; } = string.Empty;
/// <summary>
/// 设备平台
/// </summary>
[Column(TypeName = "varchar(64)")]
public string Platform { get; set; } = string.Empty;
/// <summary>
/// 浏览器
/// </summary>
[Column(TypeName = "varchar(64)")]
public string Browser { get; set; } = string.Empty;
/// <summary>
/// 建立时间
/// </summary>
[Column(TypeName = "timestamptz")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 最后更新时间
/// </summary>
[Column(TypeName = "timestamptz")]
public DateTime? UpdateTime { get; set; }
}
}

View File

@@ -0,0 +1,49 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Atomx.Common.Entities
{
/// <summary>
/// IP访问控制
/// </summary>
[Table("IpAccessControls")]
public class IpAccessControl
{
/// <summary>
/// 数据ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public long Id { get; set; }
/// <summary>
/// 限制类型1黑名单2白名单
/// </summary>
public int Type { get; set; }
/// <summary>
/// 开始IP
/// </summary>
[Column(TypeName = "varchar(64)")]
public string StartIp { get; set; } = string.Empty;
/// <summary>
/// 结束IP
/// </summary>
[Column(TypeName = "varchar(64)")]
public string EndIp { get; set; } = string.Empty;
/// <summary>
/// 建立时间
/// </summary>
[Column(TypeName = "timestamptz")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 最后更新时间
/// </summary>
[Column(TypeName = "timestamptz")]
public DateTime? UpdateTime { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Atomx.Common.Entities
{
/// <summary>
/// 用户访问控制表
/// </summary>
[Table("UserAccessControls")]
public class UserAccessControl
{
/// <summary>
/// 数据ID
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public long Id { get; set; }
}
}

View File

@@ -42,6 +42,14 @@ namespace Atomx.Data.CacheServices
/// <returns></returns> /// <returns></returns>
Task<List<Area>> GetAreas(long countryId, bool? reload = false); Task<List<Area>> GetAreas(long countryId, bool? reload = false);
/// <summary>
/// 获取城市地区数据
/// </summary>
/// <param name="countryId"></param>
/// <param name="areaId"></param>
/// <returns></returns>
Task<Area> GetArea(long countryId, long areaId);
/// <summary> /// <summary>
/// 更新调整缓存数据 /// 更新调整缓存数据
/// </summary> /// </summary>
@@ -199,6 +207,19 @@ namespace Atomx.Data.CacheServices
return cacheData; return cacheData;
} }
/// <summary>
/// 获取城市地区数据
/// </summary>
/// <param name="countryId"></param>
/// <param name="areaId"></param>
/// <returns></returns>
public async Task<Area> GetArea(long countryId, long areaId)
{
var cacheData = await GetAreas(countryId);
var data = cacheData.SingleOrDefault(p => p.Id == areaId);
return data;
}
public async Task UpdateArea(Area area) public async Task UpdateArea(Area area)
{ {
var cacheData = await GetAreas(area.CountryId); var cacheData = await GetAreas(area.CountryId);