合并云商品分支到 master 并适配插件结构
This commit is contained in:
commit
1fa91a9cfb
15 files changed
+968
-48
No files matched your search
@@ -0,0 +1,118 @@
|
||||
using FreeSql;
|
||||
using MAX.Core.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Store.Modules.CloudProduct.Entities;
|
||||
using Store.Modules.CloudProduct.Dtos;
|
||||
|
||||
namespace Store.Modules.CloudProduct.Repositorys;
|
||||
|
||||
public class GoodsViolationRepository(
|
||||
[FromKeyedServices("CloudProductConnection")] IFreeSql fsql)
|
||||
: BaseRepository<GoodsViolationEntity>(fsql), IScopedDependency
|
||||
{
|
||||
public Task<List<ViolationReasonDto>> GetReasonsAsync() => Orm.Select<ViolationReasonEntity>()
|
||||
.OrderBy(x => x.Id).ToListAsync(x => new ViolationReasonDto
|
||||
{
|
||||
Name = x.Name,
|
||||
IsViolation = x.IsViolation
|
||||
});
|
||||
|
||||
public Task<List<long>> GetViolationIdsAsync(long[] ids) => Select
|
||||
.Where(x => ids.Contains(x.GoodsId)).Distinct().ToListAsync(x => x.GoodsId);
|
||||
|
||||
public async Task<List<long>> GetOffShelfGoodsIdsAsync(long[] ids)
|
||||
{
|
||||
var records = await Select.Where(x => ids.Contains(x.GoodsId)).ToListAsync();
|
||||
return records.GroupBy(x => x.GoodsId).Where(x => x.All(row => row.IsIndexDeleted))
|
||||
.Select(x => x.Key).ToList();
|
||||
}
|
||||
|
||||
// 解除违规和设置待同步必须一起提交,进程中断后后台索引任务仍可恢复。
|
||||
public async Task<int> RemoveAndScheduleRestoreAsync(long[] ids)
|
||||
{
|
||||
using var unit = Orm.CreateUnitOfWork();
|
||||
var violations = unit.GetRepository<GoodsViolationEntity>();
|
||||
var goods = unit.GetRepository<GoodsEntity>();
|
||||
var removedIds = await violations.Select.Where(x => ids.Contains(x.GoodsId)).Distinct().ToListAsync(x => x.GoodsId);
|
||||
await violations.DeleteAsync(x => ids.Contains(x.GoodsId));
|
||||
await goods.UpdateDiy.Set(x => x.IsSegmented, (byte)0)
|
||||
.Where(x => ids.Contains(x.GoodsId) && x.Status == 0).ExecuteAffrowsAsync();
|
||||
unit.Commit();
|
||||
return removedIds.Count;
|
||||
}
|
||||
|
||||
public Task<List<GoodsEntity>> GetRestorableGoodsAsync(long[] ids) => Orm.Select<GoodsEntity>()
|
||||
.Where(x => ids.Contains(x.GoodsId) && x.Status == 0).ToListAsync();
|
||||
|
||||
public Task<int> MarkRestoredAsync(long[] ids) => Orm.Update<GoodsEntity>()
|
||||
.Set(x => x.IsSegmented, (byte)1)
|
||||
.Where(x => ids.Contains(x.GoodsId) && x.Status == 0).ExecuteAffrowsAsync();
|
||||
|
||||
// 调用方持有 GoodsIndexLock,事务内合并原因,避免并发覆盖。
|
||||
public async Task<long[]> MergeAsync(Dictionary<long, string[]> items)
|
||||
{
|
||||
using var unit = Orm.CreateUnitOfWork();
|
||||
var repository = unit.GetRepository<GoodsViolationEntity>();
|
||||
var reasonRepository = unit.GetRepository<ViolationReasonEntity>();
|
||||
var reasonIds = new Dictionary<string, uint>(StringComparer.Ordinal);
|
||||
foreach (var name in items.Values.SelectMany(x => x).Distinct(StringComparer.Ordinal))
|
||||
{
|
||||
// 让数据库按字典表的排序规则匹配名称,与唯一索引保持一致。
|
||||
var reason = await reasonRepository.Select.Where(x => x.Name == name).FirstAsync();
|
||||
// 新类型只收录到字典,绝不因首次上报自动启用商品封禁。
|
||||
reason ??= await reasonRepository.InsertAsync(new ViolationReasonEntity { Name = name, IsViolation = false });
|
||||
// 数据库排序规则可能忽略部分字符差异;判定时仍要求名称完整相等。
|
||||
if (reason.IsViolation && string.Equals(reason.Name, name, StringComparison.Ordinal))
|
||||
reasonIds.Add(name, reason.Id);
|
||||
}
|
||||
var ids = items.Keys.ToArray();
|
||||
var existing = (await repository.Select.Where(x => ids.Contains(x.GoodsId))
|
||||
.ToListAsync()).ToLookup(x => x.GoodsId);
|
||||
var now = DateTime.UtcNow;
|
||||
var recordedIds = new List<long>();
|
||||
foreach (var (goodsId, reasons) in items)
|
||||
{
|
||||
var accepted = reasons.Where(reasonIds.ContainsKey).Select(x => reasonIds[x]).Distinct().ToArray();
|
||||
// 忽略原因仅记录字典,不新增或改变该商品已有的违规状态。
|
||||
if (accepted.Length == 0) continue;
|
||||
var rows = existing[goodsId].ToArray();
|
||||
var previous = rows.Select(x => x.ReasonId).ToHashSet();
|
||||
var added = accepted.Where(x => !previous.Contains(x)).ToArray();
|
||||
if (added.Length == 0 && rows.All(x => x.IsIndexDeleted)) continue;
|
||||
|
||||
// 下架是商品级操作:新增原因或存在失败记录时,整件商品重新标记待下架。
|
||||
foreach (var row in rows)
|
||||
{
|
||||
row.IsIndexDeleted = false;
|
||||
row.UpdatedTime = now;
|
||||
await repository.UpdateAsync(row);
|
||||
}
|
||||
foreach (var reasonId in added)
|
||||
{
|
||||
await repository.InsertAsync(new GoodsViolationEntity
|
||||
{
|
||||
GoodsId = goodsId, ReasonId = reasonId, IsIndexDeleted = false,
|
||||
CreatedTime = now, UpdatedTime = now
|
||||
});
|
||||
}
|
||||
recordedIds.Add(goodsId);
|
||||
}
|
||||
unit.Commit();
|
||||
return recordedIds.ToArray();
|
||||
}
|
||||
|
||||
public Task<int> MarkDeletedAsync(long[] ids) => Orm.Update<GoodsViolationEntity>()
|
||||
.Set(x => x.IsIndexDeleted, true)
|
||||
.Set(x => x.UpdatedTime, DateTime.UtcNow)
|
||||
.Where(x => ids.Contains(x.GoodsId)).ExecuteAffrowsAsync();
|
||||
|
||||
public Task<List<long>> GetBatchAsync(long afterId, int size, bool pendingOnly) => Select
|
||||
.Where(x => x.GoodsId > afterId)
|
||||
.WhereIf(pendingOnly, x => !x.IsIndexDeleted)
|
||||
.Distinct().OrderBy(x => x.GoodsId).Limit(size).ToListAsync(x => x.GoodsId);
|
||||
|
||||
public Task<List<long>> GetByReasonAsync(uint reasonId, long afterId, int size) => Select
|
||||
.Where(x => x.ReasonId == reasonId)
|
||||
.Where(x => x.GoodsId > afterId).OrderBy(x => x.GoodsId)
|
||||
.Limit(size).ToListAsync(x => x.GoodsId);
|
||||
}
|
||||
Reference in new issue
Block a user