Laservall_manager_system/VOL.YSErp/Services/Biz/YSERPService.cs

376 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using SqlSugar;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Web;
using VOL.Core.Services;
using VOL.YSErp.Models;
using VOL.YSErp.Models.Biz;
using static Dm.net.buffer.ByteArrayBuffer;
namespace VOL.YSErp.Services.Biz
{
public class YSERPService
{
private readonly string _apiUrl;
private readonly string _appKey;
private readonly string _appSecret;
private string _accessToken;
private DateTime? _tokenExpiry;
private readonly SemaphoreSlim _tokenLock = new SemaphoreSlim(1, 1);
private SystemToken _token;
private readonly HttpClient _httpClient;
// YS API URLs
private readonly string _tokenUrl;
private readonly string _employeeListUrl;
private readonly string _deptListUrl;
private readonly string _empInfoUrl;
private static readonly string[] resposeSuccessCodes = ["200", "00000"];
public YSERPService(SystemToken token, YSConfig config)
{
_token = token;
_apiUrl = config.ApiUrl.TrimEnd('/');
_appKey = config.Appkey;
_appSecret = config.AppSecret;
_httpClient = new HttpClient();
_tokenUrl = $"{_apiUrl}/iuap-api-auth/open-auth/selfAppAuth/getAccessToken";
_employeeListUrl = $"{_apiUrl}/iuap-api-gateway/yonbip/hrcloud/staff/listdetailmdd";
//_updateEmployeeUrl = $"{_apiUrl}/iuap-api-gateway/yonbip/hrcloud/batchInsertOrUpdateDetailNew";
_deptListUrl = $"{_apiUrl}/iuap-api-gateway/yonbip/digitalModel/basedoc/dept/list";
_empInfoUrl = $"{_apiUrl}/iuap-api-gateway/yonbip/hrcloud/HRCloud/getStaffDetail";
}
private string GenerateSignature(Dictionary<string, string> parameters)
{
try
{
var filteredParams = new Dictionary<string, string>();
foreach (var param in parameters)
{
if (param.Key != "signature")
{
filteredParams[param.Key] = param.Value;
}
}
var sortedParams = new SortedDictionary<string, string>(filteredParams);
var paramStr = string.Join("", sortedParams.Select(p => p.Key + p.Value));
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(_appSecret)))
{
var signatureBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(paramStr));
return Convert.ToBase64String(signatureBytes);
}
}
catch (Exception ex)
{
//_logger.LogError(ex, "生成签名时出错");
return null;
}
}
private async Task<(string Token, DateTime Expiry)?> GetAccessTokenAsync()
{
try
{
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
var parameters = new Dictionary<string, string>
{
["appKey"] = _appKey,
["timestamp"] = timestamp
};
var signature = GenerateSignature(parameters);
if (string.IsNullOrEmpty(signature))
{
return null;
}
parameters["signature"] = signature;
var queryString = string.Join("&", parameters.Select(p =>
$"{p.Key}={HttpUtility.UrlEncode(p.Value)}"));
var fullUrl = $"{_tokenUrl}?{queryString}";
var response = await _httpClient.GetAsync(fullUrl);
if (!response.IsSuccessStatusCode)
{
//_logger.LogError($"获取access_token失败: HTTP {response.StatusCode}");
return null;
}
var content = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<JsonElement>(content);
if (data.GetProperty("code").GetString() != "00000")
{
var errorMsg = data.GetProperty("message").GetString();
//_logger.LogError($"获取access_token失败: {errorMsg}");
return null;
}
var tokenData = data.GetProperty("data");
var accessToken = tokenData.GetProperty("access_token").GetString();
var expireSeconds = tokenData.GetProperty("expire").GetInt32();
return (accessToken, DateTime.Now.AddSeconds(expireSeconds - 300));
}
catch (Exception ex)
{
//_logger.LogError(ex, "获取access_token时出错");
return null;
}
}
private async Task<string> GetValidTokenAsync()
{
await _tokenLock.WaitAsync();
try
{
if (string.IsNullOrEmpty(_token.Token) || !_token.IsTokenExpiry())
{
//_logger.LogInformation("YS access_token已过期重新获取...");
var result = await GetAccessTokenAsync();
if (result.HasValue)
{
(_accessToken, _tokenExpiry) = result.Value;
_token.Token = _accessToken;
_token.TokenEndTime = _tokenExpiry ?? DateTime.Now;
}
else
{
//_logger.LogError("无法获取有效的YS access_token");
return null;
}
}
return _token.Token;
}
finally
{
_tokenLock.Release();
}
}
public async Task<List<YSERPEmployee>> GetAllEmployeesAsync()
{
var token = await GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
{
return [];
}
var allEmployees = new List<YSERPEmployee>();
var pageIndex = 1;
const int pageSize = 50;
//Logger.Info($"员工信息API: {_employeeListUrl}");
while (true)
{
try
{
//Logger.Info($"获取YS员工数据第 {pageIndex} 页...");
var payload = new
{
pageIndex,
pageSize,
};
var request = new HttpRequestMessage(HttpMethod.Post, $"{_employeeListUrl}?access_token={token}")
{
Content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json")
};
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Logger.Error("认证失败: 无效的API令牌或权限不足");
_accessToken = null;
//return [];
throw new Exception("认证失败: 无效的YS ERP API令牌或权限不足");
}
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<YSERPPagedResponse<YSERPEmployee>>(content);
if (data == null || !resposeSuccessCodes.Contains(data.code))
{
var errorMsg = data?.message;
Logger.Error($"API业务错误: {errorMsg}");
throw new Exception($"API业务错误: 【{errorMsg}】");
}
var recordList = data.data.recordList;
if (recordList?.Count == 0)
{
//Logger.Info("没有更多员工记录");
break;
}
var toAdd = recordList.Where(r => !allEmployees.Any(e => e.id == r.id)).ToList();
allEmployees.AddRange(toAdd);
var haveNext = data.data.haveNextPage;
var pageCount = data.data.pageCount;
if (!haveNext || pageIndex >= pageCount)
{
break;
}
//Logger.Info($"第 {pageIndex}/{pageCount} 页,获取 {recordList.Count} 条员工记录");
pageIndex++;
await Task.Delay(500); // 避免请求过快
}
catch (Exception ex)
{
Logger.Error($"获取员工数据失败,{ex}");
throw;
}
}
//_logger.LogInformation($"共获取 {allEmployees.Count} 条YS员工记录");
return allEmployees;
}
public async Task<List<YSERPDepartment>> GetAllDepartmentsAsync()
{
var token = await GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
{
return [];
}
var allDepts = new List<YSERPDepartment>();
try
{
var payload = new
{
data = new
{
code = new List<string>(),
pubts = new List<string>() { "1900-01-01 00:00:00" }, // 必须带一个参数,不然接口返回的数据格式有问题 2025年9月26日
}
};
var request = new HttpRequestMessage(HttpMethod.Post, $"{_deptListUrl}?access_token={token}")
{
Content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json")
};
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Logger.Error("认证失败: 无效的API令牌或权限不足");
_accessToken = null;
return [];
}
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<YSERPListResponse<YSERPDepartment>>(content);
if (data == null || !resposeSuccessCodes.Contains(data.code))
{
var errorMsg = data?.message;
Logger.Error($"API业务错误: {errorMsg}");
throw new Exception($"API业务错误【{errorMsg}】");
}
var recordList = data.data;
if(recordList?.Count == 0)
{
//Logger.Info("没有更多部门记录");
return allDepts;
}
else
{
allDepts.AddRange(recordList ?? []);
}
}
catch (Exception ex)
{
Logger.Error($"获取部门数据失败,{ex}");
throw;
}
//_logger.LogInformation($"共获取 {allEmployees.Count} 条YS员工记录");
return allDepts;
}
public async Task<YSERPEmployeeInfo> GetEmpInfoById(string empId)
{
var token = await GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
{
return new YSERPEmployeeInfo();
}
try
{
var payload = new
{
id = empId
};
var request = new HttpRequestMessage(HttpMethod.Post, $"{_empInfoUrl}?access_token={token}")
{
Content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json")
};
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Logger.Error("认证失败: 无效的API令牌或权限不足");
_accessToken = null;
//return new YSERPEmployeeInfo();
throw new Exception("认证失败: 无效的YS ERP API令牌或权限不足");
}
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<YSERPResponse<YSERPEmployeeInfo>>(content);
if (data==null || !resposeSuccessCodes.Contains(data.code))
{
var errorMsg = data?.message;
Logger.Error($"API业务错误: {errorMsg}");
throw new Exception($"API业务错误: 【{errorMsg}】");
}
return data.data;
}
catch (Exception ex)
{
Logger.Error($"获取部门数据失败,{ex}");
throw;
}
}
public void Dispose()
{
_tokenLock?.Dispose();
_httpClient?.Dispose();
}
}
}