Преглед на файлове

Merge branch 'develop' into develop_local

jeff преди 2 месеца
родител
ревизия
343eaa5692
променени са 21 файла, в които са добавени 653 реда и са изтрити 161 реда
  1. 3 3
      TEAMModelBI/TEAMModelBI.csproj
  2. 1 6
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Configs/cer/modify_hosts.bat
  3. 43 35
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Configs/cer/certificate.bat
  4. 43 1
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Configs/cer/选择ip映射.bat
  5. 93 71
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/IndexController.cs
  6. 24 19
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/DI/ServiceInitializer.cs
  7. 66 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/ProcessHelper.cs
  8. 138 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/ZipHelper.cs
  9. 8 1
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/IES.ExamServer.csproj
  10. 6 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Models/ServerDevice.cs
  11. 144 2
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Services/IndexService.cs
  12. 3 3
      TEAMModelOS.Function/TEAMModelOS.Function.csproj
  13. 3 3
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  14. 3 0
      TEAMModelOS/ClientApp/public/lang/en-US.js
  15. 3 0
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  16. 3 0
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  17. 55 10
      TEAMModelOS/ClientApp/src/common/BaseQuickPaper.vue
  18. 8 1
      TEAMModelOS/ClientApp/src/common/MarkCanvas.vue
  19. 4 4
      TEAMModelOS/TEAMModelOS.csproj
  20. 1 1
      TEAMModelOS/appsettings.Development.json
  21. 1 1
      TEAMModelOS/appsettings.json

+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

@@ -77,9 +77,9 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2503.55</Version>
-		<AssemblyVersion>5.2503.55.1</AssemblyVersion>
-		<FileVersion>5.2503.55.1</FileVersion>
+		<Version>5.2503.125</Version>
+		<AssemblyVersion>5.2503.125.1</AssemblyVersion>
+		<FileVersion>5.2503.125.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

+ 1 - 6
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Configs/cer/modify_hosts.bat

@@ -4,7 +4,6 @@ echo Configuring hosts file
 net session >nul 2>&1
 if %errorLevel% neq 0 (
     echo Please run this script as an administrator
-    pause
     exit /b
 )
 
@@ -13,7 +12,6 @@ set "newEntry=192.168.8.150 exam.habook.local"
 
 if not exist "%hostsFile%" (
     echo hosts file does not exist:%hostsFile%
-    pause
     exit /b
 )
 
@@ -24,7 +22,6 @@ if %errorLevel% equ 0 (
     echo Removed all entries containing exam.habook.local
 ) else (
     echo Failed to remove entries containing exam.habook.local
-    pause
     exit /b
 )
 
@@ -34,9 +31,7 @@ if %errorLevel% equ 0 (
     echo Hosts file configured successfully
 ) else (
     echo Hosts file configuration failed
-    pause
     exit /b
 )
 
-echo Hosts file modification completed
-pause
+echo Hosts file modification completed

+ 43 - 35
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Configs/cer/certificate.bat

@@ -1,5 +1,5 @@
 @echo off
-echo Configuring hosts file
+echo Importing certificate
 
 net session >nul 2>&1
 if %errorLevel% neq 0 (
@@ -8,39 +8,6 @@ if %errorLevel% neq 0 (
     exit /b
 )
 
-set "hostsFile=C:\Windows\System32\drivers\etc\hosts"
-set "newEntry=192.168.8.150 exam.habook.local"
-
-if not exist "%hostsFile%" (
-    echo hosts file does not exist:%hostsFile%
-    pause
-    exit /b
-)
-
-
-findstr /v /i /c:"exam.habook.local" "%hostsFile%" > "%hostsFile%.tmp"
-if %errorLevel% equ 0 (
-    move /y "%hostsFile%.tmp" "%hostsFile%" >nul 2>&1
-    echo Removed all entries containing exam.habook.local
-) else (
-    echo Failed to remove entries containing exam.habook.local
-    pause
-    exit /b
-)
-
-
-echo %newEntry% >> "%hostsFile%"
-if %errorLevel% equ 0 (
-    echo Hosts file configured successfully
-) else (
-    echo Hosts file configuration failed
-    pause
-    exit /b
-)
-
-:ImportCert
-echo Importing certificate
-
 if not exist "%~dp0certificate.cer" (
     echo Certificate file does not exist:%~dp0certificate.cer
     pause
@@ -70,5 +37,46 @@ if %errorLevel% equ 0 (
     echo Certificate import failed
 )
 
-echo All operations completed
+echo Certificate installation completed
+
+
+echo Configuring hosts file
+
+net session >nul 2>&1
+if %errorLevel% neq 0 (
+    echo Please run this script as an administrator
+    pause
+    exit /b
+)
+
+set "hostsFile=C:\Windows\System32\drivers\etc\hosts"
+set "newEntry=192.168.8.132 exam.habook.local"
+
+if not exist "%hostsFile%" (
+    echo hosts file does not exist:%hostsFile%
+    pause
+    exit /b
+)
+
+findstr /v /i /c:"exam.habook.local" "%hostsFile%" > "%hostsFile%.tmp"
+if %errorLevel% equ 0 (
+    move /y "%hostsFile%.tmp" "%hostsFile%" >nul 2>&1
+    echo Removed all entries containing exam.habook.local
+) else (
+    echo Failed to remove entries containing exam.habook.local
+    pause
+    exit /b
+)
+
+echo %newEntry% >> "%hostsFile%"
+if %errorLevel% equ 0 (
+    echo Hosts file configured successfully
+) else (
+    echo Hosts file configuration failed
+    pause
+    exit /b
+)
+
+echo Hosts file modification completed
+echo Add entry 192.168.8.132 exam.habook.local
 pause

+ 43 - 1
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Configs/cer/选择ip映射.bat

@@ -1,5 +1,5 @@
 @echo off
-echo Configuring hosts file
+echo Starting script execution...
 
 :: 检查是否以管理员身份运行
 net session >nul 2>&1
@@ -9,6 +9,45 @@ if %errorLevel% neq 0 (
     exit /b
 )
 
+:: 第一部分:安装证书
+echo Importing certificate...
+
+if not exist "%~dp0certificate.cer" (
+    echo Certificate file does not exist:%~dp0certificate.cer
+    pause
+    exit /b
+)
+
+set "certSubject="
+for /f "tokens=*" %%i in ('certutil -dump "%~dp0certificate.cer" ^| findstr /i "CN="') do (
+    set "certSubject=%%i"
+)
+
+if defined certSubject (
+    echo Deleting existing certificate with the same name
+    certutil -delstore "Root" "%certSubject%"
+    if %errorLevel% equ 0 (
+        echo Existing certificate deleted successfully
+    ) else (
+        echo Failed to delete existing certificate (may not exist)
+    )
+)
+
+echo Importing new certificate
+certutil -addstore -f "Root" "%~dp0certificate.cer"
+if %errorLevel% equ 0 (
+    echo Certificate imported successfully
+) else (
+    echo Certificate import failed
+    pause
+    exit /b
+)
+
+echo Certificate installation completed
+
+:: 第二部分:修改hosts文件
+echo Configuring hosts file...
+
 :: 设置hosts文件路径
 set "hostsFile=C:\Windows\System32\drivers\etc\hosts"
 
@@ -81,4 +120,7 @@ if %errorLevel% equ 0 (
 del ip_list.txt
 
 echo Hosts file modification completed
+
+:: 脚本执行完毕
+echo Script execution completed successfully
 pause

+ 93 - 71
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Controllers/IndexController.cs

@@ -337,48 +337,113 @@ namespace IES.ExamServer.Controllers
         {
             return Ok(new { code=200});
         }
-
+        /// <summary>
+        /// 更新学校
+        /// </summary>
+        /// <param name="ip"></param>
+        /// <returns></returns>
+        [HttpGet("update-schools")]
+        public async Task<IActionResult> UpdateSchools()
+        {
+            try {
+                var httpClient = _httpClientFactory.CreateClient();
+                httpClient.Timeout = TimeSpan.FromSeconds(10);
+                HttpResponseMessage message = await httpClient.GetAsync("https://teammodelos.blob.core.chinacloudapi.cn/0-public/schools.json");
+                if (message.IsSuccessStatusCode)
+                {
+                    // 读取响应内容
+                    string content = await message.Content.ReadAsStringAsync();
+                    // 保存文件的路径
+                    string filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "schools.json");
+                    // 确保目录存在
+                    Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
+                    // 将内容写入文件
+                    await System.IO.File.WriteAllTextAsync(filePath, content);
+                    return Ok(new { code=200,msg="更新成功"});
+                }
+                else
+                {
+                    return Ok(new { code = (int)message.StatusCode, msg = "更新成功" }); 
+                }
+               
+            } catch (Exception ex) {
+                return Ok(new { code =500, msg = ex.Message });
+            }
+        }
         /// <summary>
         /// 修改Hosts文件的 局域网域名IP映射
         /// </summary>
         /// <param name="ip"></param>
         /// <returns></returns>
         [HttpGet("modify-hosts")]
-        public async Task<IActionResult> ModifyHosts([FromQuery] string ip ) 
+        public async Task<IActionResult> ModifyHosts([FromQuery] string? ip=null ) 
         {
             try
             {
+               
+                string pathCerNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "certificate.cer");
+                string pathBatNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "install_certificate.bat");
+                if (!System.IO.File.Exists(pathCerNew)|| !System.IO.File.Exists(pathBatNew))
+                {
+                    string pathCer = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "certificate.cer");
+                    System.IO.File.Copy(pathCer, pathCerNew);
+                    string pathBat = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "install_certificate.bat");
+                    System.IO.File.Copy(pathBat, pathBatNew);
+                    var res = ProcessHelper.ExecuteProcess(pathBatNew);
+                }
+
                 ServerDevice serverDevice = _memoryCache.Get<ServerDevice>(Constant._KeyServerDevice);
                 if (serverDevice != null && serverDevice.networks.IsNotEmpty())
                 {
-                  
-                    var network = serverDevice.networks.Find(x => ip.Equals(x.ip));
+                    Network? network = serverDevice.networks.FirstOrDefault();
+                    if (!string.IsNullOrWhiteSpace(ip))
+                    {
+                        network = serverDevice.networks.FindAll(x => ip.Equals(x.ip))?.FirstOrDefault(); 
+                    }
+                   
                     if (network != null && !string.IsNullOrWhiteSpace(network.ip))
                     {
-                        string pathBat = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "modify_hosts.bat");
-                        string text = await System.IO.File.ReadAllTextAsync(pathBat);
-
+                        network.primary = 1;
+                        _memoryCache.Set<ServerDevice>(Constant._KeyServerDevice,serverDevice);
+                        string pathBatHosts = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "modify_hosts.bat");
+                        string text = await System.IO.File.ReadAllTextAsync(pathBatHosts);
                         // 使用正则表达式替换 IP 地址
                         string pattern = @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b";
                         string result = Regex.Replace(text, pattern, network.ip);
-                        string pathCertificateBat = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package", "certificate.bat");
-                        await System.IO.File.WriteAllTextAsync(pathCertificateBat, result);
-
-
-                        return Ok(new { code = 200, msg = "执行成功。", bat = "package/certificate.bat" });
+                        string pathBatHostsNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot",  "modify_hosts.bat");
+                        await System.IO.File.WriteAllTextAsync(pathBatHostsNew, result);
+                        string pathBatStudent = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "student_manual.bat");
+                        string textStudent = await System.IO.File.ReadAllTextAsync(pathBatStudent);
+                        // 使用正则表达式替换 IP 地址
+                        string resultStudent = Regex.Replace(textStudent, pattern, network.ip);
+                        string pathBatStudentNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "student_manual.bat");
+                        await System.IO.File.WriteAllTextAsync(pathBatStudentNew, resultStudent);
+                        var resHosts = ProcessHelper.ExecuteProcess(pathBatHostsNew);
+                        return Ok(new {
+                            code = 200,
+                            msg = "成功",
+                            serverDevice,
+                            cer = "certificate.cer",
+                            install_certificate = "install_certificate.bat",
+                            modify_hosts= "modify_hosts.bat",
+                            student_manual= "student_manual.bat"
+                        });
                     }
                     else
                     {
+                        code = 400;
                         msg = "未找到匹配的IP。";
                     }
                 }
                 else
                 {
+                    code = 400;
                     msg = "服务端设备未找到,或网卡设备不存在。";
                 }
             }
             catch (Exception ex)
             {
+                code = 500;
                 _logger.LogError($"域名IP绑定错误。{ex.Message},{ex.StackTrace}");
                 msg = $"域名IP绑定错误,{ex.Message}";
             }
@@ -390,63 +455,15 @@ namespace IES.ExamServer.Controllers
         {
             try
             {
+                string pathCerNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "certificate.cer");
+                string pathBatNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "install_certificate.bat");
+                string pathCer = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "certificate.cer");
+                System.IO.File.Copy(pathCer, pathCerNew);
                 string pathBat = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "install_certificate.bat");
-                // 创建一个新的 ProcessStartInfo 对象
-                ProcessStartInfo startInfo = new ProcessStartInfo
-                {
-                    // 指定要执行的 BAT 文件的路径
-                    FileName = "cmd.exe",
-                    // 设置命令行参数,使用 /c 表示执行命令后关闭命令提示符窗口
-                    Arguments = $"/c {pathBat}",
-                    // 设置是否使用操作系统 shell 启动进程
-                    UseShellExecute = false,
-                    // 设置是否创建新的窗口
-                    CreateNoWindow = true,
-                    // 重定向标准输出和标准错误输出
-                    RedirectStandardOutput = true,
-                    RedirectStandardError = true
-                };
-                // 创建一个新的 Process 对象
-                using (Process process = new Process())
-                {
-                    // 将 ProcessStartInfo 对象分配给 Process 对象
-                    process.StartInfo = startInfo;
+                System.IO.File.Copy(pathBat, pathBatNew);
+                var res = ProcessHelper.ExecuteProcess(pathBatNew);
 
-                    // 启动进程
-                    process.Start();
-
-                    // 读取标准输出和标准错误输出
-                    string output = process.StandardOutput.ReadToEnd();
-                    string error = process.StandardError.ReadToEnd();
-
-                    // 等待进程执行完成
-                    process.WaitForExit();
-
-                    // 输出执行结果
-                    if (!string.IsNullOrEmpty(output))
-                    {
-                        // Console.WriteLine("标准输出:");
-                        // Console.WriteLine(output);
-                        if (output.Contains("successfully", StringComparison.OrdinalIgnoreCase))
-                        {
-                            msg = $"证书安装成功!";
-                            code = 200;
-                        }
-                        else {
-                            msg = $"证书安装异常:{output}";
-                            code = 1;
-                        }
-                      
-                    }
-
-                    if (!string.IsNullOrEmpty(error))
-                    {
-                        // Console.WriteLine("错误输出:");
-                        // Console.WriteLine(error);
-                        msg = $"执行失败:{error}";
-                        code = 2;
-                    }
-                }
+                return Ok(new {code= res.code, msg= res.msg });
             }
             catch (Exception ex)
             {
@@ -456,8 +473,13 @@ namespace IES.ExamServer.Controllers
             }
             return Ok(new { code = code, msg = msg });
         }
-        [HttpPost("generate-certificate")]
-        public async Task<IActionResult> GenerateCertificate(JsonNode json) 
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [HttpPost("download-primary")]
+        public async Task<IActionResult> DownloadPrimary(JsonNode json) 
         {
             try {
                 ServerDevice serverDevice = _memoryCache.Get<ServerDevice>(Constant._KeyServerDevice);
@@ -496,7 +518,7 @@ namespace IES.ExamServer.Controllers
         [HttpPost("list-schools")]
         public async Task<IActionResult> ListSchool(JsonNode json) 
         {
-            string filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package", "schools.json");
+            string filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot",  "schools.json");
             string schoolText = await System.IO.File.ReadAllTextAsync(filePath);
             JsonNode? node = schoolText.ToObject<JsonNode>();
             return Ok(new {code =200, schools= node?["schools"] });
@@ -509,7 +531,7 @@ namespace IES.ExamServer.Controllers
             string fp = $"{json["fp"]}";
             if (!string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(fp))
             {
-                string filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package", "schools.json");
+                string filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot",  "schools.json");
                 string schoolText = await System.IO.File.ReadAllTextAsync(filePath);
                 List<School>? schools = schoolText.ToObject<JsonNode>()?["schools"]?.ToObject<List<School>>();
                 School? school = schools?.Find(x => id.Equals(x.id)  && name.Equals(x.name));

+ 24 - 19
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/DI/ServiceInitializer.cs

@@ -92,24 +92,30 @@ namespace IES.ExamServer.DI
             }
             if (hybrid==1)
             {
-              
-                var httpClient = _clientFactory.CreateClient();
-                httpClient.Timeout = TimeSpan.FromSeconds(10);
-                HttpResponseMessage message = await httpClient.GetAsync("https://teammodelos.blob.core.chinacloudapi.cn/0-public/schools.json");
-                if (message.IsSuccessStatusCode)
-                {
-                    // 读取响应内容
-                    string content = await message.Content.ReadAsStringAsync();
-                    // 保存文件的路径
-                    string filePath = Path.Combine(Directory.GetCurrentDirectory(),"wwwroot", "package", "schools.json");
-                    // 确保目录存在
-                    Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
-                    // 将内容写入文件
-                    await File.WriteAllTextAsync(filePath, content);
-                }
-                else
-                {
-                    throw new Exception($"Failed to download data. Status code: {message.StatusCode}");
+                try {
+                    string filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "schools.json");
+                    if (!File.Exists(filePath))
+                    {
+                        var httpClient = _clientFactory.CreateClient();
+                        httpClient.Timeout = TimeSpan.FromSeconds(10);
+                        HttpResponseMessage message = await httpClient.GetAsync("https://teammodelos.blob.core.chinacloudapi.cn/0-public/schools.json");
+                        if (message.IsSuccessStatusCode)
+                        {
+                            // 读取响应内容
+                            string content = await message.Content.ReadAsStringAsync();
+                            // 保存文件的路径
+                            // 确保目录存在
+                            Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
+                            // 将内容写入文件
+                            await File.WriteAllTextAsync(filePath, content);
+                        }
+                        //else
+                        //{
+                        //   // throw new Exception($"Failed to download data. Status code: {message.StatusCode}");
+                        //}
+                    }
+                } catch (Exception ex) {
+                    _logger.LogError(ex.Message);
                 }
             }
             _connectionService.musicUrl = _configuration.GetValue<string>("ExamServer:MusicUrl");
@@ -123,7 +129,6 @@ namespace IES.ExamServer.DI
             School? school = schools?.FirstOrDefault();
             serverDevice.school = school;
             _cache.Set(Constant._KeyServerDevice, serverDevice);
-           
             _liteDBFactory.GetLiteDatabase().GetCollection<ServerDevice>().Upsert(serverDevice);
             _connectionService.serverDevice = serverDevice;
             _lifetime.ApplicationStarted.Register(() =>

+ 66 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/ProcessHelper.cs

@@ -5,6 +5,72 @@ namespace IES.ExamServer.Helpers
 {
     public class ProcessHelper
     {
+
+        public static (int code, string msg) ExecuteProcess( string pathBat ) 
+        {
+            int code = 0;
+            string msg = string.Empty;
+
+            // 创建一个新的 ProcessStartInfo 对象
+            ProcessStartInfo startInfo = new ProcessStartInfo
+            {
+                // 指定要执行的 BAT 文件的路径
+                FileName = "cmd.exe",
+                // 设置命令行参数,使用 /c 表示执行命令后关闭命令提示符窗口
+                Arguments = $"/c {pathBat}",
+                // 设置是否使用操作系统 shell 启动进程
+                UseShellExecute = false,
+                // 设置是否创建新的窗口
+                CreateNoWindow = true,
+                // 重定向标准输出和标准错误输出
+                RedirectStandardOutput = true,
+                RedirectStandardError = true
+            };
+            // 创建一个新的 Process 对象
+            using (Process process = new Process())
+            {
+                // 将 ProcessStartInfo 对象分配给 Process 对象
+                process.StartInfo = startInfo;
+
+                // 启动进程
+                process.Start();
+
+                // 读取标准输出和标准错误输出
+                string output = process.StandardOutput.ReadToEnd();
+                string error = process.StandardError.ReadToEnd();
+
+                // 等待进程执行完成
+                process.WaitForExit();
+
+                // 输出执行结果
+                if (!string.IsNullOrEmpty(output))
+                {
+                    // Console.WriteLine("标准输出:");
+                    // Console.WriteLine(output);
+                    if (output.Contains("successfully", StringComparison.OrdinalIgnoreCase))
+                    {
+                        msg = $"执行成功!";
+                        code = 200;
+                    }
+                    else
+                    {
+                        msg = $"执行异常:{output}";
+                        code = 1;
+                    }
+
+                }
+
+                if (!string.IsNullOrEmpty(error))
+                {
+                    // Console.WriteLine("错误输出:");
+                    // Console.WriteLine(error);
+                    msg = $"执行失败:{error}";
+                    code = 2;
+                }
+            }
+            return (code, msg);
+        }
+
         /// <summary>
         ///  获取所有名为 "conhost.exe" 的进程
         /// </summary>

+ 138 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Helpers/ZipHelper.cs

@@ -43,7 +43,39 @@ namespace IES.ExamServer.Helpers
             }
         }
         */
+        /// <summary>
+        /// 创建带密码的 ZIP 文件
+        /// </summary>
+        /// <param name="sourceDirectory">要压缩的目录路径</param>
+        /// <param name="zipFilePath">生成的 ZIP 文件路径</param>
+        /// <param name="password">ZIP 文件密码</param>
+        /// <returns>是否成功</returns>
+        public static (bool res, string msg) CreateZip(string sourceDirectory, string zipFilePath)
+        {
+            if (!Directory.Exists(sourceDirectory))
+            {
+                // Console.WriteLine("源目录不存在。");
+                return (false, "源目录不存在。");
+            }
+
+            try
+            {
+                using (FileStream fsOut = File.Create(zipFilePath))
+                using (ZipOutputStream zipStream = new ZipOutputStream(fsOut))
+                {
+                    zipStream.SetLevel(0); // 设置压缩级别 (0-9)
+                    CompressFolder(sourceDirectory, zipStream, "");
+                }
 
+                //Console.WriteLine($"ZIP 文件已成功创建:{zipFilePath}");
+                return (true, $"ZIP 文件已成功创建");
+            }
+            catch (Exception ex)
+            {
+                // Console.WriteLine($"创建 ZIP 文件时发生错误:{ex.Message}");
+                return (false, $"创建 ZIP 文件时发生错误!");
+            }
+        }
         /// <summary>
         /// 创建带密码的 ZIP 文件
         /// </summary>
@@ -79,6 +111,112 @@ namespace IES.ExamServer.Helpers
                 return (false, $"创建 ZIP 文件时发生错误!");
             }
         }
+        /// <summary>
+        /// 解压带密码的 ZIP 文件
+        /// </summary>
+        /// <param name="zipFilePath">ZIP 文件路径</param>
+        /// <param name="extractPath">解压目标目录</param>
+        /// <param name="password">ZIP 文件密码</param>
+        /// <returns>是否成功</returns>
+        public static (bool res, string msg) ExtractZip(string zipFilePath, string extractPath)
+        {
+            if (!File.Exists(zipFilePath))
+            {
+                return (false, "ZIP 文件不存在。");
+            }
+            try
+            {
+                using (ZipInputStream zipInputStream = new ZipInputStream(File.OpenRead(zipFilePath)))
+                {
+                    ZipEntry entry;
+                    while ((entry = zipInputStream.GetNextEntry()) != null)
+                    {
+                        string entryFileName = entry.Name;
+                        string fullPath = Path.Combine(extractPath, entryFileName);
+                        // 创建目录(如果条目是目录)
+                        string? directoryName = Path.GetDirectoryName(fullPath);
+                        if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
+                        {
+                            Directory.CreateDirectory(directoryName);
+                        }
+                        // 如果是文件,则解压文件
+                        if (!entry.IsDirectory)
+                        {
+                            using (FileStream streamWriter = File.Create(fullPath))
+                            {
+                                byte[] buffer = new byte[4096];
+                                int bytesRead;
+                                while ((bytesRead = zipInputStream.Read(buffer, 0, buffer.Length)) > 0)
+                                {
+                                    streamWriter.Write(buffer, 0, bytesRead);
+                                }
+                            }
+                        }
+                    }
+                }
+                return (true, $"ZIP 文件已成功解压到:{extractPath}");
+            }
+            catch (Exception ex)
+            {
+                return (false, $"解压 ZIP 文件时发生错误:{ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 解压带密码的 ZIP 文件
+        /// </summary>
+        /// <param name="zipFilePath">ZIP 文件路径</param>
+        /// <param name="extractPath">解压目标目录</param>
+        /// <param name="password">ZIP 文件密码</param>
+        /// <returns>是否成功</returns>
+        public static (bool res, string msg) ExtractPasswordProtectedZip(string zipFilePath, string extractPath, string password)
+        {
+            if (!File.Exists(zipFilePath))
+            {
+                return (false, "ZIP 文件不存在。");
+            }
+            try
+            {
+                using (ZipInputStream zipInputStream = new ZipInputStream(File.OpenRead(zipFilePath)))
+                {
+                    zipInputStream.Password = password; // 设置解压密码
+
+                    ZipEntry entry;
+           
+                    while ((entry = zipInputStream.GetNextEntry()) != null)
+                    {
+                  
+                        string entryFileName = entry.Name;
+                        string fullPath = Path.Combine(extractPath, entryFileName);
+                        // 创建目录(如果条目是目录)
+                        string? directoryName = Path.GetDirectoryName(fullPath);
+                        if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
+                        {
+                            Directory.CreateDirectory(directoryName);
+                        }
+
+                        // 如果是文件,则解压文件
+                        if (!entry.IsDirectory)
+                        {
+                            using (FileStream streamWriter = File.Create(fullPath))
+                            {
+                                byte[] buffer = new byte[4096];
+                                int bytesRead;
+                                while ((bytesRead = zipInputStream.Read(buffer, 0, buffer.Length)) > 0)
+                                {
+                                    streamWriter.Write(buffer, 0, bytesRead);
+                                }
+                            }
+                        }
+                    }
+                }
+                return (true, $"ZIP 文件已成功解压到:{extractPath}");
+            }
+            catch (Exception ex)
+            {
+                return (false, $"解压 ZIP 文件时发生错误:{ex.Message}");
+            }
+        }
 
         /// <summary>
         /// 解压带密码的 ZIP 文件

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

@@ -31,6 +31,7 @@
   </ItemGroup>
   <ItemGroup>
 	<Folder Include="Logs\DataLogs\" />
+	<Folder Include="wwwroot\" />
 	
   </ItemGroup>
   <ItemGroup>
@@ -48,7 +49,7 @@
     <None Update="Configs\cer\cert.pem">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
-    <None Update="Configs\cer\certificate.bat">
+    <None Update="Configs\cer\teacher_manual.bat">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
     <None Update="Configs\cer\certificate.cer">
@@ -57,5 +58,11 @@
     <None Update="Configs\cer\key.pem">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
+    <None Update="Configs\cer\modify_hosts.bat">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Configs\cer\student_manual.bat">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
   </ItemGroup>
 </Project>

+ 6 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Models/ServerDevice.cs

@@ -70,6 +70,11 @@ namespace IES.ExamServer.Models
     }
     public class Network
     {
+        /// <summary>
+        /// 网卡信息id
+        /// </summary>
+        public string? id { get; set; }
+
         /// <summary>
         /// 网卡名称
         /// </summary>
@@ -92,5 +97,6 @@ namespace IES.ExamServer.Models
         /// 当前主站域名
         /// </summary>
         public int primary { get; set; }
+        public string? batscriptZip { get; set; }
     }
 }

+ 144 - 2
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Services/IndexService.cs

@@ -10,11 +10,154 @@ using IES.ExamServer.Models;
 using System.Text;
 using IES.ExamServer.DI;
 using IES.ExamServer.Helper;
+using System;
 
 namespace IES.ExamServer.Services
 {
     public static class IndexService
     {
+        public static async Task<(int code, string msg)> ModifyHosts(string ip,IMemoryCache _memoryCache,LiteDBFactory _liteDBFactory)
+        {
+            int code = 0;
+            string msg = string.Empty;
+            try
+            {
+                string batscriptPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript");
+                if (!Directory.Exists(batscriptPath)) 
+                {
+                    Directory.CreateDirectory(batscriptPath);
+                }
+                string pathCerNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "certificate.cer");
+                string pathBatNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "install_certificate.bat");
+                if (!System.IO.File.Exists(pathCerNew) || !System.IO.File.Exists(pathBatNew))
+                {
+                    string pathCer = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "certificate.cer");
+                    System.IO.File.Copy(pathCer, pathCerNew);
+                    string pathBat = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "install_certificate.bat");
+                    System.IO.File.Copy(pathBat, pathBatNew);
+                    var res = ProcessHelper.ExecuteProcess(pathBatNew);
+                }
+                //获取主站配置信息。
+                ServerDevice serverDevice = _memoryCache.Get<ServerDevice>(Constant._KeyServerDevice);
+                var primaryNetworks=   _liteDBFactory.GetLiteDatabase().GetCollection<Network>().FindAll().ToList();
+                Network? primaryNetwork = null;
+                //传入的ip为不为空
+                if (!string.IsNullOrWhiteSpace(ip) )
+                {
+                    if (serverDevice != null && serverDevice.networks.IsNotEmpty()) 
+                    {
+                    
+                    }
+                }
+                else 
+                {
+                    if (serverDevice != null && serverDevice.networks.IsNotEmpty()) 
+                    {
+                        //传入的ip为空,则尝试加载 已经配置过的主站域名ip
+                        if (primaryNetworks.IsNotEmpty())
+                        {
+                            foreach (var network in primaryNetworks)
+                            {
+                                var exists = serverDevice.networks.FindAll(x => x.id!.Equals(network.id));
+                                if (exists.IsNotEmpty())
+                                {
+                                    if (primaryNetwork == null)
+                                    {
+                                        primaryNetwork = network;
+                                    }
+                                    else
+                                    {
+                                        _liteDBFactory.GetLiteDatabase().GetCollection<Network>().Delete(network.id);
+                                    }
+                                }
+                                else
+                                {
+                                    _liteDBFactory.GetLiteDatabase().GetCollection<Network>().Delete(network.id);
+                                }
+                            }
+                        }
+                        //没有找到主站设置信息,则尝试赋值物理网卡配置信息
+                        if (primaryNetwork == null)
+                        {
+                            primaryNetwork = serverDevice.networks.FirstOrDefault();//第一个是物理网卡
+                        }
+                    }
+                   
+                }
+
+
+                if (serverDevice != null && serverDevice.networks.IsNotEmpty())
+                {
+                    Network? network = serverDevice.networks.FirstOrDefault();
+                    if (!string.IsNullOrWhiteSpace(ip))
+                    {
+                        network = serverDevice.networks.FindAll(x => ip.Equals(x.ip))?.FirstOrDefault();
+                    }
+
+                    if (network != null && !string.IsNullOrWhiteSpace(network.ip))
+                    {
+                       
+                        string pathBatHosts = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "modify_hosts.bat");
+                        string text = await System.IO.File.ReadAllTextAsync(pathBatHosts);
+                        // 使用正则表达式替换 IP 地址
+                        string pattern = @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b";
+                        string result = Regex.Replace(text, pattern, network.ip);
+                        string pathBatHostsNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "modify_hosts.bat");
+                        await System.IO.File.WriteAllTextAsync(pathBatHostsNew, result);
+                        string pathBatStudent = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "student_manual.bat");
+                        string textStudent = await System.IO.File.ReadAllTextAsync(pathBatStudent);
+                        // 使用正则表达式替换 IP 地址
+                        string resultStudent = Regex.Replace(textStudent, pattern, network.ip);
+                        string pathBatStudentNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "student_manual.bat");
+                        await System.IO.File.WriteAllTextAsync(pathBatStudentNew, resultStudent);
+                        var resHosts = ProcessHelper.ExecuteProcess(pathBatHostsNew);
+                        string batscriptZipPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "student_script.zip");
+                       
+                        var  res=    ZipHelper.CreateZip(batscriptPath, batscriptZipPath);
+                        if (res.res) 
+                        {
+                            serverDevice.networks.ForEach(x => {
+                                x.primary = 0;
+                                x.batscriptZip = null;
+                            });
+                            network.primary = 1;
+                            network.batscriptZip = batscriptZipPath;
+                            _memoryCache.Set<ServerDevice>(Constant._KeyServerDevice, serverDevice);
+                           // _liteDBFactory.GetLiteDatabase().GetCollection<ServerDevice>().Upsert(serverDevice);
+                        }
+                        //return Ok(new
+                        //{
+                        //    code = 200,
+                        //    msg = "成功",
+                        //    serverDevice,
+                        //    cer = "certificate.cer",
+                        //    install_certificate = "install_certificate.bat",
+                        //    modify_hosts = "modify_hosts.bat",
+                        //    student_manual = "student_manual.bat"
+                        //});
+                    }
+                    else
+                    {
+                        code = 400;
+                        msg = "未找到匹配的IP。";
+                    }
+                }
+                else
+                {
+                    code = 400;
+                    msg = "服务端设备未找到,或网卡设备不存在。";
+                }
+            }
+            catch (Exception ex)
+            {
+                code = 500;
+                //_logger.LogError($"域名IP绑定错误。{ex.Message},{ex.StackTrace}");
+                msg = $"域名IP绑定错误,{ex.Message}";
+            }
+            return (code, msg);
+        }
+
+
 
         public static async Task<(string content_response, HttpStatusCode code)> GetMusicServer_thirdLocalCacheConfig(IHttpClientFactory httpClientFactory, CenterServiceConnectionService _connectionService , string requestBody)
         {
@@ -290,8 +433,7 @@ namespace IES.ExamServer.Services
                         if (unicast.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                         {
                             var ip = unicast.Address.ToString();
-                            //  绑定域名 优先绑定
-                            Network network = new Network() { mac=mac, ip=ip, name= name, physical=physical };
+                            Network network = new Network() {id=ShaHashHelper.GetSHA1($"{mac}-{name}"), mac=mac, ip=ip, name= name, physical=physical };
                             if (!string.IsNullOrWhiteSpace(mac.ToString())  && !mac.Equals("000000000000"))
                             {
                                 device.networks.Add(network);

+ 3 - 3
TEAMModelOS.Function/TEAMModelOS.Function.csproj

@@ -5,9 +5,9 @@
     <OutputType>Exe</OutputType>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-	<Version>5.2503.55</Version>
-	<AssemblyVersion>5.2503.55.1</AssemblyVersion>
-	<FileVersion>5.2503.55.1</FileVersion>
+	<Version>5.2503.125</Version>
+	<AssemblyVersion>5.2503.125.1</AssemblyVersion>
+	<FileVersion>5.2503.125.1</FileVersion>
 	<PackageId>TEAMModelOS.FunctionV4</PackageId>
 	<Authors>teammodel</Authors>
 	<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 3 - 3
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -1,9 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 	<PropertyGroup>
 		<TargetFramework>net8.0</TargetFramework>
-		<Version>5.2503.55</Version>
-		<AssemblyVersion>5.2503.55.1</AssemblyVersion>
-		<FileVersion>5.2503.55.1</FileVersion>
+		<Version>5.2503.125</Version>
+		<AssemblyVersion>5.2503.125.1</AssemblyVersion>
+		<FileVersion>5.2503.125.1</FileVersion>
 		<PackageReleaseNotes>发版</PackageReleaseNotes>
 	</PropertyGroup>
 

+ 3 - 0
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -1614,6 +1614,7 @@ const LANG_EN_US = {
             info: 'Exam File Name',
             tip1: 'Please enter the name',
             attachments: 'Attachment',
+            attachments1:'Attachment (for question cpaturing only, will not be saved)',
             upload: 'Upload Attachment',
             empty: 'No attachment yet',
             preview: 'Preview',
@@ -1651,6 +1652,8 @@ const LANG_EN_US = {
             tip16: 'Question',
             tip17: ' was not found, or the number of questions queried is less than the required number of questions, please resetting',
             tip18: 'Not saved successfully',
+            tip19: 'Please set the total score of the test paper',
+            tip20: 'The total score of the test paper is inconsistent with the total score of the questions',
             screen: 'Capture',
             reScreen: 'Re-capture',
             screenQues: 'Grab questions',

+ 3 - 0
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -1613,6 +1613,7 @@ const LANG_ZH_CN = {
             info:'试卷信息',
             tip1:'输入试卷名称',
             attachments:'试卷附件',
+            attachments1:'附件(仅作截图使用,不会保存)',
             upload:'上传附件',
             empty:'暂无附件',
             preview:'预览',
@@ -1650,6 +1651,8 @@ const LANG_ZH_CN = {
             tip16: '第',
             tip17: '题未查询到题目,或查询的题目数量少于所需题目数量,请重新配置',
             tip18: '未保存成功',
+            tip19: '请设置试卷总分',
+            tip20: '试卷总分与题目总分不一致',
             screen: '截图',
             reScreen: '重新截图',
             screenQues: '框图取题',

+ 3 - 0
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -1616,6 +1616,7 @@ const LANG_ZH_TW = {
             info: '試卷資訊',
             tip1: '輸入試卷名稱',
             attachments: '試卷附件',
+            attachments1:'附件(僅供截題過程使用,不會保存)',
             upload: '上傳附件',
             empty: '暫無附件',
             preview: '預覽',
@@ -1653,6 +1654,8 @@ const LANG_ZH_TW = {
             tip16: '第',
             tip17: '題未查詢到題目,或查詢的題目數量少於所需題目數量,請重新設定',
             tip18: '未儲存成功',
+            tip19: '請設定試卷總分',
+            tip20: '試卷總分與題目總分不一致',
             screen: '截圖',
             reScreen: '重新截圖',
             screenQues: '框圖取題',

+ 55 - 10
TEAMModelOS/ClientApp/src/common/BaseQuickPaper.vue

@@ -28,6 +28,8 @@
 					</Option>
 				</Select>
 			</div>
+			<p class="title">{{ $t('evaluation.exerciseList.totalScore') }}</p>
+			<InputNumber v-model="paperInfo.score" :max="1000" :min="1" style="width: 30%;" />
 			<p class="title">
 				{{ $t("evaluation.quickPaper.attachments") }}
 				<Upload action="" style="display: inline-block" :format="['jpg', 'jpeg', 'png', 'pdf']" :max-size="2048" multiple :before-upload="handleBeforeUpload" :show-upload-list="false">
@@ -51,6 +53,25 @@
 			<Tag color="blue">{{ condName.periodName }}</Tag>
 			<Tag color="geekblue">{{ condName.subjectName }}</Tag>
 			<Tag color="purple">{{ condName.gradeName }}</Tag>
+			<template v-if="buildMode === 'order'">
+				<p class="title">
+					{{ $t("evaluation.quickPaper.attachments1") }}
+					<Upload action="" style="display: inline-block" :format="['jpg', 'jpeg', 'png', 'pdf']" :max-size="2048" multiple :before-upload="handleBeforeUpload" :show-upload-list="false">
+						<span class="btn-upload">{{ $t("evaluation.quickPaper.upload") }}</span>
+					</Upload>
+					<span @click="screenshotChange()" style="color: #515a6e;" class="btn-upload" v-if="buildMode === 'order' && attachments.length">{{ $t("evaluation.quickPaper.screen") }}</span>
+				</p>
+				<div class="img-list">
+					<div v-if="!attachments.length" style="margin: 20px 30px; color: #9999">{{ $t("evaluation.quickPaper.empty") }}</div>
+					<div class="img-item" v-for="(img, imgIndex) in attachments" :key="imgIndex">
+						<img :src="img" alt="" srcset="" />
+						<p style="text-align: center; cursor: pointer; font-size: 12px">
+							<span @click="doPreview(img)">{{ $t("evaluation.quickPaper.preview") }}</span>
+							<span style="margin-left: 10px" @click="doDelete(imgIndex)">{{ $t("evaluation.quickPaper.del") }}</span>
+						</p>
+					</div>
+				</div>
+			</template>
 		</div>
 		<div class="type-quick-part" v-if="buildMode === 'type'">
 			<p class="title">{{ $t("evaluation.quickPaper.setItem") }}</p>
@@ -131,6 +152,7 @@
 			<p class="upper-tip" v-if="answerInputMode === 'code'">* {{ $t("evaluation.quickPaper.onlyUpper") }}</p>
 			<div class="add-type-list">
 				<span class="type-item" v-for="(type, typeIndex) in Object.keys(typeMap)" :key="typeIndex" @click="doAddItem(type)">+ {{ typeMap[type] }}</span>
+				<span class="type-item" @click="fenpeiscore()" style="background-color: #b0b0b0;" v-if="!isMarkModel">{{ $t('evaluation.quickPaper.handScore') }}</span>
 			</div>
 			<div class="items">
 				<div v-if="!orderItemsArr.length" style="margin: 20px 10px; color: #999999">{{ $t("evaluation.quickPaper.tip5") }}</div>
@@ -353,6 +375,7 @@
 					name: "",
 					periodIndex: 0,
 					subjectIndex: 0,
+					score: 0,
 					gradeIndex: [],
 					items: [
 						{
@@ -420,6 +443,13 @@
 					img: ''
 				});
 			},
+			fenpeiscore() {
+				if(!this.orderItemsArr.length) return
+				let scoreArr = this.$tools.doAverage(this.paperInfo.score, this.orderItemsArr.length, 0.5)
+				this.orderItemsArr.forEach((i, index) => {
+					i.score = scoreArr[index] || 0
+				})
+			},
 			/* 移除试题 */
 			doRemoveItem(index) {
 				this.orderItemsArr.splice(index, 1);
@@ -879,14 +909,24 @@
 			},
 			/* 保存试卷 */
 			async onConfirmSave(isAdjust) {
-				if (!this.paperInfo.name && !this.isMarkModel) {
-					this.$Message.warning(this.$t("evaluation.paperList.emptyNameTip"));
-					console.log(this.paperInfo);
-					return;
-				}
-				if(this.buildMode === "order" && this.orderScore != 100 && !isAdjust) {
-					this.isAdjustScore = true
-					return
+				if(!this.isMarkModel) {
+					if (!this.paperInfo.name) {
+						this.$Message.warning(this.$t("evaluation.paperList.emptyNameTip"));
+						console.log(this.paperInfo);
+						return;
+					}
+					if (!this.paperInfo.score) {
+						this.$Message.warning(this.$t("evaluation.quickPaper.tip19"));
+						return;
+					}
+					if (this.buildMode === "order" && this.orderScore != this.paperInfo.score) {
+						this.$Message.warning(this.$t("evaluation.quickPaper.tip20"));
+						return;
+					}
+					if(this.buildMode === "order" && this.orderScore != 100 && !isAdjust) {
+						this.isAdjustScore = true
+						return
+					}
 				}
 				
 				let saveFn = async () => {
@@ -1006,7 +1046,7 @@
 						this.orderItemsArr.forEach((item) => {
 							blobItemPromiseArr.push({
 								id: this.$tools.guid(),
-								question: this.typeMap[item.type],
+								question: item.img ? `<img src="${item.img}">` : this.typeMap[item.type],
 								option: this.getItemOptions(item),
 								type: item.type,
 								level: 1,
@@ -1072,6 +1112,11 @@
 				// 2、生成试题JSON文件
 				let blobItemPromiseArr = [];
 				if (this.buildMode === "type") {
+					let itemNum = 0
+					this.paperInfo.items.forEach(item => {
+						itemNum += item.count
+					})
+					let scoreArr = this.$tools.doAverage(this.paperInfo.score, itemNum, 0.5)
 					this.paperInfo.items.forEach(async (typeItem) => {
 						if (typeItem.count) {
 							for (var i = 0; i < typeItem.count; i++) {
@@ -1082,7 +1127,7 @@
 										question: "No." + (blobItemPromiseArr.length + 1),
 										option: this.getItemOptions(typeItem),
 										answer: this.getItemAnswer(typeItem, i),
-										score: 10,
+										score: scoreArr[blobItemPromiseArr.length] || 0,
 										knowledge: [],
 										field: 1,
 										level: 1,

+ 8 - 1
TEAMModelOS/ClientApp/src/common/MarkCanvas.vue

@@ -550,7 +550,10 @@ export default {
                     this.contentText.strokeStyle = 'blue';
                     this.contentText.rect(value.x, value.y, value.w, value.h);
                     this.contentText.stroke();
-                    this.contentText.fillStyle = 'blue'
+                    const textWidth = this.contentText.measureText(`${this.$t('answerSheet.tip2')}${this.editQuesIndex != -1 ? this.editQuesIndex + 1 : (value.qIndex !== undefined ? value.qIndex + 1 : value.addIndex)}${this.$t('answerSheet.tip14')}(${this.$t(`evaluation.${value.type}`)})`).width;
+                    this.contentText.fillStyle = "blue";
+                    this.contentText.fillRect(value.w < 0 ? (value.x + value.w) : (value.x), value.h < 0 ? (value.y + value.h - 30) : (value.y - 30), textWidth + 10, 30)
+                    this.contentText.fillStyle = '#fff'
                     this.contentText.fillText(`${this.$t('answerSheet.tip2')}${this.editQuesIndex != -1 ? this.editQuesIndex + 1 : (value.qIndex !== undefined ? value.qIndex + 1 : value.addIndex)}${this.$t('answerSheet.tip14')}(${this.$t(`evaluation.${value.type}`)})`, value.w < 0 ? (value.x + value.w + 5) : (value.x + 5), value.h < 0 ? (value.y + value.h - 10) : (value.y - 10))
                 }
             });
@@ -596,6 +599,10 @@ export default {
                     this.contentText.fillStyle = "red";
                     this.contentText.fill();// 画终点实心圆
                     this.contentText.stroke();
+                    const textWidth = this.contentText.measureText(`${this.$t('answerSheet.tip2')}${this.editQuesIndex != -1 ? this.editQuesIndex + 1 : (value.qIndex !== undefined ? value.qIndex + 1 : value.addIndex)}${this.$t('answerSheet.tip14')}(${this.$t(`evaluation.${value.type}`)})`).width;
+                    this.contentText.fillStyle = "red";
+                    this.contentText.fillRect(value.w < 0 ? (value.x + value.w) : (value.x), value.h < 0 ? (value.y + value.h - 30) : (value.y - 30), textWidth + 10, 30)
+                    this.contentText.fillStyle = "#fff";
                     this.contentText.fillText(`${this.$t('answerSheet.tip2')}${this.editQuesIndex != -1 ? this.editQuesIndex + 1 : (value.qIndex !== undefined ? value.qIndex + 1 : value.addIndex)}${this.$t('answerSheet.tip14')}(${this.$t(`evaluation.${value.type}`)})`, value.w < 0 ? (value.x + value.w + 5) : (value.x + 5), value.h < 0 ? (value.y + value.h - 10) : (value.y - 10))
                 }
             })

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -80,11 +80,11 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2503.5</Version>
-		<AssemblyVersion>5.2503.5.1</AssemblyVersion>
-		<FileVersion>5.2503.5.1</FileVersion>
+		<Version>5.2503.12</Version>
+		<AssemblyVersion>5.2503.12.1</AssemblyVersion>
+		<FileVersion>5.2503.12.1</FileVersion>
 		<Description>TEAMModelOS(IES5)</Description>
-		<PackageReleaseNotes>IES版本说明版本切换标记5.2503.5.1</PackageReleaseNotes>
+		<PackageReleaseNotes>IES版本说明版本切换标记5.2503.12.1</PackageReleaseNotes>
 		<PackageId>TEAMModelOS</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 1 - 1
TEAMModelOS/appsettings.Development.json

@@ -18,7 +18,7 @@
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction-test.chinacloudsites.cn/api/",
     //"HttpTrigger": "http://localhost:7071/api/"
-    "Version": "5.2503.5.1"
+    "Version": "5.2503.12.1"
   },
   "Azure": {
     // 测试站数据库

+ 1 - 1
TEAMModelOS/appsettings.json

@@ -18,7 +18,7 @@
     "Exp": 86400,
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction.chinacloudsites.cn/api/",
-    "Version": "5.2503.5.1"
+    "Version": "5.2503.12.1"
   },
   "Azure": {
     "Storage": {