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

436 lines
16 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 _updateEmployeeUrl;
private readonly string _deptListUrl;
private readonly string _empInfoUrl;
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 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);
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;
}
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<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)
{
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();
}
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;
}
}
public void Dispose()
{
_tokenLock?.Dispose();
_httpClient?.Dispose();
}
}
}