From 87313aec197c4eda0fbca6cb0e155142b9683f5b Mon Sep 17 00:00:00 2001 From: 李曜臣 Date: Wed, 29 Apr 2026 18:43:33 +0800 Subject: [PATCH] 门店支持;登陆接口优化 --- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationSupportAppService.cs | 11 ++++++----- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs | 38 ++++++++++++++++++++++++++++++++------ 项目相关文档/美国版App登录接口说明.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 98 insertions(+), 23 deletions(-) diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationSupportAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationSupportAppService.cs index e1aff20..f5263f0 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationSupportAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LocationSupportAppService.cs @@ -33,8 +33,9 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp throw new UserFriendlyException("门店Id不能为空"); } + // 全门店共用一套 Support 联系方式,按任意门店 Id 查询都返回同一条配置。 var entity = await _dbContext.SqlSugarClient.Queryable() - .FirstAsync(x => !x.IsDeleted && x.LocationId == lid); + .FirstAsync(x => !x.IsDeleted); if (entity is null) { return null; @@ -60,10 +61,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp await EnsureLocationExistsAsync(locationId); var existed = await _dbContext.SqlSugarClient.Queryable() - .AnyAsync(x => !x.IsDeleted && x.LocationId == locationId); + .AnyAsync(x => !x.IsDeleted); if (existed) { - throw new UserFriendlyException("该门店已配置 Support 联系方式,请使用编辑接口"); + throw new UserFriendlyException("已存在全局 Support 联系方式,请使用编辑接口"); } var now = Clock.Now; @@ -113,10 +114,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp await EnsureLocationExistsAsync(locationId); var conflict = await _dbContext.SqlSugarClient.Queryable() - .AnyAsync(x => !x.IsDeleted && x.LocationId == locationId && x.Id != supportId); + .AnyAsync(x => !x.IsDeleted && x.Id != supportId); if (conflict) { - throw new UserFriendlyException("目标门店已配置 Support 联系方式,一个门店仅允许一条"); + throw new UserFriendlyException("系统仅允许一条全局 Support 联系方式"); } entity.LocationId = locationId; diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs index a045d6e..efbdc4c 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; +using SqlSugar; using Volo.Abp.Application.Services; using Volo.Abp.Authorization; using Volo.Abp.Caching; @@ -83,7 +84,7 @@ namespace Yi.Framework.Rbac.Application.Services //登录不想要验证码 ,可不校验 if (!_captcha.Validate(uuid, code)) { - throw new UserFriendlyException("验证码错误"); + throw new UserFriendlyException("Invalid captcha."); } } } @@ -97,21 +98,46 @@ namespace Yi.Framework.Rbac.Application.Services [AllowAnonymous] public async Task PostLoginAsync(LoginInputVo input) { - if (string.IsNullOrEmpty(input.Password) || string.IsNullOrEmpty(input.UserName)) + var email = input.UserName?.Trim(); + var password = input.Password ?? string.Empty; + if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password)) { - throw new UserFriendlyException("请输入合理数据!"); + throw new UserFriendlyException("Email and password are required."); + } + + if (!IsPlausibleEmail(email)) + { + // Platform sign-in supports email only. + throw new UserFriendlyException("Sign-in failed: email is required as the account."); } //校验验证码 ValidationImageCaptcha(input.Uuid,input.Code); - UserAggregateRoot user = new(); - //校验 - await _accountManager.LoginValidationAsync(input.UserName, input.Password, x => user = x); + var normalized = email.ToLowerInvariant(); + var candidates = await _userRepository._DbQueryable + .Where(u => !u.IsDeleted && u.State == true) + .Where(u => u.Email != null && SqlFunc.ToLower(u.Email) == normalized) + .ToListAsync(); + var user = candidates.FirstOrDefault(); + if (user is null) + { + throw new UserFriendlyException("Sign-in failed: account not found."); + } + + if (!user.JudgePassword(password)) + { + throw new UserFriendlyException("Sign-in failed: incorrect email or password."); + } return await PostLoginAsync(user.Id); } + private static bool IsPlausibleEmail(string email) => + email.Contains("@", StringComparison.Ordinal) && + !email.StartsWith("@", StringComparison.Ordinal) && + !email.EndsWith("@", StringComparison.Ordinal); + /// /// 提供其他服务使用,根据用户id,直接返回token diff --git a/项目相关文档/美国版App登录接口说明.md b/项目相关文档/美国版App登录接口说明.md index 15c7d3e..bb213c3 100644 --- a/项目相关文档/美国版App登录接口说明.md +++ b/项目相关文档/美国版App登录接口说明.md @@ -287,8 +287,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ## 接口 6:门店 Support 联系方式(App 展示) -用于 App「Support」页面读取当前门店的联系方式(电话、邮箱)。 -后台由 `LocationSupportAppService` 维护,规则是 **一个门店仅允许一条** 联系方式记录。 +用于 App「Support」页面读取联系方式(电话、邮箱)。 +后台由 `LocationSupportAppService` 维护,规则已调整为 **全门店共用一条全局联系方式**。 ### HTTP @@ -300,15 +300,15 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | 参数名 | 位置 | 类型 | 必填 | 说明 | |--------|------|------|------|------| -| `locationId` | Query | string | 是 | 门店主键(Guid 字符串) | +| `locationId` | Query | string | 是 | 门店主键(Guid 字符串)。当前用于入参兼容,返回值按全局联系方式配置 | ### 响应体(LocationSupportGetOutputDto) | 字段(JSON) | 类型 | 说明 | |--------------|------|------| | `id` | string | 联系方式主键 | -| `locationId` | string | 门店主键 | -| `locationName` | string \| null | 门店名称 | +| `locationId` | string | 配置记录中的门店主键(仅作兼容字段) | +| `locationName` | string \| null | 配置记录中的门店名称(仅作兼容字段) | | `supportPhone` | string | Support 电话 | | `supportEmail` | string | Support 邮箱 | @@ -330,9 +330,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ## 后台维护接口:Location Support(新增/编辑) -仅后台管理端使用,用于配置 App Support 页面展示内容。 +仅后台管理端使用,用于配置 App Support 页面展示内容(全局唯一)。 -### 接口 A:新增门店联系方式 +### 接口 A:新增 Support 联系方式(全局) - **方法**:`POST` - **路径**:`/api/app/location-support` @@ -349,9 +349,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` 约束: -- 同一 `locationId` 只能新增一条,重复会报错:`该门店已配置 Support 联系方式,请使用编辑接口` +- 系统内仅允许存在一条未删除记录;若已存在,再次新增会报错:`已存在全局 Support 联系方式,请使用编辑接口` -### 接口 B:编辑门店联系方式 +### 接口 B:编辑 Support 联系方式(全局) - **方法**:`PUT` - **路径**:`/api/app/location-support/{id}` @@ -371,7 +371,55 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... - `门店Id不能为空` / `门店Id格式不正确` - `Support 电话不能为空` - `Support 邮箱不能为空` / `Support 邮箱格式不正确` -- `目标门店已配置 Support 联系方式,一个门店仅允许一条` +- `系统仅允许一条全局 Support 联系方式` + +--- + +## 平台端登录接口(Web) + +> 对应 `RBAC.AccountService.PostLoginAsync`。当前平台端登录规则已调整为:**仅支持 Email 作为账号,不再支持 UserName**。 + +### HTTP + +- **方法**:`POST` +- **路径**:`/api/app/account/login`(以 Swagger 中 `Account` 为准) +- **Content-Type**:`application/json` +- **鉴权**:匿名 + +### 请求体(LoginInputVo) + +| 字段(JSON) | 类型 | 必填 | 说明 | +|--------------|------|------|------| +| `userName` | string | 是 | 兼容历史字段名;现必须传 **邮箱**(例如 `admin@example.com`) | +| `password` | string | 是 | 密码 | +| `uuid` | string | 条件 | 开启图形验证码时必填 | +| `code` | string | 条件 | 开启图形验证码时必填 | + +### 请求示例 + +```json +{ + "userName": "admin@example.com", + "password": "YourPassword", + "uuid": "captcha-uuid", + "code": "captcha-code" +} +``` + +### 响应体(LoginOutputDto) + +| 字段(JSON) | 类型 | 说明 | +|--------------|------|------| +| `token` | string | Access Token | +| `refreshToken` | string | Refresh Token | + +### 错误文案(英文) + +- `Email and password are required.` +- `Sign-in failed: email is required as the account.` +- `Sign-in failed: account not found.` +- `Sign-in failed: incorrect email or password.` +- `Invalid captcha.` --- @@ -379,7 +427,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | 场景 | 说明 | |------|------| -| Web 管理端 | 仍使用 RBAC **`AccountService.PostLoginAsync`**,一般为人 **`userName`** + 密码 | -| 美国版 App | **仅**本模块 **`/api/app/us-app-auth/login`** 使用 **邮箱 + 密码** | +| Web 管理端 | 使用 RBAC **`/api/app/account/login`**,字段名虽为 `userName`,但值必须是 **Email** | +| 美国版 App | 使用 **`/api/app/us-app-auth/login`**,显式字段 `email` + `password` | 两者共用同一 `User` 表与 JWT 体系;App 端需保证账号已维护 **`Email`** 字段,否则无法通过邮箱登录。 -- libgit2 0.21.4