diff --git a/Ramitta/Ramitta.cs b/Ramitta/Ramitta.cs
index 370b963..1764674 100644
--- a/Ramitta/Ramitta.cs
+++ b/Ramitta/Ramitta.cs
@@ -118,6 +118,31 @@ namespace Ramitta.lib
#endregion
#region 文件解析
+ public static string? GetExeVersion(string exePath)
+ {
+ try
+ {
+ if (!File.Exists(exePath))
+ {
+ return null; // 文件不存在时返回null
+ }
+
+ var versionInfo = FileVersionInfo.GetVersionInfo(exePath);
+ string? version = versionInfo.FileVersion;
+
+ // 如果FileVersion为空,尝试使用ProductVersion
+ if (string.IsNullOrEmpty(version))
+ {
+ version = versionInfo.ProductVersion;
+ }
+
+ return string.IsNullOrEmpty(version) ? null : version;
+ }
+ catch
+ {
+ return null; // 出现任何异常都返回null
+ }
+ }
public static bool IsPathExist(string databasePath)
{
if (string.IsNullOrWhiteSpace(databasePath))
diff --git a/Ramitta/WeComRobot.cs b/Ramitta/WeComRobot.cs
new file mode 100644
index 0000000..ea900ca
--- /dev/null
+++ b/Ramitta/WeComRobot.cs
@@ -0,0 +1,259 @@
+锘縰sing HelixToolkit.Maths;
+using NPOI.HPSF;
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+namespace Ramitta
+{
+ public class WeComRobot
+ {
+ private readonly string _webhookUrl;
+ private readonly HttpClient _httpClient;
+
+ public WeComRobot(string webhookUrl)
+ {
+ _webhookUrl = webhookUrl;
+ _httpClient = new HttpClient();
+ }
+
+ ///
+ /// 鍙戦佹枃鏈秷鎭
+ ///
+ public async Task SendTextMessageAsync(string content, string[] mentionedList = null, string[] mentionedMobileList = null)
+ {
+ var message = new
+ {
+ msgtype = "text",
+ text = new
+ {
+ content = content,
+ mentioned_list = mentionedList,
+ mentioned_mobile_list = mentionedMobileList
+ }
+ };
+
+ return await SendMessageAsync(message);
+ }
+
+ ///
+ /// 鍙戦丮arkdown娑堟伅
+ ///
+ public async Task SendMarkdownMessageAsync(string content)
+ {
+ var message = new
+ {
+ msgtype = "markdown",
+ markdown = new
+ {
+ content = content
+ }
+ };
+
+ return await SendMessageAsync(message);
+ }
+
+ ///
+ /// 鍙戦佸浘鐗囨秷鎭
+ ///
+ public async Task SendImageMessageAsync(string base64, string md5)
+ {
+ var message = new
+ {
+ msgtype = "image",
+ image = new
+ {
+ base64 = base64,
+ md5 = md5
+ }
+ };
+
+ return await SendMessageAsync(message);
+ }
+
+ ///
+ /// 鍙戦佸浘鏂囨秷鎭
+ ///
+ public async Task SendNewsMessageAsync(Article[] articles)
+ {
+ var message = new
+ {
+ msgtype = "news",
+ news = new
+ {
+ articles = articles
+ }
+ };
+
+ return await SendMessageAsync(message);
+ }
+
+ ///
+ /// 鍙戦佹枃浠舵秷鎭
+ ///
+ public async Task SendFileMessageAsync(string mediaId)
+ {
+ var message = new
+ {
+ msgtype = "file",
+ file = new
+ {
+ media_id = mediaId
+ }
+ };
+
+ return await SendMessageAsync(message);
+ }
+
+ private async Task SendMessageAsync(object message)
+ {
+ try
+ {
+ var json = JsonSerializer.Serialize(message);
+ var content = new StringContent(json, Encoding.UTF8, "application/json");
+
+ var response = await _httpClient.PostAsync(_webhookUrl, content);
+ var responseContent = await response.Content.ReadAsStringAsync();
+
+ if (response.IsSuccessStatusCode)
+ {
+ var result = JsonSerializer.Deserialize(responseContent);
+ return result?.errcode == 0;
+ }
+
+ Console.WriteLine($"鍙戦佸け璐: {responseContent}");
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"鍙戦佹秷鎭紓甯: {ex.Message}");
+ return false;
+ }
+ }
+ ///
+ /// 涓婁紶鏂囦欢鍒颁紒涓氬井淇″苟鑾峰彇media_id (淇鐗)
+ ///
+ public async Task UploadFileAsync(string filePath,string? fileName=null)
+ {
+ try
+ {
+ // 1. 浠巜ebhook鍦板潃涓彁鍙杒ey
+ var uri = new Uri(_webhookUrl);
+ var key = System.Web.HttpUtility.ParseQueryString(uri.Query)["key"];
+ string uploadUrl = $"https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key={key}&type=file";
+
+ // 2. 鍑嗗鏂囦欢鍜岃竟鐣
+ if(fileName==null) fileName = Path.GetFileName(filePath);
+ var fileBytes = await File.ReadAllBytesAsync(filePath);
+ string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x"); // 闅忔満杈圭晫瀛楃涓
+ string startBoundary = "--" + boundary;
+ string endBoundary = "--" + boundary + "--";
+
+ // 3. 鍒涘缓骞堕厤缃瓾ttpWebRequest
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uploadUrl);
+ request.Method = "POST";
+ request.ContentType = "multipart/form-data; boundary=" + boundary;
+ request.Timeout = 30000; // 鍙牴鎹渶瑕佽皟鏁磋秴鏃
+
+ // 4. 鎵嬪姩鏋勫缓骞跺啓鍏ヨ姹備綋锛堝叧閿楠わ級
+ using (Stream requestStream = await request.GetRequestStreamAsync())
+ {
+ using (var writer = new StreamWriter(requestStream, Encoding.UTF8, 1024, true))
+ {
+ // 4.1 鍐欏叆寮濮嬭竟鐣 (蹇呴』鏈夊洖杞︽崲琛)
+ await writer.WriteAsync(startBoundary + "\r\n");
+ await writer.FlushAsync();
+
+ // 4.2 鍐欏叆鏂囦欢澶翠俊鎭 (娉ㄦ剰鏍煎紡涓殑鍙屽紩鍙)
+ string header = $"Content-Disposition: form-data; name=\"media\"; filename=\"{fileName}\"\r\n";
+ header += "Content-Type: application/octet-stream\r\n";
+ header += "\r\n"; // 鏂囦欢澶寸粨鏉熷悗闇瑕佷竴涓澶栫殑绌鸿锛堝嵆涓や釜杩炵画鐨刓r\n锛
+ await writer.WriteAsync(header);
+ await writer.FlushAsync();
+
+ // 4.3 鐩存帴鍐欏叆鏂囦欢瀛楄妭
+ await requestStream.WriteAsync(fileBytes, 0, fileBytes.Length);
+ await writer.WriteAsync("\r\n"); // 鏂囦欢鍐呭鍚庨渶瑕佷竴涓洖杞︽崲琛
+ await writer.FlushAsync();
+
+ // 4.4 鍐欏叆缁撴潫杈圭晫
+ await writer.WriteAsync(endBoundary + "\r\n");
+ await writer.FlushAsync();
+ }
+ }
+
+ // 5. 鑾峰彇骞惰В鏋愬搷搴
+ using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
+ using (StreamReader reader = new StreamReader(response.GetResponseStream()))
+ {
+ string responseContent = await reader.ReadToEndAsync();
+ Console.WriteLine($"涓婁紶鍝嶅簲: {responseContent}");
+
+ using (var doc = JsonDocument.Parse(responseContent))
+ {
+ if (doc.RootElement.TryGetProperty("media_id", out var mediaIdElement))
+ {
+ return mediaIdElement.GetString();
+ }
+ else
+ {
+ // 瑙f瀽閿欒淇℃伅
+ var errcode = doc.RootElement.GetProperty("errcode").GetInt32();
+ var errmsg = doc.RootElement.GetProperty("errmsg").GetString();
+ Console.WriteLine($"鏂囦欢涓婁紶澶辫触: errcode={errcode}, errmsg={errmsg}");
+ return null;
+ }
+ }
+ }
+ }
+ catch (WebException ex)
+ {
+ // 灏濊瘯璇诲彇閿欒鍝嶅簲浣
+ if (ex.Response is HttpWebResponse errorResponse)
+ {
+ using (var reader = new StreamReader(errorResponse.GetResponseStream()))
+ {
+ string errorContent = await reader.ReadToEndAsync();
+ Console.WriteLine($"HTTP璇锋眰澶辫触 ({errorResponse.StatusCode}): {errorContent}");
+ }
+ }
+ else
+ {
+ Console.WriteLine($"缃戠粶璇锋眰寮傚父: {ex.Message}");
+ }
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"鏂囦欢涓婁紶杩囩▼寮傚父: {ex.Message}");
+ return null;
+ }
+ }
+
+
+ }
+
+ ///
+ /// 鍥炬枃娑堟伅鏂囩珷
+ ///
+ public class Article
+ {
+ public string title { get; set; }
+ public string description { get; set; }
+ public string url { get; set; }
+ public string picurl { get; set; }
+ }
+
+ ///
+ /// 浼佷笟寰俊鍝嶅簲
+ ///
+ public class WeComResponse
+ {
+ public int errcode { get; set; }
+ public string errmsg { get; set; }
+ }
+
+}
\ No newline at end of file