Commit 5d2dea03230e4a3fad84f797b6a7fb1b29780f28
Merge branch 'main' of http://39.98.150.180/wangming/Food-Labeling-Management-Platform
Showing
14 changed files
with
252 additions
and
350 deletions
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/Reports/ReportsPrintLogListItemDto.cs
| ... | ... | @@ -27,7 +27,7 @@ public class ReportsPrintLogListItemDto |
| 27 | 27 | /// <summary>模板展示(尺寸 + 模板名)</summary> |
| 28 | 28 | public string TemplateText { get; set; } = "无"; |
| 29 | 29 | |
| 30 | - /// <summary>打印时间展示(<c>MM/dd/yy HH:mm</c>)</summary> | |
| 30 | + /// <summary>打印时间展示(<c>MM/dd/yy</c>,即 MM/DD/YY)</summary> | |
| 31 | 31 | public string PrintedAt { get; set; } = "无"; |
| 32 | 32 | |
| 33 | 33 | /// <summary>打印人姓名</summary> | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IReportsAppService.cs
| ... | ... | @@ -13,7 +13,7 @@ public interface IReportsAppService : IApplicationService |
| 13 | 13 | { |
| 14 | 14 | /// <summary> |
| 15 | 15 | /// Print Log 分页列表;角色 <c>admin</c> 可查全部,否则仅当前用户打印记录。 |
| 16 | - /// 出参 <c>printedAt</c>、<c>expiryDateText</c> 统一为美式短日期 <c>MM/dd/yy HH:mm</c>(精确到分钟)。 | |
| 16 | + /// 出参 <c>printedAt</c>、<c>expiryDateText</c> 日期部分统一为美式短日期 <c>MM/dd/yy</c>(MM/DD/YY);含时分时 <c>MM/dd/yy HH:mm</c>。 | |
| 17 | 17 | /// </summary> |
| 18 | 18 | Task<PagedResultWithPageDto<ReportsPrintLogListItemDto>> GetPrintLogListAsync(ReportsPrintLogGetListInputVo input); |
| 19 | 19 | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs
| ... | ... | @@ -138,7 +138,7 @@ public static class LabelEntityPartnerScopeHelper |
| 138 | 138 | } |
| 139 | 139 | |
| 140 | 140 | /// <summary> |
| 141 | - /// 保存 Company 适用范围(关联表 + <c>AppliedPartnerType</c> 列);未执行迁移脚本时 no-op。 | |
| 141 | + /// 保存 Company 适用范围(关联表与 <c>AppliedPartnerType</c> 列独立探测与落库);未执行迁移脚本时 no-op。 | |
| 142 | 142 | /// </summary> |
| 143 | 143 | public static async Task SavePartnerScopeAsync( |
| 144 | 144 | ISqlSugarClient db, |
| ... | ... | @@ -154,25 +154,54 @@ public static class LabelEntityPartnerScopeHelper |
| 154 | 154 | return; |
| 155 | 155 | } |
| 156 | 156 | |
| 157 | + var needsPartnerRows = NeedsPartnerRowPersistence(scope); | |
| 157 | 158 | var schema = await GetSchemaStatusAsync(db); |
| 158 | - if (!HasPartnerScopeForKind(schema, kind)) | |
| 159 | + var hasTable = HasPartnerTableForKind(schema, kind); | |
| 160 | + var hasColumn = HasPartnerColumnForKind(schema, kind); | |
| 161 | + | |
| 162 | + if (!hasTable && !hasColumn) | |
| 159 | 163 | { |
| 160 | - return; | |
| 164 | + if (needsPartnerRows) | |
| 165 | + { | |
| 166 | + schema = await RefreshSchemaCacheAsync(db); | |
| 167 | + hasTable = HasPartnerTableForKind(schema, kind); | |
| 168 | + hasColumn = HasPartnerColumnForKind(schema, kind); | |
| 169 | + } | |
| 170 | + else | |
| 171 | + { | |
| 172 | + return; | |
| 173 | + } | |
| 174 | + } | |
| 175 | + else if (needsPartnerRows && !hasTable) | |
| 176 | + { | |
| 177 | + schema = await RefreshSchemaCacheAsync(db); | |
| 178 | + hasTable = HasPartnerTableForKind(schema, kind); | |
| 179 | + hasColumn = HasPartnerColumnForKind(schema, kind); | |
| 161 | 180 | } |
| 162 | 181 | |
| 163 | - await DeletePartnerScopeRowsAsync(db, kind, entityId); | |
| 182 | + if (needsPartnerRows && !hasTable) | |
| 183 | + { | |
| 184 | + throw new UserFriendlyException( | |
| 185 | + "Company 适用范围关联表尚未就绪,请联系管理员执行数据库迁移(fl_label_entity_partner_scope.sql)后重试"); | |
| 186 | + } | |
| 164 | 187 | |
| 165 | - if (string.Equals(scope.AppliedPartnerType, ScopeSpecified, StringComparison.OrdinalIgnoreCase) | |
| 166 | - && scope.PartnerIds.Count > 0) | |
| 188 | + if (hasTable) | |
| 167 | 189 | { |
| 168 | - await InsertPartnerRowsAsync(db, guidGenerator, kind, entityId, scope.PartnerIds, currentUserId, now); | |
| 190 | + await DeletePartnerScopeRowsCoreAsync(db, kind, entityId); | |
| 191 | + if (needsPartnerRows) | |
| 192 | + { | |
| 193 | + await InsertPartnerRowsAsync(db, guidGenerator, kind, entityId, scope.PartnerIds, currentUserId, now); | |
| 194 | + } | |
| 169 | 195 | } |
| 170 | 196 | |
| 171 | - await SetAppliedPartnerTypeAsync(db, kind, entityId, scope.AppliedPartnerType); | |
| 197 | + if (hasColumn) | |
| 198 | + { | |
| 199 | + await SetAppliedPartnerTypeAsync(db, kind, entityId, scope.AppliedPartnerType); | |
| 200 | + } | |
| 172 | 201 | } |
| 173 | 202 | |
| 174 | 203 | /// <summary> |
| 175 | - /// 删除实体下 Company 关联行;未迁移 partner 表时跳过。 | |
| 204 | + /// 删除实体下 Company 关联行;未迁移 partner 表时跳过(缓存过期时会刷新再试)。 | |
| 176 | 205 | /// </summary> |
| 177 | 206 | public static async Task DeletePartnerScopeRowsAsync( |
| 178 | 207 | ISqlSugarClient db, |
| ... | ... | @@ -185,29 +214,19 @@ public static class LabelEntityPartnerScopeHelper |
| 185 | 214 | } |
| 186 | 215 | |
| 187 | 216 | var schema = await GetSchemaStatusAsync(db); |
| 188 | - if (!HasPartnerTableForKind(schema, kind)) | |
| 217 | + var hasTable = HasPartnerTableForKind(schema, kind); | |
| 218 | + if (!hasTable) | |
| 189 | 219 | { |
| 190 | - return; | |
| 220 | + schema = await RefreshSchemaCacheAsync(db); | |
| 221 | + hasTable = HasPartnerTableForKind(schema, kind); | |
| 191 | 222 | } |
| 192 | 223 | |
| 193 | - switch (kind) | |
| 224 | + if (!hasTable) | |
| 194 | 225 | { |
| 195 | - case LabelEntityPartnerKind.Type: | |
| 196 | - await db.Deleteable<FlLabelTypePartnerDbEntity>() | |
| 197 | - .Where(x => x.LabelTypeId == entityId) | |
| 198 | - .ExecuteCommandAsync(); | |
| 199 | - break; | |
| 200 | - case LabelEntityPartnerKind.Category: | |
| 201 | - await db.Deleteable<FlLabelCategoryPartnerDbEntity>() | |
| 202 | - .Where(x => x.CategoryId == entityId) | |
| 203 | - .ExecuteCommandAsync(); | |
| 204 | - break; | |
| 205 | - case LabelEntityPartnerKind.MultipleOption: | |
| 206 | - await db.Deleteable<FlLabelMultipleOptionPartnerDbEntity>() | |
| 207 | - .Where(x => x.MultipleOptionId == entityId) | |
| 208 | - .ExecuteCommandAsync(); | |
| 209 | - break; | |
| 226 | + return; | |
| 210 | 227 | } |
| 228 | + | |
| 229 | + await DeletePartnerScopeRowsCoreAsync(db, kind, entityId); | |
| 211 | 230 | } |
| 212 | 231 | |
| 213 | 232 | /// <summary> |
| ... | ... | @@ -234,9 +253,10 @@ public static class LabelEntityPartnerScopeHelper |
| 234 | 253 | } |
| 235 | 254 | |
| 236 | 255 | var schema = await GetSchemaStatusAsync(db); |
| 237 | - var hasScope = HasPartnerScopeForKind(schema, kind); | |
| 256 | + var hasTable = HasPartnerTableForKind(schema, kind); | |
| 257 | + var hasColumn = HasPartnerColumnForKind(schema, kind); | |
| 238 | 258 | |
| 239 | - var partnerLinks = hasScope | |
| 259 | + var partnerLinks = hasTable | |
| 240 | 260 | ? await LoadPartnerLinksAsync(db, kind, ids) |
| 241 | 261 | : new List<(string EntityId, string PartnerId)>(); |
| 242 | 262 | |
| ... | ... | @@ -249,7 +269,7 @@ public static class LabelEntityPartnerScopeHelper |
| 249 | 269 | partnerLinks.Where(x => x.EntityId == entityId).Select(x => x.PartnerId).ToList()); |
| 250 | 270 | |
| 251 | 271 | var partnerType = pIds.Count > 0 ? ScopeSpecified : ScopeAll; |
| 252 | - if (hasScope) | |
| 272 | + if (hasColumn) | |
| 253 | 273 | { |
| 254 | 274 | var storedType = await GetAppliedPartnerTypeAsync(db, kind, entityId); |
| 255 | 275 | if (!string.IsNullOrWhiteSpace(storedType)) |
| ... | ... | @@ -261,6 +281,10 @@ public static class LabelEntityPartnerScopeHelper |
| 261 | 281 | partnerType = ScopeSpecified; |
| 262 | 282 | } |
| 263 | 283 | } |
| 284 | + else if (pIds.Count > 0) | |
| 285 | + { | |
| 286 | + partnerType = ScopeSpecified; | |
| 287 | + } | |
| 264 | 288 | |
| 265 | 289 | var companyDisplay = string.Equals(partnerType, ScopeAll, StringComparison.OrdinalIgnoreCase) |
| 266 | 290 | ? AllCompaniesDisplay |
| ... | ... | @@ -456,6 +480,41 @@ public static class LabelEntityPartnerScopeHelper |
| 456 | 480 | /// <summary>单元测试或切换库后调用。</summary> |
| 457 | 481 | public static void ResetSchemaCacheForTests() => _cachedSchema = null; |
| 458 | 482 | |
| 483 | + private static bool NeedsPartnerRowPersistence(LabelEntityPartnerScopeSaveResult scope) => | |
| 484 | + string.Equals(scope.AppliedPartnerType, ScopeSpecified, StringComparison.OrdinalIgnoreCase) | |
| 485 | + && scope.PartnerIds.Count > 0; | |
| 486 | + | |
| 487 | + private static async Task<LabelEntityPartnerScopeSchemaStatus> RefreshSchemaCacheAsync(ISqlSugarClient db) | |
| 488 | + { | |
| 489 | + _cachedSchema = null; | |
| 490 | + return await GetSchemaStatusAsync(db); | |
| 491 | + } | |
| 492 | + | |
| 493 | + private static async Task DeletePartnerScopeRowsCoreAsync( | |
| 494 | + ISqlSugarClient db, | |
| 495 | + LabelEntityPartnerKind kind, | |
| 496 | + string entityId) | |
| 497 | + { | |
| 498 | + switch (kind) | |
| 499 | + { | |
| 500 | + case LabelEntityPartnerKind.Type: | |
| 501 | + await db.Deleteable<FlLabelTypePartnerDbEntity>() | |
| 502 | + .Where(x => x.LabelTypeId == entityId) | |
| 503 | + .ExecuteCommandAsync(); | |
| 504 | + break; | |
| 505 | + case LabelEntityPartnerKind.Category: | |
| 506 | + await db.Deleteable<FlLabelCategoryPartnerDbEntity>() | |
| 507 | + .Where(x => x.CategoryId == entityId) | |
| 508 | + .ExecuteCommandAsync(); | |
| 509 | + break; | |
| 510 | + case LabelEntityPartnerKind.MultipleOption: | |
| 511 | + await db.Deleteable<FlLabelMultipleOptionPartnerDbEntity>() | |
| 512 | + .Where(x => x.MultipleOptionId == entityId) | |
| 513 | + .ExecuteCommandAsync(); | |
| 514 | + break; | |
| 515 | + } | |
| 516 | + } | |
| 517 | + | |
| 459 | 518 | private static void ValidatePartnerType(string type) |
| 460 | 519 | { |
| 461 | 520 | if (type != ScopeAll && type != ScopeSpecified) |
| ... | ... | @@ -514,9 +573,6 @@ public static class LabelEntityPartnerScopeHelper |
| 514 | 573 | return _cachedSchema; |
| 515 | 574 | } |
| 516 | 575 | |
| 517 | - private static bool HasPartnerScopeForKind(LabelEntityPartnerScopeSchemaStatus schema, LabelEntityPartnerKind kind) => | |
| 518 | - HasPartnerTableForKind(schema, kind) && HasPartnerColumnForKind(schema, kind); | |
| 519 | - | |
| 520 | 576 | private static bool HasPartnerTableForKind(LabelEntityPartnerScopeSchemaStatus schema, LabelEntityPartnerKind kind) => |
| 521 | 577 | kind switch |
| 522 | 578 | { | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs
| ... | ... | @@ -150,13 +150,29 @@ public static class LabelTemplateScopeHelper |
| 150 | 150 | string? currentUserId, |
| 151 | 151 | DateTime now) |
| 152 | 152 | { |
| 153 | - var hasExtendedScope = await LabelTemplateScopeSchemaHelper.HasPartnerRegionScopeTablesAsync(db); | |
| 153 | + var needsPartnerRows = string.Equals(scope.AppliedPartnerType, ScopeSpecified, StringComparison.OrdinalIgnoreCase) | |
| 154 | + && scope.PartnerIds.Count > 0; | |
| 155 | + var needsRegionRows = string.Equals(scope.AppliedRegionType, ScopeSpecified, StringComparison.OrdinalIgnoreCase) | |
| 156 | + && scope.RegionIds.Count > 0; | |
| 154 | 157 | |
| 155 | - if (hasExtendedScope) | |
| 158 | + var hasPartnerTable = await LabelTemplateScopeSchemaHelper.EnsurePartnerScopeTableAsync(db, needsPartnerRows); | |
| 159 | + var hasRegionTable = await LabelTemplateScopeSchemaHelper.EnsureRegionScopeTableAsync(db, needsRegionRows); | |
| 160 | + | |
| 161 | + if (needsPartnerRows && !hasPartnerTable) | |
| 162 | + { | |
| 163 | + throw new UserFriendlyException( | |
| 164 | + "Company 适用范围关联表尚未就绪,请联系管理员执行数据库迁移(fl_label_template_scope.sql)后重试"); | |
| 165 | + } | |
| 166 | + | |
| 167 | + if (hasPartnerTable) | |
| 156 | 168 | { |
| 157 | 169 | await db.Deleteable<FlLabelTemplatePartnerDbEntity>() |
| 158 | 170 | .Where(x => x.TemplateId == templateId) |
| 159 | 171 | .ExecuteCommandAsync(); |
| 172 | + } | |
| 173 | + | |
| 174 | + if (hasRegionTable) | |
| 175 | + { | |
| 160 | 176 | await db.Deleteable<FlLabelTemplateRegionDbEntity>() |
| 161 | 177 | .Where(x => x.TemplateId == templateId) |
| 162 | 178 | .ExecuteCommandAsync(); |
| ... | ... | @@ -166,9 +182,7 @@ public static class LabelTemplateScopeHelper |
| 166 | 182 | .Where(x => x.TemplateId == templateId) |
| 167 | 183 | .ExecuteCommandAsync(); |
| 168 | 184 | |
| 169 | - if (hasExtendedScope | |
| 170 | - && string.Equals(scope.AppliedPartnerType, ScopeSpecified, StringComparison.OrdinalIgnoreCase) | |
| 171 | - && scope.PartnerIds.Count > 0) | |
| 185 | + if (hasPartnerTable && needsPartnerRows) | |
| 172 | 186 | { |
| 173 | 187 | var rows = scope.PartnerIds.Select(pid => new FlLabelTemplatePartnerDbEntity |
| 174 | 188 | { |
| ... | ... | @@ -181,9 +195,7 @@ public static class LabelTemplateScopeHelper |
| 181 | 195 | await db.Insertable(rows).ExecuteCommandAsync(); |
| 182 | 196 | } |
| 183 | 197 | |
| 184 | - if (hasExtendedScope | |
| 185 | - && string.Equals(scope.AppliedRegionType, ScopeSpecified, StringComparison.OrdinalIgnoreCase) | |
| 186 | - && scope.RegionIds.Count > 0) | |
| 198 | + if (hasRegionTable && needsRegionRows) | |
| 187 | 199 | { |
| 188 | 200 | var rows = scope.RegionIds.Select(gid => new FlLabelTemplateRegionDbEntity |
| 189 | 201 | { | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeSchemaHelper.cs
| ... | ... | @@ -116,6 +116,13 @@ public static class LabelTemplateScopeSchemaHelper |
| 116 | 116 | /// <summary>单元测试或切换库后调用。</summary> |
| 117 | 117 | public static void ResetCacheForTests() => _cached = null; |
| 118 | 118 | |
| 119 | + /// <summary>清除缓存并重新探测 schema(应用启动早于迁移脚本执行后调用)。</summary> | |
| 120 | + public static async Task<LabelTemplateScopeSchemaStatus> RefreshStatusAsync(ISqlSugarClient db) | |
| 121 | + { | |
| 122 | + _cached = null; | |
| 123 | + return await GetStatusAsync(db); | |
| 124 | + } | |
| 125 | + | |
| 119 | 126 | /// <summary> |
| 120 | 127 | /// 是否已创建 <c>fl_label_template_partner</c> 与 <c>fl_label_template_region</c>。 |
| 121 | 128 | /// </summary> |
| ... | ... | @@ -126,6 +133,46 @@ public static class LabelTemplateScopeSchemaHelper |
| 126 | 133 | } |
| 127 | 134 | |
| 128 | 135 | /// <summary> |
| 136 | + /// 是否已创建 <c>fl_label_template_partner</c>;缓存未命中时刷新后再探测。 | |
| 137 | + /// </summary> | |
| 138 | + public static async Task<bool> EnsurePartnerScopeTableAsync(ISqlSugarClient db, bool needsPartnerRows) | |
| 139 | + { | |
| 140 | + var status = await GetStatusAsync(db); | |
| 141 | + if (status.HasPartnerScopeTable) | |
| 142 | + { | |
| 143 | + return true; | |
| 144 | + } | |
| 145 | + | |
| 146 | + if (!needsPartnerRows) | |
| 147 | + { | |
| 148 | + return false; | |
| 149 | + } | |
| 150 | + | |
| 151 | + status = await RefreshStatusAsync(db); | |
| 152 | + return status.HasPartnerScopeTable; | |
| 153 | + } | |
| 154 | + | |
| 155 | + /// <summary> | |
| 156 | + /// 是否已创建 <c>fl_label_template_region</c>;缓存未命中时刷新后再探测。 | |
| 157 | + /// </summary> | |
| 158 | + public static async Task<bool> EnsureRegionScopeTableAsync(ISqlSugarClient db, bool needsRegionRows) | |
| 159 | + { | |
| 160 | + var status = await GetStatusAsync(db); | |
| 161 | + if (status.HasRegionScopeTable) | |
| 162 | + { | |
| 163 | + return true; | |
| 164 | + } | |
| 165 | + | |
| 166 | + if (!needsRegionRows) | |
| 167 | + { | |
| 168 | + return false; | |
| 169 | + } | |
| 170 | + | |
| 171 | + status = await RefreshStatusAsync(db); | |
| 172 | + return status.HasRegionScopeTable; | |
| 173 | + } | |
| 174 | + | |
| 175 | + /// <summary> | |
| 129 | 176 | /// 已迁移 scope 列时,写入 <c>AppliedPartnerType</c> / <c>AppliedRegionType</c>(未迁移则 no-op)。 |
| 130 | 177 | /// </summary> |
| 131 | 178 | public static async Task SetAppliedScopeTypesAsync( | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationScopeBindingHelper.cs
| ... | ... | @@ -336,6 +336,34 @@ public static class LocationScopeBindingHelper |
| 336 | 336 | } |
| 337 | 337 | |
| 338 | 338 | /// <summary> |
| 339 | + /// 标签类型/分类/多选项门店范围落库:仅按 Region/Location 合并,不因 Company(partner)展开并集。 | |
| 340 | + /// </summary> | |
| 341 | + public static async Task<List<string>> ResolveEntityLocationIdsForSaveAsync( | |
| 342 | + ISqlSugarClient db, | |
| 343 | + bool locationSpecified, | |
| 344 | + IReadOnlyList<string>? regionIds, | |
| 345 | + IReadOnlyList<string>? locationIds) | |
| 346 | + { | |
| 347 | + if (!locationSpecified) | |
| 348 | + { | |
| 349 | + return new List<string>(); | |
| 350 | + } | |
| 351 | + | |
| 352 | + var merged = await MergeToLocationIdsAsync( | |
| 353 | + db, | |
| 354 | + (IReadOnlyList<string>?)null, | |
| 355 | + regionIds, | |
| 356 | + locationIds); | |
| 357 | + if (merged.Count == 0) | |
| 358 | + { | |
| 359 | + throw new UserFriendlyException("指定适用区域或门店时,至少需要匹配到一个有效门店"); | |
| 360 | + } | |
| 361 | + | |
| 362 | + await ValidateLocationIdsExistAsync(db, merged); | |
| 363 | + return merged; | |
| 364 | + } | |
| 365 | + | |
| 366 | + /// <summary> | |
| 339 | 367 | /// 根据已绑定门店反推适用的 Company Id(<c>fl_partner.Id</c>)。 |
| 340 | 368 | /// </summary> |
| 341 | 369 | public static async Task<List<string>> ResolvePartnerIdsFromLocationIdsAsync( | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/ReportsDateTimeDisplayHelper.cs
| 1 | 1 | using System.Globalization; |
| 2 | 2 | |
| 3 | - | |
| 4 | - | |
| 5 | 3 | namespace FoodLabeling.Application.Helpers; |
| 6 | 4 | |
| 7 | - | |
| 8 | - | |
| 9 | 5 | /// <summary> |
| 10 | - | |
| 11 | -/// Reports Print Log 日期时间展示:统一为 <c>MM/dd/yy HH:mm</c>(精确到分钟)。 | |
| 12 | - | |
| 6 | +/// Reports Print Log 日期展示:统一为美式短日期 <c>MM/dd/yy</c>(MM/DD/YY)。 | |
| 13 | 7 | /// </summary> |
| 14 | - | |
| 15 | 8 | public static class ReportsDateTimeDisplayHelper |
| 16 | - | |
| 17 | 9 | { |
| 10 | + /// <summary>列表日期列统一格式(MM/DD/YY)。</summary> | |
| 11 | + public const string DateDisplayFormat = "MM/dd/yy"; | |
| 18 | 12 | |
| 19 | - public const string DisplayFormat = "MM/dd/yy HH:mm"; | |
| 20 | - | |
| 13 | + /// <summary>含时分时在同日期格式后追加 HH:mm。</summary> | |
| 14 | + public const string DateTimeDisplayFormat = "MM/dd/yy HH:mm"; | |
| 21 | 15 | |
| 16 | + /// <summary>兼容旧引用。</summary> | |
| 17 | + public const string DisplayFormat = DateTimeDisplayFormat; | |
| 22 | 18 | |
| 23 | 19 | private static readonly string[] ExpiryParseFormats = |
| 24 | - | |
| 25 | 20 | { |
| 26 | - | |
| 27 | - DisplayFormat, | |
| 28 | - | |
| 21 | + DateTimeDisplayFormat, | |
| 22 | + DateDisplayFormat, | |
| 29 | 23 | "MM/dd/yy", |
| 30 | - | |
| 31 | 24 | "MM/dd", |
| 32 | - | |
| 33 | 25 | "yyyy-MM-dd H:mm", |
| 34 | - | |
| 35 | 26 | "yyyy-MM-dd", |
| 36 | - | |
| 37 | 27 | "yyyy/MM/dd HH:mm", |
| 38 | - | |
| 39 | 28 | "yyyy/MM/dd", |
| 40 | - | |
| 41 | 29 | "MM/dd/yyyy hh:mm tt", |
| 42 | - | |
| 43 | 30 | "MM/dd/yyyy h:mm tt", |
| 44 | - | |
| 45 | 31 | "MM/dd/yyyy HH:mm", |
| 46 | - | |
| 47 | 32 | "MM/dd/yyyy", |
| 48 | - | |
| 49 | 33 | "M/d/yyyy hh:mm tt", |
| 50 | - | |
| 51 | 34 | "M/d/yyyy h:mm tt", |
| 52 | - | |
| 53 | 35 | "M/d/yyyy", |
| 54 | - | |
| 55 | 36 | "dd/MM/yyyy HH:mm", |
| 56 | - | |
| 57 | 37 | "dd/MM/yyyy", |
| 58 | - | |
| 59 | 38 | "d/M/yyyy HH:mm", |
| 60 | - | |
| 61 | 39 | "d/M/yyyy", |
| 62 | - | |
| 63 | 40 | }; |
| 64 | 41 | |
| 65 | - | |
| 66 | - | |
| 67 | - /// <summary>打印时间展示(Printed at 列)</summary> | |
| 68 | - | |
| 42 | + /// <summary>打印时间展示(Printed at 列):统一 MM/DD/YY。</summary> | |
| 69 | 43 | public static string FormatPrintedAt(DateTime printedAt) |
| 70 | - | |
| 71 | 44 | { |
| 72 | - | |
| 73 | 45 | if (printedAt == DateTime.MinValue) |
| 74 | - | |
| 75 | 46 | { |
| 76 | - | |
| 77 | 47 | return "无"; |
| 78 | - | |
| 79 | 48 | } |
| 80 | 49 | |
| 81 | - | |
| 82 | - | |
| 83 | - return printedAt.ToString(DisplayFormat, CultureInfo.InvariantCulture); | |
| 84 | - | |
| 50 | + return printedAt.ToString(DateDisplayFormat, CultureInfo.InvariantCulture); | |
| 85 | 51 | } |
| 86 | 52 | |
| 87 | - | |
| 88 | - | |
| 89 | - /// <summary>保质期展示(Expiration 列):解析后统一为 <see cref="DisplayFormat"/>。</summary> | |
| 90 | - | |
| 53 | + /// <summary>保质期展示(Expiration 列):解析后统一为 <see cref="DateDisplayFormat"/> 或含时分时 <see cref="DateTimeDisplayFormat"/>。</summary> | |
| 91 | 54 | public static string FormatExpiryDisplay(string? raw, DateTime? anchor = null) |
| 92 | - | |
| 93 | 55 | { |
| 94 | - | |
| 95 | 56 | if (string.IsNullOrWhiteSpace(raw) || string.Equals(raw.Trim(), "无", StringComparison.Ordinal)) |
| 96 | - | |
| 97 | 57 | { |
| 98 | - | |
| 99 | 58 | return "无"; |
| 100 | - | |
| 101 | 59 | } |
| 102 | 60 | |
| 103 | - | |
| 104 | - | |
| 105 | 61 | var s = raw.Trim(); |
| 106 | - | |
| 107 | 62 | if (TryParseToDateTime(s, out var dt)) |
| 108 | - | |
| 109 | 63 | { |
| 110 | - | |
| 111 | - return dt.ToString(DisplayFormat, CultureInfo.InvariantCulture); | |
| 112 | - | |
| 64 | + return FormatExpiryDateTime(dt); | |
| 113 | 65 | } |
| 114 | 66 | |
| 115 | - | |
| 116 | - | |
| 117 | - if (anchor.HasValue && TryParsePartialDateTime(s, anchor.Value, out dt)) | |
| 118 | - | |
| 67 | + var reference = anchor ?? DateTime.Now; | |
| 68 | + if (TryParsePartialDateTime(s, reference, out dt)) | |
| 119 | 69 | { |
| 120 | - | |
| 121 | - return dt.ToString(DisplayFormat, CultureInfo.InvariantCulture); | |
| 122 | - | |
| 70 | + return FormatExpiryDateTime(dt); | |
| 123 | 71 | } |
| 124 | 72 | |
| 125 | - | |
| 126 | - | |
| 127 | 73 | return s; |
| 128 | - | |
| 129 | 74 | } |
| 130 | 75 | |
| 131 | - | |
| 132 | - | |
| 133 | 76 | /// <summary>合并日期片段(如 07/09)与时间片段(如 11:56),缺少年份时用 anchor 补全。</summary> |
| 134 | - | |
| 135 | 77 | public static string MergeDateAndTimeParts(string datePart, string timePart, DateTime anchor) |
| 136 | - | |
| 137 | 78 | { |
| 138 | - | |
| 139 | 79 | var date = datePart.Trim(); |
| 140 | - | |
| 141 | 80 | var time = timePart.Trim(); |
| 142 | - | |
| 143 | 81 | if (string.IsNullOrWhiteSpace(date)) |
| 144 | - | |
| 145 | 82 | { |
| 146 | - | |
| 147 | 83 | return string.IsNullOrWhiteSpace(time) ? "无" : time; |
| 148 | - | |
| 149 | 84 | } |
| 150 | 85 | |
| 151 | - | |
| 152 | - | |
| 153 | 86 | if (!TryParsePartialDateTime(date, anchor, out var dt) && !TryParseToDateTime(date, out dt)) |
| 154 | - | |
| 155 | 87 | { |
| 156 | - | |
| 157 | 88 | return string.IsNullOrWhiteSpace(time) ? date : $"{date} {time}"; |
| 158 | - | |
| 159 | 89 | } |
| 160 | 90 | |
| 161 | - | |
| 162 | - | |
| 163 | 91 | if (!string.IsNullOrWhiteSpace(time)) |
| 164 | - | |
| 165 | 92 | { |
| 166 | - | |
| 167 | 93 | var timeMatch = System.Text.RegularExpressions.Regex.Match( |
| 168 | - | |
| 169 | 94 | time, |
| 170 | - | |
| 171 | 95 | @"^(?<h>\d{1,2}):(?<m>\d{2})", |
| 172 | - | |
| 173 | 96 | System.Text.RegularExpressions.RegexOptions.CultureInvariant); |
| 174 | - | |
| 175 | 97 | if (timeMatch.Success && |
| 176 | - | |
| 177 | 98 | int.TryParse(timeMatch.Groups["h"].Value, out var h) && |
| 178 | - | |
| 179 | 99 | int.TryParse(timeMatch.Groups["m"].Value, out var m)) |
| 180 | - | |
| 181 | 100 | { |
| 182 | - | |
| 183 | 101 | dt = new DateTime(dt.Year, dt.Month, dt.Day, h, m, 0, dt.Kind); |
| 184 | - | |
| 185 | 102 | } |
| 186 | - | |
| 187 | 103 | } |
| 188 | 104 | |
| 189 | - | |
| 190 | - | |
| 191 | - return dt.ToString(DisplayFormat, CultureInfo.InvariantCulture); | |
| 192 | - | |
| 105 | + return FormatExpiryDateTime(dt); | |
| 193 | 106 | } |
| 194 | 107 | |
| 195 | - | |
| 196 | - | |
| 197 | 108 | private static bool TryParsePartialDateTime(string s, DateTime anchor, out DateTime dt) |
| 198 | - | |
| 199 | 109 | { |
| 200 | - | |
| 201 | 110 | dt = default; |
| 202 | - | |
| 203 | 111 | var text = s.Trim(); |
| 204 | - | |
| 205 | 112 | var timeMatch = System.Text.RegularExpressions.Regex.Match( |
| 206 | - | |
| 207 | 113 | text, |
| 208 | - | |
| 209 | 114 | @"^(?<date>\d{1,2}/\d{1,2}(?:/\d{2,4})?)\s+(?<time>\d{1,2}:\d{2})$", |
| 210 | - | |
| 211 | 115 | System.Text.RegularExpressions.RegexOptions.CultureInvariant); |
| 212 | - | |
| 213 | 116 | if (timeMatch.Success) |
| 214 | - | |
| 215 | 117 | { |
| 216 | - | |
| 217 | 118 | text = timeMatch.Groups["date"].Value; |
| 218 | - | |
| 219 | 119 | if (TryParsePartialDateOnly(text, anchor, out dt)) |
| 220 | - | |
| 221 | 120 | { |
| 222 | - | |
| 223 | 121 | var timePart = timeMatch.Groups["time"].Value; |
| 224 | - | |
| 225 | 122 | var parts = timePart.Split(':'); |
| 226 | - | |
| 227 | 123 | if (parts.Length == 2 && |
| 228 | - | |
| 229 | 124 | int.TryParse(parts[0], out var h) && |
| 230 | - | |
| 231 | 125 | int.TryParse(parts[1], out var m)) |
| 232 | - | |
| 233 | 126 | { |
| 234 | - | |
| 235 | 127 | dt = new DateTime(dt.Year, dt.Month, dt.Day, h, m, 0, dt.Kind); |
| 236 | - | |
| 237 | 128 | return true; |
| 238 | - | |
| 239 | 129 | } |
| 240 | - | |
| 241 | 130 | } |
| 242 | - | |
| 243 | 131 | } |
| 244 | 132 | |
| 245 | - | |
| 246 | - | |
| 247 | 133 | return TryParsePartialDateOnly(text, anchor, out dt); |
| 248 | - | |
| 249 | 134 | } |
| 250 | 135 | |
| 251 | - | |
| 252 | - | |
| 253 | 136 | private static bool TryParsePartialDateOnly(string s, DateTime anchor, out DateTime dt) |
| 254 | - | |
| 255 | 137 | { |
| 256 | - | |
| 257 | 138 | dt = default; |
| 258 | - | |
| 259 | 139 | var parts = s.Split('/'); |
| 260 | - | |
| 261 | 140 | if (parts.Length is < 2 or > 3) |
| 262 | - | |
| 263 | 141 | { |
| 264 | - | |
| 265 | 142 | return false; |
| 266 | - | |
| 267 | 143 | } |
| 268 | 144 | |
| 269 | - | |
| 270 | - | |
| 271 | 145 | if (!int.TryParse(parts[0], out var month) || !int.TryParse(parts[1], out var day)) |
| 272 | - | |
| 273 | 146 | { |
| 274 | - | |
| 275 | 147 | return false; |
| 276 | - | |
| 277 | 148 | } |
| 278 | 149 | |
| 279 | - | |
| 280 | - | |
| 281 | 150 | var year = anchor.Year; |
| 282 | - | |
| 283 | 151 | if (parts.Length == 3) |
| 284 | - | |
| 285 | 152 | { |
| 286 | - | |
| 287 | 153 | if (!int.TryParse(parts[2], out var y)) |
| 288 | - | |
| 289 | 154 | { |
| 290 | - | |
| 291 | 155 | return false; |
| 292 | - | |
| 293 | 156 | } |
| 294 | 157 | |
| 295 | - | |
| 296 | - | |
| 297 | 158 | year = parts[2].Length == 2 ? 2000 + y : y; |
| 298 | - | |
| 299 | 159 | } |
| 300 | 160 | |
| 301 | - | |
| 302 | - | |
| 303 | 161 | try |
| 304 | - | |
| 305 | 162 | { |
| 306 | - | |
| 307 | 163 | dt = new DateTime(year, month, day, 0, 0, 0, anchor.Kind); |
| 308 | - | |
| 309 | 164 | return true; |
| 310 | - | |
| 311 | 165 | } |
| 312 | - | |
| 313 | 166 | catch |
| 314 | - | |
| 315 | 167 | { |
| 316 | - | |
| 317 | 168 | return false; |
| 318 | - | |
| 319 | 169 | } |
| 320 | - | |
| 321 | 170 | } |
| 322 | 171 | |
| 323 | - | |
| 324 | - | |
| 325 | 172 | private static bool TryParseToDateTime(string s, out DateTime dt) |
| 326 | - | |
| 327 | 173 | { |
| 328 | - | |
| 329 | 174 | if (DateTime.TryParse( |
| 330 | - | |
| 331 | 175 | s, |
| 332 | - | |
| 333 | 176 | CultureInfo.InvariantCulture, |
| 334 | - | |
| 335 | 177 | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal, |
| 336 | - | |
| 337 | 178 | out dt)) |
| 338 | - | |
| 339 | 179 | { |
| 340 | - | |
| 341 | 180 | return true; |
| 342 | - | |
| 343 | 181 | } |
| 344 | 182 | |
| 345 | - | |
| 346 | - | |
| 347 | 183 | if (DateTime.TryParse( |
| 348 | - | |
| 349 | 184 | s, |
| 350 | - | |
| 351 | 185 | CultureInfo.GetCultureInfo("en-US"), |
| 352 | - | |
| 353 | 186 | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal, |
| 354 | - | |
| 355 | 187 | out dt)) |
| 356 | - | |
| 357 | 188 | { |
| 358 | - | |
| 359 | 189 | return true; |
| 360 | - | |
| 361 | 190 | } |
| 362 | 191 | |
| 363 | - | |
| 364 | - | |
| 365 | 192 | foreach (var fmt in ExpiryParseFormats) |
| 366 | - | |
| 367 | 193 | { |
| 368 | - | |
| 369 | 194 | if (DateTime.TryParseExact( |
| 370 | - | |
| 371 | 195 | s, |
| 372 | - | |
| 373 | 196 | fmt, |
| 374 | - | |
| 375 | 197 | CultureInfo.InvariantCulture, |
| 376 | - | |
| 377 | 198 | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal, |
| 378 | - | |
| 379 | 199 | out dt)) |
| 380 | - | |
| 381 | 200 | { |
| 382 | - | |
| 383 | 201 | return true; |
| 384 | - | |
| 385 | 202 | } |
| 386 | 203 | |
| 387 | - | |
| 388 | - | |
| 389 | 204 | if (DateTime.TryParseExact( |
| 390 | - | |
| 391 | 205 | s, |
| 392 | - | |
| 393 | 206 | fmt, |
| 394 | - | |
| 395 | 207 | CultureInfo.GetCultureInfo("en-US"), |
| 396 | - | |
| 397 | 208 | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal, |
| 398 | - | |
| 399 | 209 | out dt)) |
| 400 | - | |
| 401 | 210 | { |
| 402 | - | |
| 403 | 211 | return true; |
| 404 | - | |
| 405 | 212 | } |
| 406 | - | |
| 407 | 213 | } |
| 408 | 214 | |
| 409 | - | |
| 410 | - | |
| 411 | 215 | return false; |
| 412 | 216 | } |
| 413 | 217 | |
| ... | ... | @@ -419,7 +223,12 @@ public static class ReportsDateTimeDisplayHelper |
| 419 | 223 | return "无"; |
| 420 | 224 | } |
| 421 | 225 | |
| 422 | - return dt.ToString(DisplayFormat, CultureInfo.InvariantCulture); | |
| 226 | + if (dt.Hour == 0 && dt.Minute == 0 && dt.Second == 0) | |
| 227 | + { | |
| 228 | + return dt.ToString(DateDisplayFormat, CultureInfo.InvariantCulture); | |
| 229 | + } | |
| 230 | + | |
| 231 | + return dt.ToString(DateTimeDisplayFormat, CultureInfo.InvariantCulture); | |
| 423 | 232 | } |
| 424 | 233 | |
| 425 | 234 | /// <summary>解析到期字面量(含 anchor 补全年份/时间)。</summary> |
| ... | ... | @@ -433,5 +242,3 @@ public static class ReportsDateTimeDisplayHelper |
| 433 | 242 | return TryParsePartialDateTime(s, anchor, out dt); |
| 434 | 243 | } |
| 435 | 244 | } |
| 436 | - | |
| 437 | - | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/ReportsPrintLogExpiryHelper.cs
| ... | ... | @@ -747,8 +747,8 @@ public static class ReportsPrintLogExpiryHelper |
| 747 | 747 | text = raw.Trim(); |
| 748 | 748 | if (TryParseOffsetPayload(text, out var amount, out var unit)) |
| 749 | 749 | { |
| 750 | - text = ApplyOffset(anchor, amount, unit) | |
| 751 | - .ToString(ReportsDateTimeDisplayHelper.DisplayFormat, CultureInfo.InvariantCulture); | |
| 750 | + text = ReportsDateTimeDisplayHelper.FormatExpiryDateTime( | |
| 751 | + ApplyOffset(anchor, amount, unit)); | |
| 752 | 752 | return true; |
| 753 | 753 | } |
| 754 | 754 | |
| ... | ... | @@ -777,8 +777,8 @@ public static class ReportsPrintLogExpiryHelper |
| 777 | 777 | |
| 778 | 778 | if (v.ValueKind == JsonValueKind.Number && v.TryGetInt64(out var unix)) |
| 779 | 779 | { |
| 780 | - text = DateTimeOffset.FromUnixTimeSeconds(unix).LocalDateTime | |
| 781 | - .ToString(ReportsDateTimeDisplayHelper.DisplayFormat, CultureInfo.InvariantCulture); | |
| 780 | + text = ReportsDateTimeDisplayHelper.FormatExpiryDateTime( | |
| 781 | + DateTimeOffset.FromUnixTimeSeconds(unix).LocalDateTime); | |
| 782 | 782 | return true; |
| 783 | 783 | } |
| 784 | 784 | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/DbModels/FlLabelCategoryDbEntity.cs
| ... | ... | @@ -47,5 +47,10 @@ public class FlLabelCategoryDbEntity |
| 47 | 47 | /// 门店可用范围:ALL / SPECIFIED |
| 48 | 48 | /// </summary> |
| 49 | 49 | public string AvailabilityType { get; set; } = "ALL"; |
| 50 | + | |
| 51 | + /// <summary> | |
| 52 | + /// 适用 Company 范围:ALL / SPECIFIED | |
| 53 | + /// </summary> | |
| 54 | + public string AppliedPartnerType { get; set; } = "ALL"; | |
| 50 | 55 | } |
| 51 | 56 | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/DbModels/FlLabelMultipleOptionDbEntity.cs
| ... | ... | @@ -34,5 +34,10 @@ public class FlLabelMultipleOptionDbEntity |
| 34 | 34 | /// 门店可用范围:ALL / SPECIFIED |
| 35 | 35 | /// </summary> |
| 36 | 36 | public string AvailabilityType { get; set; } = "ALL"; |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 适用 Company 范围:ALL / SPECIFIED | |
| 40 | + /// </summary> | |
| 41 | + public string AppliedPartnerType { get; set; } = "ALL"; | |
| 37 | 42 | } |
| 38 | 43 | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/DbModels/FlLabelTypeDbEntity.cs
| ... | ... | @@ -32,5 +32,10 @@ public class FlLabelTypeDbEntity |
| 32 | 32 | /// 门店可用范围:ALL / SPECIFIED |
| 33 | 33 | /// </summary> |
| 34 | 34 | public string AvailabilityType { get; set; } = "ALL"; |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 适用 Company 范围:ALL / SPECIFIED | |
| 38 | + /// </summary> | |
| 39 | + public string AppliedPartnerType { get; set; } = "ALL"; | |
| 35 | 40 | } |
| 36 | 41 | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs
| ... | ... | @@ -176,6 +176,7 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ |
| 176 | 176 | State = input.State, |
| 177 | 177 | ButtonAppearance = appearance, |
| 178 | 178 | AvailabilityType = availabilityType, |
| 179 | + AppliedPartnerType = partnerScope.AppliedPartnerType, | |
| 179 | 180 | OrderNum = input.OrderNum |
| 180 | 181 | }; |
| 181 | 182 | |
| ... | ... | @@ -219,6 +220,7 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ |
| 219 | 220 | entity.State = input.State; |
| 220 | 221 | entity.ButtonAppearance = appearance; |
| 221 | 222 | entity.AvailabilityType = availabilityType; |
| 223 | + entity.AppliedPartnerType = partnerScope.AppliedPartnerType; | |
| 222 | 224 | entity.OrderNum = input.OrderNum; |
| 223 | 225 | entity.LastModificationTime = DateTime.Now; |
| 224 | 226 | entity.LastModifierId = CurrentUser?.Id?.ToString(); |
| ... | ... | @@ -305,37 +307,14 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ |
| 305 | 307 | throw new UserFriendlyException("门店可用范围不合法(ALL/SPECIFIED)"); |
| 306 | 308 | } |
| 307 | 309 | |
| 308 | - var partnerSpecified = string.Equals( | |
| 309 | - partnerScope.AppliedPartnerType, | |
| 310 | - LabelEntityPartnerScopeHelper.ScopeSpecified, | |
| 311 | - StringComparison.OrdinalIgnoreCase); | |
| 312 | 310 | var locationSpecified = string.Equals(availabilityType, "SPECIFIED", StringComparison.OrdinalIgnoreCase); |
| 311 | + var savedLocationIds = await LocationScopeBindingHelper.ResolveEntityLocationIdsForSaveAsync( | |
| 312 | + _dbContext.SqlSugarClient, | |
| 313 | + locationSpecified, | |
| 314 | + regionIds, | |
| 315 | + explicitLocationIds); | |
| 313 | 316 | |
| 314 | - if (partnerSpecified || locationSpecified) | |
| 315 | - { | |
| 316 | - var merged = await LocationScopeBindingHelper.MergeToLocationIdsAsync( | |
| 317 | - _dbContext.SqlSugarClient, | |
| 318 | - partnerSpecified ? partnerScope.PartnerIds : null, | |
| 319 | - locationSpecified ? regionIds : null, | |
| 320 | - locationSpecified ? explicitLocationIds : null); | |
| 321 | - if (merged.Count == 0) | |
| 322 | - { | |
| 323 | - throw new UserFriendlyException("指定适用范围后至少需要匹配到一个有效门店"); | |
| 324 | - } | |
| 325 | - | |
| 326 | - if (locationSpecified) | |
| 327 | - { | |
| 328 | - await LocationScopeBindingHelper.ValidateLocationIdsExistAsync(_dbContext.SqlSugarClient, merged); | |
| 329 | - return (partnerScope, "SPECIFIED", merged); | |
| 330 | - } | |
| 331 | - } | |
| 332 | - | |
| 333 | - if (string.Equals(availabilityType, "ALL", StringComparison.OrdinalIgnoreCase)) | |
| 334 | - { | |
| 335 | - return (partnerScope, "ALL", new List<string>()); | |
| 336 | - } | |
| 337 | - | |
| 338 | - throw new UserFriendlyException("指定适用区域或门店时,至少需要匹配到一个有效门店"); | |
| 317 | + return (partnerScope, locationSpecified ? "SPECIFIED" : "ALL", savedLocationIds); | |
| 339 | 318 | } |
| 340 | 319 | |
| 341 | 320 | private static List<string> NormalizeRegionIds(LabelCategoryCreateInputVo input) | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs
| ... | ... | @@ -148,6 +148,7 @@ public class LabelMultipleOptionAppService : ApplicationService, ILabelMultipleO |
| 148 | 148 | OptionValuesJson = input.OptionValuesJson?.Trim(), |
| 149 | 149 | State = input.State, |
| 150 | 150 | AvailabilityType = availabilityType, |
| 151 | + AppliedPartnerType = partnerScope.AppliedPartnerType, | |
| 151 | 152 | OrderNum = input.OrderNum |
| 152 | 153 | }; |
| 153 | 154 | |
| ... | ... | @@ -185,6 +186,7 @@ public class LabelMultipleOptionAppService : ApplicationService, ILabelMultipleO |
| 185 | 186 | entity.OptionValuesJson = input.OptionValuesJson?.Trim(); |
| 186 | 187 | entity.State = input.State; |
| 187 | 188 | entity.AvailabilityType = availabilityType; |
| 189 | + entity.AppliedPartnerType = partnerScope.AppliedPartnerType; | |
| 188 | 190 | entity.OrderNum = input.OrderNum; |
| 189 | 191 | entity.LastModificationTime = DateTime.Now; |
| 190 | 192 | entity.LastModifierId = CurrentUser?.Id?.ToString(); |
| ... | ... | @@ -252,37 +254,14 @@ public class LabelMultipleOptionAppService : ApplicationService, ILabelMultipleO |
| 252 | 254 | throw new UserFriendlyException("门店可用范围不合法(ALL/SPECIFIED)"); |
| 253 | 255 | } |
| 254 | 256 | |
| 255 | - var partnerSpecified = string.Equals( | |
| 256 | - partnerScope.AppliedPartnerType, | |
| 257 | - LabelEntityPartnerScopeHelper.ScopeSpecified, | |
| 258 | - StringComparison.OrdinalIgnoreCase); | |
| 259 | 257 | var locationSpecified = string.Equals(availabilityType, "SPECIFIED", StringComparison.OrdinalIgnoreCase); |
| 258 | + var savedLocationIds = await LocationScopeBindingHelper.ResolveEntityLocationIdsForSaveAsync( | |
| 259 | + _dbContext.SqlSugarClient, | |
| 260 | + locationSpecified, | |
| 261 | + regionIds, | |
| 262 | + explicitLocationIds); | |
| 260 | 263 | |
| 261 | - if (partnerSpecified || locationSpecified) | |
| 262 | - { | |
| 263 | - var merged = await LocationScopeBindingHelper.MergeToLocationIdsAsync( | |
| 264 | - _dbContext.SqlSugarClient, | |
| 265 | - partnerSpecified ? partnerScope.PartnerIds : null, | |
| 266 | - locationSpecified ? regionIds : null, | |
| 267 | - locationSpecified ? explicitLocationIds : null); | |
| 268 | - if (merged.Count == 0) | |
| 269 | - { | |
| 270 | - throw new UserFriendlyException("指定适用范围后至少需要匹配到一个有效门店"); | |
| 271 | - } | |
| 272 | - | |
| 273 | - if (locationSpecified) | |
| 274 | - { | |
| 275 | - await LocationScopeBindingHelper.ValidateLocationIdsExistAsync(_dbContext.SqlSugarClient, merged); | |
| 276 | - return (partnerScope, "SPECIFIED", merged); | |
| 277 | - } | |
| 278 | - } | |
| 279 | - | |
| 280 | - if (string.Equals(availabilityType, "ALL", StringComparison.OrdinalIgnoreCase)) | |
| 281 | - { | |
| 282 | - return (partnerScope, "ALL", new List<string>()); | |
| 283 | - } | |
| 284 | - | |
| 285 | - throw new UserFriendlyException("指定适用区域或门店时,至少需要匹配到一个有效门店"); | |
| 264 | + return (partnerScope, locationSpecified ? "SPECIFIED" : "ALL", savedLocationIds); | |
| 286 | 265 | } |
| 287 | 266 | |
| 288 | 267 | private async Task SaveMultipleOptionPartnerScopeAsync( | ... | ... |
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs
| ... | ... | @@ -155,6 +155,7 @@ public class LabelTypeAppService : ApplicationService, ILabelTypeAppService |
| 155 | 155 | TypeName = name, |
| 156 | 156 | State = input.State, |
| 157 | 157 | AvailabilityType = availabilityType, |
| 158 | + AppliedPartnerType = partnerScope.AppliedPartnerType, | |
| 158 | 159 | OrderNum = input.OrderNum |
| 159 | 160 | }; |
| 160 | 161 | |
| ... | ... | @@ -193,6 +194,7 @@ public class LabelTypeAppService : ApplicationService, ILabelTypeAppService |
| 193 | 194 | entity.TypeName = name; |
| 194 | 195 | entity.State = input.State; |
| 195 | 196 | entity.AvailabilityType = availabilityType; |
| 197 | + entity.AppliedPartnerType = partnerScope.AppliedPartnerType; | |
| 196 | 198 | entity.OrderNum = input.OrderNum; |
| 197 | 199 | entity.LastModificationTime = DateTime.Now; |
| 198 | 200 | entity.LastModifierId = CurrentUser?.Id?.ToString(); |
| ... | ... | @@ -267,37 +269,14 @@ public class LabelTypeAppService : ApplicationService, ILabelTypeAppService |
| 267 | 269 | throw new UserFriendlyException("门店可用范围不合法(ALL/SPECIFIED)"); |
| 268 | 270 | } |
| 269 | 271 | |
| 270 | - var partnerSpecified = string.Equals( | |
| 271 | - partnerScope.AppliedPartnerType, | |
| 272 | - LabelEntityPartnerScopeHelper.ScopeSpecified, | |
| 273 | - StringComparison.OrdinalIgnoreCase); | |
| 274 | 272 | var locationSpecified = string.Equals(availabilityType, "SPECIFIED", StringComparison.OrdinalIgnoreCase); |
| 273 | + var savedLocationIds = await LocationScopeBindingHelper.ResolveEntityLocationIdsForSaveAsync( | |
| 274 | + _dbContext.SqlSugarClient, | |
| 275 | + locationSpecified, | |
| 276 | + regionIds, | |
| 277 | + explicitLocationIds); | |
| 275 | 278 | |
| 276 | - if (partnerSpecified || locationSpecified) | |
| 277 | - { | |
| 278 | - var merged = await LocationScopeBindingHelper.MergeToLocationIdsAsync( | |
| 279 | - _dbContext.SqlSugarClient, | |
| 280 | - partnerSpecified ? partnerScope.PartnerIds : null, | |
| 281 | - locationSpecified ? regionIds : null, | |
| 282 | - locationSpecified ? explicitLocationIds : null); | |
| 283 | - if (merged.Count == 0) | |
| 284 | - { | |
| 285 | - throw new UserFriendlyException("指定适用范围后至少需要匹配到一个有效门店"); | |
| 286 | - } | |
| 287 | - | |
| 288 | - if (locationSpecified) | |
| 289 | - { | |
| 290 | - await LocationScopeBindingHelper.ValidateLocationIdsExistAsync(_dbContext.SqlSugarClient, merged); | |
| 291 | - return (partnerScope, "SPECIFIED", merged); | |
| 292 | - } | |
| 293 | - } | |
| 294 | - | |
| 295 | - if (string.Equals(availabilityType, "ALL", StringComparison.OrdinalIgnoreCase)) | |
| 296 | - { | |
| 297 | - return (partnerScope, "ALL", new List<string>()); | |
| 298 | - } | |
| 299 | - | |
| 300 | - throw new UserFriendlyException("指定适用区域或门店时,至少需要匹配到一个有效门店"); | |
| 279 | + return (partnerScope, locationSpecified ? "SPECIFIED" : "ALL", savedLocationIds); | |
| 301 | 280 | } |
| 302 | 281 | |
| 303 | 282 | private async Task SaveTypePartnerScopeAsync( | ... | ... |