CrazyIter_Bin 3 hónapja
szülő
commit
873a3b569f

+ 63 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/FrameworkController.cs

@@ -0,0 +1,63 @@
+using Microsoft.AspNetCore.Mvc;
+using System.Text.Json.Nodes;
+
+namespace IES.ExamServer.Controllers
+{
+    [ApiController]
+    [Route("controller/framework")]
+    public class FrameworkController : BaseController
+    {
+        public FrameworkController() 
+        {
+        
+        }
+        [HttpGet("doHttpRequest")]
+        public IActionResult DoHttpRequest(JsonNode json )
+        {
+            string ip = $"{json["id"]}";//请求:{"id":"ip"}返回:192.168.56.1
+            return Ok("ok");
+        }
+        /// <summary>
+        /// 本地服务状态检查接⼝(⽹⻚调本地服务接⼝)  完成
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("check")]
+        public IActionResult check()
+        {
+            return Ok(1==1);
+        }
+        [HttpGet("getCacheFile")]
+        public IActionResult GetCacheFile([FromQuery] string name )
+        {
+            return Ok("ok");
+        }
+        [HttpPost("uploadFile")]
+        public IActionResult UploadFile(JsonNode json)
+        {
+            /*
+              {
+                 "fileName": "f824810b-0d3a-4772-85dc-443eb8895955.wav",
+                 "musicQuestionId": "1835",
+                 "thirdAnswerId": "62abefa1-dfd4-419f-8f4d-05b9e9ea3057::82be3962-674c-1172-0caf-b2dcdc2bd935::202106001",
+                 "thirdStudentName": "曾义程",
+                 "thirdSchoolId": "hbcn",
+                 "thirdStudentId": "202106001",
+                 "schoolUniCode": "cb138fa4-31ba-423c-a0b7-c954c9d3c445",
+                 "questionItemId": "249",
+                 "id": "b6141be4c697bd9aa008013a3857e971",
+                 "status": 0,
+                 "name": "f824810b-0d3a-4772-85dc-443eb8895955.wav",
+                 "createTime": 1733389000260
+             }
+            返回正常
+            返回
+             {newurl: fileName}
+            异常
+ 
+            返回
+             false
+             */
+            return Ok("ok");
+        }
+    }
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 79 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/IndexController.cs


+ 15 - 1
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/ManageController.cs

@@ -81,7 +81,12 @@ namespace IES.ExamServer.Controllers
         }
          */
         //如果要访问中心,则需要教师登录联网。  
-
+        [HttpPost("download-package-music")]
+        [AuthToken("admin", "teacher", "visitor")]
+        public async Task<IActionResult> DownloadPackageMusic(JsonNode json) 
+        {
+            return Ok();
+        }
         [HttpPost("download-package")]
         [AuthToken("admin", "teacher", "visitor")]
         public async Task<IActionResult> DownloadPackage(JsonNode json)
@@ -393,6 +398,12 @@ namespace IES.ExamServer.Controllers
             }
 
         }
+        /// <summary>
+        /// 检查数据包是否有更新,zip是否存在,数据文件是否完整,名单文件是否完整。
+        /// 如果有智音模块,则需要检查智音音乐缓存是否完整。
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
 
         [HttpPost("check-evaluation")]
         [AuthToken("admin", "teacher", "visitor")]
@@ -788,6 +799,7 @@ namespace IES.ExamServer.Controllers
                                     roundStudentPapers.AddRange(evaluationStudentPapers);
                                 }
                             }
+                            long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
                             IEnumerable<EvaluationStudentResult> studentResults = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationStudentResult>()
                                 .Find(x => members.Select(x => x.id).Contains(x.studentId)&&!string.IsNullOrWhiteSpace(x.evaluationId)  && x.evaluationId.Equals(evaluationClient.id));
                             foreach (var member in members)
@@ -829,6 +841,7 @@ namespace IES.ExamServer.Controllers
                                                 subjectName = studentPaper.subjectName,
                                                 paperId = studentPaper.paperId,
                                                 paperName = studentPaper.paperName,
+                                                createTime=now
                                             });
                                         }
                                     }
@@ -860,6 +873,7 @@ namespace IES.ExamServer.Controllers
                                                     subjectName = studentPaper.subjectName,
                                                     paperId = studentPaper.paperId,
                                                     paperName = studentPaper.paperName,
+                                                    createTime=now
                                                 };
                                                 //studentResult.subjectResults.Add();
                                             }

+ 165 - 39
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/StudentController.cs

@@ -1,6 +1,8 @@
 using IES.ExamLibrary.Models;
 using IES.ExamServer.DI;
+using IES.ExamServer.Filters;
 using IES.ExamServer.Helper;
+using IES.ExamServer.Helpers;
 using IES.ExamServer.Models;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Caching.Memory;
@@ -31,17 +33,126 @@ namespace IES.ExamServer.Controllers
             _connectionService=connectionService;
             _liteDBFactory=liteDBFactory;
         }
+
+        /// <summary>
+        ///  学生提交科目作答
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [HttpPost("answer-subject-result")]
+        [AuthToken("student")]
+        public IActionResult AnswerSubjectResult(JsonNode json)
+        {
+            List<List<string>>? answers = json["answer"]?.ToObject<List<List<string>>>();
+            string evaluationId = $"{json["evaluationId"]}";
+            string examId = $"{json["examId"]}";
+            string subjectId = $"{json["subjectId"]}";
+            string paperId = $"{json["paperId"]}";
+            int costTime = int.Parse($"{json["costTime"]}");
+            string settingId = $"{json["settingId"]}";
+            var token = GetAuthTokenInfo();
+            EvaluationRoundSetting? setting = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationRoundSetting>().FindOne(x => x.id!.Equals(settingId) && evaluationId.Equals(x.evaluationId) && x.activate==1);
+            EvaluationClient? evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x=>evaluationId.Equals(x.id));
+            if (evaluationClient!=null && setting!=null && setting.activate==1)
+            {
+                string resultId = ShaHashHelper.GetSHA1(evaluationId+_connectionService?.serverDevice?.school?.id+token.id);
+                EvaluationStudentResult studentResult = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationStudentResult>()
+                .FindOne(x => resultId.Equals(x.id) && token.id.Equals(x.studentId) && evaluationId.Equals(x.evaluationId));
+                if (studentResult!=null)
+                {
+                    long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
+                    //判断开始时间
+                    if ((setting.startline>0 && setting.startline>now)|| evaluationClient.stime>now)
+                    {
+                        //未到开始时间
+                        return Ok(new { msg = "未到开始时间。", code = 1 });
+                    }
+
+                    //判断截止时间
+                    long deadline;
+                    if (setting.countdownType==2)
+                    {
+
+                        deadline= studentResult.startTime+setting.countdown;
+                    }
+                    else
+                    {
+                        deadline= setting.startline+setting.countdown;
+
+                    }
+                    deadline+= 10*60*1000;//漂移10分钟,允许学生延迟提交,但是前端页面显示的截止时间是准的,时间一到,可自动提交。
+                    if ((deadline>0&&deadline<now)|| evaluationClient.etime<now)
+                    {
+                        //已过截止时间
+                        return Ok(new { msg = "已过截止时间。", code = 2 });
+                    }
+                    if (!string.IsNullOrWhiteSpace(subjectId)  && !string.IsNullOrWhiteSpace(examId) && !string.IsNullOrWhiteSpace(paperId)&& costTime>0)
+                    {
+                        var subjectResult = studentResult.subjectResults.Where(x => subjectId.Equals(x.subjectId) && examId.Equals(x.examId) && paperId.Equals(x.paperId)).FirstOrDefault();
+                        if (subjectResult!=null)
+                        {
+                            if (answers!=null) 
+                            {
+                                subjectResult.answers=answers!;
+                            }
+                            subjectResult.finished=1;
+                            subjectResult.costTime=costTime;
+                            subjectResult.submitTime=now;
+                        }
+                        if (_connectionService!.centerIsConnected) 
+                        {
+                        
+                        }
+                    }
+                    return Ok(new { code = 200, studentResult = studentResult, msg = "提交成功!" });
+                }
+                else { 
+                    return Ok(new { msg = "未找到该学生的作答信息。", code = 4});
+                }
+
+            }
+            else 
+            {
+                return Ok(new { msg = "未匹配到正则开考的评测。", code = 3 });
+            }
+           
+
+           
+        }
+
+
+
         /// <summary>
-        /// 提交作答
+        /// 获取学生当前考试的作答信息。
         /// </summary>
         /// <param name="json"></param>
         /// <returns></returns>
-        [HttpPost("submit-answer")]
-        public IActionResult SubmitAnswer(JsonNode json)
+        [HttpPost("load-evaluation-result")]
+        [AuthToken("student")]
+        public IActionResult LoadEvaluationResult(JsonNode json)
         {
-            //提交作答,多种保存方式,在数据库,文件中,缓存中,以及日志中都记录防止丢失。
-            return Ok();
+            string evaluationId = $"{json["evaluationId"]}";
+            var token = GetAuthTokenInfo();
+            string resultId = ShaHashHelper.GetSHA1(evaluationId+_connectionService?.serverDevice?.school?.id+token.id);
+            EvaluationStudentResult studentResult = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationStudentResult>()
+                .FindOne(x=> resultId.Equals(x.id) && token.id.Equals(x.studentId) && evaluationId.Equals(x.evaluationId));
+            if (studentResult!=null)
+            {
+                //标记开始作答
+                studentResult.finished=1;
+
+                if (studentResult.startTime<=0) 
+                {
+                    studentResult.startTime=DateTimeOffset.Now.ToUnixTimeMilliseconds();
+                }
+                _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationStudentResult>().Update(studentResult);
+                return Ok(new { code = 200, studentResult = studentResult });
+            }
+            else { 
+                return Ok(new { msg = "未找到该学生的作答信息。", code = 404});
+            }
         }
+
         /// <summary>
         /// 登录
         /// </summary>
@@ -50,15 +161,16 @@ namespace IES.ExamServer.Controllers
         [HttpPost("login")]
         public IActionResult Login(JsonNode json) 
         {
-            string? studentId = json["studentId"]?.ToString();
-            string? studentName = json["studentName"]?.ToString();
-            string? evaluationId = json["evaluationId"]?.ToString();
-            EvaluationRoundSetting? setting = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationRoundSetting>().FindOne(x => x.id!.Equals(evaluationId)&& x.activate==1);
+            string studentId = $"{json["studentId"]}";
+            string studentName = $"{json["studentName"]}";
+            string evaluationId = $"{json["evaluationId"]}";
+            string settingId = $"{json["settingId"]}";
+            EvaluationRoundSetting? setting = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationRoundSetting>().FindOne(x => x.id!.Equals(settingId) && evaluationId.Equals(x.evaluationId) && x.activate==1);
             EvaluationClient? evaluationClient = null;
             if (setting!=null)
             {
-                evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x => x.id == setting.evaluationId);
-                if (evaluationClient!=null) 
+                evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x => x.id!.Equals(setting.evaluationId));
+                if (evaluationClient!=null)
                 {
                     //检查是否在作答时间内
                     (code, msg)=  CheckActivate(evaluationClient, setting);
@@ -72,16 +184,38 @@ namespace IES.ExamServer.Controllers
                         {
                             school = server.school;
                         }
-                        string id = $"{studentId}";
-                        string name = $"{studentName}";
+                        EvaluationMember? member = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationMember>().FindOne(x => studentId.Equals(x.id)&& studentName.Equals(x.name));
+                        if (member!=null)
+                        {
+                            if (evaluationId.Equals(member.evaluationId))
+                            {
+                                string x_auth_token = JwtAuthExtension.CreateAuthToken("www.teammodel.cn", studentId, studentName, picture: string.Empty, ExamConstant.JwtSecretKey, ExamConstant.ScopeVisitor, 8, schoolID: school?.id, new string[] { "student" }, expire: 1);
+                                return Ok(new { code = 200, x_auth_token = x_auth_token });
+                            }
+                            else
+                            {
 
-                        string  x_auth_token = JwtAuthExtension.CreateAuthToken("www.teammodel.cn", id, name, picture: string.Empty , ExamConstant.JwtSecretKey, ExamConstant.ScopeVisitor, 8, schoolID: school?.id, new string[] { "student" }, expire: 1);
-                        //_liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().Upsert(new Teacher { id = id, name = $"{name}",  picture = null, x_auth_token = x_auth_token, loginTime=time });
-                        return Ok(new { code = 200, x_auth_token = x_auth_token });
+                                return Ok(new { msg = "当前考试未添加该学生!", code = 7 });
+                            }
+
+                        }
+                        else
+                        {
+                           return Ok(new { msg = "学者账号和姓名不匹配!", code = 1 });
+                        }
+
+                    }
+                    else { 
+                        return Ok(new { msg = msg, code = code });
                     }
                 }
+                else { 
+                    return Ok(new { msg = "未找到考试设置。", code = 6 });
+                }
+            }
+            else { 
+                return Ok(new { msg = "未找到考试设置。", code = 2 });
             }
-            return Ok(new { msg =msg, code = 200 });
         }
         /// <summary>
         /// 学生端获取激活的考试
@@ -160,31 +294,23 @@ namespace IES.ExamServer.Controllers
             }
             //当前时间
             long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
-            if (setting.countdownType>0)
+            //if (setting.countdownType>0)
+            //{
+               
+            //}
+            //else
+            //{
+               
+            //}
+            if ((setting.startline>0 &&setting.startline>now) || evaluationClient.stime>now)
             {
-                if (setting.startline>now || evaluationClient.stime>now)
-                {
-                    msg="评测暂未开始。";
-                    code=4;
-                }
-                if ((setting.deadline>0 && setting.deadline<now)|| evaluationClient.etime<now)
-                {
-                    msg="评测已经结束。";
-                    code=5;
-                }
+                msg="评测暂未开始。";
+                code=4;
             }
-            else
+            if ((setting.deadline>0 && setting.deadline<now)|| evaluationClient.etime<now)
             {
-                if (evaluationClient.stime>now)
-                {
-                    msg="评测暂未开始。";
-                    code=4;
-                }
-                if (evaluationClient.etime<now)
-                {
-                    msg="评测已经结束。";
-                    code=5;
-                }
+                msg="评测已经结束。";
+                code=5;
             }
             return (code, msg);
         }

+ 145 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/DI/AnswerPushService.cs

@@ -0,0 +1,145 @@
+using IES.ExamServer.Models;
+using LiteDB;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Channels;
+
+namespace IES.ExamServer.DI
+{
+    public class AnswerPushService: BackgroundService
+    {
+        private readonly DataQueue _dataQueue;
+        private readonly IHttpClientFactory _httpClientFactory;
+        private readonly LiteDBFactory _liteDBFactory;
+        private readonly CenterServiceConnectionService _connectionService;
+        public AnswerPushService(DataQueue dataQueue, IHttpClientFactory httpClientFactory, LiteDBFactory liteDBFactory, CenterServiceConnectionService connectionService)
+        {
+            
+            _dataQueue = dataQueue;
+            _httpClientFactory = httpClientFactory;
+            _liteDBFactory = liteDBFactory;
+            _connectionService = connectionService;
+
+        }
+        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            ///数据中心链接了,开始推送数据
+            if (_connectionService.centerIsConnected) 
+            {
+                // 启动时加载未推送的数据
+                await LoadUnpushedDataAsync(stoppingToken);
+            }
+            while (!stoppingToken.IsCancellationRequested)
+            {
+                // 从 Channel 中读取数据
+                if (await _dataQueue.Reader.WaitToReadAsync(stoppingToken))
+                {
+                    while (_dataQueue.Reader.TryRead(out var data))
+                    {
+
+                        await PushSubjectResultDataToCloudAsync(data, stoppingToken);
+                        await PushMusicAIResultDataToCloudAsync(data, stoppingToken);
+                    }
+                }
+            }
+
+        }
+        private async Task PushMusicAIResultDataToCloudAsync(EvaluationStudentResult data, CancellationToken cancellationToken)
+        {
+
+            if (_connectionService.centerIsConnected)
+            {
+                try
+                {
+                    //  var json = JsonSerializer.Serialize(data);
+                    //var content = new StringContent(json, Encoding.UTF8, "application/json");
+                    var httpClient = _httpClientFactory.CreateClient();
+                    var response = await httpClient.PostAsJsonAsync("", data, cancellationToken);
+
+                    if (response.IsSuccessStatusCode)
+                    {
+                        MarkDataAsPushed(data);
+                        Console.WriteLine($"Data {data.id} pushed successfully.");
+                    }
+                    else
+                    {
+                        Console.WriteLine($"Failed to push data {data.id}. Retrying...");
+                        // 推送失败,重新加入队列
+                        await _dataQueue.Writer.WriteAsync(data, cancellationToken);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine($"Error pushing data {data.id}: {ex.Message}");
+                    // 推送失败,重新加入队列
+                    await _dataQueue.Writer.WriteAsync(data, cancellationToken);
+                }
+            }
+        }
+        private async Task PushSubjectResultDataToCloudAsync(EvaluationStudentResult data, CancellationToken cancellationToken)
+        {
+            if (_connectionService.centerIsConnected) 
+            {
+                try
+                {
+                    //  var json = JsonSerializer.Serialize(data);
+                    //var content = new StringContent(json, Encoding.UTF8, "application/json");
+                    var httpClient = _httpClientFactory.CreateClient();
+                    var response = await httpClient.PostAsJsonAsync("", data, cancellationToken);
+
+                    if (response.IsSuccessStatusCode)
+                    {
+                        MarkDataAsPushed(data);
+                        Console.WriteLine($"Data {data.id} pushed successfully.");
+                    }
+                    else
+                    {
+                        Console.WriteLine($"Failed to push data {data.id}. Retrying...");
+                        // 推送失败,重新加入队列
+                        await _dataQueue.Writer.WriteAsync(data, cancellationToken);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine($"Error pushing data {data.id}: {ex.Message}");
+                    // 推送失败,重新加入队列
+                    await _dataQueue.Writer.WriteAsync(data, cancellationToken);
+                }
+            }
+        }
+        private void MarkDataAsPushed(EvaluationStudentResult data)
+        {
+            var collection = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationStudentResult>();
+            data.pushed = 1;
+            collection.Upsert(data);
+        }
+        private async Task LoadUnpushedDataAsync(CancellationToken cancellationToken)
+        {
+            var collection = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationStudentResult>();
+            var unpushedData = collection.Find(x => x.pushed!=1);
+
+            // 将未推送的数据写入 Channel
+            await _dataQueue.WriteBatchAsync(unpushedData, cancellationToken);
+        }
+    }
+
+    public class DataQueue
+    {
+        private readonly Channel<EvaluationStudentResult> _channel;
+        public DataQueue() {
+            // 创建一个无界 Channel
+            _channel = Channel.CreateUnbounded<EvaluationStudentResult>();
+        }
+        public ChannelWriter<EvaluationStudentResult> Writer => _channel.Writer;
+        public ChannelReader<EvaluationStudentResult> Reader => _channel.Reader;
+
+        // 批量写入数据
+        public async Task WriteBatchAsync(IEnumerable<EvaluationStudentResult> dataList, CancellationToken cancellationToken = default)
+        {
+            foreach (var data in dataList)
+            {
+                await _channel.Writer.WriteAsync(data, cancellationToken);
+            }
+        }
+    }
+}

+ 23 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/DI/CenterServiceConnectionService.cs

@@ -6,9 +6,32 @@ namespace IES.ExamServer.DI
     {
         private bool _centerIsConnected;
         private bool _notifyIsConnected;
+       // private bool _musicIsConnected;
         public string? centerUrl { get; set; }
         public string? notifyUrl { get; set; }
+        /// <summary>
+        /// 音乐播放服务
+        /// "MusicAIServer": {
+        ///    "MusicUrl": "https://musicapi.winteach.cn/api/v1",
+        ///    "AppId": "8a68f563f3384662acbc268336b98ae2",
+        ///    "KeyAES": "GcRHG7pGgepXXOOU",
+        ///    "IvAES": "W5yt6WthEs2mQlSn"
+        ///  }
+        /// "MusicAIServer": {
+        ///    "MusicUrl": "https://tmdapi.yosocloud.com/api/v1",
+        ///    "AppId": "8a68f563f3384662acbc268336b98ae2",
+        ///    "KeyAES": "GcRHG7pGgepXXOOU",
+        ///    "IvAES": "W5yt6WthEs2mQlSn"
+        ///  }
+        /// </summary>
+        public string? musicUrl { get; set; }
+       
         public ServerDevice? serverDevice {  get; set; }
+        public bool musicIsConnected
+        { get;set;
+            //get { return string.IsNullOrWhiteSpace(musicUrl) ? false : _musicIsConnected; }
+            //set { _musicIsConnected = value; }
+        }
         public bool notifyIsConnected
         {
             get { return string.IsNullOrWhiteSpace(notifyUrl) ? false : _notifyIsConnected; }

+ 1 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/DI/ServiceInitializer.cs

@@ -112,6 +112,7 @@ namespace IES.ExamServer.DI
                     throw new Exception($"Failed to download data. Status code: {message.StatusCode}");
                 }
             }
+            _connectionService.musicUrl = _configuration.GetValue<string>("ExamServer:MusicUrl");
             _connectionService.notifyUrl = notify == 1 ? notifyUrl : null;
             _connectionService.notifyIsConnected = notify == 1;
             // 单例模式存储云端数据中心连接状态

+ 76 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/AESHelper.cs

@@ -0,0 +1,76 @@
+using IES.ExamServer.Helper;
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.Json;
+
+namespace IES.ExamServer.Helpers
+{
+    public class AESHelper
+    {
+        private static readonly byte[] Key = Encoding.UTF8.GetBytes(Constant._MusicAIServerAESKey);
+        private static readonly byte[] IV = Encoding.UTF8.GetBytes(Constant._MusicAIServerAESIv);
+
+        // 解密方法
+        public static string Decrypt(string encryptedText)
+        {
+            Console.WriteLine("解密前的内容:", encryptedText);
+            if (string.IsNullOrEmpty(encryptedText))
+            {
+                return encryptedText;
+            }
+
+            using (Aes aesAlg = Aes.Create())
+            {
+                aesAlg.Key = Key;
+                aesAlg.IV = IV;
+                aesAlg.Mode = CipherMode.CBC;
+                aesAlg.Padding = PaddingMode.PKCS7;
+
+                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
+
+                byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
+                byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
+
+                string decryptedText = Encoding.UTF8.GetString(decryptedBytes);
+                Console.WriteLine("解密后的内容:", decryptedText);
+
+                if (decryptedText.StartsWith("{"))
+                {
+                    return JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(decryptedText));
+                }
+                else
+                {
+                    return decryptedText;
+                }
+            }
+        }
+
+        // 加密方法
+        public static string Encrypt(string plainText)
+        {
+            Console.WriteLine("加密前的内容:", plainText);
+            if (string.IsNullOrEmpty(plainText))
+            {
+                return plainText;
+            }
+
+            using (Aes aesAlg = Aes.Create())
+            {
+                aesAlg.Key = Key;
+                aesAlg.IV = IV;
+                aesAlg.Mode = CipherMode.CBC;
+                aesAlg.Padding = PaddingMode.PKCS7;
+
+                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
+
+                byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
+                byte[] encryptedBytes = encryptor.TransformFinalBlock(plainTextBytes, 0, plainTextBytes.Length);
+
+                string encryptedText = Convert.ToBase64String(encryptedBytes);
+                Console.WriteLine("加密后的内容:", encryptedText);
+                return encryptedText;
+            }
+        }
+    }
+}

+ 5 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/Constant.cs

@@ -27,5 +27,10 @@ namespace IES.ExamServer.Helper
         public static readonly int _Message_status_info = 0;
         public static readonly int _Message_status_success = 1;
         public static readonly int _Message_status_warning = 2;
+        #region 智音AI音乐相关常量
+        public static readonly string _MusicAIServerAppId = "8a68f563f3384662acbc268336b98ae2";
+        public static readonly string _MusicAIServerAESKey = "GcRHG7pGgepXXOOU";
+        public static readonly string _MusicAIServerAESIv = "W5yt6WthEs2mQlSn";
+        #endregion
     }
 }

+ 1 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/IES.ExamServer.csproj

@@ -27,6 +27,7 @@
 	<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />
 	<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
     <PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="6.0.36" />
+    <PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
   </ItemGroup>
   <ItemGroup>
 	<Folder Include="Logs\DataLogs\" />

+ 6 - 2
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Models/EvaluationStudent.cs

@@ -119,7 +119,7 @@
         /// </summary>
         //public long submitTime { get; set; }
        
-        //public long createTime { get; set; }
+        
         public string? ownerId { get; set; }
         /// <summary>
         /// 数据范围
@@ -134,10 +134,14 @@
     public class EvaluationStudentResult : EvaluationStudent
     {
         /// <summary>
-        /// 是否作答完成0 未完成,1完成,2缺考
+        /// 是否作答完成0 未开始(未登录,最终状态变为缺考),1未完成(已经登录,倒计时结束,需要自动提交。未完成的,需要教师手动推送(联网的情况)。),2已完成(完成作答,直接推送),3缺考(教师手动设置缺考的学生,或者全部推送时,批量设置。)
         /// </summary>
         public int finished { get; set; }
         /// <summary>
+        /// 开考时间,单位毫秒
+        /// </summary>
+        public long startTime { get; set; }
+        /// <summary>
         /// 是否推送0 未推送,1推送
         /// </summary>
         public int pushed { get; set; }

+ 59 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Models/MusicAiRecord.cs

@@ -0,0 +1,59 @@
+namespace IES.ExamServer.Models
+{
+    public class MusicAiRecord
+    {
+        /// <summary>
+        ///  文件名
+        /// </summary>
+        public string? fileName { get; set; }
+        /// <summary>
+        /// 问题id
+        /// </summary>
+        public string? musicQuestionId { get; set; }
+        /// <summary>
+        /// 醍摩豆传输的答案id
+        /// </summary>
+        public string? thirdAnswerId { get; set; }
+        /// <summary>
+        /// 学生名字
+        /// </summary>
+        public string? thirdStudentName { get; set; }
+        /// <summary>
+        /// 醍摩豆学校编码
+        /// </summary>
+        public string? thirdSchoolId { get; set; }
+        /// <summary>
+        /// 醍摩豆学生id
+        /// </summary>
+        public string? thirdStudentId { get; set; }
+        /// <summary>
+        /// 智音学校编码
+        /// </summary>
+        public string? schoolUniCode { get; set; }
+        /// <summary>
+        /// 音乐id
+        /// </summary>
+        public string? questionItemId { get; set; }
+        /// <summary>
+        /// 数据id
+        /// </summary>
+        public string? id { get; set; }
+        /// <summary>
+        /// 状态
+        /// </summary>
+        public int status { get; set; }
+        /// <summary>
+        /// 文件名
+        /// </summary>
+        public string? name { get; set; }
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public long createTime { get; set; }
+        /// <summary>
+        /// 阿里云OSS文件地址
+        /// </summary>
+        public string? recordUrl { get; set;}
+    }
+    
+}

+ 36 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Services/IndexService.cs

@@ -8,11 +8,47 @@ using System.Text.Json.Nodes;
 using System.Text.RegularExpressions;
 using IES.ExamServer.Models;
 using System.Text;
+using IES.ExamServer.DI;
+using IES.ExamServer.Helper;
 
 namespace IES.ExamServer.Services
 {
     public static class IndexService
     {
+
+        public static async Task<(string content_response, HttpStatusCode code)> GetMusicServer_thirdLocalCacheConfig(IHttpClientFactory httpClientFactory, CenterServiceConnectionService _connectionService , string requestBody)
+        {
+            string content_response = string.Empty;
+            HttpStatusCode code = HttpStatusCode.OK ;
+            try {
+                string url = _connectionService!.musicUrl!;
+                var client = httpClientFactory.CreateClient();
+                //client.DefaultRequestHeaders.Add("Accept", "application/json, text/plain, */*");
+                client.DefaultRequestHeaders.Add("appId", Constant._MusicAIServerAppId);
+                client.DefaultRequestHeaders.Add("encrypt", "1");
+                client.DefaultRequestHeaders.Add("schoolCode", _connectionService.serverDevice?.school?.id);
+                var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
+                // 发送 PUT 请求
+                HttpResponseMessage response = await client.PutAsync($"{url}/musicLocalCache/thirdLocalCacheConfig", content);
+                // 处理响应
+
+                if (response.IsSuccessStatusCode)
+                {
+                    content_response = await response.Content.ReadAsStringAsync();
+                    //Console.WriteLine("Response: " + responseData);
+                }
+                else
+                {
+                    //   Console.WriteLine("Error: " + response.StatusCode);
+                    code=response.StatusCode;
+                    content_response = await response.Content.ReadAsStringAsync();
+                }
+            } catch (Exception ex) {
+                code= HttpStatusCode.InternalServerError;
+                content_response = ex.Message;
+            }
+            return (content_response, code);
+        }
         public static ServerDevice GetServerDevice( string remote,string region)
         {
             string hostName = $"{Environment.UserName}-{Dns.GetHostName()}";

+ 2 - 1
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/appsettings.json

@@ -32,7 +32,8 @@
     "Timeout": 30000,
     "Delay": 500,
     "CenterUrl": "https://www.teammodel.cn",
-    "NotifyUrl": "https://www.winteach.cn"
+    "NotifyUrl": "https://www.winteach.cn",
+    "MusicUrl": "https://musicapi.winteach.cn/api/v1"
   },
   "ExamClient": {
     "Domain": "habook.local"