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

436 lines
16 KiB
C#
Raw Normal View History

2025-09-26 13:35:45 +08:00
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 _updateEmployeeUrl;
private readonly string _deptListUrl;
private readonly string _empInfoUrl;
2025-09-26 13:35:45 +08:00
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";
2025-09-26 13:35:45 +08:00
}
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 new List<YSERPEmployee>();
}
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 [];
}
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<YSERPPagedResponse<YSERPEmployee>>(content);
2025-09-26 13:35:45 +08:00
if (!new[] { "200", "00000" }.Contains(data.code))
{
var errorMsg = data.message;
Logger.Error($"API业务错误: {errorMsg}");
throw new Exception(errorMsg);
}
var recordList = data.data.recordList;
if (recordList?.Count == 0)
{
Logger.Info("没有更多员工记录");
break;
}
2025-09-26 13:35:45 +08:00
var toAdd = recordList.Where(r => !allEmployees.Any(e => e.id == r.id)).ToList();
allEmployees.AddRange(toAdd);
2025-09-26 13:35:45 +08:00
var haveNext = data.data.haveNextPage;
var pageCount = data.data.pageCount;
if (!haveNext || pageIndex >= pageCount)
{
break;
}
//Logger.Info($"第 {pageIndex}/{pageCount} 页,获取 {recordList.Count} 条员工记录");
2025-09-26 13:35:45 +08:00
pageIndex++;
await Task.Delay(500); // 避免请求过快
}
catch (Exception ex)
{
Logger.Error($"获取员工数据失败,{ex}");
throw;
}
}
//_logger.LogInformation($"共获取 {allEmployees.Count} 条YS员工记录");
return allEmployees;
}
public async Task<bool> UpdateEmployeesAsync(List<Dictionary<string, string>> employeeUpdates)
{
var token = await GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
{
return false;
}
//_logger.LogInformation($"YS更新内容: {JsonSerializer.Serialize(employeeUpdates)}");
try
{
var request = new HttpRequestMessage(HttpMethod.Post, $"{_updateEmployeeUrl}?access_token={token}")
{
Content = new StringContent(
JsonSerializer.Serialize(new { data = employeeUpdates }),
Encoding.UTF8,
"application/json")
};
var response = await _httpClient.SendAsync(request);
//_logger.LogInformation($"YS更新响应状态: {response.StatusCode}");
var content = await response.Content.ReadAsStringAsync();
//_logger.LogInformation($"YS更新响应内容: {content}");
response.EnsureSuccessStatusCode();
var data = JsonSerializer.Deserialize<JsonElement>(content);
if (data.GetProperty("code").GetString() == "00000")
{
//_logger.LogInformation($"成功更新 {employeeUpdates.Count} 名员工信息");
if (data.TryGetProperty("data", out var resultData))
{
if (resultData.TryGetProperty("messages", out var messages))
{
foreach (var msg in messages.EnumerateArray())
{
//_logger.LogWarning($"失败信息: {msg}");
}
}
}
return true;
}
else
{
var errorMsg = data.GetProperty("message").GetString();
Logger.Error($"更新失败: {errorMsg}");
return false;
}
}
catch (Exception ex)
{
Logger.Error( $"更新员工信息失败,{ex}");
return false;
}
}
public async Task<List<YSERPDepartment>> GetAllDepartmentsAsync()
{
var token = await GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
{
return [];
}
var allDepts = new List<YSERPDepartment>();
//Logger.Info($"员工信息API: {_employeeListUrl}");
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 (!new[] { "200", "00000" }.Contains(data.code))
{
var errorMsg = data.message;
Logger.Error($"API业务错误: {errorMsg}");
throw new Exception(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)
2025-09-26 13:35:45 +08:00
{
var token = await GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
2025-09-26 13:35:45 +08:00
{
return new YSERPEmployeeInfo();
}
try
{
var payload = new
{
id = empId
};
2025-09-26 13:35:45 +08:00
var request = new HttpRequestMessage(HttpMethod.Post, $"{_empInfoUrl}?access_token={token}")
{
Content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json")
};
2025-09-26 13:35:45 +08:00
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Logger.Error("认证失败: 无效的API令牌或权限不足");
_accessToken = null;
return new YSERPEmployeeInfo();
}
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<YSERPResponse<YSERPEmployeeInfo>>(content);
if (!new[] { "200", "00000" }.Contains(data.code))
{
var errorMsg = data.message;
Logger.Error($"API业务错误: {errorMsg}");
throw new Exception(errorMsg);
}
return data.data;
}
catch (Exception ex)
{
Logger.Error($"获取部门数据失败,{ex}");
throw;
}
2025-09-26 13:35:45 +08:00
}
public void Dispose()
{
_tokenLock?.Dispose();
_httpClient?.Dispose();
}
}
}