using dodohold.core; namespace molilian.core { public partial class CouponCenterCore { public const string Version = "0.0.1"; private const string CacheKey = "cache:coupon_center:activities:v1"; private const int CacheExpireSeconds = 600; private const int EmptyCacheExpireSeconds = 60; private static readonly object _lockObj = new(); private static CouponCenterActivitiesResponseDTO? _cached; private static DateTime _cachedExpireAt = DateTime.MinValue; public static CouponCenterActivitiesResponseDTO GetActivities(string channel = "", bool force = false) { var snapshot = GetSnapshot(force); var platformId = NormalizePlatformId(channel); return BuildResponse(snapshot, platformId); } public static void Refresh() { _ = GetSnapshot(true); } private static CouponCenterActivitiesResponseDTO GetSnapshot(bool force = false) { if (!force && _cached != null && _cachedExpireAt > DateTime.Now) { return _cached; } if (!force) { try { var cached = RedisHelper.Get(CacheKey); if (cached != null) { SetLocalCache(cached, CacheExpireSeconds); return cached; } } catch { } } lock (_lockObj) { if (!force && _cached != null && _cachedExpireAt > DateTime.Now) { return _cached; } var snapshot = LoadFromDb(); var cacheSeconds = HasData(snapshot) ? CacheExpireSeconds : EmptyCacheExpireSeconds; SetLocalCache(snapshot, cacheSeconds); if (HasData(snapshot)) { try { RedisHelper.Set(CacheKey, snapshot, CacheExpireSeconds); } catch { } } return snapshot; } } private static CouponCenterActivitiesResponseDTO LoadFromDb() { try { var platformEntities = new DBContext.Table("coupon_center_platforms") .Where("status=@status", new { status = 1 }) .Select()? .OrderBy(item => item.sort) .ThenBy(item => item.id) .ToList() ?? []; var platformIds = platformEntities .Where(item => !string.IsNullOrWhiteSpace(item.id)) .Select(item => item.id) .ToHashSet(StringComparer.OrdinalIgnoreCase); var activityEntities = new DBContext.Table("coupon_center_activities") .Where("status=@status", new { status = 1 }) .Select()? .Where(item => !string.IsNullOrWhiteSpace(item.id) && platformIds.Contains(item.platform_id)) .OrderBy(item => item.sort) .ThenBy(item => item.id) .ToList() ?? []; var activityIds = activityEntities .Select(item => item.id) .ToHashSet(StringComparer.OrdinalIgnoreCase); var couponLookup = (new DBContext.Table("coupon_center_coupons") .Where("status=@status", new { status = 1 }) .Select()? .Where(item => !string.IsNullOrWhiteSpace(item.activity_id) && activityIds.Contains(item.activity_id)) .OrderBy(item => item.sort) .ThenBy(item => item.id) .GroupBy(item => item.activity_id, StringComparer.OrdinalIgnoreCase) .ToDictionary( group => group.Key, group => group.Select(MapCoupon).ToList(), StringComparer.OrdinalIgnoreCase)) ?? new Dictionary>(StringComparer.OrdinalIgnoreCase); return new CouponCenterActivitiesResponseDTO { version = Version, platforms = platformEntities.Select(MapPlatform).ToList(), activities = activityEntities.Select(item => MapActivity(item, couponLookup)).ToList(), pagination = new CouponCenterPaginationDTO() }; } catch (Exception ex) { _ = new LoggerLibrary("CouponCenterCore", "LoadFromDb") .Info(ex.Message, ex.StackTrace) .SaveAsync(); return new CouponCenterActivitiesResponseDTO { version = Version, pagination = new CouponCenterPaginationDTO() }; } } private static CouponCenterActivitiesResponseDTO BuildResponse(CouponCenterActivitiesResponseDTO snapshot, string platformId) { if (snapshot == null) { return new CouponCenterActivitiesResponseDTO { version = Version, pagination = new CouponCenterPaginationDTO() }; } if (string.IsNullOrWhiteSpace(platformId)) { return CloneResponse(snapshot); } var platforms = snapshot.platforms ?? []; var activities = snapshot.activities ?? []; return new CouponCenterActivitiesResponseDTO { version = snapshot.version, platforms = platforms .Where(item => item.id.Equals(platformId, StringComparison.OrdinalIgnoreCase)) .Select(ClonePlatform) .ToList(), activities = activities .Where(item => item.platformId.Equals(platformId, StringComparison.OrdinalIgnoreCase)) .Select(CloneActivity) .ToList(), pagination = new CouponCenterPaginationDTO() }; } private static CouponCenterActivitiesResponseDTO CloneResponse(CouponCenterActivitiesResponseDTO source) { var platforms = source.platforms ?? []; var activities = source.activities ?? []; var pagination = source.pagination ?? new CouponCenterPaginationDTO(); return new CouponCenterActivitiesResponseDTO { version = source.version, platforms = platforms.Select(ClonePlatform).ToList(), activities = activities.Select(CloneActivity).ToList(), pagination = new CouponCenterPaginationDTO { hasMore = pagination.hasMore, nextCursor = pagination.nextCursor } }; } private static CouponCenterPlatformDTO ClonePlatform(CouponCenterPlatformDTO item) { return new CouponCenterPlatformDTO { id = item.id, name = item.name, iconUrl = item.iconUrl }; } private static CouponCenterActivityDTO CloneActivity(CouponCenterActivityDTO item) { var coupons = item.coupons ?? []; return new CouponCenterActivityDTO { id = item.id, platformId = item.platformId, name = item.name, shortDesc = item.shortDesc, deeplink = item.deeplink, coupons = coupons.Select(CloneCoupon).ToList() }; } private static CouponCenterCouponDTO CloneCoupon(CouponCenterCouponDTO item) { return new CouponCenterCouponDTO { id = item.id, value = item.value, expireTime = item.expireTime, category = item.category, threshold = item.threshold, status = item.status }; } private static CouponCenterPlatformDTO MapPlatform(CouponCenterPlatformEntityDTO item) { return new CouponCenterPlatformDTO { id = item.id, name = item.name, iconUrl = item.icon_url }; } private static CouponCenterActivityDTO MapActivity(CouponCenterActivityEntityDTO item, IReadOnlyDictionary> couponLookup) { return new CouponCenterActivityDTO { id = item.id, platformId = item.platform_id, name = item.name, shortDesc = item.short_desc, deeplink = string.IsNullOrWhiteSpace(item.deeplink) ? $"magicchain://coupon-center/activity?activityId={item.id}" : item.deeplink, coupons = couponLookup.TryGetValue(item.id, out var coupons) ? coupons.Select(CloneCoupon).ToList() : [] }; } private static CouponCenterCouponDTO MapCoupon(CouponCenterCouponEntityDTO item) { return new CouponCenterCouponDTO { id = item.id, value = item.value, expireTime = item.expire_time, category = item.category, threshold = item.threshold, status = string.IsNullOrWhiteSpace(item.coupon_status) ? "available" : item.coupon_status }; } private static bool HasData(CouponCenterActivitiesResponseDTO snapshot) { if (snapshot == null) { return false; } return (snapshot.platforms?.Count ?? 0) > 0 || (snapshot.activities?.Count ?? 0) > 0; } private static void SetLocalCache(CouponCenterActivitiesResponseDTO snapshot, int cacheSeconds) { _cached = snapshot; _cachedExpireAt = DateTime.Now.AddSeconds(cacheSeconds); } private static string NormalizePlatformId(string channel) { channel = channel?.Trim().ToLowerInvariant() ?? string.Empty; return channel switch { "taobao" => "tb", "vip" => "vipshop", "tbflash" => "tb_flash", "taobaoflash" => "tb_flash", "淘宝闪购" => "tb_flash", _ => channel, }; } } }