Explorar o código

分离coupon业务;
京东转链增加爬虫模式;
拆分coupon和parse的报表调用;

dodo hold %!s(int64=2) %!d(string=hai) anos
pai
achega
3a87e56542
Modificáronse 28 ficheiros con 1037 adicións e 245 borrados
  1. 183 0
      molilian.api/Controllers/admin/JdUnionController.cs
  2. 5 2
      molilian.api/Controllers/admin/ReportController.cs
  3. 14 14
      molilian.api/Controllers/admin/TaobaoController.cs
  4. 13 6
      molilian.api/Controllers/public/TaskController.cs
  5. 0 0
      molilian.api/Properties/PublishProfiles/https___ccr.ccs.tencentyun.com_shaobin.pubxml.user
  6. 16 2
      molilian.api/Properties/launchSettings.json
  7. 3 1
      molilian.api/molilian.api.csproj
  8. 10 0
      molilian.core/Core/CenterHub.cs
  9. 51 1
      molilian.core/Core/admin/ChartDataCore.cs
  10. 140 6
      molilian.core/Core/taoke/JdPoolCore.cs
  11. 15 3
      molilian.core/Core/taoke/OrderTrackingCore.cs
  12. 147 27
      molilian.core/Core/taoke/TkLogCore.cs
  13. 11 13
      molilian.core/Core/taoke/UnionCouponCore.cs
  14. 48 20
      molilian.core/Core/taoke/UnionParseCore.cs
  15. 3 0
      molilian.core/DTO/alimama/TkConfigDTO.cs
  16. 8 0
      molilian.core/DTO/alimama/TkPoolDTO.cs
  17. 13 1
      molilian.core/DTO/alimama/UnionCouponDTO.cs
  18. 25 2
      molilian.core/DTO/jd/JdPoolDTO.cs
  19. 23 6
      molilian.core/Plus/Alimama/coupon.cs
  20. 124 66
      molilian.core/Plus/Alimama/crawler.cs
  21. 1 1
      molilian.core/Plus/Alimama/orders.cs
  22. 2 1
      molilian.core/Plus/Alimama/parse.cs
  23. 12 31
      molilian.core/Plus/JDUnion/JdUnionPlus.cs
  24. 45 13
      molilian.core/Plus/JDUnion/base.cs
  25. 1 14
      molilian.core/Plus/JDUnion/coupon.cs
  26. 120 11
      molilian.core/Plus/JDUnion/goods.cs
  27. 3 3
      molilian.core/Plus/Tool/ToolDailyLogs.cs
  28. 1 1
      molilian.core/molilian.core.csproj

+ 183 - 0
molilian.api/Controllers/admin/JdUnionController.cs

@@ -0,0 +1,183 @@
+using molilian.core;
+using dodohold.core;
+using Microsoft.AspNetCore.Mvc;
+using System.Text.Json;
+using System.Net;
+using static QRCoder.PayloadGenerator;
+using MySqlX.XDevAPI;
+using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
+namespace molilian.api.Controllers
+{
+
+
+    [ApiController]
+    [MyAuthorize("admin")]
+    [Route("api/[controller]/[action]")]
+    [Route("coupon_api/[controller]/[action]")]
+    public class JdUnionController : ControllerBase
+    {
+        readonly IAuthorizationProvider provider = new AdminProvider();
+        protected IHttpContextAccessor _accessor;
+        public JdUnionController(IHttpContextAccessor accessor)
+        {
+            _accessor = accessor;
+        }
+
+        [HttpPost]
+        public async Task<ActionResult> updateCookies([FromBody] JsonElement form)
+        {
+            var clientIp = _accessor.HttpContext.GetUserIp();
+            var token = provider.Get(_accessor.HttpContext);
+            string user_agent = _accessor.HttpContext.Request.UserAgent();
+
+
+            string cookie = form.Read<string>("cookie", string.Empty);
+            var accountId = JdPoolCore.UpdateCookies(cookie, user_agent);
+            bool success = accountId > 0;
+            if (success)
+            {
+                //string desc = ObjectComparer.PrintCompareToString(old, form).Trim();
+                OperationLogCore.LogOperation(token.AccessKey, clientIp, $"tk_pool:{accountId}:cookie", string.Empty, cookie);
+            }
+            return new APIResult(new
+            {
+                data = new { success, msg = success ? "更新成功" : "更新失败,请检查输入的cookie" },
+            });
+        }
+
+        /// <summary>
+        /// 账号列表
+        /// </summary>
+        /// <param name="form"></param>
+        /// <returns></returns>
+        [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);
+            string keyword = form.Read("name", string.Empty);
+            bool getTotal = form.Read("getTotal", true);
+            string _status = form.Read("status", string.Empty);
+            int status = _status switch
+            {
+                "online" => 1,
+                "offline" => 0,
+                _ => -1,
+            };
+            var lastTime = form.PathReadArray<string>("lastTime[]");
+
+            string sort = form.Read<string>("sort");
+            string order = form.Read<string>("order");
+
+            string filter = string.Empty;
+            if (!string.IsNullOrEmpty(keyword))
+            {
+                filter += $" AND (`name` LIKE @keyword OR `description` LIKE @keyword)";
+                keyword = $"%{keyword}%";
+            }
+            DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
+            if (lastTime.Count == 2)
+            {
+                if (DateTime.TryParse(lastTime[0], out stime) && DateTime.TryParse(lastTime[1], out etime))
+                {
+                    etime = etime.AddDays(1).AddSeconds(-1);
+                    filter += $" AND last_time BETWEEN @stime AND @etime";
+                }
+            }
+            if (status != -1)
+            {
+                filter += $" AND status=@status";
+
+            }
+
+            filter = filter.StringTrimStart(" AND ");
+
+            //排序
+            string orderBy = "id DESC";
+            if (!string.IsNullOrEmpty(order))
+            {
+                order = "descending".Equals(order) ? "DESC" : "ASC";
+                orderBy = sort switch
+                {
+                    //"num" => $"num {order}",
+                    _ => $"{sort} {order}",
+                };
+            }
+
+            using var conn = DBContext.GetOpenConnection();
+            var result = new DBContext.Table(conn, "tk_pool")
+                .Where(filter, new { keyword, status, stime, etime })
+                .Page(size, page)
+                .Order(orderBy)
+                .PageList<TkPoolDTO>(getTotal);
+
+            foreach (var item in result.List)
+            {
+                item.current_amt = Math.Round(TkPoolCore.GetIncomeAmt($"{item.id}"), 2);
+                item.cookies = string.Empty;
+            }
+            return new APIResult(new { data = result });
+        }
+
+         
+        /*
+         {
+	"code": 420,
+	"message": "未登录",
+	"totalNum": 0
+}
+         */
+
+        [HttpPost]
+        public async Task<ActionResult> update([FromBody] JsonElement form)
+        {
+            var clientIp = _accessor.HttpContext.GetUserIp();
+            var token = provider.Get(_accessor.HttpContext);
+
+            int id = form.Read<int>("id", 0);
+            string name = form.Read<string>("name", string.Empty);
+            string val = form.Read<string>("val", string.Empty);
+
+            if (id == 0)
+            {
+                return new APIResult(new { data = new { success = false, msg = "更新失败,请检查输入的cookie" } });
+            }
+
+            int result;
+            switch (name)
+            {
+                case "enable_fake_click":
+                case "enable_parse":
+                case "enable_coupon":
+                case "enable_sync_order":
+                case "enable_promotionQuery":
+                case "status":
+                    bool bVal = val.Equals("True");
+                    result = new DBContext.Table("tk_pool")
+                           .Add(name, bVal)
+                           .Add("last_time", DateTime.Now)
+                           .Where("id=@id", new { id })
+                           .Update();
+                    break;
+                default:
+                    return new APIResult(new { data = new { success = false, msg = "更新失败,未授权操作" } });
+            }
+            bool success = result > 0;
+            if (success)
+            {
+                //string desc = ObjectComparer.PrintCompareToString(old, form).Trim();
+                OperationLogCore.LogOperation(token.AccessKey, clientIp, $"tk_pool:{id}:{name}", string.Empty, val);
+                await EndPointCore.NotifyReload(true);
+
+            }
+            return new APIResult(new
+            {
+                data = new { success, msg = success ? "更新成功" : "更新失败,请检查输入信息" },
+            });
+        }
+
+
+    }
+}

+ 5 - 2
molilian.api/Controllers/admin/ReportController.cs

@@ -70,8 +70,8 @@ namespace molilian.api.Controllers
                 };
             }
 
-            using var conn = DBContext.GetOpenConnection();
-            var result = new DBContext.Table(conn, "daily_logs")
+            using var conn = CenterHub.GetOpenConnection();
+            var result = new DBContext.Table(conn, "center_daily_logs")
                 .Where(filter, new { channel, accountName, stime, etime })
                 .Page(size, page)
                 .Order(orderBy)
@@ -111,6 +111,9 @@ namespace molilian.api.Controllers
                 case "coupon_total":
                     result = GetTaobaoData(total_key, accountName, _report_date);
                     break;
+                //case "coupon_total":
+                //    result = GetTaobaoCouponData(total_key, accountName, _report_date);
+                //    break;
                 case "jd_parse_total":
                     result = GetJdData(total_key, accountName, _report_date);
 

+ 14 - 14
molilian.api/Controllers/admin/TaobaoController.cs

@@ -256,11 +256,11 @@ namespace molilian.api.Controllers
 
                 if (item.coupon_total_count == 0)
                 {
-                    item.coupon_total_count = TkLogCore.GetTotal($":coupon_total:tb:{item.report_date:yyyyMMdd}");
+                    item.coupon_total_count = TkLogCore.GetTotal($":coupon_total:tb:{item.report_date:yyyyMMdd}", false);
                     if (item.coupon_total_count > 0)
                     {
-                        item.coupon_success_count = TkLogCore.GetTotal($":coupon_total:tb:success:{item.report_date:yyyyMMdd}");
-                        item.coupon_abandon_count = TkLogCore.GetTotal($":coupon_total:tb:放弃转链:{item.report_date:yyyyMMdd}");
+                        item.coupon_success_count = TkLogCore.GetTotal($":coupon_total:tb:success:{item.report_date:yyyyMMdd}", false);
+                        item.coupon_abandon_count = TkLogCore.GetTotal($":coupon_total:tb:放弃转链:{item.report_date:yyyyMMdd}", false);
                         if (item.coupon_total_count > 0)
                         {
                             item.coupon_success_percentage = $"{item.coupon_success_count / (double)item.coupon_total_count * 100:f2}%";
@@ -394,11 +394,11 @@ namespace molilian.api.Controllers
 
                 if (item.coupon_total_count == 0)
                 {
-                    item.coupon_total_count = TkLogCore.GetTotal($":coupon_total:{accountName}:{item.report_date:yyyyMMdd}");
+                    item.coupon_total_count = TkLogCore.GetTotal($":coupon_total:{accountName}:{item.report_date:yyyyMMdd}", false);
                     if (item.coupon_total_count > 0)
                     {
-                        item.coupon_success_count = TkLogCore.GetTotal($":coupon_total:{accountName}:success:{item.report_date:yyyyMMdd}");
-                        item.coupon_abandon_count = TkLogCore.GetTotal($":coupon_total:{accountName}:放弃转链:{item.report_date:yyyyMMdd}");
+                        item.coupon_success_count = TkLogCore.GetTotal($":coupon_total:{accountName}:success:{item.report_date:yyyyMMdd}", false);
+                        item.coupon_abandon_count = TkLogCore.GetTotal($":coupon_total:{accountName}:放弃转链:{item.report_date:yyyyMMdd}", false);
                         if (item.coupon_total_count > 0)
                         {
                             item.coupon_success_percentage = $"{item.coupon_success_count / (double)item.coupon_total_count * 100:f2}%";
@@ -518,11 +518,11 @@ namespace molilian.api.Controllers
 
                 if (item.coupon_total_count == 0)
                 {
-                    item.coupon_total_count = TkLogCore.GetTotal($":coupon_total:{accountName}:{item.report_date:yyyyMMddHH}");
+                    item.coupon_total_count = TkLogCore.GetTotal($":coupon_total:{accountName}:{item.report_date:yyyyMMddHH}", false);
                     if (item.coupon_total_count > 0)
                     {
-                        item.coupon_success_count = TkLogCore.GetTotal($":coupon_total:{item.accountName}:success:{item.report_date:yyyyMMddHH}");
-                        item.coupon_abandon_count = TkLogCore.GetTotal($":coupon_total:{item.accountName}:放弃转链:{item.report_date:yyyyMMddHH}");
+                        item.coupon_success_count = TkLogCore.GetTotal($":coupon_total:{item.accountName}:success:{item.report_date:yyyyMMddHH}", false);
+                        item.coupon_abandon_count = TkLogCore.GetTotal($":coupon_total:{item.accountName}:放弃转链:{item.report_date:yyyyMMddHH}", false);
                         if (item.coupon_total_count > 0)
                         {
                             item.coupon_success_percentage = $"{item.coupon_success_count / (double)item.coupon_total_count * 100:f2}%";
@@ -617,13 +617,13 @@ namespace molilian.api.Controllers
             else
             {
                 string cacheKey = $":{total_key}:{accountName}:{_report_date}";
-                double total = TkLogCore.GetTotal(cacheKey);
+                double total = TkLogCore.GetTotal(cacheKey, false);
                 if (total > 0)
                 {
                     string[] keys = ["success"];
 
                     cacheKey = $":{total_key}:{accountName}:message:{_report_date}";
-                    string[] message_keys = TkLogCore.GetTotalKeys(cacheKey);
+                    string[] message_keys = TkLogCore.GetTotalKeys(cacheKey, false);
 
                     var combinedKeys = keys.Union(message_keys).ToList();
                     combinedKeys.RemoveAll(item => item == "fail");
@@ -631,19 +631,19 @@ namespace molilian.api.Controllers
                     foreach (var keyname in combinedKeys)
                     {
                         cacheKey = $":{total_key}:{accountName}:{keyname}:{_report_date}";
-                        int value = TkLogCore.GetTotal(cacheKey);
+                        int value = TkLogCore.GetTotal(cacheKey, false);
                         if (value == 0) continue;
                         result.Add(new { name = keyname, value, increases = Math.Round(value / total * 100, 2) });
                     }
                     result = result.OrderByDescending(item => item.value).ToList();
 
                     cacheKey = $":{total_key}:{accountName}:reason:{_report_date}";
-                    string[] reason_keys = TkLogCore.GetTotalKeys(cacheKey);
+                    string[] reason_keys = TkLogCore.GetTotalKeys(cacheKey, false);
 
                     foreach (var keyname in reason_keys)
                     {
                         cacheKey = $":{total_key}:{accountName}:{keyname}:{_report_date}";
-                        int value = TkLogCore.GetTotal(cacheKey);
+                        int value = TkLogCore.GetTotal(cacheKey, false);
                         if (value < 50) continue;
                         reason_result.Add(new { name = keyname, value, increases = Math.Round(value / total * 100, 2) });
                     }

+ 13 - 6
molilian.api/Controllers/public/TaskController.cs

@@ -247,19 +247,25 @@ namespace molilian.api.Controllers
         {
             try
             {
-                //第三方老的统计
-                AlimamaPlus.DailyLogs(intervalDay);
 
                 //第三方老的统计
                 JdUnionPlus.DailyLogs(intervalDay);
-
                 ToolParsePlus.DailyLogs(intervalDay);
 
 
-                //产商统计
-                AlimamaPlus.DailyLogs(intervalDay, "parse_", "tb");
-                AlimamaPlus.DailyLogs(intervalDay, "coupon_", "tb");
 
+                //本节点统计
+                AlimamaPlus.NodeDailyLogs(intervalDay, "parse_", "tb");
+                AlimamaPlus.NodeDailyLogs(intervalDay, "coupon_", "tb");
+                AlimamaPlus.NodeDailyLogs(intervalDay); //第三方老的统计
+
+                if (CenterHub.IsCenter)
+                {
+                    //中心服务器统计
+                    AlimamaPlus.AllDailyLogs(intervalDay, "parse_", "tb");
+                    AlimamaPlus.AllDailyLogs(intervalDay, "coupon_", "tb");
+                    AlimamaPlus.AllDailyLogs(intervalDay);
+                }
             }
             catch (Exception ex)
             {
@@ -490,6 +496,7 @@ namespace molilian.api.Controllers
             ProxyNodesCore.Refresh();
             TkPoolCore.Refresh();
             VeapiPoolCore.Refresh();
+            JdPoolCore.Refresh();
 
             return new APIResult(new
             {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
molilian.api/Properties/PublishProfiles/https___ccr.ccs.tencentyun.com_shaobin.pubxml.user


+ 16 - 2
molilian.api/Properties/launchSettings.json

@@ -6,12 +6,26 @@
       "launchUrl": "swagger",
       "environmentVariables": {
         "ASPNETCORE_ENVIRONMENT": "Development",
-        "EndPoint": "gz",
+        "EndPoint": "admin",
         "NtfyServer": "https://ntfy.yunhui800.com/5Sq9BytXXM5WDY3G",
         "ANPush": "",
         "DBType": "MySQL",
         "DBConfig": "Server=rm-2zey1jqxnoqy9mcc0zo.rwlb.rds.aliyuncs.com; Port=3306; Database=taoke; Uid=taoke; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60",
-        "RedisConfig": "101.200.46.46:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook"
+        "RedisConfig": "101.200.46.46:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook",
+        "CenterDB": "",
+        "CenterRedis": "",
+      },
+      "environmentVariables2": {
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "EndPoint": "cadmin",
+        "NtfyServer": "https://ntfy.yunhui800.com/5Sq9BytXXM5WDY3G",
+        "ANPush": "",
+        "DBType": "MySQL",
+        "DBConfig": "Server=rm-2ze74506m3gfsqe7mco.rwlb.rds.aliyuncs.com; Port=3306; Database=coupon; Uid=coupon; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60;",
+        "RedisConfig": "8.140.49.136:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=coupon",
+        "CenterDB": "Server=rm-2zey1jqxnoqy9mcc0zo.rwlb.rds.aliyuncs.com; Port=3306; Database=taoke; Uid=taoke; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60",
+        "CenterRedis": "101.200.46.46:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook"
+
       },
       "dotnetRunMessages": true,
       "applicationUrl": "http://localhost:8186"

+ 3 - 1
molilian.api/molilian.api.csproj

@@ -8,8 +8,10 @@
     <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
   </PropertyGroup>
 
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'" />
+
   <ItemGroup>
-    <PackageReference Include="dodohold.core" Version="1.0.1.13" />
+    <PackageReference Include="dodohold.core" Version="1.0.1.14" />
     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.0-Preview.1" />
     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
   </ItemGroup>

+ 10 - 0
molilian.core/Core/CenterHub.cs

@@ -9,15 +9,21 @@ namespace molilian.core
     public partial class CenterHub
     {
         private static CSRedisClient _redis;
+        private static bool _is_center = true;
+        private static string _centerDB;
+        public static bool IsCenter { get => _is_center; }
         static CenterHub()
         {
             string centerRedis = Environment.GetEnvironmentVariable("CenterRedis");
+            string centerDB = Environment.GetEnvironmentVariable("CenterDB");
             if (string.IsNullOrEmpty(centerRedis))
             {
+                _is_center = true;
                 _redis = RedisHelper.Instance;
             }
             else
             {
+                _is_center = false;
                 _redis = RedisClientManager.GetRedisClient(centerRedis);
             }
         }
@@ -26,6 +32,10 @@ namespace molilian.core
 
         public static IDbConnection GetOpenConnection()
         {
+            if (_is_center)
+            {
+                return DBContext.GetOpenConnection();
+            }
             return DBContext.GetOpenConnection("CenterDB");
         }
     }

+ 51 - 1
molilian.core/Core/admin/ChartDataCore.cs

@@ -113,7 +113,7 @@ namespace molilian.core
                 {
                     cacheKey = $":{total_key}:{accountName}:{keyname}:{report_date}";
                     int value = TkLogCore.GetTotal(cacheKey);
-                    if (value < 50) continue;
+                    //if (value < 50) continue;
                     result.data2.Add(new ChartDataItem
                     {
                         name = keyname,
@@ -126,6 +126,56 @@ namespace molilian.core
             return result;
         }
 
+        public static ChartDataRes GetTaobaoCouponData(string total_key, string accountName, string report_date)
+        {
+            ChartDataRes result = new();
+            if (string.IsNullOrEmpty(accountName) || "all".Equals(accountName)) accountName = "tb";
+            string cacheKey = $":{total_key}:{accountName}:{report_date}";
+            result.total = TkLogCore.GetTotal(cacheKey, false);
+            if (result.total > 0)
+            {
+                string[] keys = ["success"];
+
+                cacheKey = $":{total_key}:{accountName}:message:{report_date}";
+                string[] message_keys = TkLogCore.GetTotalKeys(cacheKey, false);
+
+                var combinedKeys = keys.Union(message_keys).ToList();
+                combinedKeys.RemoveAll(item => item == "fail");
+                combinedKeys.RemoveAll(item => item == "OK");
+
+                foreach (var keyname in combinedKeys)
+                {
+                    cacheKey = $":{total_key}:{accountName}:{keyname}:{report_date}";
+                    int value = TkLogCore.GetTotal(cacheKey, false);
+                    if (value == 0) continue;
+                    result.data.Add(new ChartDataItem
+                    {
+                        name = keyname,
+                        value = value,
+                        increases = Math.Round((decimal)value / result.total * 100, 2)
+                    });
+                }
+                result.data = result.data.OrderByDescending(item => item.value).ToList();
+
+                cacheKey = $":{total_key}:{accountName}:reason:{report_date}";
+                string[] reason_keys = TkLogCore.GetTotalKeys(cacheKey, false);
+
+                foreach (var keyname in reason_keys)
+                {
+                    cacheKey = $":{total_key}:{accountName}:{keyname}:{report_date}";
+                    int value = TkLogCore.GetTotal(cacheKey, false);
+                    if (value < 50) continue;
+                    result.data2.Add(new ChartDataItem
+                    {
+                        name = keyname,
+                        value = value,
+                        increases = Math.Round((decimal)value / result.total * 100, 2)
+                    });
+                }
+                result.data2 = result.data2.OrderByDescending(item => item.value).ToList();
+            }
+            return result;
+        }
 
         public static ChartDataRes GetToolData(string total_key, string accountName, string report_date)
         {

+ 140 - 6
molilian.core/Core/taoke/JdPoolCore.cs

@@ -7,12 +7,27 @@ using System.Linq;
 using System.Text;
 using dodohold.core;
 using Dataoke;
+using static molilian.core.TkPoolCore;
 
 
 namespace molilian.core
 {
+
     public partial class JdPoolCore
     {
+        public enum JdAction
+        {
+            all,
+            parse,
+            coupon,
+            promotionQuery
+        }
+        private static string _end_point;
+        static JdPoolCore()
+        {
+            _end_point = Environment.GetEnvironmentVariable("EndPoint");
+        }
+
         private static readonly object _lockObj = new();
         private static IEnumerable<JdPoolDTO> _cached;
         public static JdPoolDTO? GetOne()
@@ -22,6 +37,44 @@ namespace molilian.core
             return list.OrderBy(l => Guid.NewGuid()).FirstOrDefault();
         }
 
+        public static JdPoolDTO? GetOne(JdAction action)
+        {
+            var list = List();
+            if (!list.Any()) return null;
+            return list.Where(e => IsNotExceedDailyIncomeLimit(e, action)).OrderBy(l => Guid.NewGuid()).FirstOrDefault();
+        }
+
+
+        public static JdPoolDTO? GetOne(int id)
+        {
+            var list = List();
+            if (!list.Any()) return null;
+            return list.Where(e => e.id == id).FirstOrDefault();
+        }
+        private static bool IsNotExceedDailyIncomeLimit(JdPoolDTO item, JdAction action)
+        {
+            if (!string.IsNullOrEmpty(_end_point) && !string.IsNullOrEmpty(item.end_point))
+            {
+                if (item.end_point != _end_point) return false;
+            }
+            switch (action)
+            {
+                case JdAction.parse:
+                    if (!item.enable_parse) return false;
+                    break;
+                case JdAction.coupon:
+                    if (!item.enable_coupon) return false;
+                    break;
+            }
+            return true;
+
+            //if (item.daily_income_limit == 0) return true;
+            //decimal income_amt = GetIncomeAmt($"{item.id}");
+            //return income_amt < item.daily_income_limit;
+        }
+
+
+
         public static IEnumerable<JdPoolDTO> List(bool force = false)
         {
             if (!force && _cached != null) return _cached;
@@ -47,28 +100,109 @@ namespace molilian.core
             _ = List(true);
         }
 
-        public static void Disabled(string name)
+
+        public static int UpdateCookies(string cookies, string user_agent)
+        {
+            if (string.IsNullOrEmpty(cookies)) return 0;
+            cookies += ";";
+            string pin = cookies.GetContentPart("pin=", ";");
+            pin = pin.UrlDecode();
+
+            string company = pin;
+            int accountId = 0;
+            if (string.IsNullOrEmpty(pin)) return 0;
+            var exist = new DBContext.Table("jd_pool").Get<JdPoolDTO>("pin=@pin", new { pin });
+            if (exist != null)
+            {
+                var status = exist.status;
+                var work_mode = exist.work_mode;
+                accountId = exist.id;
+                if (work_mode == JdUnionWorkMode.Crawler) status = true;
+                new DBContext.Table("jd_pool")
+                   .Add("pin", pin)
+                   .Add("cookies", cookies)
+                   .Add("user_agent", user_agent)
+                   .Add("status", status)
+                   .Add("last_time", DateTime.Now)
+                   .Add("login_time", DateTime.Now)
+                   .Where("id=@id", new { exist.id })
+                   .Update();
+                if (status) _ = List(true);
+            }
+            else
+            {
+                accountId = new DBContext.Table("jd_pool")
+                    .Add("pin", pin)
+                    .Add("name", pin)
+                    .Add("company", pin)
+                    .Add("description", "由cookies上报创建此记录")
+                    .Add("cookies", cookies)
+                    .Add("user_agent", user_agent)
+                    .Add("create_time", DateTime.Now)
+                    .Add("last_time", DateTime.Now)
+                    .Add("login_time", DateTime.Now)
+                    .Add("status", 0)
+                    .Create();
+            }
+
+            NotifyCore.Notify(new NifyMessage
+            {
+                message = $"【京东{accountId}:{company}】cookie 上线",
+                tags = ["green_circle"]
+            });
+            EndPointCore.NotifyReload(true);
+            //NotifyCore.AnPushNotify("上线", $"【淘宝联盟:{dnk}】cookie 上报更新");
+            return accountId;
+        }
+
+
+        public static void Disabled(int accountId, string name, string content)
         {
             string cache_key = $"cache:jd_pool:{name}:disabled";
             long count = RedisHelper.IncrBy(cache_key);
             RedisHelper.Expire(cache_key, 10);
             if (count > 1) return;
 
-            new DBContext.Table("jd_pool")
-                .Add("status", 0)
-                .Where("name=@name", new { name })
-                .Update();
+            var update = new DBContext.Table("jd_pool").Add("status", 0);
+            if (accountId > 0)
+            {
+                update.Where("id=@accountId", new { accountId }).Update();
+            }
+            else
+            {
+                update.Where("name=@name", new { name }).Update();
+            }
+
             _ = List(true);
 
             NotifyCore.Notify(new NifyMessage
             {
-                message = $"【京东账号:{name}】禁用",
+                message = $"【京东联盟{accountId}:{name}】cookie 掉线\n\n{content}",
                 priority = NifyMessagePriority.high,
                 tags = ["red_circle"]
             });
+
+            NotifyCore.AnPushNotify("掉线", $"【京东{accountId}:{name}】cookie 掉线");
+            EndPointCore.NotifyReload(true);
         }
 
 
+
+        internal static void AccountExhausted()
+        {
+            string cache_key = $"cache:tk_pool:account:exhausted";
+            long count = RedisHelper.IncrBy(cache_key);
+            if (count > 1) return;
+            RedisHelper.Expire(cache_key, 3600);
+            NotifyCore.Notify(new NifyMessage
+            {
+                message = $"【京东联盟】没有匹配账号",
+                priority = NifyMessagePriority.high,
+                tags = ["red_circle"]
+            });
+            NotifyCore.AnPushNotify("没账号", $"【京东联盟】没有匹配账号");
+        }
+
     }
 
 

+ 15 - 3
molilian.core/Core/taoke/OrderTrackingCore.cs

@@ -89,7 +89,7 @@ namespace molilian.core
             });
         }
 
-        public static bool MatchOrder(TkOrderDetailDTO item, IDbConnection conn)
+        public static bool MatchOrder(TkPoolDTO account, TkOrderDetailDTO item, IDbConnection conn)
         {
             if (item.tbPaidTime < DateTime.Now.AddDays(-1)) return false;
 
@@ -110,6 +110,18 @@ namespace molilian.core
 
             string accountName = item.accountName;
 
+            string shortLinkUrl = summary.shortLinkurl;
+            string deeplinkUrl = summary.deeplink_url;
+            switch (account.fake_click_link_type)
+            {
+                case FakeClickLinkType.Deeplink:
+                    shortLinkUrl = string.Empty;
+                    break;
+                case FakeClickLinkType.H5:
+                    deeplinkUrl = string.Empty;
+                    break;
+            }
+
             DateTime expTime = item.tbPaidTime.Hour >= 21 ? item.tbPaidTime.AddHours(3) : item.tbPaidTime.Date.AddDays(1);
             var data = new TkOrderTrackingDTO()
             {
@@ -122,8 +134,8 @@ namespace molilian.core
                 itemId = summary.itemId,
                 itemName = summary.itemName,
                 taoToken = summary.taoToken,
-                shortLinkUrl = summary.shortLinkurl,
-                deeplinkUrl = summary.deeplink_url,
+                shortLinkUrl = shortLinkUrl,
+                deeplinkUrl = deeplinkUrl,
 
                 tradeId = item.tradeId,
                 tradeParentId = item.tradeParentId,

+ 147 - 27
molilian.core/Core/taoke/TkLogCore.cs

@@ -40,6 +40,16 @@ namespace molilian.core
             var result = EndPointCore.ProcessEndPointNodes<int>(node =>
             {
                 if (!node.is_public_api) return 0;
+
+                if (CenterHub.IsCenter)
+                {
+                    if (node.is_coupon_api) return 0;
+                }
+                else
+                {
+                    if (!node.is_coupon_api) return 0;
+                }
+
                 if (string.IsNullOrEmpty(node.redis_server)) return 0;
 
                 var redis = RedisClientManager.GetRedisClient(node.redis_server);
@@ -107,7 +117,33 @@ namespace molilian.core
                 .Add("create_time", data.create_time)
                 .Create(DBContext.InsertType.NORMAL, transaction);
         }
-
+        private static int save_jd_parse_logs(JdDataDTO data, string tablename, IDbConnection connection, IDbTransaction transaction)
+        {
+            return new DBContext.Table(connection, tablename)
+                .Add("end_point", data.end_point)
+                .Add("channel", (int)data.channel)
+                .Add("accountId", data.accountId)
+                .Add("accountName", data.accountName)
+                .Add("rawContent", data.rawContent)
+                .Add("success", data.success)
+                .Add("message", data.message)
+                .Add("reason", data.reason)
+                .Add("content", data.content)
+                .Add("itemId", data.itemId)
+                .Add("itemName", data.itemName)
+                .Add("pic", data.pic)
+                .Add("couponAmount", data.couponAmount)
+                .Add("promotionPrice", data.promotionPrice)
+                .Add("taoToken", data.taoToken)
+                .Add("shortLinkurl", data.shortLinkurl)
+                .Add("deeplink_url", data.deeplink_url)
+                .Add("elapsedTime", data.elapsedTime)
+                .Add("subCode", data.subCode)
+                .Add("ip", data.ip)
+                .Add("oaid", data.oaid)
+                .Add("create_time", data.create_time)
+                .Create(DBContext.InsertType.NORMAL, transaction);
+        }
         public static int BatchInsertLogDB(int limit, CSRedisClient redis)
         {
             int total = 0;
@@ -127,7 +163,7 @@ namespace molilian.core
                     var data = redis.LPop<TkDataDTO>(queue_tb_key);
                     if (data == null) break;
                     if ("3JDaxNfPy83okP3kLScwCkGiuMcyC4PcyntF424979CC9C51BCAD0C245B1C7BA2".Equals(data.oaid) ||
-                        "127.0.0.1".Equals(data.ip) || data.elapsedTime > 1000)
+                         data.ip.Contains("127.0.0") || data.elapsedTime > 1000)
                     {
                         save_tk_log(data, "tk_logs_test", connection, transaction);
                     }
@@ -193,7 +229,7 @@ namespace molilian.core
                     //}
 
                     if ("3JDaxNfPy83okP3kLScwCkGiuMcyC4PcyntF424979CC9C51BCAD0C245B1C7BA2".Equals(data.oaid) ||
-                        "127.0.0.1".Equals(data.ip) || data.elapsedTime > 1000)
+                          data.ip.Contains("127.0.0") || data.elapsedTime > 1000)
                     {
                         save_tk_parse_logs(data, "tk_parse_logs_test", connection, transaction);
 
@@ -229,30 +265,21 @@ namespace molilian.core
                 {
                     var data = redis.LPop<JdDataDTO>(queue_parse_jd_key);
                     if (data == null) break;
-                    new DBContext.Table(connection, "jd_parse_logs")
-                        .Add("end_point", data.end_point)
-                        .Add("channel", (int)data.channel)
-                        .Add("accountId", data.accountId)
-                        .Add("accountName", data.accountName)
-                        .Add("rawContent", data.rawContent)
-                        .Add("success", data.success)
-                        .Add("message", data.message)
-                        .Add("reason", data.reason)
-                        .Add("content", data.content)
-                        .Add("itemId", data.itemId)
-                        .Add("itemName", data.itemName)
-                        .Add("pic", data.pic)
-                        .Add("couponAmount", data.couponAmount)
-                        .Add("promotionPrice", data.promotionPrice)
-                        .Add("taoToken", data.taoToken)
-                        .Add("shortLinkurl", data.shortLinkurl)
-                        .Add("deeplink_url", data.deeplink_url)
-                        .Add("elapsedTime", data.elapsedTime)
-                        .Add("subCode", data.subCode)
-                        .Add("ip", data.ip)
-                        .Add("oaid", data.oaid)
-                        .Add("create_time", data.create_time)
-                        .Create(DBContext.InsertType.NORMAL, transaction);
+
+                    save_jd_parse_logs(data, "jd_parse_logs", connection, transaction);
+
+                    if ("3JDaxNfPy83okP3kLScwCkGiuMcyC4PcyntF424979CC9C51BCAD0C245B1C7BA2".Equals(data.oaid) ||
+                       data.ip.Contains("127.0.0") || data.elapsedTime > 1000)
+                    {
+                        save_jd_parse_logs(data, "jd_parse_logs_test", connection, transaction);
+                    }
+                    else
+                    {
+                        if (data.success)
+                        {
+                            save_jd_parse_logs(data, "jd_parse_logs_success", connection, transaction);
+                        }
+                    }
                     total++;
                 }
                 for (int i = 0; i < limit; i++)
@@ -314,6 +341,21 @@ namespace molilian.core
                     var data = redis.LPop<UnionCouponDTO>(queue_coupon_key);
                     if (data == null) break;
                     connection.Insert(data);
+
+                    if ("3JDaxNfPy83okP3kLScwCkGiuMcyC4PcyntF424979CC9C51BCAD0C245B1C7BA2".Equals(data.oaid) ||
+                        data.ip.Contains("127.0.0") || data.elapsedTime > 1000)
+                    {
+                        var test_data = data.Convert2Json().Convert2Object<TestUnionCouponDTO>();
+                        connection.Insert(test_data);
+                    }
+                    else
+                    {
+                        if (data.success)
+                        {
+                            var success_data = data.Convert2Json().Convert2Object<SuccessUnionCouponDTO>();
+                            connection.Insert(success_data);
+                        }
+                    }
                     total++;
                 }
 
@@ -507,6 +549,34 @@ namespace molilian.core
                 _ = RedisHelper.RPushAsync(queue_parse_jd_key, response);
                 saveParseCache(response.channel.ToString(), response.accountId, response.accountName, response.success, response.message, response.reason);
 
+                if (response.success) saveClientRequestTotal(response.channel, response.ip, response.oaid);
+
+                if (!response.success && ("nologin".Equals(response.reason) || "未登录".Equals(response.reason)))
+                {
+                    await Task.Run(() =>
+                    {
+                        JdPoolCore.Disabled(response.accountId, response.accountName, $"{response.rawContent}\n{response.rawContent2}");
+                    });
+                    //switch (response.channel)
+                    //{
+                    //    case TkChannelEnum.tb:
+
+                    //        //await Task.Run(() =>
+                    //        //{
+                    //        //    if (alimamaPlus != null)
+                    //        //    {
+                    //        //        (bool success, string message) = alimamaPlus.RenewCookie();
+                    //        //        if (success) return;
+                    //        //    }
+                    //        //    TkPoolCore.Disabled(response.accountId, response.accountName, $"{response.rawContent}\n{response.rawContent2}");
+                    //        //});
+                    //        break;
+                    //}
+                }
+                if ("没有匹配账号".Equals(response.reason))
+                {
+                    JdPoolCore.AccountExhausted();
+                }
             }
             catch (Exception ex) { }
         }
@@ -596,6 +666,31 @@ namespace molilian.core
                 return Task.CompletedTask;
             });
         }
+        private static void saveClientRequestTotal(TkChannelEnum channel, string ip, string oaid)
+        {
+            string cacheKey = $":cache:{channel}:ip:{DateTime.Now:yyyyMMdd}:{ip}";
+            RedisHelper.IncrBy(cacheKey);
+            RedisHelper.Expire(cacheKey, 86400);
+
+            if (!string.IsNullOrEmpty(oaid))
+            {
+                cacheKey = $":cache:{channel}:oaid:{DateTime.Now:yyyyMMdd}:{oaid}";
+                RedisHelper.IncrBy(cacheKey);
+                RedisHelper.Expire(cacheKey, 86400);
+            }
+        }
+        public static int getClientRequestTotalByOAID(TkChannelEnum channel, string oaid)
+        {
+            if (string.IsNullOrEmpty(oaid)) return 0;
+            string cacheKey = $":cache:{channel}:oaid:{DateTime.Now:yyyyMMdd}:{oaid}";
+            return RedisHelper.Get<int>(cacheKey);
+        }
+        public static int getClientRequestTotalByIp(TkChannelEnum channel, string ip)
+        {
+            if (string.IsNullOrEmpty(ip)) return 0;
+            string cacheKey = $":cache:{channel}:ip:{DateTime.Now:yyyyMMdd}:{ip}";
+            return RedisHelper.Get<int>(cacheKey);
+        }
 
         private static void saveParseCache(string channel, int accountId, string accountName, bool success, string message, string reason)
         {
@@ -745,6 +840,19 @@ namespace molilian.core
             {
                 if (!node.is_public_api) return 0;
                 if (string.IsNullOrEmpty(node.redis_server)) return 0;
+
+                if (!all_node)
+                {
+                    if (CenterHub.IsCenter)
+                    {
+                        if (node.is_coupon_api) { return 0; }
+                    }
+                    else
+                    {
+                        if (!node.is_coupon_api) { return 0; }
+                    }
+                }
+
 #if DEBUG
                 switch (node.name)
                 {
@@ -776,6 +884,18 @@ namespace molilian.core
             {
                 if (!node.is_public_api) return [];
                 if (string.IsNullOrEmpty(node.redis_server)) return [];
+
+                if (!all_node)
+                {
+                    if (CenterHub.IsCenter)
+                    {
+                        if (node.is_coupon_api) { return []; }
+                    }
+                    else
+                    {
+                        if (!node.is_coupon_api) { return []; }
+                    }
+                }
 #if DEBUG
                 switch (node.name)
                 {

+ 11 - 13
molilian.core/Core/taoke/UnionCouponCore.cs

@@ -89,13 +89,6 @@ namespace molilian.core
                 result.accountName = account.name;
                 alimama = new AlimamaPlus(account);
                 result = await alimama.UnionCoupon2Async(content, result);
-
-                if (result.success && result.couponAmount == 0)
-                {
-                    result.success = false;
-                    result.message = "没有优惠券";
-                    result.reason = "没有优惠券";
-                }
             }
             catch (Exception ex)
             {
@@ -162,7 +155,8 @@ namespace molilian.core
 
             try
             {
-                if (JdUnionPlus.ShouldIgnoreRequest(ip, oaid, out string reason))
+                var config = TkConfigCore.Get();
+                if (JdUnionPlus.ShouldIgnoreRequest(config, ip, oaid, out string reason))
                 {
                     result.success = false;
                     result.message = "放弃转链";
@@ -171,7 +165,8 @@ namespace molilian.core
                     return new APIResult(new
                     {
                         result.success,
-                        message = "没有优惠券",
+                        result.reason,
+                        result.message,
                         channel = result.channel.ToString(),
                     });
                 }
@@ -187,7 +182,8 @@ namespace molilian.core
                     return new APIResult(new
                     {
                         result.success,
-                        message = "没有优惠券",
+                        result.reason,
+                        result.message,
                         channel = result.channel.ToString(),
                     });
                 }
@@ -202,7 +198,8 @@ namespace molilian.core
                     return new APIResult(new
                     {
                         result.success,
-                        message = "没有优惠券",
+                        result.reason,
+                        result.message,
                         channel = result.channel.ToString(),
                     });
                 }
@@ -210,7 +207,7 @@ namespace molilian.core
                 if (result.success && result.couponAmount == 0)
                 {
                     result.success = false;
-                    result.message = "没有优惠券";
+                    result.message = "放弃转链";
                     result.reason = "没有优惠券";
                 }
             }
@@ -246,7 +243,8 @@ namespace molilian.core
                 return new APIResult(new
                 {
                     result.success,
-                    message = "没有优惠券",
+                    result.reason,
+                    result.message,
                     channel = result?.channel.ToString(),
                 });
             }

+ 48 - 20
molilian.core/Core/taoke/UnionParseCore.cs

@@ -20,6 +20,7 @@ using System.Threading;
 using TencentCloud.Soe.V20180724.Models;
 using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
 using System.Runtime.Intrinsics.Arm;
+using ZstdSharp.Unsafe;
 
 
 namespace molilian.core
@@ -34,7 +35,7 @@ namespace molilian.core
             {
                 "wemeet" => await WemeetParseAsync(content, ip, oaid),
                 "bdpan" => PanParse(content, ip, oaid),
-                "jd" => await JdParseAsync(content, ip, oaid),
+                "jd" => await JdParseAsync(content, ip, oaid, accountid),
                 "dy" => await DyParseAsync(content, ip, oaid),
                 _ => await TaobaoParseAsync(content, ip, oaid, accountid),
             };
@@ -425,7 +426,24 @@ namespace molilian.core
             });
         }
 
-        public static async Task<APIResult> JdParseAsync(string content, string ip, string oaid, CancellationToken cancellationToken = default)
+        private static APIResult JdParseOutput(JdDataDTO result, APIResultCodeEnum code = APIResultCodeEnum.OK)
+        {
+            return new APIResult(new
+            {
+                result.success,
+                result.message,
+                link_type = result.link_type.ToString(),
+                channel = result?.channel.ToString(),
+                result.channel_type,
+                result.itemId,
+                result.itemName,
+                result.shortLinkurl,
+                result.deeplink_url,
+            }, code);
+        }
+
+        public static async Task<APIResult> JdParseAsync(string content, string ip, string oaid,
+            int accountid = 0, CancellationToken cancellationToken = default)
         {
             var result = JdUnionPlus.GetFormattedObject(content, ip, oaid);
             content = content.UrlDecode();
@@ -433,26 +451,46 @@ namespace molilian.core
             bool IfExceptional = false;
             try
             {
-                if (JdUnionPlus.ShouldIgnoreRequest(ip, oaid, out string reason))
+                var config = TkConfigCore.Get();
+
+                if (accountid == 0 && JdUnionPlus.ShouldIgnoreRequest(config,ip, oaid, out string reason))
                 {
                     result.success = false;
                     result.message = "放弃转链";
                     result.reason = reason;
                     _ = TkLogCore.ParseLogAsync(result);
-                    return new APIResult(result);
+                    return JdParseOutput(result);
+                }
+
+                //============================== 放弃转链-地区过滤 ==============================
+                bool is_ignore2 = JdUnionPlus.FlowControlIgnoreRequest(config, out reason);
+#if DEBUG
+                is_ignore2 = false;
+#endif
+                if (accountid == 0 && is_ignore2)
+                {
+                    result.success = false;
+                    result.message = "放弃转链";
+                    result.reason = reason;
+                    _ = TkLogCore.ParseLogAsync(result);
+                    return JdParseOutput(result);
                 }
 
-                var account = JdPoolCore.GetOne();
+                var account = accountid > 0 ? JdPoolCore.GetOne(accountid) : JdPoolCore.GetOne(JdPoolCore.JdAction.parse);
                 if (account == null)
                 {
                     result.success = false;
                     result.message = "放弃转链";
                     result.reason = "没有匹配账号";
                     _ = TkLogCore.ParseLogAsync(result);
-                    return new APIResult(result);
+                    return JdParseOutput(result);
                 }
-                 
-                result = await JdUnionPlus.JdParseAsync(account, content, result, cancellationToken);
+                result.accountId = account.id;
+                result.accountName = account.name;
+
+                var plus = new JdUnionPlus(account);
+
+                result = await plus.JdParseAsync(content, result, cancellationToken);
             }
             catch (Exception ex)
             {
@@ -482,18 +520,8 @@ namespace molilian.core
                 }
             }
             _ = TkLogCore.ParseLogAsync(result);
-            return new APIResult(new
-            {
-                result.success,
-                result.message,
-                link_type = result.link_type.ToString(),
-                channel = result?.channel.ToString(),
-                result.channel_type,
-                result.itemId,
-                result.itemName,
-                result.shortLinkurl,
-                result.deeplink_url,
-            }, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
+            return JdParseOutput(result, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
+
         }
 
         public static async Task<APIResult> DyParseAsync(string content, string ip, string oaid, CancellationToken cancellationToken = default)

+ 3 - 0
molilian.core/DTO/alimama/TkConfigDTO.cs

@@ -25,5 +25,8 @@ namespace molilian.core
         public string tk_whitelist_regular { get; set; } = string.Empty;
         public string tk_blacklist_regular { get; set; } = string.Empty;
         public string multi_token_regular { get; set; } = string.Empty;
+
+        public int jd_limit_per_ip_24h { get; set; } = 0;
+        public int tk_limit_per_ip_24h { get; set; } = 0;
     }
 }

+ 8 - 0
molilian.core/DTO/alimama/TkPoolDTO.cs

@@ -1,5 +1,12 @@
 namespace molilian.core
 {
+    public enum FakeClickLinkType
+    {
+        All = 0,
+        H5 = 1,
+        Deeplink = 2,
+
+    }
     public class TkPoolDTO
     {
         public int id { get; set; }
@@ -24,6 +31,7 @@
         public int api_id { get; set; } = 0;
         public string end_point { get; set; } = string.Empty;
         public bool enable_fake_click { get; set; } = false;
+        public FakeClickLinkType fake_click_link_type { get; set; } = 0;
         public bool enable_parse { get; set; } = false;
         public bool enable_coupon { get; set; } = false;
         public bool enable_sync_order { get; set; } = false;

+ 13 - 1
molilian.core/DTO/alimama/UnionCouponDTO.cs

@@ -3,8 +3,20 @@ using dodohold.core;
 
 namespace molilian.core
 {
+
     [Table("tk_coupon_logs")]
-    public class UnionCouponDTO
+
+    public class UnionCouponDTO : BaseUnionCouponDTO;
+
+    [Table("tk_coupon_logs_test")]
+    public class TestUnionCouponDTO : BaseUnionCouponDTO;
+
+
+    [Table("tk_coupon_logs_success")]
+    public class SuccessUnionCouponDTO : BaseUnionCouponDTO;
+
+
+    public class BaseUnionCouponDTO
     {
         [Key]
         public long id { get; set; }

+ 25 - 2
molilian.core/DTO/jd/JdPoolDTO.cs

@@ -1,17 +1,40 @@
 namespace molilian.core
 {
+    public enum JdUnionWorkMode
+    {
+        SiteApi = 1,
+        AffApi = 2,
+        Crawler = 3,
+
+    }
     public class JdPoolDTO
     {
         public int id { get; set; }
         public string name { get; set; } = string.Empty;
+        public string pin { get; set; } = string.Empty;
+        public string company { get; set; } = string.Empty;
         public string unionid { get; set; } = string.Empty;
         public string description { get; set; } = string.Empty;
         public string site_id { get; set; } = string.Empty;
         public string app_key { get; set; } = string.Empty;
         public string app_secret { get; set; } = string.Empty;
-        public DateTime create_time { get; set; }
-        public DateTime last_time { get; set; }
+        public DateTime create_time { get; set; } = DateTime.Now;
+        public DateTime last_time { get; set; } = DateTime.Now;
+        public DateTime login_time { get; set; } = DateTime.Now;
         public bool status { get; set; }
+        public JdUnionWorkMode work_mode { get; set; } = JdUnionWorkMode.SiteApi;
+        public string user_agent { get; set; } = string.Empty;
+        public string cookies { get; set; } = string.Empty;
+
+
+        public string nodeName { get; set; } = string.Empty;
+        public string end_point { get; set; } = string.Empty;
+        public decimal current_amt { get; set; } = 0;
+        public decimal daily_income_limit { get; set; } = 0;
+        public decimal draw_balance { get; set; } = 0;
+        public bool enable_parse { get; set; } = false;
+        public bool enable_coupon { get; set; } = false;
+        public bool enable_sync_order { get; set; } = false;
 
     }
 }

+ 23 - 6
molilian.core/Plus/Alimama/coupon.cs

@@ -18,12 +18,29 @@ namespace molilian.core
             result.success = data.success;
             result.reason = data.reason;
             result.message = data.success ? "OK" : data.message;
-            result.deeplink_url = data.deeplink_url;
-            result.couponAmount = data.couponAmount;
-            result.couponEffectiveStartTime = data.couponEffectiveStartTime;
-            result.couponEffectiveEndTime = data.couponEffectiveEndTime;
-            result.itemId = data.itemId;
-            result.pic = data.pic;
+
+            if (result.success)
+            {
+                if (result.couponAmount == 0)
+                {
+                    result.success = false;
+                    result.message = "放弃转链";
+                    result.reason = "没有优惠券";
+                    result.deeplink_url = string.Empty;
+                }
+                else
+                {
+                    result.deeplink_url = data.deeplink_url;
+                    result.couponAmount = data.couponAmount;
+                    result.couponEffectiveStartTime = data.couponEffectiveStartTime;
+                    result.couponEffectiveEndTime = data.couponEffectiveEndTime;
+                    result.itemId = data.itemId;
+                    result.pic = data.pic;
+                }
+            }
+
+
+
 
             //public bool success { get; set; } = false;
             //public string reason { get; set; } = string.Empty;

+ 124 - 66
molilian.core/Plus/Alimama/crawler.cs

@@ -11,7 +11,7 @@ namespace molilian.core
         /// 更新API调用日志(1天一次)
         /// </summary>
         /// <param name="intervalDay"></param>
-        public static void DailyLogs(int intervalDay, string prefix = "", string channel = "all")
+        public static void DailyLogs_bak(int intervalDay, string prefix = "", string channel = "all")
         {
             int channelId = (int)TkChannelEnum.tb;
             var db_prefix = channel switch
@@ -24,6 +24,7 @@ namespace molilian.core
             DateTime log_date = DateTime.Now.AddDays(-intervalDay).Date;
 
             var accounts = TkPoolCore.List();
+            using var conn = DBContext.GetOpenConnection();
 
             foreach (var account in accounts)
             {
@@ -52,7 +53,7 @@ namespace molilian.core
                      .Get<dynamic>("log_date=@log_date AND channel=@channel AND accountId=@accountId", new { log_date, channel = channelId, accountId });
 
 
-                var createArgs = new DBContext.Table("daily_logs")
+                var createArgs = new DBContext.Table(conn, "daily_logs")
 
                     .Add($"{db_prefix}total_count", total_count)
                     .Add($"{db_prefix}abandon_count", abandon_count)
@@ -87,12 +88,131 @@ namespace molilian.core
                 all_success_percentage = $"{all_success_count / (double)all_total_count * 100:f2}%";
                 all_abandon_percentage = $"{all_abandon_count / (double)all_total_count * 100:f2}%";
             }
-            var exist2 = new DBContext.Table("daily_logs")
+            var exist2 = new DBContext.Table(conn, "daily_logs")
                  .Fields("id,log_date")
                  .Get<dynamic>("log_date=@log_date AND channel=@channel AND accountId=@accountId",
                  new { log_date, channel = channelId, accountId = 0 });
 
-            var createArgs2 = new DBContext.Table("daily_logs")
+            var createArgs2 = new DBContext.Table(conn, "daily_logs")
+                .Add($"{db_prefix}total_count", all_total_count)
+                .Add($"{db_prefix}abandon_count", all_abandon_count)
+                .Add($"{db_prefix}abandon_percentage", all_abandon_percentage)
+                .Add($"{db_prefix}success_count", all_success_count)
+                .Add($"{db_prefix}success_percentage", all_success_percentage)
+                .Add("last_time", DateTime.Now);
+
+            if (exist2 == null)
+            {
+                createArgs2.Add("channel", channelId)
+                    .Add("accountId", 0)
+                    .Add("accountName", "all")
+                    .Add("log_date", log_date)
+                    .Add("create_time", DateTime.Now)
+                    .Create();
+            }
+            else
+            {
+                createArgs2.Where("id=@id", new { exist2.id }).Update();
+            }
+
+        }
+
+
+        public static void AllDailyLogs(int intervalDay, string prefix = "", string channel = "all")
+        {
+            DailyLogs(true, intervalDay, prefix, channel);
+        }
+
+
+        public static void NodeDailyLogs(int intervalDay, string prefix = "", string channel = "all")
+        {
+            DailyLogs(false, intervalDay, prefix, channel);
+        }
+
+        public static void DailyLogs(bool all_node, int intervalDay, string prefix = "", string channel = "all")
+        {
+            int channelId = (int)TkChannelEnum.tb;
+            var db_prefix = channel switch
+            {
+                "tool" => "tool_",
+                "jd" => "jd_parse_",
+                _ => prefix,
+            };
+
+            DateTime log_date = DateTime.Now.AddDays(-intervalDay).Date;
+
+            var accounts = TkPoolCore.List();
+            using var conn = all_node ? CenterHub.GetOpenConnection() : DBContext.GetOpenConnection();
+            string tableName = all_node ? "center_daily_logs" : "daily_logs";
+
+            foreach (var account in accounts)
+            {
+                int accountId = account.id;
+                string accountName = $"{TkChannelEnum.tb}_{account.id}";
+
+                int total_count = TkLogCore.GetTotal($":{prefix}total:{accountName}:{log_date:yyyyMMdd}", all_node);
+                if (total_count == 0) accountName = account.name;
+
+                total_count = TkLogCore.GetTotal($":{prefix}total:{accountName}:{log_date:yyyyMMdd}", all_node);
+                if (total_count == 0) continue;
+
+                var success_count = TkLogCore.GetTotal($":{prefix}total:{accountName}:success:{log_date:yyyyMMdd}", all_node);
+                var abandon_count = TkLogCore.GetTotal($":{prefix}total:{accountName}:放弃转链:{log_date:yyyyMMdd}", all_node);
+                string success_percentage = string.Empty;
+                string abandon_percentage = string.Empty;
+
+                if (total_count > 0)
+                {
+                    success_percentage = $"{success_count / (double)total_count * 100:f2}%";
+                    abandon_percentage = $"{abandon_count / (double)total_count * 100:f2}%";
+                }
+
+                var exist = new DBContext.Table(tableName)
+                     .Fields("id,log_date")
+                     .Get<dynamic>("log_date=@log_date AND channel=@channel AND accountId=@accountId", new { log_date, channel = channelId, accountId });
+
+
+                var createArgs = new DBContext.Table(conn, tableName)
+
+                    .Add($"{db_prefix}total_count", total_count)
+                    .Add($"{db_prefix}abandon_count", abandon_count)
+                    .Add($"{db_prefix}abandon_percentage", abandon_percentage)
+                    .Add($"{db_prefix}success_count", success_count)
+                    .Add($"{db_prefix}success_percentage", success_percentage)
+                    .Add("last_time", DateTime.Now);
+
+                if (exist == null)
+                {
+                    createArgs.Add("channel", channelId)
+                        .Add("accountId", accountId)
+                        .Add("accountName", account.company)
+                        .Add("log_date", log_date)
+                        .Add("create_time", DateTime.Now)
+                        .Create();
+                }
+                else
+                {
+                    createArgs.Where("id=@id", new { exist.id }).Update();
+                }
+            }
+
+            int all_total_count = TkLogCore.GetTotal($":{prefix}total:{channel}:{log_date:yyyyMMdd}", all_node);
+            var all_success_count = TkLogCore.GetTotal($":{prefix}total:{channel}:success:{log_date:yyyyMMdd}", all_node);
+            var all_abandon_count = TkLogCore.GetTotal($":{prefix}total:{channel}:放弃转链:{log_date:yyyyMMdd}", all_node);
+
+            string all_success_percentage = string.Empty;
+            string all_abandon_percentage = string.Empty;
+            if (all_total_count > 0)
+            {
+                all_success_percentage = $"{all_success_count / (double)all_total_count * 100:f2}%";
+                all_abandon_percentage = $"{all_abandon_count / (double)all_total_count * 100:f2}%";
+            }
+            var exist2 = new DBContext.Table(conn, tableName)
+                 .Fields("id,log_date")
+                 .Get<dynamic>("log_date=@log_date AND channel=@channel AND accountId=@accountId",
+                 new { log_date, channel = channelId, accountId = 0 });
+
+            var createArgs2 = new DBContext.Table(conn, tableName)
                 .Add($"{db_prefix}total_count", all_total_count)
                 .Add($"{db_prefix}abandon_count", all_abandon_count)
                 .Add($"{db_prefix}abandon_percentage", all_abandon_percentage)
@@ -114,68 +234,6 @@ namespace molilian.core
                 createArgs2.Where("id=@id", new { exist2.id }).Update();
             }
 
-            /*
-
-		-- 定义变量用于日期间隔
-SET @interval_days = 4;
-
--- 汇总所有账户的数据
-INSERT INTO daily_logs (
-    channel, accountId, accountName, log_date, total_count, abandon_count, abandon_percentage, success_count, success_percentage, create_time, last_time
-)
-SELECT
-    0 AS channel,
-    0 AS accountId,
-    'all' AS accountName,
-    DATE_SUB(CURDATE(), INTERVAL @interval_days DAY) AS log_date,
-    COUNT(*) AS total_count,
-    COALESCE(SUM(CASE WHEN message = '放弃转链' THEN 1 ELSE 0 END), 0) AS abandon_count,
-    COALESCE(CONCAT(ROUND((SUM(CASE WHEN message = '放弃转链' THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2), '%'), 0) AS abandon_percentage,
-    COALESCE(SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END), 0) AS success_count,
-    COALESCE(CONCAT(ROUND((SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2), '%'), 0) AS success_percentage,
-    NOW() AS create_time,
-    NOW() AS last_time
-FROM tk_logs
-WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL @interval_days DAY)
-  AND create_time < DATE_SUB(CURDATE(), INTERVAL @interval_days - 1 DAY)
-ON DUPLICATE KEY UPDATE
-    total_count = VALUES(total_count),
-    abandon_count = VALUES(abandon_count),
-    abandon_percentage = VALUES(abandon_percentage),
-    success_count = VALUES(success_count),
-    success_percentage = VALUES(success_percentage),
-    last_time = NOW();
-
--- 按渠道、账户分组的数据
-INSERT INTO daily_logs (
-    channel, accountId, accountName, log_date, total_count, abandon_count, abandon_percentage, success_count, success_percentage, create_time, last_time
-)
-SELECT
-    channel,
-    accountId,
-    accountName,
-    DATE_SUB(CURDATE(), INTERVAL @interval_days DAY) AS log_date,
-    COUNT(*) AS total_count,
-    COALESCE(SUM(CASE WHEN message = '放弃转链' THEN 1 ELSE 0 END), 0) AS abandon_count,
-    COALESCE(CONCAT(ROUND((SUM(CASE WHEN message = '放弃转链' THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2), '%'), 0) AS abandon_percentage,
-    COALESCE(SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END), 0) AS success_count,
-    COALESCE(CONCAT(ROUND((SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2), '%'), 0) AS success_percentage,
-    NOW() AS create_time,
-    NOW() AS last_time
-FROM tk_logs
-WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL @interval_days DAY)
-  AND create_time < DATE_SUB(CURDATE(), INTERVAL @interval_days - 1 DAY)
-GROUP BY channel, accountId, accountName
-ON DUPLICATE KEY UPDATE
-    total_count = VALUES(total_count),
-    abandon_count = VALUES(abandon_count),
-    abandon_percentage = VALUES(abandon_percentage),
-    success_count = VALUES(success_count),
-    success_percentage = VALUES(success_percentage),
-    last_time = NOW();
-             */
-            //DBContext.Execute(sql, new { });
-            //DBContext.Execute(sql2, new { });
         }
 
         public static void ApiCallStatistics(int intervalDay, TkChannelEnum channel, string prefix = "")

+ 1 - 1
molilian.core/Plus/Alimama/orders.cs

@@ -366,7 +366,7 @@ SET  order_ord_num = order_ord_num_3 + order_ord_num_12 + order_ord_num_13 + ord
                         if (id != null)
                         {
                             item.id = (int)id;
-                            TkOrderTrackingCore.MatchOrder(item, conn);
+                            TkOrderTrackingCore.MatchOrder(_account, item, conn);
                         }
                         total++;
                     }

+ 2 - 1
molilian.core/Plus/Alimama/parse.cs

@@ -27,6 +27,7 @@ namespace molilian.core
         private int _api_id = 0;
         public TkConfigDTO _config;
         private static string _end_point;
+        private static TkPoolDTO _account;
         static Random _random = new Random();
 
         public static string _url_pattern = @"https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
@@ -42,7 +43,7 @@ namespace molilian.core
             //    string cookies, string user_agent, string nodeName
             _config = TkConfigCore.Get();
 
-
+            _account = account;
             _accountId = account.id;
             _accountName = account.name;
             _company = account.company;

+ 12 - 31
molilian.core/Plus/JDUnion/JdUnionPlus.cs

@@ -23,12 +23,6 @@ namespace molilian.core
 {
     public partial class JdUnionPlus
     {
-        private static string _end_point;
-        static JdUnionPlus()
-        {
-            _end_point = Environment.GetEnvironmentVariable("EndPoint");
-        }
-
         public static string GetLink(string content)
         {
             if (string.IsNullOrEmpty(content)) return content;
@@ -218,7 +212,7 @@ namespace molilian.core
         //    return result;
         //}
 
-        public static async Task<JdDataDTO> JdParseAsync(JdPoolDTO account, string content, JdDataDTO result, CancellationToken cancellationToken = default)
+        public async Task<JdDataDTO> JdParseAsync(string content, JdDataDTO result, CancellationToken cancellationToken = default)
         {
             string message = "OK";
             string url = GetLink(content);
@@ -236,7 +230,6 @@ namespace molilian.core
                 return result;
             }
             string shortLinkurl = url;
-            var plus = new JdUnionPlus(account.app_key, account.app_secret);
 
             //result.link_type = plus.IsAffLlink(url) ? LinkTypeEnum.other_aff : LinkTypeEnum.goods;
             result.link_type = GetLinkType(url, out string out_url, out string itemId);
@@ -257,31 +250,19 @@ namespace molilian.core
                 return result;
             }
 
-
-            //============================== 放弃转链-地区过滤 ==============================
-            bool is_ignore2 = FlowControlIgnoreRequest(out string reason);
-            if (is_ignore2)
-            {
-                result.success = false;
-                result.message = "放弃转链";
-                result.reason = reason;
-                return result;
-            }
-
-            result.shortLinkurl = await plus.GetPromotionAsync(account.site_id, url, cancellationToken);
-
-            var success = !string.IsNullOrEmpty(result.shortLinkurl);
-            if (!success)
+            switch (_account.work_mode)
             {
-                result.shortLinkurl = shortLinkurl;
-                message = "转链失败";
+                case JdUnionWorkMode.SiteApi:
+                    result = await GetPromotionBySiteAsync(result, url, cancellationToken);
+                    break;
+                case JdUnionWorkMode.AffApi:
+                    result = await GetPromotionByAffAsync(result, url, cancellationToken);
+                    break;
+                case JdUnionWorkMode.Crawler:
+                default:
+                    result = await GetPromotionByCrawlerAsync(result, url, cancellationToken);
+                    break;
             }
-
-            result.content = result.shortLinkurl;
-            result.shortLinkurl = result.shortLinkurl;
-            result.success = success;
-            result.message = message;
-            result.deeplink_url = GetDeeplink(result.shortLinkurl);
             return result;
         }
     }

+ 45 - 13
molilian.core/Plus/JDUnion/base.cs

@@ -19,28 +19,44 @@ using System.Security.Policy;
 using Google.Protobuf.WellKnownTypes;
 using Microsoft.AspNetCore.Components;
 using Org.BouncyCastle.Pqc.Crypto.Ntru;
+using System.Net;
 
 
 namespace molilian.core
 {
     public partial class JdUnionPlus
     {
-        string _app_key;
-        string _app_secret;
         static Random _random = new Random();
-        public JdUnionPlus(string app_key, string app_secret)
+        private WebProxy? _proxy = null;
+
+        public TkConfigDTO _config;
+        private static JdPoolDTO _account;
+        private static string _end_point;
+
+        static JdUnionPlus()
         {
-            _app_key = app_key;
-            _app_secret = app_secret;
+            _end_point = Environment.GetEnvironmentVariable("EndPoint");
         }
 
+        public JdUnionPlus(JdPoolDTO account)
+        {
+            _account = account;
+            _config = TkConfigCore.Get();
+
+            if (!string.IsNullOrEmpty(account.nodeName))
+            {
+                _proxy = ProxyNodesCore.GetOne(account.nodeName);
+            }
+        }
+
+
         private string _sign(string method, string version, string param_json, string timestamp)
         {
             Dictionary<string, string> sysParameters = new()
             {
                 { "360buy_param_json", param_json },
                 { "access_token", ""},
-                { "app_key", _app_key },
+                { "app_key", _account.app_key },
                 { "method", method},
                 { "timestamp", timestamp },
                 { "v", version }
@@ -52,7 +68,7 @@ namespace molilian.core
                 stringBuilder.Append(key);
                 stringBuilder.Append(value);
             }
-            string strParameters = _app_secret + stringBuilder.ToString() + _app_secret;
+            string strParameters = _account.app_secret + stringBuilder.ToString() + _account.app_secret;
             string result = strParameters.MD5(false, false);
             return result;
         }
@@ -67,7 +83,7 @@ namespace molilian.core
             string api = "https://api.jd.com/routerjson";
             string url = api;
             url += "?access_token=";
-            url += $"&app_key={_app_key}";
+            url += $"&app_key={_account.app_key}";
             url += $"&method={method.UrlEncode()}";
             url += $"&v={version.UrlEncode()}";
             url += $"&sign={sign}";
@@ -93,7 +109,7 @@ namespace molilian.core
             string api = "https://api.jd.com/routerjson";
             string url = api;
             url += "?access_token=";
-            url += $"&app_key={_app_key}";
+            url += $"&app_key={_account.app_key}";
             url += $"&method={method.UrlEncode()}";
             url += $"&v={version.UrlEncode()}";
             url += $"&sign={sign}";
@@ -110,13 +126,12 @@ namespace molilian.core
             return body;
         }
 
-        public static bool ShouldIgnoreRequest(string ip, string oaid, out string reason)
+        public static bool ShouldIgnoreRequest(TkConfigDTO config, string ip, string oaid, out string reason)
         {
             reason = string.Empty;
             try
             {
                 // IP和流量控制
-                var config = TkConfigCore.Get();
                 string ignorePercentageCity = config.jdIgnorePercentageCity;
                 string? ipInfo = IP2RegionPlus.Search(ip);
                 if (AlimamaPlus.IgnoreRegionIncluded(ignorePercentageCity, ipInfo, out string regionInfo))
@@ -124,6 +139,23 @@ namespace molilian.core
                     reason = $"地区控制:{regionInfo}";
                     return true;
                 }
+
+                int limit_num = config.jd_limit_per_ip_24h;
+                if (limit_num > 0)
+                {
+                    int num = TkLogCore.getClientRequestTotalByIp(TkChannelEnum.jd, ip);
+                    if (num > limit_num)
+                    {
+                        reason = "IP控制";
+                        return true;
+                    }
+                    num = TkLogCore.getClientRequestTotalByOAID(TkChannelEnum.jd, oaid);
+                    if (num > limit_num)
+                    {
+                        reason = "OAID控制";
+                        return true;
+                    }
+                }
             }
             catch (Exception ex)
             {
@@ -132,16 +164,16 @@ namespace molilian.core
             return false;
         }
 
-        public static bool FlowControlIgnoreRequest(out string reason)
+        public static bool FlowControlIgnoreRequest(TkConfigDTO config, out string reason)
         {
             reason = string.Empty;
             try
             {
                 // IP和流量控制
-                var config = TkConfigCore.Get();
                 int ignorePercentage = config.jdIgnorePercentage;
                 if (ignorePercentage == 0) return false;
 
+
                 var randomValue = (decimal)_random.Next(0, 100);
                 bool result = randomValue <= ignorePercentage; // 如果生成的随机数小于忽略百分比,则返回 true,表示需要忽略请求
                 if (result)

+ 1 - 14
molilian.core/Plus/JDUnion/coupon.cs

@@ -70,24 +70,11 @@ namespace molilian.core
             }
             if (DateTime.TryParse(dtkResult.couponEndTime, out DateTime couponEndTime))
             {
-                result.couponEffectiveEndTime =couponEndTime.Convert2UnixTimestamp(true).ToString();
+                result.couponEffectiveEndTime = couponEndTime.Convert2UnixTimestamp(true).ToString();
             }
 
             result.pic = dtkResult.picMain;
 
-            //2202076
-            //https://item.jd.com/2202076.html
-
-            //https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoenWURVae-88AobuUWD3IOE8_N_oOkCsUv63B3gneyzoFQPJsQBfdvIG52TqcOEuYv1tVKLg",
-
-            //result.channel = data.channel;
-            //result.success = data.success;
-            //result.reason = data.reason;
-            //result.message = data.message;
-            //result.deeplink_url = data.deeplink_url;
-            //result.couponAmount = data.couponAmount;
-            //result.itemId = data.itemId;
-            //result.pic = data.pic;
             return result;
         }
     }

+ 120 - 11
molilian.core/Plus/JDUnion/goods.cs

@@ -20,17 +20,19 @@ using Google.Protobuf.WellKnownTypes;
 using Microsoft.AspNetCore.Components;
 using Org.BouncyCastle.Pqc.Crypto.Ntru;
 using Newtonsoft.Json;
+using Sayaka.Common;
+using System.Net;
 
 
 namespace molilian.core
 {
     public partial class JdUnionPlus
     {
-        public async Task<string> GetPromotionAsync(string siteId, string materialId, CancellationToken cancellationToken = default)
+        public async Task<JdDataDTO> GetPromotionBySiteAsync(JdDataDTO result, string shortLinkurl, CancellationToken cancellationToken = default)
         {
-            if (string.IsNullOrEmpty(siteId))
+            if (string.IsNullOrEmpty(_account.site_id))
             {
-                return await GetPromotionAsync(materialId, cancellationToken);
+                return await GetPromotionByAffAsync(result, shortLinkurl, cancellationToken);
             }
 
             string method = "jd.union.open.promotion.common.get";
@@ -39,8 +41,8 @@ namespace molilian.core
             {
                 promotionCodeReq = new
                 {
-                    siteId,
-                    materialId,
+                    siteId = _account.site_id,
+                    materialId = shortLinkurl,
                     command = 1,
                     chainType = 2,
                 }
@@ -55,14 +57,28 @@ namespace molilian.core
                 if (promotion_data.code == 200)
                 {
                     var url = promotion_data.data.clickURL;
-                    return url;
+
+                    result.success = true;
+                    result.message = "OK";
+                    result.shortLinkurl = url;
+                    result.content = result.shortLinkurl;
+                    result.deeplink_url = GetDeeplink(result.shortLinkurl);
+
+                    return result;
                 }
             }
+
+            result.success = false;
+            result.message = "转链失败";
+            result.reason = root.jd_union_open_promotion_common_get_responce.message;
+            result.shortLinkurl = shortLinkurl;
+            result.deeplink_url = GetDeeplink(result.shortLinkurl);
+
             _ = new LoggerLibrary("JdUnion", "promotion_get_error").Info(body).SaveAsync();
-            return null;
+            return result;
         }
 
-        public async Task<string> GetPromotionAsync(string materialId, CancellationToken cancellationToken = default)
+        public async Task<JdDataDTO> GetPromotionByAffAsync(JdDataDTO result, string shortLinkurl, CancellationToken cancellationToken = default)
         {
 
             string method = "jd.union.open.promotion.bysubunionid.get";
@@ -71,7 +87,7 @@ namespace molilian.core
             {
                 promotionCodeReq = new
                 {
-                    materialId,
+                    materialId = shortLinkurl,
                     command = 1,
                     chainType = 2,
                 }
@@ -86,11 +102,104 @@ namespace molilian.core
                 if (promotion_data.code == 200)
                 {
                     var url = promotion_data.data.clickURL;
-                    return url;
+
+                    result.success = true;
+                    result.message = "OK";
+                    result.shortLinkurl = url;
+                    result.content = result.shortLinkurl;
+                    result.deeplink_url = GetDeeplink(result.shortLinkurl);
+
+                    return result;
                 }
             }
+
+            result.success = false;
+            result.message = "转链失败";
+            result.reason = root.jd_union_open_promotion_common_get_responce.message;
+            result.shortLinkurl = shortLinkurl;
+            result.deeplink_url = GetDeeplink(result.shortLinkurl);
+
             _ = new LoggerLibrary("JdUnion", "bysubunionid_get_error").Info(body).SaveAsync();
-            return null;
+            return result;
+        }
+        public async Task<JdDataDTO> GetPromotionByCrawlerAsync(JdDataDTO result, string wareUrl, CancellationToken cancellationToken = default)
+        {
+            var ts = DateTime.Now.Convert2UnixTimestamp(true);
+            string cookies = _account.cookies;
+
+            string uuid = cookies.GetContentPart("__jdu=", ";");
+            string __jda = cookies.GetContentPart("__jda=", ";");
+            if (__jda.Split('.').Length > 1)
+            {
+                uuid = __jda.Split('.')[1];
+            }
+
+            string useragent = _account.user_agent;
+            if (string.IsNullOrEmpty(useragent)) useragent = ProviderFakeUserAgent.RandomComputer;
+            string url = $"https://api.m.jd.com/api?functionId=unionPromoteLinkService&" +
+                $"appid=unionpc&_={ts}&loginType=3&uuid={uuid}";
+
+            var args = new
+            {
+                funName = "getCode",
+                param = new
+                {
+                    couponLink = "",
+                    isPinGou = 0,
+                    materialId = result.itemId,
+                    materialType = 1,
+                    planId = 3479956501,
+                    promotionType = 15,
+                    receiveType = "cps",
+                    wareUrl = wareUrl,
+                    isSmartGraphics = 0,
+                    command = 1,
+                    ext1 = "618|pc|".UrlEncode()
+                },
+                lientPageId = "jingfen_pc"
+            };
+            string data = args.Convert2Json().UrlEncode();
+
+            WebClientUtility client = new WebClientUtility();
+            client.Proxy = _proxy;
+#if DEBUG
+            client.Proxy = null;
+#endif
+            client.SetContentType("application/x-www-form-urlencoded");
+            client.AddHeaders("X-Referer-Page", "https://union.jd.com/proManager/index");
+            client.AddHeaders("X-Rp-Client", "h5_1.0.0");
+            client.AddHeaders("Referer", "https://union.jd.com/");
+            client.AddHeaders("Origin", "https://union.jd.com");
+            client.UserAgent = useragent;
+            client.AddHeaders("Cookie", cookies);
+            client.Post($"body={data}");
+            var response = await client.RequestAsync(url, "POST", cancellationToken);
+
+            string body = response.Body();
+            var root = body.Convert2JsonElement();
+            int code = root.Read<int>("code");
+            string message = root.Read<string>("message");
+            string shortCode = root.PathRead<string>("data.shortCode");
+
+            if (code == 200)
+            {
+                result.success = true;
+                result.message = "OK";
+                result.shortLinkurl = shortCode;
+                result.content = result.shortLinkurl;
+                result.deeplink_url = GetDeeplink(result.shortLinkurl);
+            }
+            else
+            {
+                if (string.IsNullOrEmpty(body)) message = "网络异常";
+                result.success = false;
+                result.message = "转链失败";
+                result.reason = message;
+                result.shortLinkurl = wareUrl;
+                result.deeplink_url = GetDeeplink(result.shortLinkurl);
+                _ = new LoggerLibrary("JdUnion", "GetPromotionByCrawlerAsync").Info(body).SaveAsync();
+            }
+            return result;
         }
 
     }

+ 3 - 3
molilian.core/Plus/Tool/ToolDailyLogs.cs

@@ -36,9 +36,9 @@ namespace molilian.core
             List<TkChannelEnum> arr = [TkChannelEnum.wemeet, TkChannelEnum.bdpan];
             foreach (var channelEnum in arr)
             {
-                all_total_count += TkLogCore.GetTotal($":parse_total:{channel}:{log_date:yyyyMMdd}");
-                all_success_count += TkLogCore.GetTotal($":parse_total:{channel}:success:{log_date:yyyyMMdd}");
-                all_abandon_count += TkLogCore.GetTotal($":parse_total:{channel}:放弃转链:{log_date:yyyyMMdd}");
+                all_total_count += TkLogCore.GetTotal($":parse_total:{channelEnum}:{log_date:yyyyMMdd}");
+                all_success_count += TkLogCore.GetTotal($":parse_total:{channelEnum}:success:{log_date:yyyyMMdd}");
+                all_abandon_count += TkLogCore.GetTotal($":parse_total:{channelEnum}:放弃转链:{log_date:yyyyMMdd}");
             }
 
             string all_success_percentage = string.Empty;

+ 1 - 1
molilian.core/molilian.core.csproj

@@ -13,7 +13,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="dodohold.core" Version="1.0.1.13" />
+    <PackageReference Include="dodohold.core" Version="1.0.1.14" />
     <PackageReference Include="FakeUserAgent" Version="1.0.2" />
     <PackageReference Include="IP2Region.Net" Version="2.0.2" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio