Commit 87313aec197c4eda0fbca6cb0e155142b9683f5b

Authored by 李曜臣
1 parent 957e20a0

门店支持;登陆接口优化

美国版/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
33 33 throw new UserFriendlyException("门店Id不能为空");
34 34 }
35 35  
  36 + // 全门店共用一套 Support 联系方式,按任意门店 Id 查询都返回同一条配置。
36 37 var entity = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>()
37   - .FirstAsync(x => !x.IsDeleted && x.LocationId == lid);
  38 + .FirstAsync(x => !x.IsDeleted);
38 39 if (entity is null)
39 40 {
40 41 return null;
... ... @@ -60,10 +61,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp
60 61 await EnsureLocationExistsAsync(locationId);
61 62  
62 63 var existed = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>()
63   - .AnyAsync(x => !x.IsDeleted && x.LocationId == locationId);
  64 + .AnyAsync(x => !x.IsDeleted);
64 65 if (existed)
65 66 {
66   - throw new UserFriendlyException("该门店已配置 Support 联系方式,请使用编辑接口");
  67 + throw new UserFriendlyException("已存在全局 Support 联系方式,请使用编辑接口");
67 68 }
68 69  
69 70 var now = Clock.Now;
... ... @@ -113,10 +114,10 @@ public class LocationSupportAppService : ApplicationService, ILocationSupportApp
113 114 await EnsureLocationExistsAsync(locationId);
114 115  
115 116 var conflict = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>()
116   - .AnyAsync(x => !x.IsDeleted && x.LocationId == locationId && x.Id != supportId);
  117 + .AnyAsync(x => !x.IsDeleted && x.Id != supportId);
117 118 if (conflict)
118 119 {
119   - throw new UserFriendlyException("目标门店已配置 Support 联系方式,一个门店仅允许一条");
  120 + throw new UserFriendlyException("系统仅允许一条全局 Support 联系方式");
120 121 }
121 122  
122 123 entity.LocationId = locationId;
... ...
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs
... ... @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http;
6 6 using Microsoft.AspNetCore.Mvc;
7 7 using Microsoft.Extensions.Caching.Distributed;
8 8 using Microsoft.Extensions.Options;
  9 +using SqlSugar;
9 10 using Volo.Abp.Application.Services;
10 11 using Volo.Abp.Authorization;
11 12 using Volo.Abp.Caching;
... ... @@ -83,7 +84,7 @@ namespace Yi.Framework.Rbac.Application.Services
83 84 //登录不想要验证码 ,可不校验
84 85 if (!_captcha.Validate(uuid, code))
85 86 {
86   - throw new UserFriendlyException("验证码错误");
  87 + throw new UserFriendlyException("Invalid captcha.");
87 88 }
88 89 }
89 90 }
... ... @@ -97,21 +98,46 @@ namespace Yi.Framework.Rbac.Application.Services
97 98 [AllowAnonymous]
98 99 public async Task<LoginOutputDto> PostLoginAsync(LoginInputVo input)
99 100 {
100   - if (string.IsNullOrEmpty(input.Password) || string.IsNullOrEmpty(input.UserName))
  101 + var email = input.UserName?.Trim();
  102 + var password = input.Password ?? string.Empty;
  103 + if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password))
101 104 {
102   - throw new UserFriendlyException("请输入合理数据!");
  105 + throw new UserFriendlyException("Email and password are required.");
  106 + }
  107 +
  108 + if (!IsPlausibleEmail(email))
  109 + {
  110 + // Platform sign-in supports email only.
  111 + throw new UserFriendlyException("Sign-in failed: email is required as the account.");
103 112 }
104 113  
105 114 //校验验证码
106 115 ValidationImageCaptcha(input.Uuid,input.Code);
107 116  
108   - UserAggregateRoot user = new();
109   - //校验
110   - await _accountManager.LoginValidationAsync(input.UserName, input.Password, x => user = x);
  117 + var normalized = email.ToLowerInvariant();
  118 + var candidates = await _userRepository._DbQueryable
  119 + .Where(u => !u.IsDeleted && u.State == true)
  120 + .Where(u => u.Email != null && SqlFunc.ToLower(u.Email) == normalized)
  121 + .ToListAsync();
  122 + var user = candidates.FirstOrDefault();
  123 + if (user is null)
  124 + {
  125 + throw new UserFriendlyException("Sign-in failed: account not found.");
  126 + }
  127 +
  128 + if (!user.JudgePassword(password))
  129 + {
  130 + throw new UserFriendlyException("Sign-in failed: incorrect email or password.");
  131 + }
111 132  
112 133 return await PostLoginAsync(user.Id);
113 134 }
114 135  
  136 + private static bool IsPlausibleEmail(string email) =>
  137 + email.Contains("@", StringComparison.Ordinal) &&
  138 + !email.StartsWith("@", StringComparison.Ordinal) &&
  139 + !email.EndsWith("@", StringComparison.Ordinal);
  140 +
115 141  
116 142 /// <summary>
117 143 /// 提供其他服务使用,根据用户id,直接返回token
... ...
项目相关文档/美国版App登录接口说明.md
... ... @@ -287,8 +287,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
287 287  
288 288 ## 接口 6:门店 Support 联系方式(App 展示)
289 289  
290   -用于 App「Support」页面读取当前门店的联系方式(电话、邮箱)。
291   -后台由 `LocationSupportAppService` 维护,规则是 **一个门店仅允许一条** 联系方式记录。
  290 +用于 App「Support」页面读取联系方式(电话、邮箱)。
  291 +后台由 `LocationSupportAppService` 维护,规则已调整为 **全门店共用一条全局联系方式**。
292 292  
293 293 ### HTTP
294 294  
... ... @@ -300,15 +300,15 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
300 300  
301 301 | 参数名 | 位置 | 类型 | 必填 | 说明 |
302 302 |--------|------|------|------|------|
303   -| `locationId` | Query | string | 是 | 门店主键(Guid 字符串) |
  303 +| `locationId` | Query | string | 是 | 门店主键(Guid 字符串)。当前用于入参兼容,返回值按全局联系方式配置 |
304 304  
305 305 ### 响应体(LocationSupportGetOutputDto)
306 306  
307 307 | 字段(JSON) | 类型 | 说明 |
308 308 |--------------|------|------|
309 309 | `id` | string | 联系方式主键 |
310   -| `locationId` | string | 门店主键 |
311   -| `locationName` | string \| null | 门店名称 |
  310 +| `locationId` | string | 配置记录中的门店主键(仅作兼容字段) |
  311 +| `locationName` | string \| null | 配置记录中的门店名称(仅作兼容字段) |
312 312 | `supportPhone` | string | Support 电话 |
313 313 | `supportEmail` | string | Support 邮箱 |
314 314  
... ... @@ -330,9 +330,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
330 330  
331 331 ## 后台维护接口:Location Support(新增/编辑)
332 332  
333   -仅后台管理端使用,用于配置 App Support 页面展示内容
  333 +仅后台管理端使用,用于配置 App Support 页面展示内容(全局唯一)
334 334  
335   -### 接口 A:新增门店联系方式
  335 +### 接口 A:新增 Support 联系方式(全局)
336 336  
337 337 - **方法**:`POST`
338 338 - **路径**:`/api/app/location-support`
... ... @@ -349,9 +349,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
349 349 ```
350 350  
351 351 约束:
352   -- 同一 `locationId` 只能新增一条,重复会报错:`该门店已配置 Support 联系方式,请使用编辑接口`
  352 +- 系统内仅允许存在一条未删除记录;若已存在,再次新增会报错:`已存在全局 Support 联系方式,请使用编辑接口`
353 353  
354   -### 接口 B:编辑门店联系方式
  354 +### 接口 B:编辑 Support 联系方式(全局)
355 355  
356 356 - **方法**:`PUT`
357 357 - **路径**:`/api/app/location-support/{id}`
... ... @@ -371,7 +371,55 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
371 371 - `门店Id不能为空` / `门店Id格式不正确`
372 372 - `Support 电话不能为空`
373 373 - `Support 邮箱不能为空` / `Support 邮箱格式不正确`
374   -- `目标门店已配置 Support 联系方式,一个门店仅允许一条`
  374 +- `系统仅允许一条全局 Support 联系方式`
  375 +
  376 +---
  377 +
  378 +## 平台端登录接口(Web)
  379 +
  380 +> 对应 `RBAC.AccountService.PostLoginAsync`。当前平台端登录规则已调整为:**仅支持 Email 作为账号,不再支持 UserName**。
  381 +
  382 +### HTTP
  383 +
  384 +- **方法**:`POST`
  385 +- **路径**:`/api/app/account/login`(以 Swagger 中 `Account` 为准)
  386 +- **Content-Type**:`application/json`
  387 +- **鉴权**:匿名
  388 +
  389 +### 请求体(LoginInputVo)
  390 +
  391 +| 字段(JSON) | 类型 | 必填 | 说明 |
  392 +|--------------|------|------|------|
  393 +| `userName` | string | 是 | 兼容历史字段名;现必须传 **邮箱**(例如 `admin@example.com`) |
  394 +| `password` | string | 是 | 密码 |
  395 +| `uuid` | string | 条件 | 开启图形验证码时必填 |
  396 +| `code` | string | 条件 | 开启图形验证码时必填 |
  397 +
  398 +### 请求示例
  399 +
  400 +```json
  401 +{
  402 + "userName": "admin@example.com",
  403 + "password": "YourPassword",
  404 + "uuid": "captcha-uuid",
  405 + "code": "captcha-code"
  406 +}
  407 +```
  408 +
  409 +### 响应体(LoginOutputDto)
  410 +
  411 +| 字段(JSON) | 类型 | 说明 |
  412 +|--------------|------|------|
  413 +| `token` | string | Access Token |
  414 +| `refreshToken` | string | Refresh Token |
  415 +
  416 +### 错误文案(英文)
  417 +
  418 +- `Email and password are required.`
  419 +- `Sign-in failed: email is required as the account.`
  420 +- `Sign-in failed: account not found.`
  421 +- `Sign-in failed: incorrect email or password.`
  422 +- `Invalid captcha.`
375 423  
376 424 ---
377 425  
... ... @@ -379,7 +427,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
379 427  
380 428 | 场景 | 说明 |
381 429 |------|------|
382   -| Web 管理端 | 仍使用 RBAC **`AccountService.PostLoginAsync`**,一般为人 **`userName`** + 密码 |
383   -| 美国版 App | **仅**本模块 **`/api/app/us-app-auth/login`** 使用 **邮箱 + 密码** |
  430 +| Web 管理端 | 使用 RBAC **`/api/app/account/login`**,字段名虽为 `userName`,但值必须是 **Email** |
  431 +| 美国版 App | 使用 **`/api/app/us-app-auth/login`**,显式字段 `email` + `password` |
384 432  
385 433 两者共用同一 `User` 表与 JWT 体系;App 端需保证账号已维护 **`Email`** 字段,否则无法通过邮箱登录。
... ...