365 lines
16 KiB
C#
365 lines
16 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Net.Http;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using AlibabaCloud.SDK.Dingtalkoauth2_1_0.Models;
|
||
using MySql.Data.MySqlClient;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using Tea;
|
||
using YiDa_WinForm.Config;
|
||
using YiDa_WinForm.Model;
|
||
using YiDa_WinForm.Service.Mqtt;
|
||
|
||
namespace YiDa_WinForm.Service
|
||
{
|
||
public class YiDaUploadService
|
||
{
|
||
private readonly ButtonOperationService _buttonService;
|
||
|
||
// 数据库连接配置
|
||
private readonly string _connectionString = AppConfig.MySqlConnectionString;
|
||
|
||
// 通知UI层
|
||
public event Action<string> MessageReceived;
|
||
|
||
// 钉钉token
|
||
static readonly string _tokenAppKey = AppConfig.YiDaTokenAppKey;
|
||
static readonly string _tokenAppSecret = AppConfig.YiDaTokenAppSecret;
|
||
|
||
// 宜搭上传配置
|
||
static readonly string _appType = AppConfig.YiDaAppType;
|
||
static readonly string _systemToken = AppConfig.YiDaSystemToken;
|
||
static readonly string _userId = AppConfig.YiDaUserId;
|
||
static readonly string _formUuid = AppConfig.YiDaFormUuid;
|
||
static readonly string _processCode = AppConfig.YiDaProcessCode;
|
||
|
||
// 报废图片
|
||
public string _reformationPicture = null;
|
||
|
||
/// <summary>
|
||
/// 创建 OAuth2 客户端(获取 token 用)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static AlibabaCloud.SDK.Dingtalkoauth2_1_0.Client CreateClient()
|
||
{
|
||
AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config();
|
||
config.Protocol = "https";
|
||
config.RegionId = "central";
|
||
return new AlibabaCloud.SDK.Dingtalkoauth2_1_0.Client(config);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取钉钉 AccessToken
|
||
/// </summary>
|
||
/// <returns>AccessToken 字符串</returns>
|
||
public string GetDingDingToken()
|
||
{
|
||
string strToken = string.Empty;
|
||
GetAccessTokenResponse token = null;
|
||
|
||
var client = CreateClient();
|
||
var getAccessTokenRequest = new GetAccessTokenRequest
|
||
{
|
||
AppKey = _tokenAppKey,
|
||
AppSecret = _tokenAppSecret,
|
||
};
|
||
|
||
try
|
||
{
|
||
token = client.GetAccessToken(getAccessTokenRequest);
|
||
}
|
||
catch (TeaException err)
|
||
{
|
||
string errorMsg = $"获取钉钉Token异常【TeaException】:错误码={err.Code},错误信息={err.Message}";
|
||
Console.WriteLine(errorMsg);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
string errorMsg = $"获取 token 异常:{ex.Message}";
|
||
Console.WriteLine(errorMsg);
|
||
}
|
||
|
||
return token != null ? token.Body.AccessToken : string.Empty;
|
||
}
|
||
|
||
//加上逻辑判断的上传
|
||
//记载宜搭上传成功日志
|
||
private static async Task RecordSuccessLog(List<MqttModel> mqttLists)
|
||
{
|
||
if (mqttLists != null && mqttLists.Count > 0)
|
||
{
|
||
var buttonService = new ButtonOperationService();
|
||
await buttonService.CreateSuccessLog(mqttLists);
|
||
}
|
||
}
|
||
|
||
//新版宜搭API
|
||
private static AlibabaCloud.SDK.Dingtalkyida_2_0.Client CreateYiDaClient()
|
||
{
|
||
AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config();
|
||
config.Protocol = "https";
|
||
config.RegionId = "central";
|
||
return new AlibabaCloud.SDK.Dingtalkyida_2_0.Client(config);
|
||
}
|
||
|
||
|
||
public async Task UploadDatabaseDataToYiDaWithLogging(string accessToken, List<YiDaModel> yidaLists,
|
||
List<MqttModel> mqttLists, MainForm form)
|
||
{
|
||
var client = CreateYiDaClient();
|
||
|
||
AlibabaCloud.SDK.Dingtalkyida_2_0.Models.StartInstanceHeaders startInstanceHeaders =
|
||
new AlibabaCloud.SDK.Dingtalkyida_2_0.Models.StartInstanceHeaders();
|
||
|
||
startInstanceHeaders.XAcsDingtalkAccessToken = accessToken;
|
||
|
||
|
||
for (int i = 0; i < yidaLists.Count; i++)
|
||
{
|
||
var item = yidaLists[i];
|
||
var mqttItem = mqttLists[i];
|
||
|
||
var dataDict = new Dictionary<string, object>
|
||
{
|
||
//左侧为宜搭表中字段唯一标识值,右侧为要传递给宜搭的值。
|
||
{ "textField_mha98neu", item.textField_mha98neu }, //供应商代码
|
||
{ "textField_mha98nev", item.textField_mha98nev }, //供应商名称
|
||
{ "textField_mha98new", item.textField_mha98new }, //车型
|
||
{ "textField_mha98nex", item.textField_mha98nex }, //零件号
|
||
{ "textField_mha98ney", item.textField_mha98ney }, //零件名称
|
||
|
||
{ "textField_mha98nf1", item.textField_mha98nf1 }, //参数名
|
||
{ "textField_mhx44i2i", item.textField_mhx44i2i }, //参数值
|
||
{ "textField_mhx44i2j", item.textField_mhx44i2j }, //下公差
|
||
{ "textField_mhx44i2k", item.textField_mhx44i2k }, //上公差
|
||
{ "textField_mha98nf7", item.textField_mha98nf7 }, //零件责任人
|
||
{ "textField_mhlvt8ht", DateTime.Now.ToString("yyyy-MM-dd") }, //写入时间
|
||
{ "textField_mha98nf5", item.textField_mha98nf5 }, //合格判断
|
||
{ "textField_mha98nf0", item.textField_mha98nf0 }, //工位
|
||
{ "textField_mha98nfh", item.textField_mha98nfh } //外保负责人
|
||
};
|
||
|
||
string jsonData = JsonConvert.SerializeObject(dataDict);
|
||
|
||
AlibabaCloud.SDK.Dingtalkyida_2_0.Models.StartInstanceRequest startInstanceRequest =
|
||
new AlibabaCloud.SDK.Dingtalkyida_2_0.Models.StartInstanceRequest
|
||
{
|
||
AppType = _appType,
|
||
SystemToken = _systemToken,
|
||
UserId = _userId,
|
||
Language = "zh_CN",
|
||
FormUuid = _formUuid,
|
||
FormDataJson = jsonData,
|
||
ProcessCode = _processCode,
|
||
};
|
||
try
|
||
{
|
||
var response = client.StartInstanceWithOptions(startInstanceRequest, startInstanceHeaders,
|
||
new AlibabaCloud.TeaUtil.Models.RuntimeOptions());
|
||
|
||
if (response != null && response.Body != null)
|
||
{
|
||
// 上传成功就存入 MySQL
|
||
await RecordSuccessLog(mqttLists);
|
||
string logData = JsonConvert.SerializeObject(dataDict, Formatting.Indented);
|
||
form.AppendLog($"上传数据成功:\r\n{logData}");
|
||
Console.WriteLine($"上传数据成功:\r\n{logData}");
|
||
}
|
||
else
|
||
{
|
||
Console.WriteLine($"上传返回空结果,数据未存入 MySQL。");
|
||
string logData = JsonConvert.SerializeObject(dataDict, Formatting.Indented);
|
||
form.AppendLog($"上传返回空结果,数据未存入 MySQL:\r\n{logData}");
|
||
}
|
||
}
|
||
catch (TeaException err)
|
||
{
|
||
Console.WriteLine($"上传异常:{err.Code} --- {err.Message}");
|
||
string logData = JsonConvert.SerializeObject(dataDict, Formatting.Indented);
|
||
form.AppendLog($"上传异常:{err.Code} --- {err.Message}\r\n数据:\r\n{logData}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"上传异常:{ex.Message}");
|
||
string logData = JsonConvert.SerializeObject(dataDict, Formatting.Indented);
|
||
form.AppendLog($"上传异常:{ex.Message}\r\n数据:\r\n{logData}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算钉钉加签
|
||
/// </summary>
|
||
/// <param name="timestamp"></param>
|
||
/// <param name="secret"></param>
|
||
/// <returns></returns>
|
||
static string CalcSign(long timestamp, string secret)
|
||
{
|
||
string stringToSign = $"{timestamp}\n{secret}";
|
||
var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
|
||
byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
|
||
return Convert.ToBase64String(hashBytes);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 图片上传至钉钉群
|
||
/// </summary>
|
||
/// <param name="token"></param>
|
||
/// <param name="filePath"></param>
|
||
public async Task UploadScrapCertificate(string token, string filePath)
|
||
{
|
||
//string chatId = "chatxxxxxxxx";
|
||
//long fileLen = new FileInfo(filePath).Length;
|
||
// 1. 初始化
|
||
HttpClient client = new HttpClient
|
||
{
|
||
BaseAddress = new Uri("https://oapi.dingtalk.com")
|
||
};
|
||
var form = new MultipartFormDataContent();
|
||
var fileStream = File.OpenRead(filePath);
|
||
var streamContent = new StreamContent(fileStream);
|
||
streamContent.Headers.ContentType =
|
||
new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg"); // 或 image/png
|
||
form.Add(streamContent, "media", Path.GetFileName(filePath));
|
||
form.Add(new StringContent("image"), "type"); // 接口要求字段 type=image
|
||
|
||
// 2. 发送请求上传文件(access_token 放查询串)
|
||
var url = $"/media/upload?access_token={token}";
|
||
var resp = await client.PostAsync(url, form);
|
||
resp.EnsureSuccessStatusCode();
|
||
|
||
string json = await resp.Content.ReadAsStringAsync();
|
||
JObject jo = JObject.Parse(json);
|
||
string mediaId = jo["media_id"].Value<string>();
|
||
|
||
MergeAndSaveData(mediaId);
|
||
|
||
Console.WriteLine($"上传完成,mediaId = {mediaId}");
|
||
|
||
// 3. 发送群消息
|
||
var webhook =
|
||
"https://oapi.dingtalk.com/robot/send?access_token=4dc45fc8b61d58f49b7c55c5941aab485d5d07b88ce68cf4e1b8518ac79419f2";
|
||
string secret = "SEC5462c700f1b98570014e584e3e304eee2e6e1df9aa2e6d1c529337437559f301"; // 机器人详情页复制
|
||
long ts = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||
string ymdhms = DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||
string sign = CalcSign(ts, secret); // HMACSHA256→Base64
|
||
string webhook_url = $"{webhook}×tamp={ts}&sign={sign}";
|
||
//var msg = new
|
||
//{
|
||
// msgtype = "text",
|
||
// text = new { content = $"报废凭证拍照({ymdhms}):" }
|
||
//};
|
||
var msg = new
|
||
{
|
||
msgtype = "markdown",
|
||
markdown = new
|
||
{
|
||
title = "报废证据上传",
|
||
text = $"## 报废凭证照片\n<img src=\"{mediaId}\" width=\"200\" />\n\n> 时间:{ymdhms}"
|
||
}
|
||
};
|
||
string transJson = JsonConvert.SerializeObject(msg);
|
||
var resp2 = await client.PostAsync(webhook_url,
|
||
new StringContent(transJson, Encoding.UTF8, "application/json"));
|
||
resp2.EnsureSuccessStatusCode();
|
||
|
||
//var msg3 = new
|
||
//{
|
||
// msgtype = "image",
|
||
// image = new { picURL = $"{mediaId}" }
|
||
//};
|
||
//string transJson3 = JsonConvert.SerializeObject(msg3);
|
||
//var resp3 = await client.PostAsync(webhook_url, new StringContent(transJson3, Encoding.UTF8, "application/json"));
|
||
//resp3.EnsureSuccessStatusCode();
|
||
|
||
string json2 = await resp2.Content.ReadAsStringAsync();
|
||
JObject res2 = JObject.Parse(json2);
|
||
string errmsg = res2["errmsg"].Value<string>();
|
||
Console.WriteLine($"发送群消息完成,msg = {errmsg}");
|
||
}
|
||
|
||
private async Task MergeAndSaveData(string mediaId)
|
||
{
|
||
try
|
||
{
|
||
// 读取最新注塑机数据的receive_data(JSON字符串)
|
||
string latestReceiveData = null;
|
||
long latestId = 0; // 用主键ID定位最新数据,避免time类型问题
|
||
using (var conn = new MySqlConnection(_connectionString))
|
||
{
|
||
await conn.OpenAsync();
|
||
|
||
// 查询最新注塑机数据(device1/2)
|
||
string getLatestSql = @"SELECT id, receive_data FROM yida_mqtt_message
|
||
WHERE device_code IN ('device1','device2')
|
||
ORDER BY id DESC LIMIT 1";
|
||
using (var cmd = new MySqlCommand(getLatestSql, conn))
|
||
{
|
||
using (var reader = await cmd.ExecuteReaderAsync())
|
||
{
|
||
if (await reader.ReadAsync())
|
||
{
|
||
latestId = reader.GetInt64(0);
|
||
latestReceiveData = reader.IsDBNull(1) ? null : reader.GetString(1);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 无注塑机数据时直接返回
|
||
if (string.IsNullOrEmpty(latestReceiveData))
|
||
{
|
||
MessageReceived?.Invoke("数据库中无注塑机数据,无法合并");
|
||
return;
|
||
}
|
||
|
||
// 反序列化注塑机JSON数据
|
||
var dataModel = JsonConvert.DeserializeObject<SQLDataModel>(latestReceiveData);
|
||
if (dataModel == null || dataModel.@params == null)
|
||
{
|
||
dataModel = new SQLDataModel
|
||
{
|
||
time = DateTime.Now.Millisecond,
|
||
@params = new SQLParamModel()
|
||
};
|
||
}
|
||
|
||
dataModel.@params.BU = mediaId;
|
||
|
||
_reformationPicture = mediaId;
|
||
|
||
// 重新序列化为JSON
|
||
string mergedData = JsonConvert.SerializeObject(dataModel);
|
||
|
||
// 更新数据库(用ID定位,避免time类型问题)
|
||
string updateSql = @"UPDATE yida_mqtt_message
|
||
SET receive_data = @mergedData
|
||
WHERE id = @latestId";
|
||
using (var updateCmd = new MySqlCommand(updateSql, conn))
|
||
{
|
||
updateCmd.Parameters.AddWithValue("@mergedData", mergedData);
|
||
updateCmd.Parameters.AddWithValue("@latestId", latestId);
|
||
int affectedRows = await updateCmd.ExecuteNonQueryAsync();
|
||
|
||
if (affectedRows > 0)
|
||
{
|
||
MessageReceived?.Invoke($"成功合并BU字段:{mediaId},更新ID={latestId}");
|
||
}
|
||
else
|
||
{
|
||
MessageReceived?.Invoke("更新失败:未找到匹配的注塑机数据");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine(ex);
|
||
throw;
|
||
}
|
||
}
|
||
}
|
||
} |