Kaynağa Gözat

增加监控链接模块

dodo hold 7 ay önce
ebeveyn
işleme
371d6302f6

+ 2 - 1
.gitignore

@@ -27,4 +27,5 @@ stats.html
 **/bin/
 **/obj/
 **/obj/Debug/
-.claude/*
+.claude/*
+.ace-tool/

+ 142 - 0
molilian.api/Controllers/admin/TracksAdminController.cs

@@ -0,0 +1,142 @@
+using System.Text.Json;
+using System.Threading.Tasks;
+using CSRedis;
+using dodohold.core;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using molilian.core;
+
+namespace molilian.api.Controllers
+{
+    [ApiController]
+    [MyAuthorize("admin")]
+    [Route("api/[controller]/[action]")]
+    public class TracksAdminController : ControllerBase
+    {
+        readonly IAuthorizationProvider provider = new AdminProvider();
+        protected IHttpContextAccessor _accessor;
+
+        public TracksAdminController(IHttpContextAccessor accessor)
+        {
+            _accessor = accessor;
+        }
+
+        [HttpPost]
+        public ActionResult list([FromBody] JsonElement form)
+        {
+            var token = provider.Get(_accessor.HttpContext);
+
+            int page = form.Read("current", 1);
+            int size = form.Read("pageSize", 10);
+            bool getTotal = form.Read("getTotal", true);
+            string sort = form.Read("sort", "id");
+            string order = form.Read("order", "DESC");
+            string keyword = form.Read("keyword", string.Empty);
+
+            string filter = string.Empty;
+            if (!string.IsNullOrEmpty(keyword))
+            {
+                filter += " AND (event_type LIKE @keyword OR platform LIKE @keyword OR scene LIKE @keyword OR unique_id LIKE @keyword)";
+                keyword = $"%{keyword}%";
+            }
+            filter = filter.StringTrimStart(" AND ");
+
+            order = "descending".Equals(order, System.StringComparison.OrdinalIgnoreCase) ? "DESC" :
+                    "ascending".Equals(order, System.StringComparison.OrdinalIgnoreCase) ? "ASC" : order;
+            string orderBy = string.IsNullOrEmpty(sort) ? "id DESC" : $"{sort} {order}";
+
+            var result = new DBContext.Table("track_links")
+                .Where(filter, new { keyword })
+                .Page(size, page)
+                .Order(orderBy)
+                .PageList<dynamic>(getTotal);
+
+            return new APIResult(new { data = result });
+        }
+
+        [HttpGet]
+        public ActionResult info([FromQuery] int id)
+        {
+            var token = provider.Get(_accessor.HttpContext);
+            var item = new DBContext.Table("track_links").Get<TrackLinkDTO>("id=@id", new { id });
+            return new APIResult(new { data = item });
+        }
+
+        [HttpPost]
+        public ActionResult report([FromBody] JsonElement form)
+        {
+            var token = provider.Get(_accessor.HttpContext);
+            int page = form.Read("current", 1);
+            int size = form.Read("pageSize", 10);
+            bool getTotal = form.Read("getTotal", true);
+            int linkId = form.Read("track_link_id", 0);
+            string eventType = form.Read("event_type", string.Empty);
+            string platform = form.Read("platform", string.Empty);
+            string scene = form.Read("scene", string.Empty);
+            string uniqueId = form.Read("unique_id", string.Empty);
+            DateTime? start = form.Read<DateTime?>("start", null);
+            DateTime? end = form.Read<DateTime?>("end", null);
+
+            string filter = string.Empty;
+            if (linkId > 0) filter += " AND track_link_id=@linkId";
+            if (!string.IsNullOrWhiteSpace(eventType)) filter += " AND event_type=@eventType";
+            if (!string.IsNullOrWhiteSpace(platform)) filter += " AND platform=@platform";
+            if (!string.IsNullOrWhiteSpace(scene)) filter += " AND scene=@scene";
+            if (!string.IsNullOrWhiteSpace(uniqueId)) filter += " AND unique_id=@uniqueId";
+            if (start.HasValue) filter += " AND report_date>=@start";
+            if (end.HasValue) filter += " AND report_date<=@end";
+            filter = filter.StringTrimStart(" AND ");
+
+            string orderBy = "report_date DESC";
+
+            var result = new DBContext.Table("track_daily_report")
+                .Where(filter, new { linkId, eventType, platform, scene, uniqueId, start, end })
+                .Page(size, page)
+                .Order(orderBy)
+                .PageList<TrackDailyReportDTO>(getTotal);
+
+            return new APIResult(new { data = result });
+        }
+
+        [HttpPost]
+        public async Task<ActionResult> create([FromBody] TrackLinkDTO data)
+        {
+            var token = provider.Get(_accessor.HttpContext);
+            var link = await TracksCore.CreateLinkAsync(data.event_type, data.platform, data.scene, data.unique_id);
+            bool success = link != null && link.id > 0;
+            return new APIResult(new
+            {
+                data = link,
+                success,
+                msg = success ? "创建成功" : "创建失败"
+            });
+        }
+
+        [HttpPost]
+        public ActionResult delete([FromBody] JsonElement form)
+        {
+            var token = provider.Get(_accessor.HttpContext);
+            int id = form.Read<int>("id");
+            using var conn = DBContext.GetOpenConnection();
+            var item = new DBContext.Table(conn, "track_links").Get<TrackLinkDTO>("id=@id", new { id });
+            if (item == null) return new APIResult(new { data = new { success = false, msg = "记录不存在" } });
+
+            var result = new DBContext.Table("track_links").Delete("id=@id", new { id });
+            bool success = result > 0;
+            if (success)
+            {
+                string eventType = (item.event_type ?? string.Empty).Trim().ToLowerInvariant();
+                string platform = (item.platform ?? string.Empty).Trim();
+                string scene = string.IsNullOrWhiteSpace(item.scene) ? string.Empty : item.scene.Trim();
+                string uniqueId = string.IsNullOrWhiteSpace(item.unique_id) ? string.Empty : item.unique_id.Trim();
+
+                string cacheKey = TracksCore.GetLinkCacheKey(eventType, platform, scene, uniqueId);
+                RedisHelper.Del(cacheKey);
+            }
+            return new APIResult(new
+            {
+                data = new { success, msg = success ? "删除成功" : "删除失败" },
+            });
+        }
+    }
+}

+ 1 - 13
molilian.api/Controllers/public/TkController.cs

@@ -1,18 +1,8 @@
 using molilian.core;
 using dodohold.core;
 using Microsoft.AspNetCore.Mvc;
-using Org.BouncyCastle.Ocsp;
 using System.Text.Json;
-using System.Runtime.InteropServices;
-using System.Net;
-using System.Security.Cryptography;
-using Microsoft.AspNetCore.Authentication;
 using TencentCloud.Ecm.V20190719.Models;
-using COSXML.Network;
-using System.Linq;
-using static dodohold.core.ZTOExpress.CreateOrderArgs;
-using MySqlX.XDevAPI;
-using TencentCloud.Ame.V20190916.Models;
 using YunhuiKit;
 
 namespace molilian.api.Controllers
@@ -28,7 +18,6 @@ namespace molilian.api.Controllers
             _accessor = accessor;
         }
 
-
         /// <summary>
         /// oppo调用
         /// </summary>
@@ -57,7 +46,6 @@ namespace molilian.api.Controllers
             var query_text = form.Read("query_text", string.Empty);
 
 
-
             //验证签名
             if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(sign))
             {
@@ -619,4 +607,4 @@ namespace molilian.api.Controllers
         }
 
     }
-}
+}

+ 65 - 0
molilian.api/Controllers/public/TracksController.cs

@@ -0,0 +1,65 @@
+using molilian.core;
+using dodohold.core;
+using Microsoft.AspNetCore.Mvc;
+using System.Text.Json;
+using TencentCloud.Ecm.V20190719.Models;
+using YunhuiKit;
+
+namespace molilian.api.Controllers
+{
+    [ApiController]
+    [Route("[controller]/[action]")]
+    public class TracksController : ControllerBase
+    {
+
+        protected IHttpContextAccessor _accessor;
+        public TracksController(IHttpContextAccessor accessor)
+        {
+            _accessor = accessor;
+        }
+
+        [HttpGet]
+        public ActionResult Track([FromQuery] string eventType, [FromQuery] string platform, [FromQuery] string scene, [FromQuery] string uniqueId = "")
+        {
+            if (string.IsNullOrEmpty(platform) || string.IsNullOrEmpty(scene) || string.IsNullOrEmpty(eventType))
+            {
+                return new APIResult(new { success = false, message = "miss" });
+            }
+            _ = TracksCore.CreateLinkAsync(eventType, platform, scene, uniqueId);
+            _ = TracksCore.TrackAsync(eventType, platform, scene, uniqueId);
+            return new APIResult(new { success = true, message = "ok" });
+        }
+
+        [HttpPost]
+        public async Task<ActionResult> Create([FromQuery] string eventType, [FromQuery] string platform, [FromQuery] string scene, [FromQuery] string uniqueId = "")
+        {
+            var link = await TracksCore.CreateLinkAsync(eventType, platform, scene, uniqueId);
+            if (link == null)
+            {
+                return new APIResult(new { success = false, message = "invalid params or eventType" });
+            }
+            //var request = _accessor.HttpContext!.Request;
+            //string url = $"{request.Scheme}://{request.Host}{link.path}";
+            return new APIResult(new { success = true, message = "ok", url = link.path });
+        }
+
+        [HttpGet]
+        public async Task<ActionResult> Daily([FromQuery] int daysAgo = 1, [FromQuery] string reportDate = "")
+        {
+            DateTime date;
+            if (!string.IsNullOrWhiteSpace(reportDate) && DateTime.TryParse(reportDate, out var parsed))
+            {
+                date = parsed.Date;
+            }
+            else
+            {
+                if (daysAgo <= 0) daysAgo = 1;
+                date = DateTime.Now.AddDays(-daysAgo).Date;
+            }
+
+            int rows = await TracksCore.FlushDailyAsync(date);
+            return new APIResult(new { success = true, message = "ok", rows });
+
+        }
+    }
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
molilian.api/Properties/PublishProfiles/latest.pubxml.user


+ 288 - 0
molilian.core/Core/TracksCore.cs

@@ -0,0 +1,288 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Net;
+using System.Threading.Tasks;
+using CSRedis;
+using dodohold.core;
+using YunhuiKit;
+
+namespace molilian.core
+{
+    public partial class TracksCore
+    {
+        private const string RedisPrefix = ":tracks";
+        private const int DailyExpireSeconds = 40 * 86400;
+        private const int HourlyExpireSeconds = 7 * 86400; // keep a week of hourly buckets
+        private const string DefaultDimensionValue = "";
+        private const int LinkCacheExpireSeconds = 30 * 86400;
+        private static readonly HashSet<string> SupportEventTypes = new(StringComparer.OrdinalIgnoreCase) { "expose", "click" };
+
+        /// <summary>
+        /// 生成一个监测链接(仅返回 path,不包含域名),同时落地到 track_links
+        /// </summary>
+        public static Task<TrackLinkDTO> CreateLinkAsync(string eventType, string platform, string scene, string uniqueId)
+        {
+            eventType = NormalizeEventType(eventType);
+            platform = Normalize(platform);
+            scene = NormalizeOrAll(scene);
+            uniqueId = NormalizeOrAll(uniqueId);
+
+            if (!SupportEventTypes.Contains(eventType) || string.IsNullOrEmpty(platform))
+            {
+                return Task.FromResult<TrackLinkDTO>(null);
+            }
+
+            string cacheKey = $"{RedisPrefix}:link:{eventType}:{platform}:{scene}:{uniqueId}";
+            try
+            {
+                int cachedId = RedisHelper.Get<int>(cacheKey);
+                if (cachedId > 0)
+                {
+                    string cachedPath = BuildPath(eventType, platform, scene, uniqueId);
+                    return Task.FromResult(new TrackLinkDTO
+                    {
+                        id = cachedId,
+                        event_type = eventType,
+                        platform = platform,
+                        scene = scene,
+                        unique_id = uniqueId,
+                        path = cachedPath
+                    });
+                }
+            }
+            catch
+            {
+                // ignore cache errors
+            }
+
+            string path = BuildPath(eventType, platform, scene, uniqueId);
+            try
+            {
+                using var conn = DBContext.GetOpenConnection();
+                var exist = new DBContext.Table(conn, "track_links")
+                    .Get<TrackLinkDTO>("event_type=@event_type AND platform=@platform AND scene=@scene AND unique_id=@unique_id",
+                        new { event_type = eventType, platform, scene, unique_id = uniqueId });
+
+                if (exist != null)
+                {
+                    if (string.IsNullOrEmpty(exist.path))
+                    {
+                        exist.path = path;
+                        new DBContext.Table(conn, "track_links")
+                            .Add("path", path)
+                            .Add("update_time", DateTime.Now)
+                            .Where("id=@id", new { exist.id })
+                            .Update();
+                    }
+                    _ = RedisHelper.Set(cacheKey, exist.id, LinkCacheExpireSeconds);
+                    return Task.FromResult(exist);
+                }
+
+                var item = new TrackLinkDTO
+                {
+                    event_type = eventType,
+                    platform = platform,
+                    scene = scene,
+                    unique_id = uniqueId,
+                    path = path,
+                    create_time = DateTime.Now,
+                    update_time = DateTime.Now
+                };
+
+                var id = conn.Insert(item);
+                if (id != null && int.TryParse(id.ToString(), out var linkId))
+                {
+                    item.id = linkId;
+                }
+                _ = RedisHelper.Set(cacheKey, item.id, LinkCacheExpireSeconds);
+                return Task.FromResult(item);
+            }
+            catch (Exception ex)
+            {
+                _ = new LoggerLibrary("TracksCore", "CreateLink")
+                    .Info(ex.Message, ex.StackTrace)
+                    .SaveAsync();
+                return Task.FromResult<TrackLinkDTO>(null);
+            }
+        }
+
+        /// <summary>
+        /// 曝光/点击触发:计入 Redis,失败不影响返回
+        /// </summary>
+        public static Task<bool> TrackAsync(string eventType, string platform, string scene, string uniqueId)
+        {
+            eventType = NormalizeEventType(eventType);
+            platform = Normalize(platform);
+            scene = NormalizeOrAll(scene);
+            uniqueId = NormalizeOrAll(uniqueId);
+
+            if (!SupportEventTypes.Contains(eventType) || string.IsNullOrEmpty(platform))
+            {
+                return Task.FromResult(false);
+            }
+
+            string dateStr = DateTime.Now.ToString("yyyyMMdd");
+            string hourStr = DateTime.Now.ToString("yyyyMMddHH");
+
+            var metrics = new List<(string key, string indexKey, string indexValue, int expire)>
+            {
+                // Daily buckets
+                ($"{RedisPrefix}:daily:{eventType}:{platform}:{dateStr}",
+                    $"{RedisPrefix}:daily:index:{dateStr}:platform",
+                    $"{eventType}|{platform}", DailyExpireSeconds),
+
+                ($"{RedisPrefix}:daily:{eventType}:{platform}:{scene}:{dateStr}",
+                    $"{RedisPrefix}:daily:index:{dateStr}:scene",
+                    $"{eventType}|{platform}|{scene}", DailyExpireSeconds),
+
+                ($"{RedisPrefix}:daily:{eventType}:{platform}:{scene}:{uniqueId}:{dateStr}",
+                    $"{RedisPrefix}:daily:index:{dateStr}:unique",
+                    $"{eventType}|{platform}|{scene}|{uniqueId}", DailyExpireSeconds),
+
+                // Hourly buckets
+                ($"{RedisPrefix}:hour:{eventType}:{platform}:{hourStr}",
+                    $"{RedisPrefix}:hour:index:{hourStr}:platform",
+                    $"{eventType}|{platform}", HourlyExpireSeconds),
+
+                ($"{RedisPrefix}:hour:{eventType}:{platform}:{scene}:{hourStr}",
+                    $"{RedisPrefix}:hour:index:{hourStr}:scene",
+                    $"{eventType}|{platform}|{scene}", HourlyExpireSeconds),
+
+                ($"{RedisPrefix}:hour:{eventType}:{platform}:{scene}:{uniqueId}:{hourStr}",
+                    $"{RedisPrefix}:hour:index:{hourStr}:unique",
+                    $"{eventType}|{platform}|{scene}|{uniqueId}", HourlyExpireSeconds),
+            };
+
+            try
+            {
+                foreach (var metric in metrics)
+                {
+                    RedisHelper.IncrBy(metric.key);
+                    RedisHelper.Expire(metric.key, metric.expire);
+
+                    RedisHelper.SAdd(metric.indexKey, metric.indexValue);
+                    RedisHelper.Expire(metric.indexKey, metric.expire);
+                }
+                return Task.FromResult(true);
+            }
+            catch (Exception ex)
+            {
+                _ = new LoggerLibrary("TracksCore", "TrackAsync")
+                    .Info(ex.Message, ex.StackTrace)
+                    .SaveAsync();
+                return Task.FromResult(false);
+            }
+        }
+
+        /// <summary>
+        /// 日报:拉取昨日 Redis 计数并落地到 track_daily_report(默认统计昨天,可传 reportDate)
+        /// </summary>
+        public static async Task<int> FlushDailyAsync(DateTime targetDate)
+        {
+            string dateStr = targetDate.ToString("yyyyMMdd");
+            string indexKey = $"{RedisPrefix}:daily:index:{dateStr}:unique";
+
+            var indexMembers = await RedisHelper.SMembersAsync<string>(indexKey) ?? [];
+            if (indexMembers == null || indexMembers.Length == 0) return 0;
+
+            int rows = 0;
+            using var conn = DBContext.GetOpenConnection();
+            foreach (var member in indexMembers)
+            {
+                var parts = member.Split('|');
+                if (parts.Length != 4) continue;
+
+                string eventType = NormalizeEventType(parts[0]);
+                string platform = Normalize(parts[1]);
+                string scene = NormalizeOrAll(parts[2]);
+                string uniqueId = NormalizeOrAll(parts[3]);
+                if (!SupportEventTypes.Contains(eventType)) continue;
+
+                string countKey = $"{RedisPrefix}:daily:{eventType}:{platform}:{scene}:{uniqueId}:{dateStr}";
+                int total = await RedisHelper.GetAsync<int>(countKey);
+                if (total <= 0) continue;
+
+                int linkId = GetTrackLinkId(conn, eventType, platform, scene, uniqueId);
+                var exist = new DBContext.Table(conn, "track_daily_report")
+                    .Fields("id")
+                    .Get<dynamic>("report_date=@report_date AND event_type=@event_type AND platform=@platform AND scene=@scene AND unique_id=@unique_id",
+                        new { report_date = targetDate, event_type = eventType, platform, scene, unique_id = uniqueId });
+
+                var update = new DBContext.Table(conn, "track_daily_report")
+                    .Add("event_count", total)
+                    .Add("track_link_id", linkId)
+                    .Add("update_time", DateTime.Now);
+
+                if (exist == null)
+                {
+                    update.Add("report_date", targetDate)
+                          .Add("event_type", eventType)
+                          .Add("platform", platform)
+                          .Add("scene", scene)
+                          .Add("unique_id", uniqueId)
+                          .Add("create_time", DateTime.Now)
+                          .Create();
+                }
+                else
+                {
+                    update.Where("id=@id", new { exist.id }).Update();
+                }
+                rows++;
+            }
+            return rows;
+        }
+
+        public static string BuildPath(string eventType, string platform, string scene, string uniqueId)
+        {
+            string safeEventType = WebUtility.UrlEncode(eventType);
+            string safePlatform = WebUtility.UrlEncode(platform);
+            string safeScene = WebUtility.UrlEncode(scene);
+            string safeUniqueId = WebUtility.UrlEncode(uniqueId);
+            return $"https://api.molilian.com/tracks/track?eventType={safeEventType}&platform={safePlatform}&scene={safeScene}&uniqueId={safeUniqueId}";
+        }
+
+        public static string GetLinkCacheKey(string eventType, string platform, string scene, string uniqueId)
+        {
+            eventType = NormalizeEventType(eventType);
+            platform = Normalize(platform);
+            scene = NormalizeOrAll(scene);
+            uniqueId = NormalizeOrAll(uniqueId);
+            return $"{RedisPrefix}:link:{eventType}:{platform}:{scene}:{uniqueId}";
+        }
+
+        private static string Normalize(string value)
+        {
+            return (value ?? string.Empty).Trim();
+        }
+
+        private static string NormalizeOrAll(string value)
+        {
+            var result = Normalize(value);
+            return string.IsNullOrEmpty(result) ? DefaultDimensionValue : result;
+        }
+
+        private static string NormalizeEventType(string value)
+        {
+            return Normalize(value).ToLowerInvariant();
+        }
+
+        private static int GetTrackLinkId(IDbConnection conn, string eventType, string platform, string scene, string uniqueId)
+        {
+            try
+            {
+                var record = new DBContext.Table(conn, "track_links")
+                    .Fields("id")
+                    .Get<TrackLinkDTO>("event_type=@event_type AND platform=@platform AND scene=@scene AND unique_id=@unique_id",
+                        new { event_type = eventType, platform, scene, unique_id = uniqueId });
+                if (record == null) return 0;
+                return record.id;
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+    }
+
+}

+ 22 - 13
molilian.core/Core/taoke/UnionParseCore/UnionParseCore.cs

@@ -7,6 +7,7 @@ using System.Net;
 using System.Security.Cryptography;
 using System.Text.RegularExpressions;
 using System.Threading.Channels;
+using TencentCloud.Cwp.V20180228.Models;
 using YunhuiKit;
 
 
@@ -154,7 +155,15 @@ namespace molilian.core
                 result.itemName,
             }, !string.IsNullOrEmpty(result.deeplink_url) ? APIResultCodeEnum.OK : APIResultCodeEnum.NotAcceptable);
         }
+        
+        private static bool ValidateDeeplinkIfRequired(bool success, string deeplink_url)
+        {
+            //根据 deeplink 是否为空返回 success 值
+            //return !string.IsNullOrEmpty(deeplink_url);
 
+            //暂时不判断
+            return success;
+        }
 
         private static APIResult TaobaoParseOutput(TkDataDTO result, Dictionary<string, long> swData, object info, APIResultCodeEnum code = APIResultCodeEnum.OK)
         {
@@ -200,7 +209,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -290,7 +299,7 @@ namespace molilian.core
 
             return TaobaoParseOutput(result, swData, new
             {
-                success = !string.IsNullOrEmpty(result.deeplink_url),
+                success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                 result.commercial,
                 result.with_middle_page,
                 result.message,
@@ -365,7 +374,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -393,7 +402,7 @@ namespace molilian.core
 
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -422,7 +431,7 @@ namespace molilian.core
 
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -466,7 +475,7 @@ namespace molilian.core
                     other_aff = true;
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -507,7 +516,7 @@ namespace molilian.core
                     other_aff = true;
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -537,7 +546,7 @@ namespace molilian.core
 
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -565,7 +574,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -595,7 +604,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -689,7 +698,7 @@ namespace molilian.core
 
             return TaobaoParseOutput(result, swData, new
             {
-                success = !string.IsNullOrEmpty(result.deeplink_url),
+                success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                 result.commercial,
                 result.with_middle_page,
                 result.message,
@@ -720,7 +729,7 @@ namespace molilian.core
         {
             return new APIResult(new
             {
-                success = !string.IsNullOrEmpty(result.deeplink_url),
+                success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                 //result.success,
                 result.message,
                 result.commercial,
@@ -1450,7 +1459,7 @@ namespace molilian.core
             return new APIResult(new
             {
                 //result.success,
-                success = !string.IsNullOrEmpty(result.deeplink_url),
+                success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                 result.message,
                 result.commercial,
                 sub_message = result.reason,

+ 11 - 11
molilian.core/Core/taoke/UnionParseCore/dp2dp.cs

@@ -45,7 +45,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -76,7 +76,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -108,7 +108,7 @@ namespace molilian.core
                         _ = TkLogCore.ParseLogAsync(result);
                         return TaobaoParseOutput(result, swData, new
                         {
-                            success = !string.IsNullOrEmpty(result.deeplink_url),
+                            success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                             result.commercial,
                             result.with_middle_page,
                             result.message,
@@ -167,7 +167,7 @@ namespace molilian.core
 
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -196,7 +196,7 @@ namespace molilian.core
 
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -246,7 +246,7 @@ namespace molilian.core
                     other_aff = true;
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -291,7 +291,7 @@ namespace molilian.core
                     other_aff = true;
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -325,7 +325,7 @@ namespace molilian.core
 
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -357,7 +357,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -391,7 +391,7 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
                     return TaobaoParseOutput(result, swData, new
                     {
-                        success = !string.IsNullOrEmpty(result.deeplink_url),
+                        success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                         result.commercial,
                         result.with_middle_page,
                         result.message,
@@ -490,7 +490,7 @@ namespace molilian.core
             return TaobaoParseOutput(result, swData, new
             {
                 //result.success,
-                success = !string.IsNullOrEmpty(result.deeplink_url),
+                success = ValidateDeeplinkIfRequired(result.success, result.deeplink_url),
                 result.commercial,
                 result.with_middle_page,
                 result.message,

+ 35 - 0
molilian.core/DTO/TracksDTO.cs

@@ -0,0 +1,35 @@
+using System;
+using dodohold.core;
+
+namespace molilian.core
+{
+    [Table("track_links")]
+    public class TrackLinkDTO
+    {
+        [Key]
+        public int id { get; set; }
+        public string event_type { get; set; } = string.Empty;
+        public string platform { get; set; } = string.Empty;
+        public string scene { get; set; } = string.Empty;
+        public string unique_id { get; set; } = string.Empty;
+        public string path { get; set; } = string.Empty;
+        public DateTime create_time { get; set; } = DateTime.Now;
+        public DateTime update_time { get; set; } = DateTime.Now;
+    }
+
+    [Table("track_daily_report")]
+    public class TrackDailyReportDTO
+    {
+        [Key]
+        public int id { get; set; }
+        public DateTime report_date { get; set; } = DateTime.Now.Date;
+        public string event_type { get; set; } = string.Empty;
+        public string platform { get; set; } = string.Empty;
+        public string scene { get; set; } = string.Empty;
+        public string unique_id { get; set; } = string.Empty;
+        public int track_link_id { get; set; } = 0;
+        public int event_count { get; set; } = 0;
+        public DateTime create_time { get; set; } = DateTime.Now;
+        public DateTime update_time { get; set; } = DateTime.Now;
+    }
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor