数据上传
This commit is contained in:
parent
e08cf86086
commit
b56bfa545c
@ -26,5 +26,12 @@ namespace VOL.Ai.IServices
|
||||
/// <param name="stuNo"></param>
|
||||
/// <returns></returns>
|
||||
Task<StudentDetailDto> GetStudentInfo(string stuNo);
|
||||
|
||||
/// <summary>
|
||||
/// 上传数据
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> PushSportsData(List<SportsDataPushDto> list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
||||
using System.Collections.Concurrent;
|
||||
using VOL.Ai.IRepositories;
|
||||
@ -25,6 +27,7 @@ using VOL.Model.Norm.Response;
|
||||
using VOL.Model.Training.Response;
|
||||
using VOL.System.IRepositories;
|
||||
using VOL.System.Repositories;
|
||||
using static Dapper.SqlMapper;
|
||||
|
||||
namespace VOL.Ai.Services
|
||||
{
|
||||
@ -51,6 +54,7 @@ namespace VOL.Ai.Services
|
||||
private readonly IClassroomSettingRepository _classroomSettingRepository;
|
||||
|
||||
private readonly IJingShiTiJiaoService _jingShiTiJiaoService;
|
||||
private readonly ILogger<AiAppService> _logger;
|
||||
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public AiAppService(IMapper mapper,
|
||||
@ -72,7 +76,8 @@ namespace VOL.Ai.Services
|
||||
IClassroomStageRepository classroomStageRepository,
|
||||
IClassroomSettingRepository classroomSettingRepository,
|
||||
IAiAppVersionRepository aiAppVersionRepository,
|
||||
IJingShiTiJiaoService jingShiTiJiaoService
|
||||
IJingShiTiJiaoService jingShiTiJiaoService,
|
||||
ILogger<AiAppService> logger
|
||||
)
|
||||
{
|
||||
_mapper = mapper;
|
||||
@ -95,6 +100,7 @@ namespace VOL.Ai.Services
|
||||
_classroomSettingRepository = classroomSettingRepository;
|
||||
_aiAppVersionRepository = aiAppVersionRepository;
|
||||
_jingShiTiJiaoService = jingShiTiJiaoService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
#region New
|
||||
@ -1062,9 +1068,42 @@ namespace VOL.Ai.Services
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
_logger.LogError(e, "心率数据保存失败");
|
||||
throw;
|
||||
}
|
||||
|
||||
// 异步上传心率数据,不阻塞主流程
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var uploadList = heartRateDatas.Select(hr => new SportsDataPushDto
|
||||
{
|
||||
StudentNo = hr.StudentNo,
|
||||
SportsItem = AppSetting.JingShiTiJiao.SportsItem,
|
||||
SportsDate = hr.ScoreTime.ToString("yyyy-MM-dd"),
|
||||
SportsService = AppSetting.JingShiTiJiao.Channel,
|
||||
SportsScene = "HeartRate",
|
||||
SportsDetail = JsonConvert.SerializeObject(hr)
|
||||
}).ToList();
|
||||
|
||||
var res = await _jingShiTiJiaoService.PushSportsData(uploadList);
|
||||
|
||||
if (res)
|
||||
|
||||
{
|
||||
_logger.LogInformation($"心率数据同步成功: {JsonConvert.SerializeObject(uploadList)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"心率数据同步失败: {JsonConvert.SerializeObject(uploadList)}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "心率数据上传异常");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1107,6 +1146,38 @@ namespace VOL.Ai.Services
|
||||
});
|
||||
await _fastJumpRopeDataRepository.AddRangeAsync(fastJumpRopeDatas);
|
||||
await _fastJumpRopeDataRepository.SaveChangesAsync();
|
||||
|
||||
// 2️⃣ 异步上传到极智体教平台
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var uploadList = fastJumpRopeDatas.Select(d => new SportsDataPushDto
|
||||
{
|
||||
StudentNo = d.StudentNo,
|
||||
SportsItem = AppSetting.JingShiTiJiao.SportsItem,
|
||||
SportsDate = d.ScoreTime.ToString("yyyy-MM-dd"),
|
||||
SportsService = AppSetting.JingShiTiJiao.Channel,
|
||||
SportsScene = "FastJumpRope",
|
||||
SportsDetail = JsonConvert.SerializeObject(d)
|
||||
}).ToList();
|
||||
|
||||
var res = await _jingShiTiJiaoService.PushSportsData(uploadList);
|
||||
|
||||
if (res)
|
||||
{
|
||||
_logger.LogInformation($"速度跳绳数据同步成功: {JsonConvert.SerializeObject(uploadList)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"速度跳绳数据同步失败: {JsonConvert.SerializeObject(uploadList)}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "速度跳绳数据上传异常");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1245,6 +1316,15 @@ namespace VOL.Ai.Services
|
||||
return new Ai_ClassRoomRecordDto();
|
||||
}
|
||||
|
||||
var teacher = await _classRepository.DbContext.Set<JS_Teacher>().Where(x => x.Id == paramDto.TeacherId).FirstOrDefaultAsync();
|
||||
|
||||
if (teacher==null)
|
||||
{
|
||||
Console.WriteLine("未找到老师信息");
|
||||
return new Ai_ClassRoomRecordDto();
|
||||
}
|
||||
|
||||
entity.TeacherNo = teacher.TeacherNo;
|
||||
entity.ClassName = classInfo.ClassName;
|
||||
entity.GradeId = (int)classInfo.GradeId;
|
||||
entity.GradeName = classInfo.GradeName;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
using VOL.Ai.IServices;
|
||||
using VOL.Core.Configuration;
|
||||
using VOL.Core.Extensions.AutofacManager;
|
||||
@ -134,5 +135,45 @@ namespace VOL.Ai.Services
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上传成绩数据
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<bool> PushSportsData(List<SportsDataPushDto> list)
|
||||
{
|
||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
string nonce = SaTokenSignHelper.RandomString();
|
||||
|
||||
var paramMap = new Dictionary<string, object>
|
||||
{
|
||||
{ "channel", AppSetting.JingShiTiJiao.Channel },
|
||||
{ "timestamp", timestamp },
|
||||
{ "nonce", nonce }
|
||||
};
|
||||
|
||||
string jsonBody = JsonConvert.SerializeObject(list);
|
||||
|
||||
// ⭐ POST JSON 的签名
|
||||
string queryStr = SaTokenSignHelper.BuildPostJsonQueryString(
|
||||
paramMap,
|
||||
AppSetting.JingShiTiJiao.SecretKey,
|
||||
jsonBody);
|
||||
|
||||
string url = $"{AppSetting.JingShiTiJiao.BaseUrl}/api/sports/data/push?{queryStr}";
|
||||
|
||||
using var client = new HttpClient();
|
||||
var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await client.PostAsync(url, content);
|
||||
string result = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var res = JsonConvert.DeserializeObject<JingShiResponse<object>>(result);
|
||||
|
||||
return res != null && res.Code == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,5 +262,7 @@ namespace VOL.Core.Configuration
|
||||
public string Channel { get; set; }
|
||||
public string SecretKey { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
public string SchoolCode { get; set; }
|
||||
public string SportsItem { get; set; }
|
||||
}
|
||||
}
|
||||
7677
VOL.Core/Migrations/20260112052447_20260112v1.Designer.cs
generated
Normal file
7677
VOL.Core/Migrations/20260112052447_20260112v1.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
VOL.Core/Migrations/20260112052447_20260112v1.cs
Normal file
37
VOL.Core/Migrations/20260112052447_20260112v1.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace VOL.Core.Migrations
|
||||
{
|
||||
public partial class _20260112v1 : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TeacherNo",
|
||||
table: "S_HomeWork",
|
||||
type: "nvarchar(200)",
|
||||
nullable: true,
|
||||
comment: "老师编号");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TeacherNo",
|
||||
table: "Ai_ClassRoomRecord",
|
||||
type: "nvarchar(200)",
|
||||
nullable: true,
|
||||
comment: "老师编号");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TeacherNo",
|
||||
table: "S_HomeWork");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TeacherNo",
|
||||
table: "Ai_ClassRoomRecord");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,6 +299,10 @@ namespace VOL.Core.Migrations
|
||||
.HasColumnType("nvarchar(200)")
|
||||
.HasComment("老师姓名");
|
||||
|
||||
b.Property<string>("TeacherNo")
|
||||
.HasColumnType("nvarchar(200)")
|
||||
.HasComment("老师编号");
|
||||
|
||||
b.Property<int>("TrainingModuleEnum")
|
||||
.HasColumnType("int")
|
||||
.HasComment("训练模块枚举");
|
||||
@ -4228,6 +4232,10 @@ namespace VOL.Core.Migrations
|
||||
.HasColumnType("nvarchar(100)")
|
||||
.HasComment("老师名称");
|
||||
|
||||
b.Property<string>("TeacherNo")
|
||||
.HasColumnType("nvarchar(200)")
|
||||
.HasComment("老师编号");
|
||||
|
||||
b.Property<string>("TeacherPhoneNo")
|
||||
.HasColumnType("nvarchar(100)")
|
||||
.HasComment("老师手机号");
|
||||
|
||||
@ -47,6 +47,57 @@ namespace VOL.Core.Utilities
|
||||
return sbQuery.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 构建 POST JSON 上传接口的 QueryString(包含 sign)
|
||||
/// ⚠️ 不与 GET 共用,避免误用
|
||||
/// </summary>
|
||||
public static string BuildPostJsonQueryString(
|
||||
Dictionary<string, object> paramMap,
|
||||
string secretKey,
|
||||
string jsonBody)
|
||||
{
|
||||
if (paramMap == null)
|
||||
throw new ArgumentNullException(nameof(paramMap));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(jsonBody))
|
||||
throw new ArgumentException("POST JSON body 不能为空");
|
||||
|
||||
// 1️⃣ 参与签名的参数(TreeMap + ASCII 排序)
|
||||
var signParams = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
|
||||
foreach (var kv in paramMap)
|
||||
signParams[kv.Key] = kv.Value.ToString();
|
||||
|
||||
// ⭐ POST JSON 特有:整个 body 作为 reqbody
|
||||
signParams["reqbody"] = jsonBody;
|
||||
|
||||
// 2️⃣ 拼接签名字符串
|
||||
// k=v&k=v&...&key=secretKey
|
||||
var sbSign = new StringBuilder();
|
||||
foreach (var kv in signParams)
|
||||
sbSign.Append(kv.Key)
|
||||
.Append("=")
|
||||
.Append(kv.Value)
|
||||
.Append("&");
|
||||
|
||||
sbSign.Append("key=").Append(secretKey.Trim());
|
||||
|
||||
string sign = Md5(sbSign.ToString());
|
||||
|
||||
// 3️⃣ 构建 URL QueryString(⚠️ 不包含 reqbody)
|
||||
var sbQuery = new StringBuilder();
|
||||
foreach (var kv in paramMap)
|
||||
sbQuery.Append(Uri.EscapeDataString(kv.Key))
|
||||
.Append("=")
|
||||
.Append(Uri.EscapeDataString(kv.Value.ToString()))
|
||||
.Append("&");
|
||||
|
||||
sbQuery.Append("sign=").Append(sign);
|
||||
|
||||
return sbQuery.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MD5 小写 32 位
|
||||
/// </summary>
|
||||
|
||||
@ -109,6 +109,14 @@ namespace VOL.Entity.DomainModels
|
||||
[Column(TypeName = "int")]
|
||||
public int TeacherId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 老师编号
|
||||
/// </summary>
|
||||
[Display(Name = "老师编号")]
|
||||
[Comment("老师编号")]
|
||||
[Column(TypeName = "nvarchar(200)")]
|
||||
public string TeacherNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 老师姓名
|
||||
/// </summary>
|
||||
|
||||
@ -143,6 +143,14 @@ namespace VOL.Entity.DomainModels
|
||||
[Column(TypeName = "int")]
|
||||
public int TeacherId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 老师编号
|
||||
/// </summary>
|
||||
[Display(Name = "老师编号")]
|
||||
[Comment("老师编号")]
|
||||
[Column(TypeName = "nvarchar(200)")]
|
||||
public string TeacherNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///老师名称
|
||||
/// </summary>
|
||||
|
||||
30
VOL.Model/JingShiTiJiao/SportsDataPushDto.cs
Normal file
30
VOL.Model/JingShiTiJiao/SportsDataPushDto.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VOL.Model.JingShiTiJiao
|
||||
{
|
||||
public class SportsDataPushDto
|
||||
{
|
||||
[JsonProperty("studentNo")]
|
||||
public string StudentNo { get; set; }
|
||||
|
||||
[JsonProperty("sportsItem")]
|
||||
public string SportsItem { get; set; }
|
||||
|
||||
[JsonProperty("sportsDate")]
|
||||
public string SportsDate { get; set; } // yyyy-MM-dd
|
||||
|
||||
[JsonProperty("sportsService")]
|
||||
public string SportsService { get; set; } // channel
|
||||
|
||||
[JsonProperty("sportsScene")]
|
||||
public string SportsScene { get; set; }
|
||||
|
||||
[JsonProperty("sportsDetail")]
|
||||
public string SportsDetail { get; set; } // json string
|
||||
}
|
||||
}
|
||||
@ -120,7 +120,9 @@
|
||||
"JingShiTiJiao": {
|
||||
"Channel": "sk-yuedong",
|
||||
"SecretKey": "JSTJ-kGfs6J7bkgdxr9mz",
|
||||
"BaseUrl": "https://api-test.aitibao.com"
|
||||
"BaseUrl": "https://api-test.aitibao.com",
|
||||
"SchoolCode": "202512240056",
|
||||
"SportsItem": "JS010000"
|
||||
},
|
||||
|
||||
"QuartzAccessKey": "65EC9387355E4717899C552963CE59FF", //定时任务的值,请自行修改
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user