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