CrazyIter_Bin 5 mesi fa
parent
commit
dd7a8f3445

+ 2 - 2
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/BaseController.cs

@@ -96,8 +96,8 @@ namespace IES.ExamServer.Controllers
 
 
 
-        public readonly int code = 0;
-        public readonly string msg = "OK";
+        public   int code = 0;
+        public   string msg = "OK";
 
 
     }

+ 10 - 9
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/IndexController.cs

@@ -24,19 +24,19 @@ namespace IES.ExamServer.Controllers
         private readonly IMemoryCache _memoryCache;
         private readonly ILogger<IndexController> _logger;
         private readonly DataCenterConnectionService _connectionService;
-        public IndexController(ILogger<IndexController> logger, IConfiguration configuration, IHttpClientFactory httpClientFactory, IMemoryCache memoryCache,DataCenterConnectionService connectionService)
+        private readonly LiteDBFactory _liteDBFactory;
+        public IndexController(ILogger<IndexController> logger, IConfiguration configuration, IHttpClientFactory httpClientFactory, IMemoryCache memoryCache,DataCenterConnectionService connectionService, LiteDBFactory liteDBFactory)
         {
             _logger = logger;
             _configuration=configuration;
             _httpClientFactory=httpClientFactory;
             _memoryCache=memoryCache;
             _connectionService=connectionService;
+            _liteDBFactory=liteDBFactory;
         }
         [HttpPost("device")]
-        public async Task<IActionResult> Device(JsonElement json )
+        public IActionResult Device(JsonElement json )
         {
-            int code = 0;
-            string msg = string.Empty;
             try
             {
                 string ip=   GetIP();
@@ -81,8 +81,6 @@ namespace IES.ExamServer.Controllers
         [HttpPost("login-check")]
         public async Task<IActionResult> LoginCheck(JsonNode json)
         {
-            int code = 0;
-            string msg = string.Empty;
             try
             {
                 var type = json["type"];
@@ -93,6 +91,7 @@ namespace IES.ExamServer.Controllers
                     string x_auth_token = string.Empty;
                     List<School>? schools = null;
                     JsonNode? jsonNode = null;
+                    long time = DateTimeOffset.Now.ToUnixTimeMilliseconds();
                     switch (true)
                     {
                         //跳过忽略,但是仍然要以访客身份登录
@@ -102,7 +101,8 @@ namespace IES.ExamServer.Controllers
                                 string name = $"访客教师-{Random.Shared.Next(100, 999)}";
                                 x_auth_token = JwtAuthExtension.CreateAuthToken("www.teammodel.cn",id ,name,null
                                     ,ExamConstant.JwtSecretKey,ExamConstant.ScopeVisitor,8,null,new string[] { "visitor" }, expire: 1);
-                                _memoryCache.Set($"Teacher:{id}", new LoginTeacher { id = id, name = $"{name}", implicit_token = token, picture = null, schools = schools, x_auth_token = x_auth_token });
+                                //  _memoryCache.Set($"Teacher:{id}", new Teacher { id = id, name = $"{name}", implicit_token = token, picture = null, schools = schools, x_auth_token = x_auth_token });
+                                _liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().Upsert(new Teacher { id = id, name = $"{name}", implicit_token = token, picture = null, schools = schools, x_auth_token = x_auth_token,loginTime=time });
                                 return Ok(new { code = 200,x_auth_token = x_auth_token });
                             }
                         case bool when $"{type}".Equals("qrcode"):
@@ -167,7 +167,8 @@ namespace IES.ExamServer.Controllers
                         var id = jwt.Payload.Sub;
                         jwt.Payload.TryGetValue("name", out object? name);
                         jwt.Payload.TryGetValue("picture", out object? picture);
-                        _memoryCache.Set($"Teacher:{id}", new LoginTeacher { id=id, name=$"{name}", implicit_token= token, picture=$"{picture}", schools=schools, x_auth_token=x_auth_token });
+                        //_memoryCache.Set($"Teacher:{id}", new Teacher { id=id, name=$"{name}", implicit_token= token, picture=$"{picture}", schools=schools, x_auth_token=x_auth_token });
+                        _liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().Upsert(new Teacher { id=id, name=$"{name}", implicit_token= token, picture=$"{picture}", schools=schools, x_auth_token=x_auth_token ,loginTime=time });
                         return Ok(new { code=200,/* implicit_token = token, schools = schools , */ x_auth_token = x_auth_token });
                     }
                     else
@@ -187,7 +188,7 @@ namespace IES.ExamServer.Controllers
                 code=500;
                 msg="异常错误";
             }
-            return Ok(new { code = code });
+            return Ok(new { code = code,msg });
         }
         /*
      

+ 132 - 14
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/ManageController.cs

@@ -1,10 +1,12 @@
 using IES.ExamLib.Models;
 using IES.ExamServer.DI;
 using IES.ExamServer.Filters;
+using IES.ExamServer.Helper;
 using IES.ExamServer.Models;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Caching.Memory;
 using Microsoft.Extensions.Configuration;
+using System.Linq.Expressions;
 using System.Net.Http;
 using System.Text.Json;
 using System.Text.Json.Nodes;
@@ -41,27 +43,139 @@ namespace IES.ExamServer.Controllers
             //下载日志记录:1.步骤,检查,2.获取描述信息,3.分类型,4下载文件,5.前端处理,6.返回结果 , 正在下载...==> https://www.doubao.com/chat/collection/687687510791426?type=Thread  Ok...
             return Ok();
         }
-        [HttpPost("search-short-code")]
-        public async Task<IActionResult> SearchShortCode(JsonNode json)
+        [HttpPost("check-short-code")]
+        public async Task<IActionResult> CheckShortCode(JsonNode json)
         {
+           
+            string shortCode = $"{json["shortCode"]}";
+            string evaluationId = $"{json["evaluationId"]}";
+            Expression<Func<EvaluationClient, bool>> predicate = x => true;
+
+            if (!string.IsNullOrEmpty(shortCode))
+            {
+                var codePredicate = ExpressionHelper.Or<EvaluationClient>(
+                    x => !string.IsNullOrWhiteSpace(x.shortCode) &&  x.shortCode == shortCode,
+                    x => !string.IsNullOrWhiteSpace(x.password) &&  x.password == shortCode
+                );
+                predicate= predicate.And(codePredicate);
+            }
+            else {
+                return Ok(new { code = 400,msg="必须输入开卷码" });
+            }
+            if (!string.IsNullOrWhiteSpace(evaluationId))
+            {
+                predicate= predicate.And(x => x.id!.Equals(evaluationId));
+            }
+            IEnumerable<EvaluationClient> evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Find(predicate);
+            EvaluationClient? evaluationLocal = null;
+            EvaluationClient? evaluationCloud = null;
+            if (evaluationClients.Count()>0)
+            {
+                evaluationLocal= evaluationClients.First();
+            }
             //如果要访问中心,则需要教师登录联网。  
             var token = GetAuthTokenInfo();
             if (token.scope.Equals(ExamConstant.ScopeTeacher))
             {
-                string shortCode = $"{json["shortCode"]}";
-                if (string.IsNullOrWhiteSpace(shortCode))
+                if (  _connectionService.dataCenterIsConnected)
                 {
-                    EvaluationClient evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>()
-                        .FindOne(x => (!string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode.Equals(shortCode)) || (!string.IsNullOrWhiteSpace(x.password) && x.password.Equals(shortCode)));
-                    if (evaluationClient == null && _connectionService.dataCenterIsConnected)
+                    Teacher teacher=  _liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().FindOne(x => x.id!.Equals(token.id));
+                    string? CenterUrl = _configuration.GetValue<string>("ExamServer:CenterUrl");
+                    var client = _httpClientFactory.CreateClient();
+                    if (client.DefaultRequestHeaders.Contains(Constant._X_Auth_AuthToken)) 
                     {
-
-
+                        client.DefaultRequestHeaders.Remove(Constant._X_Auth_AuthToken);
+                    }
+                    client.DefaultRequestHeaders.Add(Constant._X_Auth_AuthToken, teacher.x_auth_token);
+                    HttpResponseMessage message = await client.PostAsJsonAsync($"{CenterUrl}/evaluation-sync/find-sync-info",new { shortCode, evaluationId });
+                    if (message.IsSuccessStatusCode) 
+                    {
+                        string content = await message.Content.ReadAsStringAsync();
+                        JsonNode? jsonNode =JsonSerializer.Deserialize<JsonNode>(content);
+                        if (jsonNode!=null) 
+                        {
+                            evaluationCloud= JsonSerializer.Deserialize<EvaluationClient>(jsonNode["evaluation"]);
+                        }
                     }
                 }
             }
+            //数据,文件,页面 0 没有更新,1 有更新
+            int data = 0,blob=0,webview=0,status=0;
+            long dataSize = 0, blobSize=0 , webviewSize=0;
+            if (evaluationLocal== null && evaluationCloud==null)
+            {
+                //线上线下没有数据
+                status=1;
+                
+            }
+            else if (evaluationLocal!=null && evaluationCloud!=null) 
+            {
+                //线上线下有数据
+                status = 2;
+                if ((!string.IsNullOrWhiteSpace(evaluationLocal.blobHash) &&  !evaluationLocal.blobHash.Equals(evaluationCloud.blobHash))
+                    ||(evaluationLocal.blobTime<evaluationCloud.blobTime) 
+                    ||(evaluationLocal.blobCount!= evaluationCloud.blobCount)
+                    ||(evaluationLocal.blobSize!= evaluationCloud.blobSize))
+                {
+                    blob=1;
+                    blobSize=evaluationCloud.blobSize;
+                }
+                if ((evaluationLocal.dataTime<evaluationCloud.dataTime)
+                    ||(evaluationLocal.dataSize!=evaluationCloud.dataSize))
+                {
+                    data=1;
+                    dataSize=evaluationCloud.dataSize;
+                }
+                if ((evaluationLocal.webviewCount!=evaluationCloud.webviewCount)
+                    ||(evaluationLocal.webviewSize!= evaluationCloud.webviewSize)
+                    ||(evaluationLocal.webviewTime!= evaluationCloud.webviewTime)
+                    ||(!string.IsNullOrWhiteSpace(evaluationLocal.webviewPath)&&  !evaluationLocal.webviewPath.Equals(evaluationCloud.webviewPath)))
+                {
+                    webview=1;
+                    webviewSize=evaluationCloud.webviewSize;
+                }
+            }
+            else if (evaluationLocal!=null && evaluationCloud==null)
+            {
+                //线下有数据,线上没有数据,可能没联网。
+                status = 3;
+            }
+            else if (evaluationLocal==null && evaluationCloud!=null)
+            {
+                //线下没有数据,线上有数据
+                evaluationLocal= evaluationCloud;
+                blob=1;
+                data=1;
+                webview=1;
+                blobSize=evaluationCloud.blobSize;
+                dataSize=evaluationCloud.dataSize;
+                webviewSize=evaluationCloud.webviewSize;
+                status = 4;
+                _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Insert(evaluationLocal);
+            }
+            List<int> file_intact = new List<int>();
+            if (evaluationLocal!=null)
+            {
+                //校验本地文件数据
+                string packagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package");
+                if (!Directory.Exists(packagePath))
+                    Directory.CreateDirectory(packagePath);
+                string evaluationPath = Path.Combine(packagePath, evaluationLocal.id!);
+                if (!System.IO.File.Exists(Path.Combine(evaluationPath, "evaluation.json")))
+                {
+                    file_intact.Add(0);
+                }
+                if (!System.IO.File.Exists(Path.Combine(evaluationPath, "groupList.json")))
+                {
+                    file_intact.Add(0);
+                }
+                if (!System.IO.File.Exists(Path.Combine(evaluationPath, "source.json")))
+                {
+                    file_intact.Add(0);
+                }
+            }
 
-            return Ok();
+            return Ok(new {code=200, evaluation= evaluationLocal,data,blob,webview,dataSize,blobSize,webviewSize,status });
         }
 
         /// <summary>
@@ -74,10 +188,13 @@ namespace IES.ExamServer.Controllers
         {
             string id = $"{json["id"]}";
             string shortCode = $"{json["shortCode"]}";
-            EvaluationClient evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x=>x.id!.Equals(id));
-            if (evaluationClient != null) 
+            if (!string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(shortCode)) 
             {
-            
+                EvaluationClient evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x => x.id!.Equals(id) && !string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode.Equals(shortCode));
+                if (evaluationClient != null)
+                {
+
+                }
             }
             return Ok();
         }
@@ -89,6 +206,7 @@ namespace IES.ExamServer.Controllers
         [HttpPost("list-local-evaluation")]
         public IActionResult ListLocalEvaluation(JsonNode json) 
         {
+
             IEnumerable<EvaluationClient> evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindAll().OrderByDescending(x=>x.activate).ThenByDescending(x=>x.stime);
             var result = evaluationClients.Select(client =>
             {
@@ -103,7 +221,7 @@ namespace IES.ExamServer.Controllers
                 }
                 return anonymousObject;
             });
-            return Ok(new { evaluation= result });
+            return Ok(new {code=200, evaluation= result });
         }
     }
 }

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

@@ -10,5 +10,6 @@ namespace IES.ExamServer.Helper
     {
         public static string _KeyServerCenter = "Server:Center:Data";
         public static string _KeyServerDevice = "Server:Device:Info";
+        public static string _X_Auth_AuthToken = "X-Auth-AuthToken";
     }
 }

+ 68 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/ExpressionHelper.cs

@@ -0,0 +1,68 @@
+using System.Linq.Expressions;
+
+namespace IES.ExamServer
+{
+    public static class ExpressionHelper
+    {
+       
+
+        public static Expression<Func<T, bool>> And<T>(  this Expression<Func<T, bool>> first,    Expression<Func<T, bool>> second)
+        {
+            // 创建一个新的参数表达式
+            var parameter = Expression.Parameter(typeof(T), "x");
+
+            // 替换第一个表达式中的参数
+            var leftVisitor = new ReplaceParameterVisitor(first.Parameters[0], parameter);
+            var left = leftVisitor.Visit(first.Body);
+
+            // 替换第二个表达式中的参数
+            var rightVisitor = new ReplaceParameterVisitor(second.Parameters[0], parameter);
+            var right = rightVisitor.Visit(second.Body);
+
+            // 组合两个表达式
+            var combined = Expression.AndAlso(left, right);
+
+            // 创建新的 lambda 表达式
+            return Expression.Lambda<Func<T, bool>>(combined, parameter);
+        }
+        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
+        {
+            // 创建一个新的参数表达式
+            var parameter = Expression.Parameter(typeof(T), "x");
+
+            // 替换第一个表达式中的参数
+            var leftVisitor = new ReplaceParameterVisitor(first.Parameters[0], parameter);
+            var left = leftVisitor.Visit(first.Body);
+
+            // 替换第二个表达式中的参数
+            var rightVisitor = new ReplaceParameterVisitor(second.Parameters[0], parameter);
+            var right = rightVisitor.Visit(second.Body);
+
+            // 组合两个表达式
+            var combined = Expression.OrElse(left, right);
+
+            // 创建新的 lambda 表达式
+            return Expression.Lambda<Func<T, bool>>(combined, parameter);
+        }
+
+        private class ReplaceParameterVisitor : ExpressionVisitor
+        {
+            private readonly ParameterExpression _oldParameter;
+            private readonly ParameterExpression _newParameter;
+
+            public ReplaceParameterVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
+            {
+                _oldParameter = oldParameter;
+                _newParameter = newParameter;
+            }
+
+            protected override Expression VisitParameter(ParameterExpression node)
+            {
+                // 如果遇到旧的参数,替换为新的参数
+                if (node == _oldParameter)
+                    return _newParameter;
+                return base.VisitParameter(node);
+            }
+        }
+    }
+}

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

@@ -16,7 +16,7 @@
 	</ItemGroup>
 	
 	<ItemGroup>
-		<Folder Include="wwwroot\" />
+		<Folder Include="wwwroot\package\" />
 	</ItemGroup>
 	
 	<ItemGroup>

+ 4 - 11
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Models/Teacher.cs

@@ -12,8 +12,9 @@ namespace IES.ExamServer.Models
         public string? name { get; set; }
         public string? picture {  get; set; }
         public string? x_auth_token {  get; set; }
-        public string? access_token { get; set; }
-        public List<School> schools { get; set; }= new List<School>();
+        public List<School>? schools { get; set; }= new List<School>();
+        public TmdidImplicit? implicit_token { get; set; }
+        public long loginTime { get; set; }
     }
 
     public class School
@@ -31,13 +32,5 @@ namespace IES.ExamServer.Models
         public string? token_type { get; set; }
     }
 
-    public class LoginTeacher 
-    {
-        public string? id { get; set; }
-        public string? name { get; set; }
-        public string? picture { get; set; }
-        public string? x_auth_token { get;set; }
-        public TmdidImplicit? implicit_token { get; set; }
-        public List<School>? schools{ get;set;}= new List<School>();
-    }
+   
 }

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

@@ -15,6 +15,7 @@ using IES.ExamServer.Filters;
 using IES.ExamServer.Helpers;
 using Microsoft.Extensions.Hosting;
 using System.Security.Principal;
+using Microsoft.Extensions.FileProviders;
 
 namespace IES.ExamServer
 {
@@ -92,9 +93,22 @@ namespace IES.ExamServer
             app.UseHttpsRedirection();
             app.UseDefaultFiles();
             var contentTypeProvider = new FileExtensionContentTypeProvider();
-            contentTypeProvider.Mappings[".glb"] = "model/gltf-binary";
+            contentTypeProvider.Mappings[".txt"] = "text/plain";
+            contentTypeProvider.Mappings[".jpg"] = "image/jpeg";
+            contentTypeProvider.Mappings[".jpeg"] = "image/jpeg";
+            contentTypeProvider.Mappings[".png"] = "image/png";
+            contentTypeProvider.Mappings[".html"] = "text/html";
+            contentTypeProvider.Mappings[".js"] = "application/javascript";
+            contentTypeProvider.Mappings[".css"] = "text/css";
+            contentTypeProvider.Mappings[".mp4"] = "video/mp4";
+            contentTypeProvider.Mappings[".mp3"] = "audio/mpeg";
+            contentTypeProvider.Mappings[".json"] = "application/json";
+            contentTypeProvider.Mappings[".pdf"] = "application/pdf";
             app.UseStaticFiles(new StaticFileOptions
             {
+                FileProvider = new PhysicalFileProvider(
+                Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package")),
+                RequestPath = "/package",
                 ContentTypeProvider = contentTypeProvider,
             });