diff --git a/RoBot.Core/ConstValue/Consts.cs b/RoBot.Core/ConstValue/Consts.cs index 0e1da2d..6b1cd45 100644 --- a/RoBot.Core/ConstValue/Consts.cs +++ b/RoBot.Core/ConstValue/Consts.cs @@ -1,5 +1,8 @@ namespace RoBot.Core.ConstValue { + /// + /// 常量 + /// public class Consts { /// @@ -18,6 +21,9 @@ public const string Config = "config.json"; } + /// + /// 缓存前缀 + /// public class RedisPrefix { public const string GoodsKey = "GoodsInfo"; diff --git a/RoBot.Core/Redis/RedisHelper.cs b/RoBot.Core/Helper/RedisHelper.cs similarity index 91% rename from RoBot.Core/Redis/RedisHelper.cs rename to RoBot.Core/Helper/RedisHelper.cs index 2a5aa88..9a608ed 100644 --- a/RoBot.Core/Redis/RedisHelper.cs +++ b/RoBot.Core/Helper/RedisHelper.cs @@ -1,8 +1,7 @@ using FreeRedis; using Newtonsoft.Json; -using RoBot.Core.Helper; -namespace RoBot.Core.Redis +namespace RoBot.Core.Helper { public class RedisHelper { diff --git a/RoBot.Core/Utils.cs b/RoBot.Core/Utils.cs new file mode 100644 index 0000000..92148ab --- /dev/null +++ b/RoBot.Core/Utils.cs @@ -0,0 +1,42 @@ +namespace RoBot.Core +{ + public class Utils + { + public static string FormatNumberToChineseUnit(decimal number) + { + if (number >= 100000000) // 亿 + { + decimal value = number / 100000000.0M; + return $"{value:0.#}亿"; + } + else if (number >= 10000) // 万 + { + decimal value = number / 10000.0M; + return $"{value:0.#}万"; + } + else + { + return number.ToString(); + } + } + + public static decimal ParseChineseNumber(string chineseNumber) + { + if (string.IsNullOrWhiteSpace(chineseNumber))return 0; + + chineseNumber = chineseNumber.Trim(); + + decimal multiplier = 1; + if (chineseNumber.Contains("亿")) + multiplier = 100000000; + else if (chineseNumber.Contains("万")) + multiplier = 10000; + var numberPart = chineseNumber.Replace("亿", "").Replace("万", ""); + if (!decimal.TryParse(numberPart, out decimal value)) return 0; + + return value * multiplier; + } + + + } +} diff --git a/RoBot.Goods/Service/GoodsService.cs b/RoBot.Goods/Service/GoodsService.cs index d8600de..c4de47f 100644 --- a/RoBot.Goods/Service/GoodsService.cs +++ b/RoBot.Goods/Service/GoodsService.cs @@ -1,6 +1,6 @@ using System.Text.RegularExpressions; using RoBot.Core.ConstValue; -using RoBot.Core.Redis; +using RoBot.Core.Helper; using RoBot.Goods.Dto; namespace RoBot.Goods.Service diff --git a/XXROBOT.sln b/XXROBOT.sln index f2a963d..200395d 100644 --- a/XXROBOT.sln +++ b/XXROBOT.sln @@ -1,14 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.12.35728.132 d17.12 +VisualStudioVersion = 17.12.35728.132 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lagrange.Core", "Lagrange.Core\Lagrange.Core\Lagrange.Core.csproj", "{C345D8FF-14D1-405B-802A-D062CA5B14B5}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoBot.Start", "XiaoXiaoRoBot\RoBot.Start.csproj", "{236CE019-D997-4286-9E33-2D6473572156}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoBot.Goods", "RoBot.Goods\RoBot.Goods.csproj", "{D25D4673-EDCA-494D-A45D-03896AC40A78}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoBot.Core", "RoBot.Core\RoBot.Core.csproj", "{E155F24D-17D8-4F43-8366-9AF6992E9DDE}" EndProject Global @@ -25,10 +23,6 @@ Global {236CE019-D997-4286-9E33-2D6473572156}.Debug|Any CPU.Build.0 = Debug|Any CPU {236CE019-D997-4286-9E33-2D6473572156}.Release|Any CPU.ActiveCfg = Release|Any CPU {236CE019-D997-4286-9E33-2D6473572156}.Release|Any CPU.Build.0 = Release|Any CPU - {D25D4673-EDCA-494D-A45D-03896AC40A78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D25D4673-EDCA-494D-A45D-03896AC40A78}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D25D4673-EDCA-494D-A45D-03896AC40A78}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D25D4673-EDCA-494D-A45D-03896AC40A78}.Release|Any CPU.Build.0 = Release|Any CPU {E155F24D-17D8-4F43-8366-9AF6992E9DDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E155F24D-17D8-4F43-8366-9AF6992E9DDE}.Debug|Any CPU.Build.0 = Debug|Any CPU {E155F24D-17D8-4F43-8366-9AF6992E9DDE}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/XiaoXiaoRoBot/Cmd/InertOrUpdateGoodsCmd.cs b/XiaoXiaoRoBot/Cmd/InertOrUpdateGoodsCmd.cs new file mode 100644 index 0000000..32adbf2 --- /dev/null +++ b/XiaoXiaoRoBot/Cmd/InertOrUpdateGoodsCmd.cs @@ -0,0 +1,32 @@ +using Lagrange.Core.Message; +using Lagrange.Core.Message.Entity; +using RoBot.Start.Service.Impl; + +namespace RoBot.Start.Cmd +{ + /// + /// 保存或更新物品价格 + /// + public class InertOrUpdateGoodsCmd + { + public static async Task Execute(MessageChain chain) + { + foreach (var item in chain) + { + if (item is TextEntity) + { + TextEntity txe = item as TextEntity; + + if (string.IsNullOrWhiteSpace(txe.Text) is false) + { + if (txe.Text.Contains("不鼓励不保障")) + { + GoodsService.AnalysisGoodsText(txe.Text); + } + } + } + } + return true; + } + } +} diff --git a/XiaoXiaoRoBot/Cmd/QueryGoodsInfoPriceCmd.cs b/XiaoXiaoRoBot/Cmd/QueryGoodsInfoPriceCmd.cs new file mode 100644 index 0000000..ec4f52c --- /dev/null +++ b/XiaoXiaoRoBot/Cmd/QueryGoodsInfoPriceCmd.cs @@ -0,0 +1,63 @@ +using Lagrange.Core.Message; +using Lagrange.Core.Message.Entity; +using RoBot.Core.ConstValue; +using RoBot.Core.Helper; +using RoBot.Start.Global; +using RoBot.Start.Message; +using RoBot.Start.Service.Dto; + +namespace RoBot.Start.Cmd +{ + /// + /// 查看物品信息命令 价格/数据更新时间 + /// + public class QueryGoodsInfoPriceCmd + { + public static async Task Execute(MessageChain chain) + { + var systemConfig = GlobalConfig.ConfigSetting; + var bot = GlobalConfig.BotContext; + + if (chain.Count == 2 && + chain.FirstOrDefault(e => e is MentionEntity) is MentionEntity mention && + chain.FirstOrDefault(e => e is TextEntity) is TextEntity text) + { + // 判断是否@了机器人 + if (mention.Uin == systemConfig.BotQQ) + { + string inputText = text.Text?.Trim(); + + // 判断是否包含“查价格” + if (!string.IsNullOrEmpty(inputText) && inputText.Contains("查价格")) + { + // 提取物品名称 + var goodsName = inputText + .Split(' ', StringSplitOptions.RemoveEmptyEntries) + .FirstOrDefault(word => word != "查价格") + ?.Replace("查价格", "")?.Trim(); + + if (!string.IsNullOrWhiteSpace(goodsName)) + { + var goodsInfo = RedisHelper.Client.HGet(RedisPrefix.GoodsKey, goodsName); + + if (goodsInfo is not null) + { + await bot.SendMsg((uint)systemConfig.GroupQQ, + $"物品:{goodsInfo.Name}\n价格:{goodsInfo.ShowPriceDesc}\n收录时间:{goodsInfo.LastUpdateTime:yyyy-MM-dd HH:mm:ss}"); + } + else + { + await bot.SendMsg((uint)systemConfig.GroupQQ, "未收录"); + } + } + else + { + await bot.SendMsg((uint)systemConfig.GroupQQ, "请输入要查询的物品名称,例如:查价格 七星草"); + } + } + } + } + return true; + } + } +} diff --git a/XiaoXiaoRoBot/Cmd/QueryGoodsUpShopPriceCmd.cs b/XiaoXiaoRoBot/Cmd/QueryGoodsUpShopPriceCmd.cs new file mode 100644 index 0000000..916277d --- /dev/null +++ b/XiaoXiaoRoBot/Cmd/QueryGoodsUpShopPriceCmd.cs @@ -0,0 +1,111 @@ +using System.Text.RegularExpressions; +using Lagrange.Core.Message; +using Lagrange.Core.Message.Entity; +using RoBot.Core; +using RoBot.Core.ConstValue; +using RoBot.Core.Helper; +using RoBot.Start.Global; +using RoBot.Start.Message; +using RoBot.Start.Service.Dto; + +namespace RoBot.Start.Cmd +{ + /// + /// 坊市上架命令 + /// + public class QueryGoodsUpShopPriceCmd + { + + public static async Task Execute(MessageChain chain) + { + var systemConfig = GlobalConfig.ConfigSetting; + if (chain.Count == 3 && + chain.FirstOrDefault(e => e is ForwardEntity) is ForwardEntity forward && + chain.FirstOrDefault(e => e is MentionEntity) is MentionEntity mention && + chain.FirstOrDefault(e => e is TextEntity) is TextEntity text) + { + if (forward.TargetUin == (uint)systemConfig.XiaoXiaoQQ && mention.Uin == (uint)systemConfig.BotQQ && (text.Text.Contains("查上架") || text.Text.Contains("查价格"))) + { + + var list = forward.Chain.Where(o => o is TextEntity); + if (!list.Any()) return false; + + List convertList = list.Cast().ToList(); + convertList = convertList.Where(o => string.IsNullOrWhiteSpace(o.Text) is false) + .ToList(); + if (convertList.Count > 0) + { + string desc = convertList[0].Text; + + if (desc.Contains("药材")) + { + _ = Herbal(desc); + } + } + } + } + + return true; + } + + /// + /// 计算药材 + /// + /// + private static async Task Herbal(string text) + { + List results = []; + + string currentGrade = ""; + var lines = text.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + if (line.StartsWith("品级:")) + { + currentGrade = line.Substring("品级:".Length).Trim(); + } + else if (line.StartsWith("名字:")) + { + var name = line.Substring("名字:".Length).Trim(); + // 找到下一行的数量 + var index = Array.IndexOf(lines, line); + if (index + 1 < lines.Length && lines[index + 1].StartsWith("拥有数量:")) + { + var quantityLine = lines[index + 1]; + var match = Regex.Match(quantityLine, @"拥有数量:(\d+)"); + if (match.Success) + { + var quantity = match.Groups[1].Value; + results.Add(new() { Name = name, Num = Convert.ToInt32(quantity) }); + } + } + } + } + + string msg = ""; + decimal totalPrice = 0; + // 打印结果 + foreach (var item in results) + { + var current = RedisHelper.Client.HGet(RedisPrefix.GoodsKey, item.Name); + if (current is not null) + { + decimal nicePrice = current.Price - 100000; + totalPrice += Convert.ToDecimal(nicePrice * item.Num); + msg += $"确认坊市上架{item.Name} {(int)current.Price - 100000} {item.Num}\n"; + } + } + if (string.IsNullOrWhiteSpace(msg) is false) + { + msg += "\r\n"; + msg += "使用前请先@小小查看坊市药材,过完一遍以获取最新价格\r\n当前价格为坊市价格-10w\r\n"; + msg += $"总价值约:{Utils.FormatNumberToChineseUnit(totalPrice)}"; + var systemConfig = GlobalConfig.ConfigSetting; + var bot = GlobalConfig.BotContext; + await bot.SendMsg((uint)systemConfig.GroupQQ, msg); + } + + return await Task.FromResult(true); + } + } +} diff --git a/XiaoXiaoRoBot/ConstValue/Consts.cs b/XiaoXiaoRoBot/ConstValue/Consts.cs deleted file mode 100644 index 18b83a7..0000000 --- a/XiaoXiaoRoBot/ConstValue/Consts.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace RoBot.Start.ConstValue -{ - public class Consts - { - /// - /// 登录文件 - /// - public const string KeystoreConfig = "keystore.json"; - - /// - /// 设备信息 - /// - public const string DeviceConfig = "device.json"; - - /// - /// 配置文件 - /// - public const string Config = "config.json"; - } -} diff --git a/XiaoXiaoRoBot/Device/DeviceConfig.cs b/XiaoXiaoRoBot/Device/DeviceConfig.cs index 20faeba..766da94 100644 --- a/XiaoXiaoRoBot/Device/DeviceConfig.cs +++ b/XiaoXiaoRoBot/Device/DeviceConfig.cs @@ -1,6 +1,6 @@ using System.Text.Json; using Lagrange.Core.Common; -using RoBot.Start.ConstValue; +using RoBot.Core.ConstValue; namespace RoBot.Start.Device { diff --git a/XiaoXiaoRoBot/Global/GlobalConfig.cs b/XiaoXiaoRoBot/Global/GlobalConfig.cs new file mode 100644 index 0000000..e9657dd --- /dev/null +++ b/XiaoXiaoRoBot/Global/GlobalConfig.cs @@ -0,0 +1,18 @@ +using Lagrange.Core; +using Lagrange.Core.Common; +using RoBot.Start.Dto.ConfigDto; +using RoBot.Start.Keystore; + +namespace RoBot.Start.Global +{ + public class GlobalConfig + { + public static ConfigSetting ConfigSetting; + + public static BotDeviceInfo BotDeviceInfo; + + public static KeystoreInfo KeystoreInfo; + + public static BotContext BotContext; + } +} diff --git a/XiaoXiaoRoBot/Keystore/KeystoreConfig.cs b/XiaoXiaoRoBot/Keystore/KeystoreConfig.cs index 219baa9..365cd25 100644 --- a/XiaoXiaoRoBot/Keystore/KeystoreConfig.cs +++ b/XiaoXiaoRoBot/Keystore/KeystoreConfig.cs @@ -1,6 +1,6 @@ using System.Text.Json; using Lagrange.Core.Common; -using RoBot.Start.ConstValue; +using RoBot.Core.ConstValue; namespace RoBot.Start.Keystore { diff --git a/XiaoXiaoRoBot/Message/RoBotMessage.cs b/XiaoXiaoRoBot/Message/RoBotMessage.cs index 85b0c77..b2275f1 100644 --- a/XiaoXiaoRoBot/Message/RoBotMessage.cs +++ b/XiaoXiaoRoBot/Message/RoBotMessage.cs @@ -12,10 +12,10 @@ namespace RoBot.Start.Message /// 群组 /// 消息 /// - public static async Task SendMsg(this Lagrange.Core.BotContext bot, uint groupId, string message) + public static async Task SendMsg(this Lagrange.Core.BotContext bot, uint groupId, string message) { var groupMessageChain = MessageBuilder.Group(groupId).Text(message); - await bot.SendMessage(groupMessageChain.Build()); + return await bot.SendMessage(groupMessageChain.Build()); } } } diff --git a/XiaoXiaoRoBot/Program.cs b/XiaoXiaoRoBot/Program.cs index bf14f24..cf9faed 100644 --- a/XiaoXiaoRoBot/Program.cs +++ b/XiaoXiaoRoBot/Program.cs @@ -2,20 +2,17 @@ using Lagrange.Core.Common.Interface; using Lagrange.Core.Common.Interface.Api; using Lagrange.Core.Message; -using Lagrange.Core.Message.Entity; -using RoBot.Core.ConstValue; -using RoBot.Core.Redis; -using RoBot.Goods.Dto; -using RoBot.Goods.Service; +using RoBot.Core.Helper; +using RoBot.Start.Cmd; using RoBot.Start.Device; using RoBot.Start.Dto.ConfigDto; +using RoBot.Start.Global; using RoBot.Start.Keystore; using RoBot.Start.LogConfig; -using RoBot.Start.Message; using RoBot.Start.RoBotConfig; +Init(); -new RedisHelper(); // 登录状态 bool LoginSuccess = false; @@ -57,6 +54,7 @@ bot.Invoker.OnBotLogEvent += (sender, e) => RecordLog = false; LoginSuccess = true; _ = KeystoreConfig.SaveBotKeystore(bot.UpdateKeystore()); + LoadLoginConfig(); } }; @@ -82,88 +80,32 @@ if ((args.Length > 0 && args[0] == "qr") || !ReLogin) else { await bot.LoginByPassword(); + LoadLoginConfig(); } async Task HandleGroupMessage(MessageChain chain) { - // 判断是否是“@消息 + 文本” - if (chain.Count == 2 && - chain.FirstOrDefault(e => e is MentionEntity) is MentionEntity mention && - chain.FirstOrDefault(e => e is TextEntity) is TextEntity text) - { - // 判断是否@了机器人 - if (mention.Uin == systemConfig.BotQQ) - { - string inputText = text.Text?.Trim(); - - // 判断是否包含“查价格” - if (!string.IsNullOrEmpty(inputText) && inputText.Contains("查价格")) - { - // 提取物品名称 - var goodsName = inputText - .Split(' ', StringSplitOptions.RemoveEmptyEntries) - .FirstOrDefault(word => word != "查价格") - ?.Replace("查价格", "")?.Trim(); - - if (!string.IsNullOrWhiteSpace(goodsName)) - { - var goodsInfo = RedisHelper.Client.HGet(RedisPrefix.GoodsKey, goodsName); - - if (goodsInfo is not null) - { - await bot.SendMsg((uint)systemConfig.GroupQQ, - $"物品:{goodsInfo.Name}\n价格:{goodsInfo.Price}万\n收录时间:{goodsInfo.LastUpdateTime:yyyy-MM-dd HH:mm:ss}"); - } - else - { - await bot.SendMsg((uint)systemConfig.GroupQQ, "未收录"); - } - } - else - { - await bot.SendMsg((uint)systemConfig.GroupQQ, "请输入要查询的物品名称,例如:查价格 七星草"); - } - } - } - } + // 坊市生成上架命令 + await QueryGoodsUpShopPriceCmd.Execute(chain); + // 保存或更新物品价格 + await InertOrUpdateGoodsCmd.Execute(chain); + + // 查看物品信息命令 价格/数据更新时间 + await QueryGoodsInfoPriceCmd.Execute(chain); - foreach (var item in chain) - { - // 艾特消息 - if (item is MentionEntity me) - { - Logs.Write($"提及用户的 Uin {me.Uin} 提及用户的 Uid {me.Uid} 提及用户的昵称{me.Name}"); - } - // 文本消息 - else if (item is TextEntity) - { - TextEntity txe = item as TextEntity; - - if (string.IsNullOrWhiteSpace(txe.Text) is false) - { - Logs.Write(txe.Text); - if (txe.Text.Contains("不鼓励不保障")) - { - GoodsService.AnalysisGoodsText(txe.Text); - } - } - } - // 回复消息 - else if (item is ForwardEntity) - { - ForwardEntity frd = item as ForwardEntity; - - Logs.Write($"回复的目标消息 Seq {frd.Sequence} 发送者 Uid {frd.Uid} 回复的目标消息的发送者 Uin{frd.TargetUin}"); - } - - // 合并转发消息 - else if (item is MultiMsgEntity) - { - MultiMsgEntity mme = item as MultiMsgEntity; - - //Logs.Write($"回复的目标消息 Seq {frd.Sequence} 发送者 Uid {frd.Uid} 回复的目标消息的发送者 Uin{frd.TargetUin}"); - } - } return true; +} + +void Init() +{ + _ = new RedisHelper(); +} + +void LoadLoginConfig() +{ + GlobalConfig.ConfigSetting = systemConfig; + GlobalConfig.KeystoreInfo = _keyStore; + GlobalConfig.BotDeviceInfo = _deviceInfo; + GlobalConfig.BotContext = bot; } \ No newline at end of file diff --git a/XiaoXiaoRoBot/RoBot.Start.csproj b/XiaoXiaoRoBot/RoBot.Start.csproj index 9456cad..c258f19 100644 --- a/XiaoXiaoRoBot/RoBot.Start.csproj +++ b/XiaoXiaoRoBot/RoBot.Start.csproj @@ -28,7 +28,6 @@ - diff --git a/XiaoXiaoRoBot/RoBotConfig/RoBotConfig.cs b/XiaoXiaoRoBot/RoBotConfig/RoBotConfig.cs index 759c792..8372d78 100644 --- a/XiaoXiaoRoBot/RoBotConfig/RoBotConfig.cs +++ b/XiaoXiaoRoBot/RoBotConfig/RoBotConfig.cs @@ -1,5 +1,5 @@ using System.Text.Json; -using RoBot.Start.ConstValue; +using RoBot.Core.ConstValue; using RoBot.Start.Dto.ConfigDto; namespace RoBot.Start.RoBotConfig diff --git a/XiaoXiaoRoBot/Service/Dto/GoodsInfo.cs b/XiaoXiaoRoBot/Service/Dto/GoodsInfo.cs new file mode 100644 index 0000000..a3cb0c9 --- /dev/null +++ b/XiaoXiaoRoBot/Service/Dto/GoodsInfo.cs @@ -0,0 +1,32 @@ +using RoBot.Core; + +namespace RoBot.Start.Service.Dto +{ + public class GoodsInfo + { + /// + /// 物品名称 + /// + public string Name { get; set; } + + /// + /// 实际价格 + /// + public decimal Price { get; set; } + + /// + /// 展示价格 + /// + public string ShowPriceDesc { get; set; } + + /// + /// 价格更新时间 + /// + public DateTime LastUpdateTime { get; set; } + + /// + /// 数量 + /// + public int? Num { get; set; } + } +} diff --git a/XiaoXiaoRoBot/Service/Impl/GoodsService.cs b/XiaoXiaoRoBot/Service/Impl/GoodsService.cs new file mode 100644 index 0000000..62124a9 --- /dev/null +++ b/XiaoXiaoRoBot/Service/Impl/GoodsService.cs @@ -0,0 +1,45 @@ +using System.Text.RegularExpressions; +using RoBot.Core; +using RoBot.Core.ConstValue; +using RoBot.Core.Helper; +using RoBot.Start.Service.Dto; + +namespace RoBot.Start.Service.Impl +{ + public class GoodsService + { + private static Regex Regex = new Regex(@"价格[::](\d+(?:\.\d+)?[万亿])\s+([^\s]+)"); + + /// + /// 解析物品信息 + /// + /// + public static void AnalysisGoodsText(string text) + { + if (string.IsNullOrWhiteSpace(text)) return; + + List results = new(); + + MatchCollection matches = Regex.Matches(text); + + foreach (Match match in matches) + { + string price = match.Groups[1].Value; + string name = match.Groups[2].Value.Replace("\u200b", "").Replace("\u200c", "").Replace("\u200d", ""); // 去除零宽字符 + GoodsInfo gds = new() + { + Name = name, + Price = Utils.ParseChineseNumber(price), + ShowPriceDesc = price, + LastUpdateTime = DateTime.Now + }; + results.Add(gds); + } + + foreach (GoodsInfo item in results) + { + RedisHelper.Client.HSet(RedisPrefix.GoodsKey, item.Name, item); + } + } + } +}