dusenyao преди 1 година
родител
ревизия
49c6e22fd2

+ 6 - 0
.env

@@ -6,3 +6,9 @@ VUE_APP_LearnWebSI = '/GCLSLearnWebSI/ServiceInterface'
 
 # BookWebSI
 VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
+
+# ExerciseComInfoQuery
+VUE_APP_ExerciseComInfoQuery = '/TeachingServer/ExerciseComInfoQuery/'
+
+# ExerciseManager
+VUE_APP_ExerciseManager = '/TeachingServer/ExerciseManager/'

+ 285 - 141
package-lock.json

@@ -79,21 +79,21 @@
       "dev": true
     },
     "@babel/core": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.23.0.tgz",
-      "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==",
+      "version": "7.23.3",
+      "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.23.3.tgz",
+      "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==",
       "dev": true,
       "requires": {
         "@ampproject/remapping": "^2.2.0",
         "@babel/code-frame": "^7.22.13",
-        "@babel/generator": "^7.23.0",
+        "@babel/generator": "^7.23.3",
         "@babel/helper-compilation-targets": "^7.22.15",
-        "@babel/helper-module-transforms": "^7.23.0",
-        "@babel/helpers": "^7.23.0",
-        "@babel/parser": "^7.23.0",
+        "@babel/helper-module-transforms": "^7.23.3",
+        "@babel/helpers": "^7.23.2",
+        "@babel/parser": "^7.23.3",
         "@babel/template": "^7.22.15",
-        "@babel/traverse": "^7.23.0",
-        "@babel/types": "^7.23.0",
+        "@babel/traverse": "^7.23.3",
+        "@babel/types": "^7.23.3",
         "convert-source-map": "^2.0.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
@@ -102,12 +102,12 @@
       },
       "dependencies": {
         "@babel/generator": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.23.0.tgz",
-          "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.23.4.tgz",
+          "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==",
           "dev": true,
           "requires": {
-            "@babel/types": "^7.23.0",
+            "@babel/types": "^7.23.4",
             "@jridgewell/gen-mapping": "^0.3.2",
             "@jridgewell/trace-mapping": "^0.3.17",
             "jsesc": "^2.5.1"
@@ -124,9 +124,9 @@
           }
         },
         "@babel/helper-module-transforms": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz",
-          "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==",
+          "version": "7.23.3",
+          "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
+          "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
           "dev": true,
           "requires": {
             "@babel/helper-environment-visitor": "^7.22.20",
@@ -136,41 +136,90 @@
             "@babel/helper-validator-identifier": "^7.22.20"
           }
         },
+        "@babel/helper-string-parser": {
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
+          "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
+          "dev": true
+        },
+        "@babel/highlight": {
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.23.4.tgz",
+          "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
+          "dev": true,
+          "requires": {
+            "@babel/helper-validator-identifier": "^7.22.20",
+            "chalk": "^2.4.2",
+            "js-tokens": "^4.0.0"
+          }
+        },
         "@babel/parser": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.23.0.tgz",
-          "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.23.4.tgz",
+          "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==",
           "dev": true
         },
         "@babel/traverse": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.0.tgz",
-          "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.4.tgz",
+          "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==",
           "dev": true,
           "requires": {
-            "@babel/code-frame": "^7.22.13",
-            "@babel/generator": "^7.23.0",
+            "@babel/code-frame": "^7.23.4",
+            "@babel/generator": "^7.23.4",
             "@babel/helper-environment-visitor": "^7.22.20",
             "@babel/helper-function-name": "^7.23.0",
             "@babel/helper-hoist-variables": "^7.22.5",
             "@babel/helper-split-export-declaration": "^7.22.6",
-            "@babel/parser": "^7.23.0",
-            "@babel/types": "^7.23.0",
+            "@babel/parser": "^7.23.4",
+            "@babel/types": "^7.23.4",
             "debug": "^4.1.0",
             "globals": "^11.1.0"
+          },
+          "dependencies": {
+            "@babel/code-frame": {
+              "version": "7.23.4",
+              "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.23.4.tgz",
+              "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==",
+              "dev": true,
+              "requires": {
+                "@babel/highlight": "^7.23.4",
+                "chalk": "^2.4.2"
+              }
+            }
           }
         },
         "@babel/types": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.23.0.tgz",
-          "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.23.4.tgz",
+          "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==",
           "dev": true,
           "requires": {
-            "@babel/helper-string-parser": "^7.22.5",
+            "@babel/helper-string-parser": "^7.23.4",
             "@babel/helper-validator-identifier": "^7.22.20",
             "to-fast-properties": "^2.0.0"
           }
         },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
         "convert-source-map": {
           "version": "2.0.0",
           "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -188,13 +237,22 @@
           "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz",
           "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
           "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
         }
       }
     },
     "@babel/eslint-parser": {
-      "version": "7.22.15",
-      "resolved": "https://registry.npmmirror.com/@babel/eslint-parser/-/eslint-parser-7.22.15.tgz",
-      "integrity": "sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg==",
+      "version": "7.23.3",
+      "resolved": "https://registry.npmmirror.com/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz",
+      "integrity": "sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==",
       "dev": true,
       "requires": {
         "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
@@ -483,23 +541,33 @@
       }
     },
     "@babel/helpers": {
-      "version": "7.23.1",
-      "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.23.1.tgz",
-      "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==",
+      "version": "7.23.4",
+      "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.23.4.tgz",
+      "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==",
       "dev": true,
       "requires": {
         "@babel/template": "^7.22.15",
-        "@babel/traverse": "^7.23.0",
-        "@babel/types": "^7.23.0"
+        "@babel/traverse": "^7.23.4",
+        "@babel/types": "^7.23.4"
       },
       "dependencies": {
+        "@babel/code-frame": {
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.23.4.tgz",
+          "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==",
+          "dev": true,
+          "requires": {
+            "@babel/highlight": "^7.23.4",
+            "chalk": "^2.4.2"
+          }
+        },
         "@babel/generator": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.23.0.tgz",
-          "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.23.4.tgz",
+          "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==",
           "dev": true,
           "requires": {
-            "@babel/types": "^7.23.0",
+            "@babel/types": "^7.23.4",
             "@jridgewell/gen-mapping": "^0.3.2",
             "@jridgewell/trace-mapping": "^0.3.17",
             "jsesc": "^2.5.1"
@@ -515,40 +583,86 @@
             "@babel/types": "^7.23.0"
           }
         },
+        "@babel/helper-string-parser": {
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
+          "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
+          "dev": true
+        },
+        "@babel/highlight": {
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.23.4.tgz",
+          "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
+          "dev": true,
+          "requires": {
+            "@babel/helper-validator-identifier": "^7.22.20",
+            "chalk": "^2.4.2",
+            "js-tokens": "^4.0.0"
+          }
+        },
         "@babel/parser": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.23.0.tgz",
-          "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.23.4.tgz",
+          "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==",
           "dev": true
         },
         "@babel/traverse": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.0.tgz",
-          "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.4.tgz",
+          "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==",
           "dev": true,
           "requires": {
-            "@babel/code-frame": "^7.22.13",
-            "@babel/generator": "^7.23.0",
+            "@babel/code-frame": "^7.23.4",
+            "@babel/generator": "^7.23.4",
             "@babel/helper-environment-visitor": "^7.22.20",
             "@babel/helper-function-name": "^7.23.0",
             "@babel/helper-hoist-variables": "^7.22.5",
             "@babel/helper-split-export-declaration": "^7.22.6",
-            "@babel/parser": "^7.23.0",
-            "@babel/types": "^7.23.0",
+            "@babel/parser": "^7.23.4",
+            "@babel/types": "^7.23.4",
             "debug": "^4.1.0",
             "globals": "^11.1.0"
           }
         },
         "@babel/types": {
-          "version": "7.23.0",
-          "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.23.0.tgz",
-          "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+          "version": "7.23.4",
+          "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.23.4.tgz",
+          "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==",
           "dev": true,
           "requires": {
-            "@babel/helper-string-parser": "^7.22.5",
+            "@babel/helper-string-parser": "^7.23.4",
             "@babel/helper-validator-identifier": "^7.22.20",
             "to-fast-properties": "^2.0.0"
           }
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
         }
       }
     },
@@ -1530,21 +1644,21 @@
       "dev": true
     },
     "@csstools/css-parser-algorithms": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.1.tgz",
-      "integrity": "sha512-xrvsmVUtefWMWQsGgFffqWSK03pZ1vfDki4IVIIUxxDKnGBzqNgv0A7SB1oXtVNEkcVO8xi1ZrTL29HhSu5kGA==",
+      "version": "2.3.2",
+      "resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.2.tgz",
+      "integrity": "sha512-sLYGdAdEY2x7TSw9FtmdaTrh2wFtRJO5VMbBrA8tEqEod7GEggFmxTSK9XqExib3yMuYNcvcTdCZIP6ukdjAIA==",
       "dev": true
     },
     "@csstools/css-tokenizer": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-2.2.0.tgz",
-      "integrity": "sha512-wErmsWCbsmig8sQKkM6pFhr/oPha1bHfvxsUY5CYSQxwyhA9Ulrs8EqCgClhg4Tgg2XapVstGqSVcz0xOYizZA==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-2.2.1.tgz",
+      "integrity": "sha512-Zmsf2f/CaEPWEVgw29odOj+WEVoiJy9s9NOv5GgNY9mZ1CZ7394By6wONrONrTsnNDv6F9hR02nvFihrGVGHBg==",
       "dev": true
     },
     "@csstools/media-query-list-parser": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmmirror.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.4.tgz",
-      "integrity": "sha512-V/OUXYX91tAC1CDsiY+HotIcJR+vPtzrX8pCplCpT++i8ThZZsq5F5dzZh/bDM3WUOjrvC1ljed1oSJxMfjqhw==",
+      "version": "2.1.5",
+      "resolved": "https://registry.npmmirror.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.5.tgz",
+      "integrity": "sha512-IxVBdYzR8pYe89JiyXQuYk4aVVoCPhMJkz6ElRwlVysjwURTsTk/bmY/z4FfeRE+CRBMlykPwXEVUg8lThv7AQ==",
       "dev": true
     },
     "@csstools/selector-specificity": {
@@ -2464,9 +2578,9 @@
       "dev": true
     },
     "@rushstack/eslint-patch": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz",
-      "integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==",
+      "version": "1.6.0",
+      "resolved": "https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.6.0.tgz",
+      "integrity": "sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA==",
       "dev": true
     },
     "@sideway/address": {
@@ -3595,9 +3709,9 @@
       }
     },
     "@vue/compiler-sfc": {
-      "version": "2.7.14",
-      "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz",
-      "integrity": "sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==",
+      "version": "2.7.15",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.15.tgz",
+      "integrity": "sha512-FCvIEevPmgCgqFBH7wD+3B97y7u7oj/Wr69zADBf403Tui377bThTjBvekaZvlRr4IwUAu3M6hYZeULZFJbdYg==",
       "requires": {
         "@babel/parser": "^7.18.4",
         "postcss": "^8.4.14",
@@ -4256,9 +4370,9 @@
       "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
     },
     "axios": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.5.1.tgz",
-      "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
+      "version": "1.6.2",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.6.2.tgz",
+      "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
       "requires": {
         "follow-redirects": "^1.15.0",
         "form-data": "^4.0.0",
@@ -4548,9 +4662,9 @@
       }
     },
     "big-integer": {
-      "version": "1.6.51",
-      "resolved": "https://registry.npmmirror.com/big-integer/-/big-integer-1.6.51.tgz",
-      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+      "version": "1.6.52",
+      "resolved": "https://registry.npmmirror.com/big-integer/-/big-integer-1.6.52.tgz",
+      "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
       "dev": true
     },
     "big.js": {
@@ -5611,9 +5725,9 @@
       }
     },
     "core-js": {
-      "version": "3.33.0",
-      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.33.0.tgz",
-      "integrity": "sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw=="
+      "version": "3.33.3",
+      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.33.3.tgz",
+      "integrity": "sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw=="
     },
     "core-js-compat": {
       "version": "3.32.2",
@@ -5683,9 +5797,9 @@
       "dev": true
     },
     "css-functions-list": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmmirror.com/css-functions-list/-/css-functions-list-3.2.0.tgz",
-      "integrity": "sha512-d/jBMPyYybkkLVypgtGv12R+pIFw4/f/IHtCTxWpZc8ofTYOPigIgmA6vu5rMHartZC+WuXhBUHfnyNUIQSYrg==",
+      "version": "3.2.1",
+      "resolved": "https://registry.npmmirror.com/css-functions-list/-/css-functions-list-3.2.1.tgz",
+      "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==",
       "dev": true
     },
     "css-line-break": {
@@ -7084,9 +7198,9 @@
       "dev": true
     },
     "eslint-plugin-prettier": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz",
-      "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz",
+      "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==",
       "dev": true,
       "requires": {
         "prettier-linter-helpers": "^1.0.0",
@@ -7094,9 +7208,9 @@
       }
     },
     "eslint-plugin-vue": {
-      "version": "9.17.0",
-      "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.17.0.tgz",
-      "integrity": "sha512-r7Bp79pxQk9I5XDP0k2dpUC7Ots3OSWgvGZNu3BxmKK6Zg7NgVtcOB6OCna5Kb9oQwJPl5hq183WD0SY5tZtIQ==",
+      "version": "9.18.1",
+      "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.18.1.tgz",
+      "integrity": "sha512-7hZFlrEgg9NIzuVik2I9xSnJA5RsmOfueYgsUGUokEDLJ1LHtxO0Pl4duje1BriZ/jDWb+44tcIlC3yi0tdlZg==",
       "dev": true,
       "requires": {
         "@eslint-community/eslint-utils": "^4.4.0",
@@ -11204,9 +11318,9 @@
       "dev": true
     },
     "known-css-properties": {
-      "version": "0.28.0",
-      "resolved": "https://registry.npmmirror.com/known-css-properties/-/known-css-properties-0.28.0.tgz",
-      "integrity": "sha512-9pSL5XB4J+ifHP0e0jmmC98OGC1nL8/JjS+fi6mnTlIf//yt/MfVLtKg7S6nCtj/8KTcWX7nRlY0XywoYY1ISQ==",
+      "version": "0.29.0",
+      "resolved": "https://registry.npmmirror.com/known-css-properties/-/known-css-properties-0.29.0.tgz",
+      "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==",
       "dev": true
     },
     "launch-editor": {
@@ -13475,9 +13589,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.0.3.tgz",
-      "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.1.0.tgz",
+      "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
       "dev": true
     },
     "prettier-linter-helpers": {
@@ -14241,9 +14355,9 @@
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "sass": {
-      "version": "1.69.0",
-      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.69.0.tgz",
-      "integrity": "sha512-l3bbFpfTOGgQZCLU/gvm1lbsQ5mC/WnLz3djL2v4WCJBDrWm58PO+jgngcGRNnKUh6wSsdm50YaovTqskZ0xDQ==",
+      "version": "1.69.5",
+      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.69.5.tgz",
+      "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==",
       "dev": true,
       "requires": {
         "chokidar": ">=3.0.0 <4.0.0",
@@ -15071,9 +15185,9 @@
       }
     },
     "stylelint": {
-      "version": "15.10.3",
-      "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-15.10.3.tgz",
-      "integrity": "sha512-aBQMMxYvFzJJwkmg+BUUg3YfPyeuCuKo2f+LOw7yYbU8AZMblibwzp9OV4srHVeQldxvSFdz0/Xu8blq2AesiA==",
+      "version": "15.11.0",
+      "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-15.11.0.tgz",
+      "integrity": "sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==",
       "dev": true,
       "requires": {
         "@csstools/css-parser-algorithms": "^2.3.1",
@@ -15083,12 +15197,12 @@
         "balanced-match": "^2.0.0",
         "colord": "^2.9.3",
         "cosmiconfig": "^8.2.0",
-        "css-functions-list": "^3.2.0",
+        "css-functions-list": "^3.2.1",
         "css-tree": "^2.3.1",
         "debug": "^4.3.4",
         "fast-glob": "^3.3.1",
         "fastest-levenshtein": "^1.0.16",
-        "file-entry-cache": "^6.0.1",
+        "file-entry-cache": "^7.0.0",
         "global-modules": "^2.0.0",
         "globby": "^11.1.0",
         "globjoin": "^0.1.4",
@@ -15097,13 +15211,13 @@
         "import-lazy": "^4.0.0",
         "imurmurhash": "^0.1.4",
         "is-plain-object": "^5.0.0",
-        "known-css-properties": "^0.28.0",
+        "known-css-properties": "^0.29.0",
         "mathml-tag-names": "^2.1.3",
         "meow": "^10.1.5",
         "micromatch": "^4.0.5",
         "normalize-path": "^3.0.0",
         "picocolors": "^1.0.0",
-        "postcss": "^8.4.27",
+        "postcss": "^8.4.28",
         "postcss-resolve-nested-selector": "^0.1.1",
         "postcss-safe-parser": "^6.0.0",
         "postcss-selector-parser": "^6.0.13",
@@ -15188,6 +15302,15 @@
           "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
           "dev": true
         },
+        "file-entry-cache": {
+          "version": "7.0.2",
+          "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-7.0.2.tgz",
+          "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==",
+          "dev": true,
+          "requires": {
+            "flat-cache": "^3.2.0"
+          }
+        },
         "find-up": {
           "version": "5.0.0",
           "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz",
@@ -15198,6 +15321,17 @@
             "path-exists": "^4.0.0"
           }
         },
+        "flat-cache": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz",
+          "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+          "dev": true,
+          "requires": {
+            "flatted": "^3.2.9",
+            "keyv": "^4.5.3",
+            "rimraf": "^3.0.2"
+          }
+        },
         "has-flag": {
           "version": "4.0.0",
           "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
@@ -15377,6 +15511,15 @@
             "strip-indent": "^4.0.0"
           }
         },
+        "rimraf": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz",
+          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        },
         "semver": {
           "version": "7.5.4",
           "resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz",
@@ -15483,9 +15626,9 @@
       "dev": true
     },
     "stylelint-config-recess-order": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmmirror.com/stylelint-config-recess-order/-/stylelint-config-recess-order-4.3.0.tgz",
-      "integrity": "sha512-EWVtxZ8oq4/meTrRNUDrS5TqMz6TX72JjKDwVQq0JJDXE+P/o7UuFw3wWV/0O9yvJfh/da6nJY71ZUn/wSfB4g==",
+      "version": "4.4.0",
+      "resolved": "https://registry.npmmirror.com/stylelint-config-recess-order/-/stylelint-config-recess-order-4.4.0.tgz",
+      "integrity": "sha512-Q99kvZyIM/aoPEV4dRDkzD3fZLzH0LXi+pawCf1r700uUeF/PHQ5PZXjwFUuGrWhOzd1N+cuVm+OUGsY2fRN5A==",
       "dev": true,
       "requires": {
         "stylelint-order": "6.x"
@@ -15498,14 +15641,14 @@
       "dev": true
     },
     "stylelint-config-recommended-scss": {
-      "version": "13.0.0",
-      "resolved": "https://registry.npmmirror.com/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-13.0.0.tgz",
-      "integrity": "sha512-7AmMIsHTsuwUQm7I+DD5BGeIgCvqYZ4BpeYJJpb1cUXQwrJAKjA+GBotFZgUEGP8lAM+wmd91ovzOi8xfAyWEw==",
+      "version": "13.1.0",
+      "resolved": "https://registry.npmmirror.com/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-13.1.0.tgz",
+      "integrity": "sha512-8L5nDfd+YH6AOoBGKmhH8pLWF1dpfY816JtGMePcBqqSsLU+Ysawx44fQSlMOJ2xTfI9yTGpup5JU77c17w1Ww==",
       "dev": true,
       "requires": {
-        "postcss-scss": "^4.0.7",
+        "postcss-scss": "^4.0.9",
         "stylelint-config-recommended": "^13.0.0",
-        "stylelint-scss": "^5.1.0"
+        "stylelint-scss": "^5.3.0"
       },
       "dependencies": {
         "stylelint-config-recommended": {
@@ -15571,12 +15714,12 @@
       }
     },
     "stylelint-config-standard-scss": {
-      "version": "11.0.0",
-      "resolved": "https://registry.npmmirror.com/stylelint-config-standard-scss/-/stylelint-config-standard-scss-11.0.0.tgz",
-      "integrity": "sha512-fGE79NBOLg09a9afqGH/guJulRULCaQWWv4cv1v2bMX92B+fGb0y56WqIguwvFcliPmmUXiAhKrrnXilIeXoHA==",
+      "version": "11.1.0",
+      "resolved": "https://registry.npmmirror.com/stylelint-config-standard-scss/-/stylelint-config-standard-scss-11.1.0.tgz",
+      "integrity": "sha512-5gnBgeNTgRVdchMwiFQPuBOtj9QefYtfXiddrOMJA2pI22zxt6ddI2s+e5Oh7/6QYl7QLJujGnaUR5YyGq72ow==",
       "dev": true,
       "requires": {
-        "stylelint-config-recommended-scss": "^13.0.0",
+        "stylelint-config-recommended-scss": "^13.1.0",
         "stylelint-config-standard": "^34.0.0"
       }
     },
@@ -15597,12 +15740,12 @@
       }
     },
     "stylelint-scss": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmmirror.com/stylelint-scss/-/stylelint-scss-5.2.1.tgz",
-      "integrity": "sha512-ZoTJUM85/qqpQHfEppjW/St//8s6p9Qsg8deWlYlr56F9iUgC9vXeIDQvH4odkRRJLTLFQzYMALSOFCQ3MDkgw==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmmirror.com/stylelint-scss/-/stylelint-scss-5.3.1.tgz",
+      "integrity": "sha512-5I9ZDIm77BZrjOccma5WyW2nJEKjXDd4Ca8Kk+oBapSO4pewSlno3n+OyimcyVJJujQZkBN2D+xuMkIamSc6hA==",
       "dev": true,
       "requires": {
-        "known-css-properties": "^0.28.0",
+        "known-css-properties": "^0.29.0",
         "postcss-media-query-parser": "^0.2.3",
         "postcss-resolve-nested-selector": "^0.1.1",
         "postcss-selector-parser": "^6.0.13",
@@ -16029,16 +16172,17 @@
       "dev": true
     },
     "svgo": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmmirror.com/svgo/-/svgo-3.0.2.tgz",
-      "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==",
+      "version": "3.0.4",
+      "resolved": "https://registry.npmmirror.com/svgo/-/svgo-3.0.4.tgz",
+      "integrity": "sha512-T+Xul3JwuJ6VGXKo/p2ndqx1ibxNKnLTvRc1ZTWKCfyKS/GgNjRZcYsK84fxTsy/izr91g/Rwx6fGnVgaFSI5g==",
       "dev": true,
       "requires": {
         "@trysound/sax": "0.2.0",
         "commander": "^7.2.0",
         "css-select": "^5.1.0",
         "css-tree": "^2.2.1",
-        "csso": "^5.0.5",
+        "css-what": "^6.1.0",
+        "csso": "5.0.5",
         "picocolors": "^1.0.0"
       },
       "dependencies": {
@@ -16374,9 +16518,9 @@
       "dev": true
     },
     "tinymce": {
-      "version": "5.10.7",
-      "resolved": "https://registry.npmmirror.com/tinymce/-/tinymce-5.10.7.tgz",
-      "integrity": "sha512-9UUjaO0R7FxcFo0oxnd1lMs7H+D0Eh+dDVo5hKbVe1a+VB0nit97vOqlinj+YwgoBDt6/DSCUoWqAYlLI8BLYA=="
+      "version": "5.10.9",
+      "resolved": "https://registry.npmmirror.com/tinymce/-/tinymce-5.10.9.tgz",
+      "integrity": "sha512-5bkrors87X9LhYX2xq8GgPHrIgJYHl87YNs+kBcjQ5I3CiUgzo/vFcGvT3MZQ9QHsEeYMhYO6a5CLGGffR8hMg=="
     },
     "titleize": {
       "version": "3.0.0",
@@ -16989,11 +17133,11 @@
       }
     },
     "vue": {
-      "version": "2.7.14",
-      "resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.14.tgz",
-      "integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
+      "version": "2.7.15",
+      "resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.15.tgz",
+      "integrity": "sha512-a29fsXd2G0KMRqIFTpRgpSbWaNBK3lpCTOLuGLEDnlHWdjB8fwl6zyYZ8xCrqkJdatwZb4mGHiEfJjnw0Q6AwQ==",
       "requires": {
-        "@vue/compiler-sfc": "2.7.14",
+        "@vue/compiler-sfc": "2.7.15",
         "csstype": "^3.1.0"
       }
     },
@@ -17012,9 +17156,9 @@
       }
     },
     "vue-eslint-parser": {
-      "version": "9.3.1",
-      "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz",
-      "integrity": "sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==",
+      "version": "9.3.2",
+      "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz",
+      "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==",
       "dev": true,
       "requires": {
         "debug": "^4.3.4",
@@ -17097,9 +17241,9 @@
       "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA=="
     },
     "vue-loader": {
-      "version": "15.10.2",
-      "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.10.2.tgz",
-      "integrity": "sha512-ndeSe/8KQc/nlA7TJ+OBhv2qalmj1s+uBs7yHDRFaAXscFTApBzY9F1jES3bautmgWjDlDct0fw8rPuySDLwxw==",
+      "version": "15.11.1",
+      "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.11.1.tgz",
+      "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==",
       "dev": true,
       "requires": {
         "@vue/component-compiler-utils": "^3.1.0",
@@ -17159,9 +17303,9 @@
       }
     },
     "vue-template-compiler": {
-      "version": "2.7.14",
-      "resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
-      "integrity": "sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==",
+      "version": "2.7.15",
+      "resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz",
+      "integrity": "sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==",
       "dev": true,
       "requires": {
         "de-indent": "^1.0.2",

+ 19 - 19
package.json

@@ -15,20 +15,20 @@
   "dependencies": {
     "@tinymce/tinymce-vue": "^3.2.8",
     "awe-dnd": "^0.3.4",
-    "axios": "^1.5.1",
+    "axios": "^1.6.2",
     "book-ui": "file:../book-ui-0.3.54.tgz",
-    "core-js": "^3.33.0",
+    "core-js": "^3.33.3",
     "dayjs": "^1.11.10",
     "element-ui": "^2.15.14",
-    "jquery": "^3.7.0",
+    "jquery": "^3.7.1",
     "js-base64": "^3.7.5",
     "js-cookie": "^3.0.5",
     "jsplumb": "^2.15.6",
     "md5": "^2.3.0",
     "normalize.css": "^8.0.1",
     "nprogress": "^0.2.0",
-    "tinymce": "^5.10.7",
-    "vue": "^2.7.14",
+    "tinymce": "^5.10.9",
+    "vue": "^2.7.15",
     "vue-i18n": "^8.28.2",
     "vue-pdf": "^4.3.0",
     "vue-router": "^3.6.5",
@@ -36,9 +36,9 @@
     "vuex": "^3.6.2"
   },
   "devDependencies": {
-    "@babel/core": "^7.23.0",
-    "@babel/eslint-parser": "^7.22.15",
-    "@rushstack/eslint-patch": "^1.5.1",
+    "@babel/core": "^7.23.3",
+    "@babel/eslint-parser": "^7.23.3",
+    "@rushstack/eslint-patch": "^1.6.0",
     "@vue/cli-plugin-babel": "~5.0.8",
     "@vue/cli-plugin-eslint": "~5.0.8",
     "@vue/cli-plugin-router": "~5.0.8",
@@ -52,27 +52,27 @@
     "babel-plugin-dynamic-import-node": "^2.3.3",
     "compression-webpack-plugin": "^6.1.1",
     "eslint": "^7.32.0",
-    "eslint-plugin-prettier": "^5.0.0",
-    "eslint-plugin-vue": "^9.17.0",
+    "eslint-plugin-prettier": "^5.0.1",
+    "eslint-plugin-vue": "^9.18.1",
     "html-webpack-plugin": "^5.5.3",
     "postcss": "^8.4.31",
     "postcss-html": "^1.5.0",
-    "prettier": "3.0.3",
-    "sass": "^1.69.0",
+    "prettier": "3.1.0",
+    "sass": "^1.69.5",
     "sass-loader": "^13.3.2",
     "script-ext-html-webpack-plugin": "^2.1.5",
-    "stylelint": "^15.10.3",
-    "stylelint-config-recess-order": "^4.3.0",
-    "stylelint-config-recommended-scss": "^13.0.0",
+    "stylelint": "^15.11.0",
+    "stylelint-config-recess-order": "^4.4.0",
+    "stylelint-config-recommended-scss": "^13.1.0",
     "stylelint-config-recommended-vue": "^1.5.0",
-    "stylelint-config-standard-scss": "^11.0.0",
+    "stylelint-config-standard-scss": "^11.1.0",
     "stylelint-declaration-block-no-ignored-properties": "^2.7.0",
     "stylelint-webpack-plugin": "^4.1.1",
     "svg-sprite-loader": "^6.0.11",
-    "svgo": "^3.0.2",
+    "svgo": "^3.0.4",
     "vue-demi": "^0.14.6",
-    "vue-loader": "^15.10.2",
-    "vue-template-compiler": "^2.7.14"
+    "vue-loader": "^15.11.1",
+    "vue-template-compiler": "^2.7.15"
   },
   "browserslist": [
     "> 1%",

+ 14 - 1
src/api/app.js

@@ -236,7 +236,6 @@ export function GetFileInfoMap(data) {
 
 /**
  * 获取文件静态资源
- * @param {Object} data
  */
 export function GetFileResource(data) {
   return request({
@@ -246,3 +245,17 @@ export function GetFileResource(data) {
     data
   });
 }
+
+/**
+ * 得到分享配置
+ * @param {object} data
+ * @returns {object} {exercise_share_url_path 练习题分享链接的路径}
+ */
+export function GetShareConfig(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_FileServer,
+    params: getRequestParams('sys_config_manager-GetShareConfig'),
+    data
+  });
+}

+ 14 - 0
src/api/list.js

@@ -100,3 +100,17 @@ export function GetMyTaskList_CSItemGroup(data) {
     data
   });
 }
+
+/**
+ * 得到我的练习题答题记录列表
+ * @param {object} data
+ * @param {string} data.courseware_id 课件ID
+ */
+export function GetMyExerciseAnswerRecordList(data) {
+  return request({
+    method: 'post',
+    url: `${process.env.VUE_APP_ExerciseManager}GetMyExerciseAnswerRecordList`,
+    params: getRequestParams(''),
+    data
+  });
+}

+ 32 - 2
src/api/user.js

@@ -65,7 +65,8 @@ export function IsExistMyMessage_NotRead(data) {
 
 /**
  * 得到我的任务每日分布(用于主页显示)
- * @param {Object} month_stamp 月份
+ * @param {object} data
+ * @param {string} data.month_stamp 月份
  */
 export function GetMyTaskDailyDistribution(data) {
   return request({
@@ -78,7 +79,8 @@ export function GetMyTaskDailyDistribution(data) {
 
 /**
  * 得到我的任务每月分布(用于主页显示)
- * @param {Object} data
+ * @param {object} data
+ * @param {string} data.year_stamp 年份
  */
 export function GetMyTaskMonthDistribution(data) {
   return request({
@@ -103,6 +105,34 @@ export function GetMyBookBuyStatus_CurTaskCoursewareBook(data) {
 }
 
 /**
+ * 得到我的练习题答题记录每日分布
+ * @param {object} data
+ * @param {string} data.month_stamp 月份
+ */
+export function GetMyExerciseAnswerRecordDailyDistribution(data) {
+  return request({
+    method: 'post',
+    url: `${process.env.VUE_APP_ExerciseComInfoQuery}GetMyExerciseAnswerRecordDailyDistribution`,
+    params: getRequestParams(''),
+    data
+  });
+}
+
+/**
+ * 得到我的练习题答题记录每月分布
+ * @param {object} data
+ * @param {string} data.year_stamp 月份
+ */
+export function GetMyExerciseAnswerRecordMonthDistribution(data) {
+  return request({
+    method: 'post',
+    url: `${process.env.VUE_APP_ExerciseComInfoQuery}GetMyExerciseAnswerRecordMonthDistribution`,
+    params: getRequestParams(''),
+    data
+  });
+}
+
+/**
  * 得到我的物品购买信息
  * @param { Object } data
  */

+ 2 - 2
src/store/data.js

@@ -1,3 +1,3 @@
-export let taskModeList = ['Simple', 'Multilayer'];
+export let taskModeList = ['Simple', 'Multilayer']; // 任务模式 Simple: 简单模式 Multilayer: 多层模式
 
-export const userTypeList = ['TEACHER', 'STUDENT'];
+export const userTypeList = ['TEACHER', 'STUDENT']; // 用户类型 TEACHER: 教师 STUDENT: 学生

+ 2 - 1
src/utils/request.js

@@ -89,7 +89,8 @@ export function getRequestParams(MethodName) {
     MethodName,
     UserCode: isHas ? token.user_code : '',
     UserType: isHas ? token.user_type : '',
-    SessionID: isHas ? token.session_id : ''
+    SessionID: isHas ? token.session_id : '',
+    AccessToken: isHas ? token.access_token : ''
   };
 }
 

+ 14 - 4
src/views/main/components/MonthlyCalendar.js

@@ -1,5 +1,10 @@
 import { ref, watchEffect, nextTick } from 'vue';
-import { GetMyTaskDailyDistribution, GetMyTaskMonthDistribution } from '@/api/user';
+import {
+  GetMyTaskDailyDistribution,
+  GetMyTaskMonthDistribution,
+  GetMyExerciseAnswerRecordDailyDistribution,
+  GetMyExerciseAnswerRecordMonthDistribution
+} from '@/api/user';
 import { useRoute } from 'vue-router/composables';
 
 import dayjs from 'dayjs';
@@ -113,8 +118,9 @@ export const modeList = [
 /**
  * 日历方法
  * @param {Emits} emits
+ * @param {boolean} isExercise
  */
-export function useMonthlyCalendar(emits) {
+export function useMonthlyCalendar(emits, isExercise) {
   const route = useRoute();
   const dateSta = route.query.dateStamp;
   let dateStamp = dateSta ? new Date(dateSta) : new Date();
@@ -131,7 +137,9 @@ export function useMonthlyCalendar(emits) {
 
   let taskMonthDistribution = ref({}); // 任务每月分布
   watchEffect(() => {
-    GetMyTaskMonthDistribution({ year_stamp: curYear.value }).then(({ status, ...data }) => {
+    (isExercise ? GetMyExerciseAnswerRecordMonthDistribution : GetMyTaskMonthDistribution)({
+      year_stamp: curYear.value
+    }).then(({ status, ...data }) => {
       if (status !== 1) return;
       const taskMonthArr = {};
       for (const [key, value] of Object.entries(data)) {
@@ -148,7 +156,9 @@ export function useMonthlyCalendar(emits) {
     curYear.value = dayjs(date.value).year();
     curMonth.value = dayjs(date.value).month() + 1;
     focusMonth.value = dayjs(date.value).month();
-    GetMyTaskDailyDistribution({ month_stamp: date.value }).then(({ status, ...data }) => {
+    (isExercise ? GetMyExerciseAnswerRecordDailyDistribution : GetMyTaskDailyDistribution)({
+      month_stamp: date.value
+    }).then(({ status, ...data }) => {
       if (status !== 1) return;
       const taskDailyArr = {};
       for (const [key, value] of Object.entries(data)) {

+ 8 - 1
src/views/main/components/MonthlyCalendar.vue

@@ -85,6 +85,13 @@ import { useMonthlyCalendar, weekList, monthList, modeList } from './MonthlyCale
 
 const emits = defineEmits(['changeDate', 'changeTimeUnit']);
 
+const props = defineProps({
+  isExercise: {
+    type: Boolean,
+    default: false
+  }
+});
+
 let {
   DAY,
   MONTH,
@@ -104,7 +111,7 @@ let {
   selectMonth,
   getTaskMonthClass,
   taskMonthDistribution
-} = useMonthlyCalendar(emits);
+} = useMonthlyCalendar(emits, props.isExercise);
 
 defineExpose({ time_unit, curYear, curMonth, focusDate });
 </script>

+ 6 - 0
src/views/main/components/OldTaskList.vue

@@ -49,6 +49,12 @@
   </div>
 </template>
 
+<script>
+export default {
+  name: 'OldTaskList'
+};
+</script>
+
 <script setup>
 import { inject } from 'vue';
 import { useTaskItem, useTaskLink, buttonColorList, getTimeTypeName } from './TaskList';

+ 3 - 1
src/views/main/components/TaskList.js

@@ -49,7 +49,8 @@ const colorMatching = [
 export const buttonColorList = new Map([
   [0, '#63A1FF'],
   [1, '#f90'],
-  [2, '#00CD8F']
+  [2, '#00CD8F'],
+  [3, '#165DFF']
 ]);
 
 /**
@@ -226,5 +227,6 @@ export function getTimeTypeName(type) {
   if (type === 0) return 'Key292';
   if (type === 1) return 'Key293';
   if (type === 2) return 'Key294';
+  if (type === 3) return '练习';
   return '';
 }

+ 72 - 0
src/views/main/exercise_list/index.js

@@ -0,0 +1,72 @@
+import { ref, computed, onMounted } from 'vue'; // Add the import statement
+
+import { GetMyExerciseAnswerRecordList } from '@/api/list';
+import { GetShareConfig } from '@/api/app';
+
+/**
+ * 练习列表
+ * @param {ref} calendar
+ */
+export function useExerciseList(calendar) {
+  let time_unit = computed(() => calendar.value?.time_unit);
+
+  let answer_record_list = ref([]);
+  // 得到我的练习列表
+  function getMyExerciseAnswerRecordList() {
+    const { curYear, curMonth, focusDate } = calendar.value;
+    GetMyExerciseAnswerRecordList({
+      time_unit: time_unit.value,
+      date_stamp: `${curYear}-${curMonth}-${focusDate}`,
+      month_stamp: `${curYear}-${curMonth}`
+    }).then(({ answer_record_list: list }) => {
+      answer_record_list.value = list;
+    });
+  }
+
+  /**
+   * 得到练习状态
+   * @param {boolean} is_finish 是否完成
+   * @param {boolean} is_remarked 是否已批阅
+   */
+  function getExerciseStatus(is_finish, is_remarked) {
+    return is_finish === 'true' ? (is_remarked === 'true' ? '教师已批改' : '已提交') : '待完成';
+  }
+
+  /**
+   * 得到练习状态样式
+   * @param {boolean} is_finish 是否完成
+   * @param {boolean} is_remarked 是否已批阅
+   */
+  function getExerciseStatusStyle(is_finish, is_remarked) {
+    let bcColor = is_finish === 'true' ? (is_remarked === 'true' ? '#F05F5F' : '#41C221') : '#F3AF00';
+
+    return {
+      backgroundColor: bcColor
+    };
+  }
+
+  function init() {
+    getMyExerciseAnswerRecordList();
+  }
+
+  let exercise_share_url_path = ref('');
+  GetShareConfig().then(({ exercise_share_url_path: path }) => {
+    exercise_share_url_path.value = path;
+  });
+
+  function exerciseLink(exercise_share_record_id) {
+    window.open(`${exercise_share_url_path.value}?share_record_id=${exercise_share_record_id}`, '_blank');
+  }
+
+  onMounted(() => {
+    init();
+  });
+
+  return {
+    init,
+    getExerciseStatus,
+    getExerciseStatusStyle,
+    exerciseLink,
+    answer_record_list
+  };
+}

+ 272 - 0
src/views/main/exercise_list/index.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="exercise">
+    <div class="exercise-left">
+      <!-- 菜单 -->
+      <MainMenu cur-tab="ExerciseList" />
+      <!-- 日历 -->
+      <MonthlyCalendar ref="calendar" :is-exercise="true" @changeTimeUnit="init" @changeDate="init" />
+      <!-- 通知 -->
+      <div class="notice">
+        <div class="notice-title">
+          <svg-icon icon-class="exercise-notification" class-name="svg-normal" />
+          <span>{{ $t('Key291') }}</span>
+          <span class="notice-title-link" @click="goPersonal">
+            {{ $t('Key110') }}
+            <i class="el-icon-arrow-right"></i>
+          </span>
+        </div>
+        <!-- 通知列表 -->
+        <div class="notice-container">
+          <ul>
+            <li v-for="{ id, is_read, content, send_time, source_entity_id, message_type } in message_list" :key="id">
+              <span class="is-read" v-text="is_read === 'false' ? 'new' : ''"></span>
+              <span
+                class="notice-content"
+                :style="{
+                  color: is_read === 'true' ? '#8c8c8c' : '#000',
+                  cursor: message_type === 201 ? 'text' : 'pointer'
+                }"
+                :title="content"
+                @click="readMyMessage(id, source_entity_id, message_type)"
+              >
+                {{ content }}
+              </span>
+              <span class="send-time">{{ send_time }}</span>
+            </li>
+          </ul>
+        </div>
+      </div>
+    </div>
+
+    <div class="exercise-right">
+      <div class="exercise-title">
+        <svg-icon icon-class="task-list" class-name="svg-normal" /><span class="exercise-title-name">练习列表</span>
+      </div>
+
+      <div class="exercise-container">
+        <ul class="exercise-list">
+          <li
+            v-for="{
+              id,
+              exercise_name,
+              exercise_share_record_id,
+              is_finish,
+              is_remarked,
+              finish_time
+            } in answer_record_list"
+            :key="id"
+            class="exercise-item"
+            @click="exerciseLink(exercise_share_record_id)"
+          >
+            <div class="exercise-list-top">
+              <span>{{ exercise_name }}</span>
+              <span class="exercise-status" :style="getExerciseStatusStyle(is_finish, is_remarked)">
+                {{ getExerciseStatus(is_finish, is_remarked) }}
+              </span>
+            </div>
+            <div class="exercise-list-bottom">{{ finish_time }}</div>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ExerciseList'
+};
+</script>
+
+<script setup>
+import { ref, inject } from 'vue';
+import { PageQueryMyMessageList } from '@/api/table';
+import { ReadMyMessage } from '@/api/user';
+import { useExerciseList } from './index';
+
+import MainMenu from '../components/MainMenu.vue';
+import MonthlyCalendar from '../components/MonthlyCalendar.vue';
+
+// 分页查询消息列表
+let message_list = ref([]);
+PageQueryMyMessageList({
+  read_status: -1,
+  message_type: -1,
+  page_capacity: 5,
+  cur_page: 1
+}).then(({ message_list: list }) => {
+  message_list.value = list;
+});
+
+let calendar = ref();
+const { init, getExerciseStatus, getExerciseStatusStyle, exerciseLink, answer_record_list } = useExerciseList(calendar);
+
+const $t = inject('$t');
+function readMyMessage(id, source_entity_id, message_type) {
+  if (message_type === 201) return;
+  ReadMyMessage({ id }).then(() => {
+    // taskLink_outside(source_entity_id);
+  });
+}
+
+function goPersonal() {
+  window.location.href = `/GCLS-Personal/#/EnterSys`;
+}
+</script>
+
+<style lang="scss" scoped>
+.exercise {
+  display: flex;
+
+  &-left {
+    width: 392px;
+    margin-right: 16px;
+
+    // 日历
+    .monthly-calendar {
+      min-height: 498px;
+      padding: 32px;
+      margin-bottom: 16px;
+      background-color: #fff;
+      border-radius: 8px;
+    }
+
+    .notice {
+      height: calc(100vh - 705px);
+      min-height: 424px;
+      padding: 32px;
+      line-height: 1.5;
+      background: #fff;
+      border-radius: 8px;
+
+      &-title {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        cursor: pointer;
+
+        > span:first-of-type {
+          flex: 1;
+          padding-left: 8px;
+        }
+
+        &-link {
+          color: #bababa;
+        }
+      }
+
+      &-container {
+        height: 100%;
+        overflow: auto;
+
+        ul {
+          margin-top: 16px;
+
+          li {
+            display: flex;
+            padding: 8px 0;
+
+            &:not(:first-child) {
+              border-top: 1px solid $border-color;
+            }
+
+            .is-read {
+              min-width: 48px;
+              color: $basic-color;
+            }
+
+            .notice-content {
+              position: relative;
+              width: 230px;
+              max-height: 3em;
+              margin-right: 16px;
+              overflow: hidden;
+              word-break: break-all;
+
+              // 多行文本隐藏
+              &::after {
+                position: absolute;
+                top: 1.2em;
+                right: 0;
+                padding-left: 40px;
+                font-size: 18px;
+                content: '...';
+                background: linear-gradient(to right, transparent, #fff 55%);
+              }
+            }
+
+            .send-time {
+              color: #8c8c8c;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  &-right {
+    width: 802px;
+    min-height: calc(100vh - 119px);
+    padding: 16px 24px;
+    background-color: #fff;
+    border-radius: 8px;
+
+    .exercise-title {
+      display: flex;
+      align-items: center;
+      padding-bottom: 16px;
+      border-bottom: 1px solid #d9d9d9;
+
+      &-name {
+        margin-left: 8px;
+        font-weight: 600;
+      }
+    }
+
+    :deep .select-course {
+      .el-input__inner {
+        border-top-left-radius: 0;
+        border-bottom-left-radius: 0;
+      }
+    }
+
+    .exercise-container {
+      min-height: calc(100% - 50px);
+
+      .exercise-list {
+        display: flex;
+        flex-direction: column;
+        row-gap: 8px;
+        margin-top: 16px;
+
+        .exercise-item {
+          padding: 16px 24px;
+          cursor: pointer;
+          border: 1px solid $border-color;
+          border-radius: 8px;
+
+          .exercise-list-top {
+            display: flex;
+            justify-content: space-between;
+            color: #000;
+
+            .exercise-status {
+              padding: 4px 8px;
+              font-size: 14px;
+              font-weight: bold;
+              color: #fff;
+              border-radius: 4px;
+            }
+          }
+
+          .exercise-list-bottom {
+            margin-top: 8px;
+            font-size: 14px;
+            color: rgba(0, 0, 0, 50%);
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 5 - 0
src/views/main/index.js

@@ -10,6 +10,11 @@ export const menuList = [
     isShow: isStudent || popedom_code_list.includes(2000001)
   },
   {
+    name: '练习',
+    tab: 'ExerciseList',
+    isShow: isStudent
+  },
+  {
     name: 'Key215',
     tab: 'CurriculaList',
     isShow: isStudent || popedom_code_list.includes(2000001)

+ 3 - 1
src/views/main/index.vue

@@ -19,6 +19,7 @@ import { useRoute } from 'vue-router/composables';
 import store from '@/store';
 
 import TaskList from './TaskList.vue';
+import ExerciseList from './exercise_list/index.vue';
 import TemplateList from './TemplateList.vue';
 import CurriculaListStudent from './curricula_list/student.vue';
 import CurriculaListTeacher from './curricula_list/teacher.vue';
@@ -45,11 +46,12 @@ function restoreId() {
 const tabList = {
   TemplateList,
   TaskList,
+  ExerciseList,
   CurriculaListStudent,
   CurriculaListTeacher
 };
 let currentTabComponent = computed(() => {
-  if (['TemplateList', 'TaskList'].includes(currentTab.value)) return tabList[currentTab.value];
+  if (['TemplateList', 'TaskList', 'ExerciseList'].includes(currentTab.value)) return tabList[currentTab.value];
   return tabList[`${currentTab.value}${isStudent ? 'Student' : 'Teacher'}`];
 });
 </script>

+ 1 - 2
src/views/new_task_view/components/common/FileView.vue

@@ -233,8 +233,7 @@ function uploadHomework(file) {
   &-content {
     display: flex;
     flex-wrap: wrap;
-    row-gap: 16px;
-    column-gap: 8px;
+    gap: 16px 8px;
     padding-top: 16px;
 
     .file-item {

+ 1 - 2
src/views/new_task_view/components/common/SubtaskItem.vue

@@ -122,8 +122,7 @@ const { state, toggle } = useSwitch(true);
     .subtask-type {
       display: flex;
       flex-wrap: wrap;
-      row-gap: 8px;
-      column-gap: 8px;
+      gap: 8px 8px;
 
       &-item {
         height: 26px;

+ 30 - 24
src/views/task_details/TaskTop.vue

@@ -17,34 +17,36 @@
           <span v-html="contentUrl"></span>
         </div>
       </template>
-      <div class="courseware-list-title">
-        {{ $t('Key309') }}
-      </div>
-      <el-tag
-        v-for="item in itemInfo.courseware_list"
-        :key="item.courseware_id"
-        color="#fff"
-        :title="item.courseware_name"
-      >
-        <div class="courseware">
-          <svg-icon icon-class="courseware" />
-          <router-link
-            target="_blank"
-            :to="{
-              path: `/task_detail/show_courseware/${item.courseware_id}?group_id_selected_info=${
-                item.group_id_selected_info ? item.group_id_selected_info : '[]'
-              }`
-            }"
-            class="courseware_name nowrap-ellipsis"
-          >
-            {{ item.courseware_name }}
-          </router-link>
+      <template v-if="!isExercises">
+        <div class="courseware-list-title">
+          {{ $t('Key309') }}
         </div>
-      </el-tag>
+        <el-tag
+          v-for="item in itemInfo.courseware_list"
+          :key="item.courseware_id"
+          color="#fff"
+          :title="item.courseware_name"
+        >
+          <div class="courseware">
+            <svg-icon icon-class="courseware" />
+            <router-link
+              target="_blank"
+              :to="{
+                path: `/task_detail/show_courseware/${item.courseware_id}?group_id_selected_info=${
+                  item.group_id_selected_info ? item.group_id_selected_info : '[]'
+                }`
+              }"
+              class="courseware_name nowrap-ellipsis"
+            >
+              {{ item.courseware_name }}
+            </router-link>
+          </div>
+        </el-tag>
+      </template>
     </div>
     <div class="learning-material">
       <div class="learning-material-title">
-        {{ $t('Key274') }}
+        {{ isExercises && type === 'teacher' ? '练习任务' : $t('Key274') }}
       </div>
       <el-tag
         v-for="item in itemInfo.cs_item_learning_material_list"
@@ -75,6 +77,10 @@ const props = defineProps({
   type: {
     type: String,
     required: true
+  },
+  isExercises: {
+    type: Boolean,
+    required: true
   }
 });
 

+ 4 - 1
src/views/task_details/student/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div v-loading="loading" class="task-detail">
-    <TaskTop :item-info="itemInfo" type="student" @viewFile="showFileVisible" />
+    <TaskTop :item-info="itemInfo" :is-exercises="isExercises" type="student" @viewFile="showFileVisible" />
 
     <div class="task-detail-main">
       <div class="time-type">{{ $t(timeType) }} {{ name }}</div>
@@ -197,6 +197,9 @@ let itemInfo = ref({
 let student_message = ref('');
 let name = ref('');
 let teaching_type = ref('');
+let isExercises = computed(() => {
+  return teaching_type.value === 15;
+});
 let time_type = ref('');
 let content = ref('');
 let time_space_view_txt = ref('');

+ 7 - 0
src/views/task_details/teacher/components/CommonTask.vue

@@ -0,0 +1,7 @@
+<template>
+  <div></div>
+</template>
+
+<script setup></script>
+
+<style lang="scss" scoped></style>

+ 83 - 72
src/views/task_details/teacher/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div v-loading="loading" class="teacher-task-detail">
-    <TaskTop :item-info="itemInfo" type="teacher" @viewFile="showFileVisible" />
+    <TaskTop :item-info="itemInfo" :is-exercises="isExercises" type="teacher" @viewFile="showFileVisible" />
 
     <div class="teacher-task-detail-main">
       <div class="student-finish-situation">
@@ -20,91 +20,96 @@
         </div>
       </div>
       <div class="finish-detail">
-        <div class="student-info">
-          <div>
-            <el-avatar :src="curFinishDetail.student_image_url" :size="32" icon="el-icon-user-solid" />
-            <span class="student-info-name">{{ curFinishDetail.student_name }}</span>
-          </div>
-          <span class="finish-time">{{ curFinishDetail.finish_time_view_txt }}</span>
-        </div>
-        <div ref="situation" class="finish-situation">
-          <div class="title">
-            {{ $t('Key312') }}
-          </div>
-          <div class="courseware-list">
-            <el-tag
-              v-for="item in curFinishDetail.courseware_list"
-              :key="item.courseware_id"
-              color="#fff"
-              :title="item.courseware_name"
-              @click="showCompletionView(item.courseware_id, item.is_finished, item.group_id_selected_info)"
-            >
-              <div class="courseware">
-                <svg-icon icon-class="courseware" />
-                <span class="courseware_name nowrap-ellipsis">{{ item.courseware_name }}</span>
-                <svg-icon v-if="item.is_finished === 'true'" class="check-mark" icon-class="check-mark-circle" />
-              </div>
-            </el-tag>
-          </div>
-          <div class="title">
-            {{ $t('Key313') }}
-          </div>
-          <div>
-            <el-tag v-for="item in accessory_list" :key="item.file_id" color="#fff" :title="item.file_name">
-              <span @click="showFileVisible(item.file_name, item.file_id)">{{ item.file_name }}</span>
-            </el-tag>
+        <template v-if="isExercises">
+          <div ref="situation" class="exercise"></div>
+        </template>
+        <template v-else>
+          <div class="student-info">
+            <div>
+              <el-avatar :src="curFinishDetail.student_image_url" :size="32" icon="el-icon-user-solid" />
+              <span class="student-info-name">{{ curFinishDetail.student_name }}</span>
+            </div>
+            <span class="finish-time">{{ curFinishDetail.finish_time_view_txt }}</span>
           </div>
-          <!-- 作业列表 -->
-          <template v-if="is_enable_homework">
+          <div ref="situation" class="finish-situation">
             <div class="title">
-              {{ $t('Key314') }}
+              {{ $t('Key312') }}
             </div>
-            <div>
+            <div class="courseware-list">
               <el-tag
-                v-for="item in curFinishDetail.homework_list"
-                :key="item.file_id"
+                v-for="item in curFinishDetail.courseware_list"
+                :key="item.courseware_id"
                 color="#fff"
-                :title="item.file_name"
+                :title="item.courseware_name"
+                @click="showCompletionView(item.courseware_id, item.is_finished, item.group_id_selected_info)"
               >
-                <span @click="showFileVisible(item.file_name, item.file_id)">{{ item.file_name }}</span>
+                <div class="courseware">
+                  <svg-icon icon-class="courseware" />
+                  <span class="courseware_name nowrap-ellipsis">{{ item.courseware_name }}</span>
+                  <svg-icon v-if="item.is_finished === 'true'" class="check-mark" icon-class="check-mark-circle" />
+                </div>
               </el-tag>
             </div>
-          </template>
-          <!-- 学员留言 -->
-          <template v-if="is_enable_message">
             <div class="title">
-              {{ $t('Key315') }}
+              {{ $t('Key313') }}
+            </div>
+            <div>
+              <el-tag v-for="item in accessory_list" :key="item.file_id" color="#fff" :title="item.file_name">
+                <span @click="showFileVisible(item.file_name, item.file_id)">{{ item.file_name }}</span>
+              </el-tag>
             </div>
-            <div>{{ curFinishDetail.student_message }}</div>
-          </template>
+            <!-- 作业列表 -->
+            <template v-if="is_enable_homework">
+              <div class="title">
+                {{ $t('Key314') }}
+              </div>
+              <div>
+                <el-tag
+                  v-for="item in curFinishDetail.homework_list"
+                  :key="item.file_id"
+                  color="#fff"
+                  :title="item.file_name"
+                >
+                  <span @click="showFileVisible(item.file_name, item.file_id)">{{ item.file_name }}</span>
+                </el-tag>
+              </div>
+            </template>
+            <!-- 学员留言 -->
+            <template v-if="is_enable_message">
+              <div class="title">
+                {{ $t('Key315') }}
+              </div>
+              <div>{{ curFinishDetail.student_message }}</div>
+            </template>
+
+            <template v-if="teachingType === 10 && is_enable_KHPJ">
+              <div class="title">
+                {{ $t('Key316') }}
+              </div>
+              <div>{{ student_remark }}</div>
+              <div class="title">
+                <span>{{ $t('Key317') }}</span>
+                <el-rate v-model="student_score" disabled />
+              </div>
+            </template>
 
-          <template v-if="teachingType === 10 && is_enable_KHPJ">
             <div class="title">
-              {{ $t('Key316') }}
+              <span>{{ $t('Key318') }}</span>
+              <el-rate v-model="teacher_score" />
             </div>
-            <div>{{ student_remark }}</div>
-            <div class="title">
-              <span>{{ $t('Key317') }}</span>
-              <el-rate v-model="student_score" disabled />
+            <div>
+              <el-input v-model="teacher_remark" type="textarea" resize="none" :rows="6" maxlength="3000" />
+            </div>
+            <div class="confirm">
+              <el-button type="primary" @click="remarkTaskStudentExecuteInfo_Teacher">
+                {{ $t('Key319') }}
+              </el-button>
+              <el-button v-if="student_list.length > 1" @click="next">
+                {{ buttonName }} <i class="el-icon-right"></i>
+              </el-button>
             </div>
-          </template>
-
-          <div class="title">
-            <span>{{ $t('Key318') }}</span>
-            <el-rate v-model="teacher_score" />
-          </div>
-          <div>
-            <el-input v-model="teacher_remark" type="textarea" resize="none" :rows="6" maxlength="3000" />
-          </div>
-          <div class="confirm">
-            <el-button type="primary" @click="remarkTaskStudentExecuteInfo_Teacher">
-              {{ $t('Key319') }}
-            </el-button>
-            <el-button v-if="student_list.length > 1" @click="next">
-              {{ buttonName }} <i class="el-icon-right"></i>
-            </el-button>
           </div>
-        </div>
+        </template>
       </div>
     </div>
 
@@ -145,6 +150,10 @@ let id = route.params.id;
 // 任务详情
 let itemInfo = ref({});
 let teachingType = ref('');
+let isExercises = computed(() => {
+  return teachingType.value === 15;
+});
+
 let accessory_list = ref([]);
 let student_list = ref([]);
 let loading = ref(true);
@@ -231,7 +240,8 @@ function getTaskStudentExecuteInfo(student_id) {
       teacher_remark: tRemake,
       teacher_score: tScore,
       student_remark: sRemake,
-      student_score: stuScore
+      student_score: stuScore,
+      exercise_info
     }) => {
       curStudentId.value = student_id;
       teacher_remark.value = tRemake;
@@ -246,6 +256,7 @@ function getTaskStudentExecuteInfo(student_id) {
         student_image_url,
         finish_time_view_txt
       };
+      console.log(exercise_info);
       nextTick(() => {
         student_list_height.value = situation.value.clientHeight;
       });

+ 1 - 2
src/views/teacher/create_course/step_three/components/layouts/create_csitem/index.vue

@@ -66,8 +66,7 @@ function addCSItem(name) {
 
   &-container {
     display: flex;
-    row-gap: 48px;
-    column-gap: 45px;
+    gap: 48px 45px;
     justify-content: center;
     margin-top: 48px;
 

+ 1 - 2
src/views/teacher/create_course/step_three/components/preview/task_preview/components/PreviewFile.vue

@@ -172,8 +172,7 @@ const showFileVisible = inject('showFileVisible');
   &-content {
     display: flex;
     flex-wrap: wrap;
-    row-gap: 16px;
-    column-gap: 8px;
+    gap: 16px 8px;
     padding-top: 16px;
 
     .file-item {

+ 1 - 2
src/views/teacher/create_course/step_three/components/preview/task_preview/components/SubtaskItem.vue

@@ -82,8 +82,7 @@ const { state, toggle } = useSwitch(true);
     .subtask-type {
       display: flex;
       flex-wrap: wrap;
-      row-gap: 8px;
-      column-gap: 8px;
+      gap: 8px 8px;
 
       &-item {
         height: 26px;

+ 1 - 2
src/views/teacher/create_course/step_three/components/task_template/subtask/SubTask.vue

@@ -129,8 +129,7 @@ const { addSubtaskItem, deleteSubtaskItem } = useSubtaskItem(info_block_list);
     .subtask-type {
       display: flex;
       flex-wrap: wrap;
-      row-gap: 8px;
-      column-gap: 8px;
+      gap: 8px 8px;
 
       &-item {
         height: 26px;