feat: 坊市药材价格命令生成

main
LyMysterious 11 months ago
parent 64e3296595
commit e6d62962c1

@ -1,5 +1,8 @@
namespace RoBot.Core.ConstValue namespace RoBot.Core.ConstValue
{ {
/// <summary>
/// 常量
/// </summary>
public class Consts public class Consts
{ {
/// <summary> /// <summary>
@ -18,6 +21,9 @@
public const string Config = "config.json"; public const string Config = "config.json";
} }
/// <summary>
/// 缓存前缀
/// </summary>
public class RedisPrefix public class RedisPrefix
{ {
public const string GoodsKey = "GoodsInfo"; public const string GoodsKey = "GoodsInfo";

@ -1,8 +1,7 @@
using FreeRedis; using FreeRedis;
using Newtonsoft.Json; using Newtonsoft.Json;
using RoBot.Core.Helper;
namespace RoBot.Core.Redis namespace RoBot.Core.Helper
{ {
public class RedisHelper public class RedisHelper
{ {

@ -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;
}
}
}

@ -1,6 +1,6 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using RoBot.Core.ConstValue; using RoBot.Core.ConstValue;
using RoBot.Core.Redis; using RoBot.Core.Helper;
using RoBot.Goods.Dto; using RoBot.Goods.Dto;
namespace RoBot.Goods.Service namespace RoBot.Goods.Service

@ -1,14 +1,12 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.12.35728.132 d17.12 VisualStudioVersion = 17.12.35728.132
MinimumVisualStudioVersion = 10.0.40219.1 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}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lagrange.Core", "Lagrange.Core\Lagrange.Core\Lagrange.Core.csproj", "{C345D8FF-14D1-405B-802A-D062CA5B14B5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoBot.Start", "XiaoXiaoRoBot\RoBot.Start.csproj", "{236CE019-D997-4286-9E33-2D6473572156}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoBot.Start", "XiaoXiaoRoBot\RoBot.Start.csproj", "{236CE019-D997-4286-9E33-2D6473572156}"
EndProject 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}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoBot.Core", "RoBot.Core\RoBot.Core.csproj", "{E155F24D-17D8-4F43-8366-9AF6992E9DDE}"
EndProject EndProject
Global Global
@ -25,10 +23,6 @@ Global
{236CE019-D997-4286-9E33-2D6473572156}.Debug|Any CPU.Build.0 = Debug|Any CPU {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.ActiveCfg = Release|Any CPU
{236CE019-D997-4286-9E33-2D6473572156}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{E155F24D-17D8-4F43-8366-9AF6992E9DDE}.Debug|Any CPU.Build.0 = 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 {E155F24D-17D8-4F43-8366-9AF6992E9DDE}.Release|Any CPU.ActiveCfg = Release|Any CPU

@ -0,0 +1,32 @@
using Lagrange.Core.Message;
using Lagrange.Core.Message.Entity;
using RoBot.Start.Service.Impl;
namespace RoBot.Start.Cmd
{
/// <summary>
/// 保存或更新物品价格
/// </summary>
public class InertOrUpdateGoodsCmd
{
public static async Task<bool> 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;
}
}
}

@ -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
{
/// <summary>
/// 查看物品信息命令 价格/数据更新时间
/// </summary>
public class QueryGoodsInfoPriceCmd
{
public static async Task<bool> 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<GoodsInfo>(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;
}
}
}

@ -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
{
/// <summary>
/// 坊市上架命令
/// </summary>
public class QueryGoodsUpShopPriceCmd
{
public static async Task<bool> 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<TextEntity> convertList = list.Cast<TextEntity>().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;
}
/// <summary>
/// 计算药材
/// </summary>
/// <returns></returns>
private static async Task<bool> Herbal(string text)
{
List<GoodsInfo> 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<GoodsInfo>(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);
}
}
}

@ -1,20 +0,0 @@
namespace RoBot.Start.ConstValue
{
public class Consts
{
/// <summary>
/// 登录文件
/// </summary>
public const string KeystoreConfig = "keystore.json";
/// <summary>
/// 设备信息
/// </summary>
public const string DeviceConfig = "device.json";
/// <summary>
/// 配置文件
/// </summary>
public const string Config = "config.json";
}
}

@ -1,6 +1,6 @@
using System.Text.Json; using System.Text.Json;
using Lagrange.Core.Common; using Lagrange.Core.Common;
using RoBot.Start.ConstValue; using RoBot.Core.ConstValue;
namespace RoBot.Start.Device namespace RoBot.Start.Device
{ {

@ -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;
}
}

@ -1,6 +1,6 @@
using System.Text.Json; using System.Text.Json;
using Lagrange.Core.Common; using Lagrange.Core.Common;
using RoBot.Start.ConstValue; using RoBot.Core.ConstValue;
namespace RoBot.Start.Keystore namespace RoBot.Start.Keystore
{ {

@ -12,10 +12,10 @@ namespace RoBot.Start.Message
/// <param name="groupId">群组</param> /// <param name="groupId">群组</param>
/// <param name="message">消息</param> /// <param name="message">消息</param>
/// <returns></returns> /// <returns></returns>
public static async Task SendMsg(this Lagrange.Core.BotContext bot, uint groupId, string message) public static async Task<MessageResult> SendMsg(this Lagrange.Core.BotContext bot, uint groupId, string message)
{ {
var groupMessageChain = MessageBuilder.Group(groupId).Text(message); var groupMessageChain = MessageBuilder.Group(groupId).Text(message);
await bot.SendMessage(groupMessageChain.Build()); return await bot.SendMessage(groupMessageChain.Build());
} }
} }
} }

@ -2,20 +2,17 @@
using Lagrange.Core.Common.Interface; using Lagrange.Core.Common.Interface;
using Lagrange.Core.Common.Interface.Api; using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message; using Lagrange.Core.Message;
using Lagrange.Core.Message.Entity; using RoBot.Core.Helper;
using RoBot.Core.ConstValue; using RoBot.Start.Cmd;
using RoBot.Core.Redis;
using RoBot.Goods.Dto;
using RoBot.Goods.Service;
using RoBot.Start.Device; using RoBot.Start.Device;
using RoBot.Start.Dto.ConfigDto; using RoBot.Start.Dto.ConfigDto;
using RoBot.Start.Global;
using RoBot.Start.Keystore; using RoBot.Start.Keystore;
using RoBot.Start.LogConfig; using RoBot.Start.LogConfig;
using RoBot.Start.Message;
using RoBot.Start.RoBotConfig; using RoBot.Start.RoBotConfig;
Init();
new RedisHelper();
// 登录状态 // 登录状态
bool LoginSuccess = false; bool LoginSuccess = false;
@ -57,6 +54,7 @@ bot.Invoker.OnBotLogEvent += (sender, e) =>
RecordLog = false; RecordLog = false;
LoginSuccess = true; LoginSuccess = true;
_ = KeystoreConfig.SaveBotKeystore(bot.UpdateKeystore()); _ = KeystoreConfig.SaveBotKeystore(bot.UpdateKeystore());
LoadLoginConfig();
} }
}; };
@ -82,88 +80,32 @@ if ((args.Length > 0 && args[0] == "qr") || !ReLogin)
else else
{ {
await bot.LoginByPassword(); await bot.LoginByPassword();
LoadLoginConfig();
} }
async Task<bool> HandleGroupMessage(MessageChain chain) async Task<bool> HandleGroupMessage(MessageChain chain)
{ {
// 判断是否是“@消息 + 文本” // 坊市生成上架命令
if (chain.Count == 2 && await QueryGoodsUpShopPriceCmd.Execute(chain);
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<GoodsInfo>(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 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; return true;
} }
void Init()
{
_ = new RedisHelper();
}
void LoadLoginConfig()
{
GlobalConfig.ConfigSetting = systemConfig;
GlobalConfig.KeystoreInfo = _keyStore;
GlobalConfig.BotDeviceInfo = _deviceInfo;
GlobalConfig.BotContext = bot;
}

@ -28,7 +28,6 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Lagrange.Core\Lagrange.Core\Lagrange.Core.csproj" /> <ProjectReference Include="..\Lagrange.Core\Lagrange.Core\Lagrange.Core.csproj" />
<ProjectReference Include="..\RoBot.Core\RoBot.Core.csproj" /> <ProjectReference Include="..\RoBot.Core\RoBot.Core.csproj" />
<ProjectReference Include="..\RoBot.Goods\RoBot.Goods.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -1,5 +1,5 @@
using System.Text.Json; using System.Text.Json;
using RoBot.Start.ConstValue; using RoBot.Core.ConstValue;
using RoBot.Start.Dto.ConfigDto; using RoBot.Start.Dto.ConfigDto;
namespace RoBot.Start.RoBotConfig namespace RoBot.Start.RoBotConfig

@ -0,0 +1,32 @@
using RoBot.Core;
namespace RoBot.Start.Service.Dto
{
public class GoodsInfo
{
/// <summary>
/// 物品名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 实际价格
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// 展示价格
/// </summary>
public string ShowPriceDesc { get; set; }
/// <summary>
/// 价格更新时间
/// </summary>
public DateTime LastUpdateTime { get; set; }
/// <summary>
/// 数量
/// </summary>
public int? Num { get; set; }
}
}

@ -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]+)");
/// <summary>
/// 解析物品信息
/// </summary>
/// <param name="text"></param>
public static void AnalysisGoodsText(string text)
{
if (string.IsNullOrWhiteSpace(text)) return;
List<GoodsInfo> 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);
}
}
}
}
Loading…
Cancel
Save