diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Common/PagedResultWithPageDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Common/PagedResultWithPageDto.cs
new file mode 100644
index 0000000..64daa2c
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Common/PagedResultWithPageDto.cs
@@ -0,0 +1,34 @@
+namespace FoodLabeling.Application.Contracts.Dtos.Common;
+
+///
+/// 分页返回(包含当前页、总页数)
+///
+/// 列表项类型
+public class PagedResultWithPageDto
+{
+ ///
+ /// 当前页码(从 1 开始)
+ ///
+ public int PageIndex { get; set; }
+
+ ///
+ /// 每页条数
+ ///
+ public int PageSize { get; set; }
+
+ ///
+ /// 总条数
+ ///
+ public long TotalCount { get; set; }
+
+ ///
+ /// 总页数
+ ///
+ public int TotalPages { get; set; }
+
+ ///
+ /// 列表数据
+ ///
+ public List Items { get; set; } = new();
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationCreateInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationCreateInputVo.cs
new file mode 100644
index 0000000..bf453f5
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationCreateInputVo.cs
@@ -0,0 +1,39 @@
+namespace FoodLabeling.Application.Contracts.Dtos.Location;
+
+///
+/// 新增门店入参
+///
+public class LocationCreateInputVo
+{
+ public string? Partner { get; set; }
+
+ public string? GroupName { get; set; }
+
+ ///
+ /// Location ID(业务编码)
+ ///
+ public string LocationCode { get; set; } = string.Empty;
+
+ public string LocationName { get; set; } = string.Empty;
+
+ public string? Street { get; set; }
+
+ public string? City { get; set; }
+
+ public string? StateCode { get; set; }
+
+ public string? Country { get; set; }
+
+ public string? ZipCode { get; set; }
+
+ public string? Phone { get; set; }
+
+ public string? Email { get; set; }
+
+ public decimal? Latitude { get; set; }
+
+ public decimal? Longitude { get; set; }
+
+ public bool State { get; set; } = true;
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationGetListInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationGetListInputVo.cs
new file mode 100644
index 0000000..1413502
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationGetListInputVo.cs
@@ -0,0 +1,30 @@
+using Volo.Abp.Application.Dtos;
+
+namespace FoodLabeling.Application.Contracts.Dtos.Location;
+
+///
+/// 门店分页查询入参
+///
+public class LocationGetListInputVo : PagedAndSortedResultRequestDto
+{
+ ///
+ /// 模糊搜索(Location ID/Name/Street/City/State/Country/Zip/Phone/Email)
+ ///
+ public string? Keyword { get; set; }
+
+ ///
+ /// Partner
+ ///
+ public string? Partner { get; set; }
+
+ ///
+ /// Group
+ ///
+ public string? GroupName { get; set; }
+
+ ///
+ /// 启用状态
+ ///
+ public bool? State { get; set; }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationGetListOutputDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationGetListOutputDto.cs
new file mode 100644
index 0000000..067aec1
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationGetListOutputDto.cs
@@ -0,0 +1,38 @@
+namespace FoodLabeling.Application.Contracts.Dtos.Location;
+
+///
+/// 门店列表输出
+///
+public class LocationGetListOutputDto
+{
+ public Guid Id { get; set; }
+
+ public string? Partner { get; set; }
+
+ public string? GroupName { get; set; }
+
+ public string LocationCode { get; set; } = string.Empty;
+
+ public string LocationName { get; set; } = string.Empty;
+
+ public string? Street { get; set; }
+
+ public string? City { get; set; }
+
+ public string? StateCode { get; set; }
+
+ public string? Country { get; set; }
+
+ public string? ZipCode { get; set; }
+
+ public string? Phone { get; set; }
+
+ public string? Email { get; set; }
+
+ public decimal? Latitude { get; set; }
+
+ public decimal? Longitude { get; set; }
+
+ public bool State { get; set; }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationUpdateInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationUpdateInputVo.cs
new file mode 100644
index 0000000..45f7731
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Location/LocationUpdateInputVo.cs
@@ -0,0 +1,40 @@
+namespace FoodLabeling.Application.Contracts.Dtos.Location;
+
+///
+/// 编辑门店入参
+///
+public class LocationUpdateInputVo
+{
+ public string? Partner { get; set; }
+
+ public string? GroupName { get; set; }
+
+ ///
+ /// Location Name
+ ///
+ public string LocationName { get; set; } = string.Empty;
+
+ public string? Street { get; set; }
+
+ public string? City { get; set; }
+
+ public string? StateCode { get; set; }
+
+ public string? Country { get; set; }
+
+ public string? ZipCode { get; set; }
+
+ public string? Phone { get; set; }
+
+ public string? Email { get; set; }
+
+ public decimal? Latitude { get; set; }
+
+ public decimal? Longitude { get; set; }
+
+ ///
+ /// 启用状态
+ ///
+ public bool State { get; set; } = true;
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuCreateInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuCreateInputVo.cs
new file mode 100644
index 0000000..ee5d658
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuCreateInputVo.cs
@@ -0,0 +1,26 @@
+namespace FoodLabeling.Application.Contracts.Dtos.RbacMenu;
+
+///
+/// 新增权限(Menu)入参(美国版对外)
+///
+public class RbacMenuCreateInputVo
+{
+ public string MenuName { get; set; } = string.Empty;
+
+ public Guid ParentId { get; set; }
+
+ public int MenuType { get; set; }
+
+ public int MenuSource { get; set; }
+
+ public string? PermissionCode { get; set; }
+
+ public string? Router { get; set; }
+
+ public string? Component { get; set; }
+
+ public int OrderNum { get; set; } = 0;
+
+ public bool State { get; set; } = true;
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListInputVo.cs
new file mode 100644
index 0000000..785f12b
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListInputVo.cs
@@ -0,0 +1,19 @@
+using Volo.Abp.Application.Dtos;
+
+namespace FoodLabeling.Application.Contracts.Dtos.RbacMenu;
+
+///
+/// 权限(Menu)分页查询入参(美国版对外)
+///
+public class RbacMenuGetListInputVo : PagedAndSortedResultRequestDto
+{
+ public string? MenuName { get; set; }
+
+ public bool? State { get; set; }
+
+ ///
+ /// 菜单来源(与 rbac 的 MenuSource 含义一致,int 存储)
+ ///
+ public int? MenuSource { get; set; }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListOutputDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListOutputDto.cs
new file mode 100644
index 0000000..6970d00
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListOutputDto.cs
@@ -0,0 +1,24 @@
+namespace FoodLabeling.Application.Contracts.Dtos.RbacMenu;
+
+///
+/// 权限(Menu)列表输出(美国版对外)
+///
+public class RbacMenuGetListOutputDto
+{
+ public Guid Id { get; set; }
+
+ public Guid ParentId { get; set; }
+
+ public string MenuName { get; set; } = string.Empty;
+
+ public string? PermissionCode { get; set; }
+
+ public int MenuType { get; set; }
+
+ public int MenuSource { get; set; }
+
+ public int OrderNum { get; set; }
+
+ public bool State { get; set; }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuUpdateInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuUpdateInputVo.cs
new file mode 100644
index 0000000..a592d89
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuUpdateInputVo.cs
@@ -0,0 +1,9 @@
+namespace FoodLabeling.Application.Contracts.Dtos.RbacMenu;
+
+///
+/// 编辑权限(Menu)入参(美国版对外)
+///
+public class RbacMenuUpdateInputVo : RbacMenuCreateInputVo
+{
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleCreateInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleCreateInputVo.cs
new file mode 100644
index 0000000..53b2e73
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleCreateInputVo.cs
@@ -0,0 +1,23 @@
+namespace FoodLabeling.Application.Contracts.Dtos.RbacRole;
+
+///
+/// 新增角色入参(美国版对外)
+///
+public class RbacRoleCreateInputVo
+{
+ public string RoleName { get; set; } = string.Empty;
+
+ public string RoleCode { get; set; } = string.Empty;
+
+ public string? Remark { get; set; }
+
+ ///
+ /// 数据范围(与 rbac 的 DataScope 含义一致,int 存储)
+ ///
+ public int DataScope { get; set; } = 0;
+
+ public bool State { get; set; } = true;
+
+ public int OrderNum { get; set; } = 0;
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetListInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetListInputVo.cs
new file mode 100644
index 0000000..02deeb7
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetListInputVo.cs
@@ -0,0 +1,25 @@
+using Volo.Abp.Application.Dtos;
+
+namespace FoodLabeling.Application.Contracts.Dtos.RbacRole;
+
+///
+/// 角色分页查询入参(美国版对外)
+///
+public class RbacRoleGetListInputVo : PagedAndSortedResultRequestDto
+{
+ ///
+ /// 角色名称(模糊)
+ ///
+ public string? RoleName { get; set; }
+
+ ///
+ /// 角色编码(模糊)
+ ///
+ public string? RoleCode { get; set; }
+
+ ///
+ /// 启用状态
+ ///
+ public bool? State { get; set; }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetListOutputDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetListOutputDto.cs
new file mode 100644
index 0000000..3940df9
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetListOutputDto.cs
@@ -0,0 +1,22 @@
+namespace FoodLabeling.Application.Contracts.Dtos.RbacRole;
+
+///
+/// 角色列表输出(美国版对外)
+///
+public class RbacRoleGetListOutputDto
+{
+ public Guid Id { get; set; }
+
+ public string RoleName { get; set; } = string.Empty;
+
+ public string RoleCode { get; set; } = string.Empty;
+
+ public string? Remark { get; set; }
+
+ public int DataScope { get; set; }
+
+ public bool State { get; set; }
+
+ public int OrderNum { get; set; }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetOutputDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetOutputDto.cs
new file mode 100644
index 0000000..877e1b0
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleGetOutputDto.cs
@@ -0,0 +1,9 @@
+namespace FoodLabeling.Application.Contracts.Dtos.RbacRole;
+
+///
+/// 角色详情输出(美国版对外)
+///
+public class RbacRoleGetOutputDto : RbacRoleGetListOutputDto
+{
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleUpdateInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleUpdateInputVo.cs
new file mode 100644
index 0000000..680ee9c
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRole/RbacRoleUpdateInputVo.cs
@@ -0,0 +1,9 @@
+namespace FoodLabeling.Application.Contracts.Dtos.RbacRole;
+
+///
+/// 编辑角色入参(美国版对外)
+///
+public class RbacRoleUpdateInputVo : RbacRoleCreateInputVo
+{
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRoleMenu/RbacRoleMenuRemoveInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRoleMenu/RbacRoleMenuRemoveInputVo.cs
new file mode 100644
index 0000000..19e588d
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRoleMenu/RbacRoleMenuRemoveInputVo.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FoodLabeling.Application.Contracts.Dtos.RbacRoleMenu;
+
+///
+/// 角色-权限移除入参
+///
+public class RbacRoleMenuRemoveInputVo
+{
+ [Required]
+ public Guid RoleId { get; set; }
+
+ [Required]
+ public List MenuIds { get; set; } = new();
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRoleMenu/RbacRoleMenuSetInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRoleMenu/RbacRoleMenuSetInputVo.cs
new file mode 100644
index 0000000..705da63
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacRoleMenu/RbacRoleMenuSetInputVo.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FoodLabeling.Application.Contracts.Dtos.RbacRoleMenu;
+
+///
+/// 角色-权限设置入参(覆盖式)
+///
+public class RbacRoleMenuSetInputVo
+{
+ ///
+ /// 角色ID
+ ///
+ [Required]
+ public Guid RoleId { get; set; }
+
+ ///
+ /// 菜单ID列表(覆盖式)
+ ///
+ [Required]
+ public List MenuIds { get; set; } = new();
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/FoodLabeling.Application.Contracts.csproj b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/FoodLabeling.Application.Contracts.csproj
index 9e3e3bd..6a5eb2d 100644
--- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/FoodLabeling.Application.Contracts.csproj
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/FoodLabeling.Application.Contracts.csproj
@@ -4,6 +4,7 @@
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/ILocationAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/ILocationAppService.cs
new file mode 100644
index 0000000..4474374
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/ILocationAppService.cs
@@ -0,0 +1,38 @@
+using FoodLabeling.Application.Contracts.Dtos.Location;
+using FoodLabeling.Application.Contracts.Dtos.Common;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace FoodLabeling.Application.Contracts.IServices;
+
+///
+/// 门店管理接口(美国版)
+///
+public interface ILocationAppService : IApplicationService
+{
+ ///
+ /// 门店分页列表
+ ///
+ /// 查询条件
+ Task> GetListAsync(LocationGetListInputVo input);
+
+ ///
+ /// 新增门店
+ ///
+ /// 门店信息
+ Task CreateAsync(LocationCreateInputVo input);
+
+ ///
+ /// 编辑门店
+ ///
+ /// 门店Id
+ /// 门店信息
+ Task UpdateAsync(Guid id, LocationUpdateInputVo input);
+
+ ///
+ /// 删除门店(逻辑删除)
+ ///
+ /// 门店Id
+ Task DeleteAsync(Guid id);
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacMenuAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacMenuAppService.cs
new file mode 100644
index 0000000..2eba979
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacMenuAppService.cs
@@ -0,0 +1,38 @@
+using FoodLabeling.Application.Contracts.Dtos.RbacMenu;
+using FoodLabeling.Application.Contracts.Dtos.Common;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace FoodLabeling.Application.Contracts.IServices;
+
+///
+/// 权限(Menu)管理接口(仅用于食品标签-美国版对外)
+///
+public interface IRbacMenuAppService : IApplicationService
+{
+ ///
+ /// 权限分页列表
+ ///
+ Task> GetListAsync(RbacMenuGetListInputVo input);
+
+ ///
+ /// 权限详情
+ ///
+ Task GetAsync(Guid id);
+
+ ///
+ /// 新增权限
+ ///
+ Task CreateAsync(RbacMenuCreateInputVo input);
+
+ ///
+ /// 编辑权限
+ ///
+ Task UpdateAsync(Guid id, RbacMenuUpdateInputVo input);
+
+ ///
+ /// 删除权限(逻辑删除)
+ ///
+ Task DeleteAsync(List ids);
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacRoleAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacRoleAppService.cs
new file mode 100644
index 0000000..48a527c
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacRoleAppService.cs
@@ -0,0 +1,38 @@
+using FoodLabeling.Application.Contracts.Dtos.RbacRole;
+using FoodLabeling.Application.Contracts.Dtos.Common;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace FoodLabeling.Application.Contracts.IServices;
+
+///
+/// 角色管理接口(仅用于食品标签-美国版对外)
+///
+public interface IRbacRoleAppService : IApplicationService
+{
+ ///
+ /// 角色分页列表
+ ///
+ Task> GetListAsync(RbacRoleGetListInputVo input);
+
+ ///
+ /// 角色详情
+ ///
+ Task GetAsync(Guid id);
+
+ ///
+ /// 新增角色
+ ///
+ Task CreateAsync(RbacRoleCreateInputVo input);
+
+ ///
+ /// 编辑角色
+ ///
+ Task UpdateAsync(Guid id, RbacRoleUpdateInputVo input);
+
+ ///
+ /// 删除角色(逻辑删除)
+ ///
+ Task DeleteAsync(List ids);
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacRoleMenuAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacRoleMenuAppService.cs
new file mode 100644
index 0000000..1a6cda5
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacRoleMenuAppService.cs
@@ -0,0 +1,26 @@
+using FoodLabeling.Application.Contracts.Dtos.RbacRoleMenu;
+using Volo.Abp.Application.Services;
+
+namespace FoodLabeling.Application.Contracts.IServices;
+
+///
+/// 角色-权限关联接口(仅用于食品标签-美国版对外)
+///
+public interface IRbacRoleMenuAppService : IApplicationService
+{
+ ///
+ /// 覆盖式设置角色的菜单权限
+ ///
+ Task SetAsync(RbacRoleMenuSetInputVo input);
+
+ ///
+ /// 获取角色已分配的菜单ID列表
+ ///
+ Task> GetMenuIdsAsync(Guid roleId);
+
+ ///
+ /// 移除角色的指定菜单权限
+ ///
+ Task RemoveAsync(RbacRoleMenuRemoveInputVo input);
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/FoodLabeling.Application.csproj b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/FoodLabeling.Application.csproj
index 67daccd..5133544 100644
--- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/FoodLabeling.Application.csproj
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/FoodLabeling.Application.csproj
@@ -5,6 +5,7 @@
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationAppService.cs
new file mode 100644
index 0000000..3b6924e
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationAppService.cs
@@ -0,0 +1,224 @@
+using FoodLabeling.Application.Contracts.Dtos.Location;
+using FoodLabeling.Application.Contracts.IServices;
+using FoodLabeling.Domain.Entities;
+using FoodLabeling.Application.Contracts.Dtos.Common;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+using Yi.Framework.SqlSugarCore.Abstractions;
+
+namespace FoodLabeling.Application.Services;
+
+///
+/// 门店管理服务(美国版)
+///
+public class LocationAppService : ApplicationService, ILocationAppService
+{
+ private readonly ISqlSugarRepository _locationRepository;
+
+ public LocationAppService(ISqlSugarRepository locationRepository)
+ {
+ _locationRepository = locationRepository;
+ }
+
+ ///
+ public async Task> GetListAsync([FromQuery] LocationGetListInputVo input)
+ {
+ RefAsync total = 0;
+
+ var keyword = input.Keyword?.Trim();
+ var partner = input.Partner?.Trim();
+ var groupName = input.GroupName?.Trim();
+
+ var query = _locationRepository._DbQueryable
+ .Where(x => x.IsDeleted == false)
+ .WhereIF(!string.IsNullOrEmpty(partner), x => x.Partner == partner)
+ .WhereIF(!string.IsNullOrEmpty(groupName), x => x.GroupName == groupName)
+ .WhereIF(input.State is not null, x => x.State == input.State)
+ .WhereIF(!string.IsNullOrEmpty(keyword),
+ x =>
+ x.LocationCode.Contains(keyword!) ||
+ x.LocationName.Contains(keyword!) ||
+ (x.Street != null && x.Street.Contains(keyword!)) ||
+ (x.City != null && x.City.Contains(keyword!)) ||
+ (x.StateCode != null && x.StateCode.Contains(keyword!)) ||
+ (x.Country != null && x.Country.Contains(keyword!)) ||
+ (x.ZipCode != null && x.ZipCode.Contains(keyword!)) ||
+ (x.Phone != null && x.Phone.Contains(keyword!)) ||
+ (x.Email != null && x.Email.Contains(keyword!))
+ );
+
+ // 先按排序字段走(如前端传入),否则默认按创建时间倒序
+ if (!string.IsNullOrWhiteSpace(input.Sorting))
+ {
+ query = query.OrderBy(input.Sorting);
+ }
+ else
+ {
+ query = query.OrderBy(x => x.CreationTime, OrderByType.Desc);
+ }
+
+ var entities = await query.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
+
+ var items = entities.Select(x => new LocationGetListOutputDto
+ {
+ Id = x.Id,
+ Partner = x.Partner,
+ GroupName = x.GroupName,
+ LocationCode = x.LocationCode,
+ LocationName = x.LocationName,
+ Street = x.Street,
+ City = x.City,
+ StateCode = x.StateCode,
+ Country = x.Country,
+ ZipCode = x.ZipCode,
+ Phone = x.Phone,
+ Email = x.Email,
+ Latitude = x.Latitude,
+ Longitude = x.Longitude,
+ State = x.State
+ }).ToList();
+
+ var pageSize = input.MaxResultCount <= 0 ? items.Count : input.MaxResultCount;
+ var pageIndex = pageSize <= 0 ? 1 : (input.SkipCount / pageSize) + 1;
+ var totalPages = pageSize <= 0 ? 0 : (int)Math.Ceiling(total / (double)pageSize);
+
+ return new PagedResultWithPageDto
+ {
+ PageIndex = pageIndex,
+ PageSize = pageSize,
+ TotalCount = total,
+ TotalPages = totalPages,
+ Items = items
+ };
+ }
+
+ ///
+ public async Task CreateAsync([FromBody] LocationCreateInputVo input)
+ {
+ var locationCode = input.LocationCode?.Trim();
+ if (string.IsNullOrWhiteSpace(locationCode))
+ {
+ throw new UserFriendlyException("Location ID不能为空");
+ }
+
+ var locationName = input.LocationName?.Trim();
+ if (string.IsNullOrWhiteSpace(locationName))
+ {
+ throw new UserFriendlyException("Location Name不能为空");
+ }
+
+ var isExist = await _locationRepository.IsAnyAsync(x => x.LocationCode == locationCode);
+ if (isExist)
+ {
+ throw new UserFriendlyException("Location ID已存在");
+ }
+
+ var entity = new LocationAggregateRoot(GuidGenerator.Create())
+ {
+ Partner = input.Partner?.Trim(),
+ GroupName = input.GroupName?.Trim(),
+ LocationCode = locationCode,
+ LocationName = locationName,
+ Street = input.Street?.Trim(),
+ City = input.City?.Trim(),
+ StateCode = input.StateCode?.Trim(),
+ Country = input.Country?.Trim(),
+ ZipCode = input.ZipCode?.Trim(),
+ Phone = input.Phone?.Trim(),
+ Email = input.Email?.Trim(),
+ Latitude = input.Latitude,
+ Longitude = input.Longitude,
+ State = input.State
+ };
+
+ await _locationRepository.InsertAsync(entity);
+
+ return new LocationGetListOutputDto
+ {
+ Id = entity.Id,
+ Partner = entity.Partner,
+ GroupName = entity.GroupName,
+ LocationCode = entity.LocationCode,
+ LocationName = entity.LocationName,
+ Street = entity.Street,
+ City = entity.City,
+ StateCode = entity.StateCode,
+ Country = entity.Country,
+ ZipCode = entity.ZipCode,
+ Phone = entity.Phone,
+ Email = entity.Email,
+ Latitude = entity.Latitude,
+ Longitude = entity.Longitude,
+ State = entity.State
+ };
+ }
+
+ ///
+ public async Task UpdateAsync(Guid id, [FromBody] LocationUpdateInputVo input)
+ {
+ var entity = await _locationRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false);
+ if (entity is null)
+ {
+ throw new UserFriendlyException("门店不存在");
+ }
+
+ var locationName = input.LocationName?.Trim();
+ if (string.IsNullOrWhiteSpace(locationName))
+ {
+ throw new UserFriendlyException("Location Name不能为空");
+ }
+
+ // LocationCode 默认不允许修改:业务编码需要保持唯一且稳定(如需变更,应走“新建+迁移”方案)
+ entity.Partner = input.Partner?.Trim();
+ entity.GroupName = input.GroupName?.Trim();
+ entity.LocationName = locationName;
+ entity.Street = input.Street?.Trim();
+ entity.City = input.City?.Trim();
+ entity.StateCode = input.StateCode?.Trim();
+ entity.Country = input.Country?.Trim();
+ entity.ZipCode = input.ZipCode?.Trim();
+ entity.Phone = input.Phone?.Trim();
+ entity.Email = input.Email?.Trim();
+ entity.Latitude = input.Latitude;
+ entity.Longitude = input.Longitude;
+ entity.State = input.State;
+
+ await _locationRepository.UpdateAsync(entity);
+
+ return new LocationGetListOutputDto
+ {
+ Id = entity.Id,
+ Partner = entity.Partner,
+ GroupName = entity.GroupName,
+ LocationCode = entity.LocationCode,
+ LocationName = entity.LocationName,
+ Street = entity.Street,
+ City = entity.City,
+ StateCode = entity.StateCode,
+ Country = entity.Country,
+ ZipCode = entity.ZipCode,
+ Phone = entity.Phone,
+ Email = entity.Email,
+ Latitude = entity.Latitude,
+ Longitude = entity.Longitude,
+ State = entity.State
+ };
+ }
+
+ ///
+ public async Task DeleteAsync(Guid id)
+ {
+ var entity = await _locationRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false);
+ if (entity is null)
+ {
+ throw new UserFriendlyException("门店不存在");
+ }
+
+ entity.IsDeleted = true;
+ await _locationRepository.UpdateAsync(entity);
+ }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacMenuAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacMenuAppService.cs
new file mode 100644
index 0000000..f4f8a4a
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacMenuAppService.cs
@@ -0,0 +1,157 @@
+using FoodLabeling.Application.Contracts.Dtos.RbacMenu;
+using FoodLabeling.Application.Contracts.Dtos.Common;
+using FoodLabeling.Application.Contracts.IServices;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using Volo.Abp;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Entities;
+using Yi.Framework.Rbac.Domain.Entities;
+using Yi.Framework.SqlSugarCore.Abstractions;
+
+namespace FoodLabeling.Application.Services;
+
+///
+/// 权限(Menu)管理(食品标签-美国版对外)
+///
+public class RbacMenuAppService : ApplicationService, IRbacMenuAppService
+{
+ private readonly ISqlSugarRepository _menuRepository;
+
+ public RbacMenuAppService(ISqlSugarRepository menuRepository)
+ {
+ _menuRepository = menuRepository;
+ }
+
+ ///
+ public async Task> GetListAsync([FromQuery] RbacMenuGetListInputVo input)
+ {
+ RefAsync total = 0;
+
+ var query = _menuRepository._DbQueryable
+ .Where(x => x.IsDeleted == false)
+ .WhereIF(!string.IsNullOrWhiteSpace(input.MenuName), x => x.MenuName.Contains(input.MenuName!.Trim()))
+ .WhereIF(input.State is not null, x => x.State == input.State)
+ .WhereIF(input.MenuSource is not null, x => x.MenuSource == (Yi.Framework.Rbac.Domain.Shared.Enums.MenuSourceEnum)input.MenuSource!.Value)
+ .OrderBy(x => x.OrderNum, OrderByType.Desc);
+
+ var entities = await query.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
+
+ var items = entities.Select(x => new RbacMenuGetListOutputDto
+ {
+ Id = x.Id,
+ ParentId = x.ParentId,
+ MenuName = x.MenuName ?? string.Empty,
+ PermissionCode = x.PermissionCode,
+ MenuType = (int)x.MenuType,
+ MenuSource = (int)x.MenuSource,
+ OrderNum = x.OrderNum,
+ State = x.State
+ }).ToList();
+
+ var pageSize = input.MaxResultCount <= 0 ? items.Count : input.MaxResultCount;
+ var pageIndex = pageSize <= 0 ? 1 : (input.SkipCount / pageSize) + 1;
+ var totalPages = pageSize <= 0 ? 0 : (int)Math.Ceiling(total / (double)pageSize);
+
+ return new PagedResultWithPageDto
+ {
+ PageIndex = pageIndex,
+ PageSize = pageSize,
+ TotalCount = total,
+ TotalPages = totalPages,
+ Items = items
+ };
+ }
+
+ ///
+ public async Task GetAsync(Guid id)
+ {
+ var entity = await _menuRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false);
+ if (entity is null)
+ {
+ throw new UserFriendlyException("权限不存在");
+ }
+
+ return new RbacMenuGetListOutputDto
+ {
+ Id = entity.Id,
+ ParentId = entity.ParentId,
+ MenuName = entity.MenuName ?? string.Empty,
+ PermissionCode = entity.PermissionCode,
+ MenuType = (int)entity.MenuType,
+ MenuSource = (int)entity.MenuSource,
+ OrderNum = entity.OrderNum,
+ State = entity.State
+ };
+ }
+
+ ///
+ public async Task CreateAsync([FromBody] RbacMenuCreateInputVo input)
+ {
+ var name = input.MenuName?.Trim();
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new UserFriendlyException("权限名称不能为空");
+ }
+
+ var entity = new MenuAggregateRoot
+ {
+ MenuName = name,
+ ParentId = input.ParentId,
+ MenuType = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuTypeEnum)input.MenuType,
+ MenuSource = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuSourceEnum)input.MenuSource,
+ PermissionCode = input.PermissionCode?.Trim(),
+ Router = input.Router?.Trim(),
+ Component = input.Component?.Trim(),
+ OrderNum = input.OrderNum,
+ State = input.State
+ };
+ EntityHelper.TrySetId(entity, () => GuidGenerator.Create());
+
+ await _menuRepository.InsertAsync(entity);
+ return await GetAsync(entity.Id);
+ }
+
+ ///
+ public async Task UpdateAsync(Guid id, [FromBody] RbacMenuUpdateInputVo input)
+ {
+ var entity = await _menuRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false);
+ if (entity is null)
+ {
+ throw new UserFriendlyException("权限不存在");
+ }
+
+ var name = input.MenuName?.Trim();
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new UserFriendlyException("权限名称不能为空");
+ }
+
+ entity.MenuName = name;
+ entity.ParentId = input.ParentId;
+ entity.MenuType = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuTypeEnum)input.MenuType;
+ entity.MenuSource = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuSourceEnum)input.MenuSource;
+ entity.PermissionCode = input.PermissionCode?.Trim();
+ entity.Router = input.Router?.Trim();
+ entity.Component = input.Component?.Trim();
+ entity.OrderNum = input.OrderNum;
+ entity.State = input.State;
+
+ await _menuRepository.UpdateAsync(entity);
+ return await GetAsync(entity.Id);
+ }
+
+ ///
+ public async Task DeleteAsync([FromBody] List ids)
+ {
+ var idList = ids?.Distinct().ToList() ?? new List();
+ if (idList.Count == 0)
+ {
+ return;
+ }
+
+ // 权限表为软删(ISoftDelete)
+ await _menuRepository.DeleteAsync(x => idList.Contains(x.Id));
+ }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacRoleAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacRoleAppService.cs
new file mode 100644
index 0000000..7a3c28a
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacRoleAppService.cs
@@ -0,0 +1,201 @@
+using FoodLabeling.Application.Contracts.Dtos.RbacRole;
+using FoodLabeling.Application.Contracts.Dtos.Common;
+using FoodLabeling.Application.Contracts.IServices;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using Volo.Abp;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Entities;
+using Volo.Abp.Uow;
+using Yi.Framework.Rbac.Domain.Entities;
+using Yi.Framework.SqlSugarCore.Abstractions;
+
+namespace FoodLabeling.Application.Services;
+
+///
+/// 角色管理(食品标签-美国版对外)
+///
+public class RbacRoleAppService : ApplicationService, IRbacRoleAppService
+{
+ private readonly ISqlSugarRepository _roleRepository;
+ private readonly ISqlSugarRepository _roleMenuRepository;
+ private readonly ISqlSugarRepository _roleDeptRepository;
+ private readonly ISqlSugarRepository _userRoleRepository;
+
+ public RbacRoleAppService(
+ ISqlSugarRepository roleRepository,
+ ISqlSugarRepository roleMenuRepository,
+ ISqlSugarRepository roleDeptRepository,
+ ISqlSugarRepository userRoleRepository)
+ {
+ _roleRepository = roleRepository;
+ _roleMenuRepository = roleMenuRepository;
+ _roleDeptRepository = roleDeptRepository;
+ _userRoleRepository = userRoleRepository;
+ }
+
+ ///
+ public async Task> GetListAsync([FromQuery] RbacRoleGetListInputVo input)
+ {
+ RefAsync total = 0;
+
+ var query = _roleRepository._DbQueryable
+ .Where(x => x.IsDeleted == false)
+ .WhereIF(!string.IsNullOrWhiteSpace(input.RoleCode), x => x.RoleCode.Contains(input.RoleCode!.Trim()))
+ .WhereIF(!string.IsNullOrWhiteSpace(input.RoleName), x => x.RoleName.Contains(input.RoleName!.Trim()))
+ .WhereIF(input.State is not null, x => x.State == input.State);
+
+ if (!string.IsNullOrWhiteSpace(input.Sorting))
+ {
+ query = query.OrderBy(input.Sorting);
+ }
+ else
+ {
+ query = query.OrderBy(x => x.OrderNum, OrderByType.Desc);
+ }
+
+ var entities = await query.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
+
+ var items = entities.Select(x => new RbacRoleGetListOutputDto
+ {
+ Id = x.Id,
+ RoleName = x.RoleName ?? string.Empty,
+ RoleCode = x.RoleCode ?? string.Empty,
+ Remark = x.Remark,
+ DataScope = (int)x.DataScope,
+ State = x.State,
+ OrderNum = x.OrderNum
+ }).ToList();
+
+ var pageSize = input.MaxResultCount <= 0 ? items.Count : input.MaxResultCount;
+ var pageIndex = pageSize <= 0 ? 1 : (input.SkipCount / pageSize) + 1;
+ var totalPages = pageSize <= 0 ? 0 : (int)Math.Ceiling(total / (double)pageSize);
+
+ return new PagedResultWithPageDto
+ {
+ PageIndex = pageIndex,
+ PageSize = pageSize,
+ TotalCount = total,
+ TotalPages = totalPages,
+ Items = items
+ };
+ }
+
+ ///
+ public async Task GetAsync(Guid id)
+ {
+ var entity = await _roleRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false);
+ if (entity is null)
+ {
+ throw new UserFriendlyException("角色不存在");
+ }
+
+ return new RbacRoleGetOutputDto
+ {
+ Id = entity.Id,
+ RoleName = entity.RoleName ?? string.Empty,
+ RoleCode = entity.RoleCode ?? string.Empty,
+ Remark = entity.Remark,
+ DataScope = (int)entity.DataScope,
+ State = entity.State,
+ OrderNum = entity.OrderNum
+ };
+ }
+
+ ///
+ public async Task CreateAsync([FromBody] RbacRoleCreateInputVo input)
+ {
+ var roleName = input.RoleName?.Trim();
+ var roleCode = input.RoleCode?.Trim();
+ if (string.IsNullOrWhiteSpace(roleName))
+ {
+ throw new UserFriendlyException("角色名称不能为空");
+ }
+
+ if (string.IsNullOrWhiteSpace(roleCode))
+ {
+ throw new UserFriendlyException("角色编码不能为空");
+ }
+
+ var isExist = await _roleRepository.IsAnyAsync(x => x.RoleCode == roleCode || x.RoleName == roleName);
+ if (isExist)
+ {
+ throw new UserFriendlyException("角色名称或编码已存在");
+ }
+
+ var entity = new RoleAggregateRoot
+ {
+ RoleName = roleName,
+ RoleCode = roleCode,
+ Remark = input.Remark?.Trim(),
+ DataScope = (Yi.Framework.Rbac.Domain.Shared.Enums.DataScopeEnum)input.DataScope,
+ State = input.State,
+ OrderNum = input.OrderNum
+ };
+ EntityHelper.TrySetId(entity, () => GuidGenerator.Create());
+
+ await _roleRepository.InsertAsync(entity);
+
+ return await GetAsync(entity.Id);
+ }
+
+ ///
+ public async Task UpdateAsync(Guid id, [FromBody] RbacRoleUpdateInputVo input)
+ {
+ var entity = await _roleRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false);
+ if (entity is null)
+ {
+ throw new UserFriendlyException("角色不存在");
+ }
+
+ var roleName = input.RoleName?.Trim();
+ var roleCode = input.RoleCode?.Trim();
+ if (string.IsNullOrWhiteSpace(roleName))
+ {
+ throw new UserFriendlyException("角色名称不能为空");
+ }
+
+ if (string.IsNullOrWhiteSpace(roleCode))
+ {
+ throw new UserFriendlyException("角色编码不能为空");
+ }
+
+ var isExist = await _roleRepository._DbQueryable
+ .Where(x => x.Id != entity.Id && x.IsDeleted == false)
+ .AnyAsync(x => x.RoleCode == roleCode || x.RoleName == roleName);
+ if (isExist)
+ {
+ throw new UserFriendlyException("角色名称或编码已存在");
+ }
+
+ entity.RoleName = roleName;
+ entity.RoleCode = roleCode;
+ entity.Remark = input.Remark?.Trim();
+ entity.DataScope = (Yi.Framework.Rbac.Domain.Shared.Enums.DataScopeEnum)input.DataScope;
+ entity.State = input.State;
+ entity.OrderNum = input.OrderNum;
+
+ await _roleRepository.UpdateAsync(entity);
+
+ return await GetAsync(entity.Id);
+ }
+
+ ///
+ [UnitOfWork]
+ public async Task DeleteAsync([FromBody] List ids)
+ {
+ var idList = ids?.Distinct().ToList() ?? new List();
+ if (idList.Count == 0)
+ {
+ return;
+ }
+
+ await _roleMenuRepository.DeleteAsync(x => idList.Contains(x.RoleId));
+ await _roleDeptRepository.DeleteAsync(x => idList.Contains(x.RoleId));
+ await _userRoleRepository.DeleteAsync(x => idList.Contains(x.RoleId));
+
+ // 角色表为软删(ISoftDelete)
+ await _roleRepository.DeleteAsync(x => idList.Contains(x.Id));
+ }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacRoleMenuAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacRoleMenuAppService.cs
new file mode 100644
index 0000000..e096e27
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacRoleMenuAppService.cs
@@ -0,0 +1,102 @@
+using FoodLabeling.Application.Contracts.Dtos.RbacRoleMenu;
+using FoodLabeling.Application.Contracts.IServices;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using Volo.Abp;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Uow;
+using Yi.Framework.Rbac.Domain.Entities;
+using Yi.Framework.SqlSugarCore.Abstractions;
+
+namespace FoodLabeling.Application.Services;
+
+///
+/// 角色-权限关联(食品标签-美国版对外)
+///
+public class RbacRoleMenuAppService : ApplicationService, IRbacRoleMenuAppService
+{
+ private readonly ISqlSugarRepository _roleRepository;
+ private readonly ISqlSugarRepository _menuRepository;
+ private readonly ISqlSugarRepository _roleMenuRepository;
+
+ public RbacRoleMenuAppService(
+ ISqlSugarRepository roleRepository,
+ ISqlSugarRepository menuRepository,
+ ISqlSugarRepository roleMenuRepository)
+ {
+ _roleRepository = roleRepository;
+ _menuRepository = menuRepository;
+ _roleMenuRepository = roleMenuRepository;
+ }
+
+ ///
+ [UnitOfWork]
+ public async Task SetAsync([FromBody] RbacRoleMenuSetInputVo input)
+ {
+ var role = await _roleRepository.GetSingleAsync(x => x.Id == input.RoleId && x.IsDeleted == false);
+ if (role is null)
+ {
+ throw new UserFriendlyException("角色不存在");
+ }
+
+ var menuIds = input.MenuIds?.Distinct().ToList() ?? new List();
+ if (menuIds.Count == 0)
+ {
+ // 覆盖式:传空表示清空
+ await _roleMenuRepository.DeleteAsync(x => x.RoleId == input.RoleId);
+ return;
+ }
+
+ // 只允许分配未删除的菜单
+ var existMenuIds = await _menuRepository._DbQueryable
+ .Where(x => x.IsDeleted == false)
+ .Where(x => menuIds.Contains(x.Id))
+ .Select(x => x.Id)
+ .ToListAsync();
+
+ await _roleMenuRepository.DeleteAsync(x => x.RoleId == input.RoleId);
+
+ var entities = existMenuIds.Select(menuId => new RoleMenuEntity
+ {
+ RoleId = input.RoleId,
+ MenuId = menuId
+ }).ToList();
+
+ if (entities.Count > 0)
+ {
+ await _roleMenuRepository.InsertRangeAsync(entities);
+ }
+ }
+
+ ///
+ public async Task> GetMenuIdsAsync([FromQuery] Guid roleId)
+ {
+ return await _roleMenuRepository._DbQueryable
+ .Where(x => x.RoleId == roleId)
+ .Select(x => x.MenuId)
+ .ToListAsync();
+ }
+
+ ///
+ [UnitOfWork]
+ public async Task RemoveAsync([FromBody] RbacRoleMenuRemoveInputVo input)
+ {
+ var role = await _roleRepository.GetSingleAsync(x => x.Id == input.RoleId && x.IsDeleted == false);
+ if (role is null)
+ {
+ throw new UserFriendlyException("角色不存在");
+ }
+
+ var menuIds = input.MenuIds?.Distinct().ToList() ?? new List();
+ if (menuIds.Count == 0)
+ {
+ return;
+ }
+
+ await _roleMenuRepository._Db.Deleteable()
+ .Where(x => x.RoleId == input.RoleId)
+ .WhereIF(menuIds.Count > 0, x => menuIds.Contains(x.MenuId))
+ .ExecuteCommandAsync();
+ }
+}
+
diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Domain/Entities/LocationAggregateRoot.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Domain/Entities/LocationAggregateRoot.cs
new file mode 100644
index 0000000..793d3e1
--- /dev/null
+++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Domain/Entities/LocationAggregateRoot.cs
@@ -0,0 +1,134 @@
+using SqlSugar;
+using Volo.Abp.Auditing;
+using Volo.Abp.Domain.Entities;
+using Yi.Framework.Core.Data;
+
+namespace FoodLabeling.Domain.Entities;
+
+///
+/// 门店/位置
+///
+[SugarTable("location")]
+public class LocationAggregateRoot : AggregateRoot, ISoftDelete, IAuditedObject, IOrderNum, IState
+{
+ public LocationAggregateRoot()
+ {
+ }
+
+ public LocationAggregateRoot(Guid id)
+ {
+ Id = id;
+ }
+
+ ///
+ /// 主键
+ ///
+ [SugarColumn(IsPrimaryKey = true)]
+ public override Guid Id { get; protected set; }
+
+ ///
+ /// 逻辑删除
+ ///
+ public bool IsDeleted { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreationTime { get; set; } = DateTime.Now;
+
+ ///
+ /// 创建者
+ ///
+ public Guid? CreatorId { get; set; }
+
+ ///
+ /// 最后修改者
+ ///
+ public Guid? LastModifierId { get; set; }
+
+ ///
+ /// 最后修改时间
+ ///
+ public DateTime? LastModificationTime { get; set; }
+
+ ///
+ /// 排序
+ ///
+ public int OrderNum { get; set; } = 0;
+
+ ///
+ /// 启用状态
+ ///
+ public bool State { get; set; } = true;
+
+ ///
+ /// Partner(原型中的 Partner 下拉)
+ ///
+ public string? Partner { get; set; }
+
+ ///
+ /// Group(原型中的 Group 下拉)
+ ///
+ [SugarColumn(ColumnName = "GroupName")]
+ public string? GroupName { get; set; }
+
+ ///
+ /// Location ID(业务编码)
+ ///
+ [SugarColumn(ColumnName = "LocationCode")]
+ public string LocationCode { get; set; } = string.Empty;
+
+ ///
+ /// Location Name
+ ///
+ [SugarColumn(ColumnName = "LocationName")]
+ public string LocationName { get; set; } = string.Empty;
+
+ ///
+ /// Street
+ ///
+ public string? Street { get; set; }
+
+ ///
+ /// City
+ ///
+ public string? City { get; set; }
+
+ ///
+ /// State(如 NY)
+ ///
+ [SugarColumn(ColumnName = "StateCode")]
+ public string? StateCode { get; set; }
+
+ ///
+ /// Country
+ ///
+ public string? Country { get; set; }
+
+ ///
+ /// Zip Code
+ ///
+ [SugarColumn(ColumnName = "ZipCode")]
+ public string? ZipCode { get; set; }
+
+ ///
+ /// Phone
+ ///
+ public string? Phone { get; set; }
+
+ ///
+ /// Email
+ ///
+ public string? Email { get; set; }
+
+ ///
+ /// Latitude
+ ///
+ public decimal? Latitude { get; set; }
+
+ ///
+ /// Longitude
+ ///
+ public decimal? Longitude { get; set; }
+}
+
diff --git a/项目相关文档/门店(Location)接口对接说明.md b/项目相关文档/门店(Location)接口对接说明.md
new file mode 100644
index 0000000..9f6a918
--- /dev/null
+++ b/项目相关文档/门店(Location)接口对接说明.md
@@ -0,0 +1,101 @@
+## 概述
+
+美国版后端采用 ABP 动态接口(ConventionalControllers),宿主统一前缀为 `api/app`,Swagger 地址为:
+
+- `http://localhost:19001/swagger`
+
+门店模块的服务类为 `LocationAppService`(模块:`food-labeling-us`)。
+
+> 说明:接口的最终 URL 以 Swagger 展示为准(在 Swagger 里搜索 `Location` 或 `LocationAppService` 即可)。
+
+---
+
+## 数据库表
+
+表名:`location`
+
+核心字段(与原型一致):
+
+- Partner:`Partner`
+- Group:`GroupName`
+- Location ID:`LocationCode`
+- Location Name:`LocationName`
+- Street/City/State/Country/Zip:`Street`/`City`/`StateCode`/`Country`/`ZipCode`
+- Phone/Email:`Phone`/`Email`
+- GPS:`Latitude`/`Longitude`
+- Active Location:`State`(1=启用,0=停用)
+
+---
+
+## 接口 1:门店分页列表
+
+### 方法签名
+
+`Task> GetListAsync(LocationGetListInputVo input)`
+
+### 入参(LocationGetListInputVo)
+
+- `SkipCount`:跳过条数(分页用)
+- `MaxResultCount`:每页条数(分页用)
+- `Sorting`:排序字段(可选;不传默认按 CreationTime 倒序)
+- `Keyword`:关键字模糊搜索(会匹配 LocationCode/LocationName/Street/City/StateCode/Country/ZipCode/Phone/Email)
+- `Partner`:Partner 精确过滤(可选)
+- `GroupName`:Group 精确过滤(可选)
+- `State`:启用状态过滤(可选,true/false)
+
+### 出参(PagedResultDto)
+
+- `TotalCount`:总数
+- `Items`:列表
+
+`LocationGetListOutputDto` 字段:
+
+- `Id`
+- `Partner`
+- `GroupName`
+- `LocationCode`
+- `LocationName`
+- `Street`
+- `City`
+- `StateCode`
+- `Country`
+- `ZipCode`
+- `Phone`
+- `Email`
+- `Latitude`
+- `Longitude`
+- `State`
+
+---
+
+## 接口 2:新增门店
+
+### 方法签名
+
+`Task CreateAsync(LocationCreateInputVo input)`
+
+### 入参(LocationCreateInputVo)
+
+- `Partner`:可选
+- `GroupName`:可选
+- `LocationCode`:必填(唯一,重复会报错)
+- `LocationName`:必填
+- `Street/City/StateCode/Country/ZipCode`:可选
+- `Phone/Email`:可选
+- `Latitude/Longitude`:可选(decimal)
+- `State`:是否启用(默认 true)
+
+### 校验规则
+
+- `LocationCode` 不能为空,且唯一
+- `LocationName` 不能为空
+
+---
+
+## Swagger 中如何找到
+
+1. 启动后端宿主(`Yi.Abp.Web`),确保端口为 `19001`
+2. 打开 `http://localhost:19001/swagger`
+3. 在接口分组里找到 **“食品标签-美国版接口”** 或直接搜索 `Location`
+4. 查看 `LocationAppService` 的 `GetListAsync` 与 `CreateAsync`
+