mo 2 年之前
父節點
當前提交
0f51481ae1

+ 306 - 20
package-lock.json

@@ -17,6 +17,7 @@
         "cropperjs": "^1.5.13",
         "dayjs": "^1.11.7",
         "echarts": "^5.4.2",
+        "html2canvas": "^1.4.1",
         "lodash": "^4.17.21",
         "lodash-es": "^4.17.21",
         "moveable": "^0.49.0",
@@ -28,8 +29,10 @@
         "umi-request": "^1.4.0",
         "vudio.js": "^1.0.3",
         "vue": "^3.3.4",
+        "vue-qr": "^4.0.9",
         "vue-router": "^4.1.6",
         "vue3-lottie": "^2.7.0",
+        "vuedraggable": "^4.1.0",
         "wavesurfer.js": "^7.0.0-beta.11"
       },
       "devDependencies": {
@@ -3609,8 +3612,15 @@
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/base64-arraybuffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+      "engines": {
+        "node": ">= 0.6.0"
+      }
     },
     "node_modules/base64-js": {
       "version": "1.5.1",
@@ -4069,6 +4079,14 @@
       "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==",
       "dev": true
     },
+    "node_modules/css-line-break": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
+      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
     "node_modules/css-render": {
       "version": "0.15.12",
       "resolved": "https://registry.npmmirror.com/css-render/-/css-render-0.15.12.tgz",
@@ -4176,6 +4194,17 @@
         "node": ">=14.16"
       }
     },
+    "node_modules/decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "dependencies": {
+        "mimic-response": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/deep-is": {
       "version": "0.1.4",
       "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz",
@@ -5054,8 +5083,7 @@
     "node_modules/fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-      "dev": true
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
     "node_modules/fsevents": {
       "version": "2.3.2",
@@ -5344,6 +5372,18 @@
         "node": ">=8"
       }
     },
+    "node_modules/html2canvas": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
+      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+      "dependencies": {
+        "css-line-break": "^2.1.0",
+        "text-segmentation": "^1.0.3"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
     "node_modules/human-signals": {
       "version": "4.3.1",
       "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-4.3.1.tgz",
@@ -5439,7 +5479,6 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-      "dev": true,
       "dependencies": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -5448,8 +5487,7 @@
     "node_modules/inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "dev": true
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
     "node_modules/ini": {
       "version": "1.3.8",
@@ -5868,6 +5906,11 @@
         "whatwg-fetch": ">=0.10.0"
       }
     },
+    "node_modules/js-binary-schema-parser": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz",
+      "integrity": "sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg=="
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -6506,6 +6549,14 @@
         "node": ">=12"
       }
     },
+    "node_modules/mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
@@ -6872,7 +6923,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
       "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-      "dev": true,
       "dependencies": {
         "wrappy": "1"
       }
@@ -7086,6 +7136,11 @@
         "node": ">=6"
       }
     },
+    "node_modules/parenthesis": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmmirror.com/parenthesis/-/parenthesis-3.1.8.tgz",
+      "integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw=="
+    },
     "node_modules/parse-filepath": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/parse-filepath/-/parse-filepath-1.0.2.tgz",
@@ -7825,6 +7880,21 @@
       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "dev": true
     },
+    "node_modules/simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
+    },
+    "node_modules/simple-get": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz",
+      "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+      "dependencies": {
+        "decompress-response": "^6.0.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
     "node_modules/slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz",
@@ -7866,6 +7936,11 @@
         "tslib": "^2.0.3"
       }
     },
+    "node_modules/sortablejs": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz",
+      "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
+    },
     "node_modules/source-map": {
       "version": "0.6.1",
       "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@@ -7929,6 +8004,14 @@
         "node": ">=0.6.19"
       }
     },
+    "node_modules/string-split-by": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/string-split-by/-/string-split-by-1.0.0.tgz",
+      "integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==",
+      "dependencies": {
+        "parenthesis": "^3.1.5"
+      }
+    },
     "node_modules/string-width": {
       "version": "5.1.2",
       "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz",
@@ -8067,6 +8150,14 @@
       "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz",
       "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
     },
+    "node_modules/text-segmentation": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
+      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
     "node_modules/text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz",
@@ -8391,6 +8482,14 @@
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
       "dev": true
     },
+    "node_modules/utrie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
+      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+      "dependencies": {
+        "base64-arraybuffer": "^1.0.2"
+      }
+    },
     "node_modules/v8flags": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/v8flags/-/v8flags-4.0.0.tgz",
@@ -8648,6 +8747,51 @@
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
+    "node_modules/vue-qr": {
+      "version": "4.0.9",
+      "resolved": "https://registry.npmmirror.com/vue-qr/-/vue-qr-4.0.9.tgz",
+      "integrity": "sha512-pAISV94T0MNEYA3NGjykUpsXRE2QfaNxlu9ZhEL6CERgqNc21hJYuP3hRVzAWfBQlgO18DPmZTbrFerJC3+Ikw==",
+      "dependencies": {
+        "glob": "^8.0.1",
+        "js-binary-schema-parser": "^2.0.2",
+        "simple-get": "^4.0.1",
+        "string-split-by": "^1.0.0"
+      }
+    },
+    "node_modules/vue-qr/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/vue-qr/node_modules/glob": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz",
+      "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^5.0.1",
+        "once": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vue-qr/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/vue-router": {
       "version": "4.2.2",
       "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.2.2.tgz",
@@ -8734,6 +8878,17 @@
         "vue": "^3.2"
       }
     },
+    "node_modules/vuedraggable": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
+      "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+      "dependencies": {
+        "sortablejs": "1.14.0"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.1"
+      }
+    },
     "node_modules/vueuc": {
       "version": "0.4.51",
       "resolved": "https://registry.npmmirror.com/vueuc/-/vueuc-0.4.51.tgz",
@@ -8899,8 +9054,7 @@
     "node_modules/wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-      "dev": true
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
     "node_modules/xml-name-validator": {
       "version": "4.0.0",
@@ -11601,8 +11755,12 @@
     "balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "base64-arraybuffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
     },
     "base64-js": {
       "version": "1.5.1",
@@ -12000,6 +12158,14 @@
       "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==",
       "dev": true
     },
+    "css-line-break": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
+      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+      "requires": {
+        "utrie": "^1.0.2"
+      }
+    },
     "css-render": {
       "version": "0.15.12",
       "resolved": "https://registry.npmmirror.com/css-render/-/css-render-0.15.12.tgz",
@@ -12084,6 +12250,14 @@
       "resolved": "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz",
       "integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ=="
     },
+    "decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "requires": {
+        "mimic-response": "^3.1.0"
+      }
+    },
     "deep-is": {
       "version": "0.1.4",
       "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz",
@@ -12779,8 +12953,7 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-      "dev": true
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
     "fsevents": {
       "version": "2.3.2",
@@ -13005,6 +13178,15 @@
       "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
       "dev": true
     },
+    "html2canvas": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
+      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+      "requires": {
+        "css-line-break": "^2.1.0",
+        "text-segmentation": "^1.0.3"
+      }
+    },
     "human-signals": {
       "version": "4.3.1",
       "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-4.3.1.tgz",
@@ -13070,7 +13252,6 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-      "dev": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -13079,8 +13260,7 @@
     "inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "dev": true
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
     "ini": {
       "version": "1.3.8",
@@ -13408,6 +13588,11 @@
         "whatwg-fetch": ">=0.10.0"
       }
     },
+    "js-binary-schema-parser": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz",
+      "integrity": "sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg=="
+    },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -13914,6 +14099,11 @@
       "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
       "dev": true
     },
+    "mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
+    },
     "minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
@@ -14219,7 +14409,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
       "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-      "dev": true,
       "requires": {
         "wrappy": "1"
       }
@@ -14387,6 +14576,11 @@
         "callsites": "^3.0.0"
       }
     },
+    "parenthesis": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmmirror.com/parenthesis/-/parenthesis-3.1.8.tgz",
+      "integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw=="
+    },
     "parse-filepath": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/parse-filepath/-/parse-filepath-1.0.2.tgz",
@@ -14979,6 +15173,21 @@
       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "dev": true
     },
+    "simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
+    },
+    "simple-get": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz",
+      "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+      "requires": {
+        "decompress-response": "^6.0.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
     "slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz",
@@ -15013,6 +15222,11 @@
         "tslib": "^2.0.3"
       }
     },
+    "sortablejs": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz",
+      "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
+    },
     "source-map": {
       "version": "0.6.1",
       "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@@ -15061,6 +15275,14 @@
       "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
       "dev": true
     },
+    "string-split-by": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/string-split-by/-/string-split-by-1.0.0.tgz",
+      "integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==",
+      "requires": {
+        "parenthesis": "^3.1.5"
+      }
+    },
     "string-width": {
       "version": "5.1.2",
       "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz",
@@ -15167,6 +15389,14 @@
         }
       }
     },
+    "text-segmentation": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
+      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+      "requires": {
+        "utrie": "^1.0.2"
+      }
+    },
     "text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz",
@@ -15421,6 +15651,14 @@
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
       "dev": true
     },
+    "utrie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
+      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+      "requires": {
+        "base64-arraybuffer": "^1.0.2"
+      }
+    },
     "v8flags": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/v8flags/-/v8flags-4.0.0.tgz",
@@ -15580,6 +15818,47 @@
         }
       }
     },
+    "vue-qr": {
+      "version": "4.0.9",
+      "resolved": "https://registry.npmmirror.com/vue-qr/-/vue-qr-4.0.9.tgz",
+      "integrity": "sha512-pAISV94T0MNEYA3NGjykUpsXRE2QfaNxlu9ZhEL6CERgqNc21hJYuP3hRVzAWfBQlgO18DPmZTbrFerJC3+Ikw==",
+      "requires": {
+        "glob": "^8.0.1",
+        "js-binary-schema-parser": "^2.0.2",
+        "simple-get": "^4.0.1",
+        "string-split-by": "^1.0.0"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
+          "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+          "requires": {
+            "balanced-match": "^1.0.0"
+          }
+        },
+        "glob": {
+          "version": "8.1.0",
+          "resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz",
+          "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^5.0.1",
+            "once": "^1.3.0"
+          }
+        },
+        "minimatch": {
+          "version": "5.1.6",
+          "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz",
+          "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+          "requires": {
+            "brace-expansion": "^2.0.1"
+          }
+        }
+      }
+    },
     "vue-router": {
       "version": "4.2.2",
       "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.2.2.tgz",
@@ -15644,6 +15923,14 @@
         "lottie-web": "5.12.2"
       }
     },
+    "vuedraggable": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
+      "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+      "requires": {
+        "sortablejs": "1.14.0"
+      }
+    },
     "vueuc": {
       "version": "0.4.51",
       "resolved": "https://registry.npmmirror.com/vueuc/-/vueuc-0.4.51.tgz",
@@ -15784,8 +16071,7 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-      "dev": true
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
     "xml-name-validator": {
       "version": "4.0.0",

+ 1 - 0
package.json

@@ -30,6 +30,7 @@
     "cropperjs": "^1.5.13",
     "dayjs": "^1.11.7",
     "echarts": "^5.4.2",
+    "html2canvas": "^1.4.1",
     "lodash": "^4.17.21",
     "lodash-es": "^4.17.21",
     "moveable": "^0.49.0",

二進制
src/common/images/logo.png


+ 16 - 16
src/components/TheQrCode/index.tsx

@@ -178,22 +178,22 @@ export default defineComponent({
         gifBackground: gifBgSrc,
         text: this.text,
         size: this.size,
-        // margin: this.margin,
-        // colorDark: this.colorDark,
-        // colorLight: this.colorLight,
-        // backgroundColor: this.backgroundColor,
-        // backgroundImage: img,
-        // // backgroundDimming: this.backgroundDimming,
-        // // // logoImage: logoImg + '?' + new Date().getTime(),
-        // logoScale: this.logoScale,
-        // logoBackgroundColor: this.logoBackgroundColor,
-        // correctLevel: this.correctLevel,
-        // logoMargin: this.logoMargin,
-        // logoCornerRadius: this.logoCornerRadius,
-        // whiteMargin: toBoolean(this.whiteMargin),
-        // dotScale: this.dotScale,
-        // autoColor: toBoolean(this.autoColor),
-        // components: this.components
+        margin: this.margin,
+        colorDark: this.colorDark,
+        colorLight: this.colorLight,
+        backgroundColor: this.backgroundColor,
+        backgroundImage: img,
+        backgroundDimming: this.backgroundDimming,
+        logoImage: logoImg + '?' + new Date().getTime(),
+        logoScale: this.logoScale,
+        logoBackgroundColor: this.logoBackgroundColor,
+        correctLevel: this.correctLevel,
+        logoMargin: this.logoMargin,
+        logoCornerRadius: this.logoCornerRadius,
+        whiteMargin: toBoolean(this.whiteMargin),
+        dotScale: this.dotScale,
+        autoColor: toBoolean(this.autoColor),
+        components: this.components
       })
         .draw()
         .then((dataUri: any) => {

+ 5 - 1
src/views/attend-class/model/train-type/index.tsx

@@ -52,6 +52,10 @@ export default defineComponent({
     offShelf: {
       type: Boolean,
       default: false
+    },
+    isCLassWork: {
+      type: Boolean,
+      default: false
     }
   },
   emits: ['click', 'delete', 'edit', 'offShelf'],
@@ -132,7 +136,7 @@ export default defineComponent({
         </div>
         <div class={styles['train-content']}>
           <NImage src={props.item.coverImg} previewDisabled objectFit="cover" />
-          {props.isDisabled ? (
+          {props.isDisabled && !props.isCLassWork ? (
             <div class={styles.disPreview}>
               <NProgress
                 percentage={

+ 0 - 1
src/views/classList/components/classStudent.tsx

@@ -191,7 +191,6 @@ export default defineComponent({
             v-model:pageTotal={state.pagination.pageTotal}
             onList={getList}
             sync
-            saveKey="orchestraRegistration-key"
           />
         </div>
       </div>

+ 0 - 1
src/views/classList/index.tsx

@@ -40,7 +40,6 @@ export default defineComponent({
         currentClass: null,
         currentGradeNum: null
       },
-
       orchestraType: null,
       courseTypeCode: null,
       loading: false,

+ 1 - 0
src/views/classList/modals/classTrainingDetails.tsx

@@ -151,6 +151,7 @@ export default defineComponent({
                 style={{ marginBottom: '20px' }}
                 isDisabled={true}
                 isDelete={false}
+                isCLassWork={true}
                 item={item}></TrainType>
             ))}
           </div>

+ 9 - 0
src/views/studentList/api.ts

@@ -18,3 +18,12 @@ export const getPracticeRecordList = (params: any) => {
     // requestType: 'form'
   });
 };
+
+/**
+ * 获取学生列表
+ */
+export const getStudentList = (params: any) => {
+  return request.post('/edu-app/student/page', {
+    data: params
+  });
+};

+ 165 - 0
src/views/studentList/components/baseInfo.tsx

@@ -0,0 +1,165 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import {
+  NImage,
+  NForm,
+  NFormItem,
+  NInput,
+  NGrid,
+  NGi,
+  NButton,
+  NSelect,
+  NSpace,
+  SelectOption,
+  useMessage,
+  NModal,
+  NCalendar,
+  NCascader
+} from 'naive-ui';
+import headerD from '../images/headerD.png';
+import defultHeade from '@/components/layout/images/teacherIcon.png';
+import maleIcon from '../images/maleIcon.png';
+import femaleIcon from '../images/femaleIcon.png';
+import { useUserStore } from '/src/store/modules/users';
+import { api_teacherUpdate } from '/src/api/user';
+import UploadFile from '/src/components/upload-file';
+export default defineComponent({
+  name: 'setting-personInfo',
+  setup() {
+    const message = useMessage();
+    const userStore = useUserStore();
+    const formOptions = reactive({
+      sexs: [
+        { label: '男', value: 1, class: 'option' },
+        { label: '女', value: 0, class: 'option' }
+      ] as SelectOption[],
+      areaList: [] as any[]
+    });
+    const formRef = ref();
+    const teacherForm = reactive({
+      provinceCode: '', // 省份编码
+      cityCode: '', // 城市编码
+      regionCode: '', // 区域编码
+      nickname: userStore.info.nickname,
+      phone: userStore.info.phone,
+      gender: userStore.info.gender,
+      schoolId: userStore.info.schoolInfos?.[0]?.id,
+      tenantId: userStore.info.schoolInfos?.[0]?.tenantId,
+      id: userStore.info.id,
+      avatar: userStore.info.avatar
+    });
+    const data = reactive({
+      disabled: true,
+      openChangePwd: false,
+      uploadShow: true
+    });
+
+    // onMounted(() => {});
+
+    const handleSave = () => {
+      formRef.value.validate(async (err: any) => {
+        if (err) {
+          return;
+        }
+        await api_teacherUpdate(teacherForm);
+        console.log(teacherForm);
+        userStore.getInfo();
+        data.disabled = true;
+        message.success('修改成功');
+      });
+    };
+    return () => (
+      <div class={styles.infoWrap}>
+        <div class={styles.setInfo}>
+          <NForm ref={formRef} model={teacherForm} disabled={data.disabled}>
+            <NGrid cols={4} x-gap="100">
+              <NGi>
+                <NFormItem
+                  label="姓名"
+                  path="nickname"
+                  rule={{
+                    required: true,
+                    message: '请填写老师姓名',
+                    trigger: 'blur'
+                  }}>
+                  <NInput
+                    bordered={!data.disabled}
+                    placeholder="请填写老师姓名"
+                    v-model:value={teacherForm.nickname}></NInput>
+                </NFormItem>
+              </NGi>
+              <NGi>
+                <NFormItem
+                  label="手机号"
+                  path="phone"
+                  rule={[
+                    {
+                      required: true,
+                      message: '请填写老师手机号',
+                      trigger: 'blur'
+                    },
+                    {
+                      pattern: /^1[3456789]\d{9}$/,
+                      message: '手机号格式不正确',
+                      trigger: 'blur'
+                    }
+                  ]}>
+                  <NInput
+                    bordered={!data.disabled}
+                    placeholder="请填写老师手机号"
+                    v-model:value={teacherForm.phone}></NInput>
+                </NFormItem>
+              </NGi>
+              <NGi>
+                <NFormItem label="性别" path="sex">
+                  <NSelect
+                    bordered={!data.disabled}
+                    class={styles.select}
+                    showArrow={!data.disabled}
+                    placeholder="请选择性别"
+                    options={formOptions.sexs}
+                    v-model:value={teacherForm.gender}
+                  />
+                </NFormItem>
+              </NGi>
+              <NGi>
+                <NFormItem label="年级班级" path="sex">
+                  <NSelect
+                    bordered={!data.disabled}
+                    class={styles.select}
+                    showArrow={!data.disabled}
+                    placeholder="请选择性别"
+                    options={formOptions.sexs}
+                    v-model:value={teacherForm.gender}
+                  />
+                </NFormItem>
+              </NGi>
+            </NGrid>
+          </NForm>
+        </div>
+        {data.disabled ? (
+          <NSpace class={styles.btnList} align="center" justify="end">
+            <NButton
+              class={styles.btn}
+              color="#f24433"
+              onClick={() => (data.disabled = false)}>
+              修改信息
+            </NButton>
+          </NSpace>
+        ) : (
+          <NSpace class={styles.btnList} align="center" justify="end">
+            <NButton class={styles.btn} onClick={() => (data.disabled = true)}>
+              取消
+            </NButton>
+            <NButton
+              class={styles.btn}
+              type="primary"
+              onClick={() => handleSave()}>
+              完成
+            </NButton>
+          </NSpace>
+        )}
+      </div>
+    );
+  }
+});

+ 1 - 1
src/views/studentList/components/practiceData.tsx

@@ -317,7 +317,7 @@ export default defineComponent({
                       <NNumberAnimation
                         from={0}
                         to={getSecend(
-                          payForm.practiceDurationTotal
+                          payForm.practiceDurationAvg
                         )}></NNumberAnimation>
                     </span>{' '}

二進制
src/views/studentList/images/cordWrap.png


二進制
src/views/studentList/images/strudentCore.png


二進制
src/views/studentList/images/studentBg.png


二進制
src/views/studentList/images/studentClose.png


二進制
src/views/studentList/images/studentStart.png


二進制
src/views/studentList/images/studentTitle.png


+ 207 - 0
src/views/studentList/index.module.less

@@ -252,3 +252,210 @@
   width: 830px;
   overflow: hidden;
 }
+.addStudentWrap {
+  position: relative;
+  width: 467px;
+  height: 688px;
+  margin: 80px auto 0;
+  background: url(./images/studentBg.png) no-repeat;
+  background-size: 467px 688px;
+  padding: 18px 21px 15px 27px;
+  .studentCLose {
+    cursor: pointer;
+    position: absolute;
+    right: -38px;
+    top: -37px;
+    width: 51px;
+    height: 51px;
+    z-index: 100;
+  }
+  .stunentStart {
+    position: absolute;
+    width: 601px;
+    height: 275px;
+    left: -38px;
+    top: -68px;
+  }
+  .addStudentInfo {
+    width: 419px;
+    height: 655px;
+    position: relative;
+
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    .studentInfoBg {
+      position: absolute;
+      width: 419px;
+      height: 655px;
+      img {
+        left: 0;
+        top: 0;
+        width: 419px;
+        height: 655px;
+      }
+    }
+    .addTitle {
+      width: 230px;
+      height: 48px;
+      top: -9px;
+      position: relative;
+      margin: 0 auto;
+      z-index: 100;
+      img {
+        width: 230px;
+        height: 48px;
+      }
+    }
+    .studentCore {
+      position: absolute;
+      bottom: 27px;
+      left: 48px;
+      width: 330px;
+      height: 339px;
+      background: rgba(255, 255, 255, 0.33);
+      border-radius: 17px;
+      border: 2px solid #ffffff;
+      backdrop-filter: blur(17px);
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      .schoolLogo {
+        width: 67px;
+        height: 67px;
+        margin-top: -34px;
+        border: 1px solid #fff;
+        border-radius: 50%;
+        z-index: 100;
+        overflow: hidden;
+        background-color: #fff;
+        position: absolute;
+      }
+      .studentCoreInfo {
+        margin-top: 6px;
+        width: 314px;
+        height: 323px;
+        background: #ffffff;
+        border-radius: 17px;
+
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        h2 {
+          margin-top: 37px;
+          height: 22px;
+          font-size: 16px;
+          font-weight: 600;
+          color: #000000;
+          line-height: 22px;
+          margin-bottom: 6px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+        .studentCoreInfoSubtitle {
+          font-size: 14px;
+          font-weight: 400;
+          color: #000000;
+          span {
+            color: #198cfe;
+            font-weight: 600;
+          }
+        }
+        .codewrap {
+          width: 147px;
+          height: 145px;
+          background: url(./images/cordWrap.png) no-repeat;
+          position: relative;
+          background-size: 147px 145px;
+          margin: 16px 0 18px;
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+        }
+        .codewrapSubmit {
+          width: 213px;
+          height: 35px;
+          background: linear-gradient(135deg, #d1fdf9 0%, #d6eeff 100%);
+          box-shadow: inset 0px 1px 0px 0px rgba(255, 255, 255, 0.62);
+          border-radius: 18px;
+          text-align: center;
+          line-height: 35px;
+          font-size: 14px;
+          color: #117de9;
+          span {
+            font-weight: 600;
+          }
+        }
+      }
+    }
+  }
+  .studentBottom {
+    width: 419px;
+
+    position: absolute;
+    bottom: -120px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    p {
+      text-align: center;
+      font-size: 16px;
+      color: #ffffff;
+      margin-bottom: 30px;
+    }
+    .downBtn {
+      width: 295px;
+      height: 60px;
+      background: linear-gradient(90deg, #ff7b57 0%, #ff3460 100%);
+      border-radius: 30px;
+      line-height: 60px;
+      font-size: 24px;
+      font-weight: 600;
+      text-align: center;
+      color: #fff;
+
+      cursor: pointer;
+    }
+  }
+}
+
+.setInfo {
+  margin-top: 64px;
+  width: 1172px;
+
+  :global {
+    .n-form-item-label {
+      font-size: 15px;
+      color: rgba(0, 0, 0, 0.8);
+    }
+
+    .n-input {
+      height: 50px;
+      border-radius: 8px;
+
+      .n-input__input-el {
+        height: 100%;
+      }
+
+      &.n-input--disabled {
+        background-color: #f5f6fa;
+        color: rgba(149, 149, 152, 1);
+      }
+    }
+
+    .n-base-selection {
+      border-radius: 8px;
+
+      .n-base-selection-label {
+        height: 50px;
+      }
+    }
+
+    .n-base-selection.n-base-selection--disabled .n-base-selection-label {
+      background-color: #f5f6fa;
+      color: rgba(149, 149, 152, 1);
+    }
+  }
+}

+ 100 - 88
src/views/studentList/index.tsx

@@ -1,4 +1,4 @@
-import { defineComponent, reactive } from 'vue';
+import { defineComponent, onMounted, reactive } from 'vue';
 import styles from './index.module.less';
 import {
   NButton,
@@ -6,6 +6,7 @@ import {
   NForm,
   NFormItem,
   NImage,
+  NModal,
   NSelect,
   NSpace
 } from 'naive-ui';
@@ -14,10 +15,19 @@ import CSelect from '@/components/CSelect';
 import Pagination from '@/components/pagination';
 import add from './images/add.png';
 import { useRoute, useRouter } from 'vue-router';
+import { getStudentList } from './api';
+import { classGroupList } from '@/views/classList/api';
+import AddStudentModel from './modals/addStudentModel';
 export default defineComponent({
   name: 'student-studentList',
   setup(props, { emit }) {
     const state = reactive({
+      searchForm: {
+        keyword: '',
+        gender: null as any,
+        classGroupId: null as any,
+        membership: null as any
+      },
       searchWord: '',
       orchestraType: null,
       courseTypeCode: null,
@@ -30,60 +40,60 @@ export default defineComponent({
         rows: 10,
         pageTotal: 4
       },
-      tableList: [
-        {
-          nickname: '汤科斯',
-          phone: '17625367893',
-          sex: '0',
-          className: '一年级3班',
-          classType: 'normal',
-          studentType: 'member',
-          id: '1001415'
-        },
-        {
-          studentName: '丁曼蓉',
-          phone: '14677789334',
-          sex: '1',
-          className: '一年级3班',
-          classType: 'normal',
-          studentType: ''
-        },
-        {
-          studentName: '李书意',
-          phone: '13467857893',
-          sex: '1',
-          className: '一年级3班',
-          classType: 'graduate',
-          studentType: 'member'
-        },
-        {
-          studentName: '夏小满',
-          phone: '13925367893',
-          sex: '0',
-          className: '一年级3班',
-          classType: 'none',
-          studentType: ''
-        }
-      ] as any
+      tableList: [] as any,
+      classList: [],
+      addStudentVisible: false
     });
     const route = useRoute();
     const router = useRouter();
     const search = () => {
-      console.log('search', state);
+      state.pagination.page = 1;
+      getList();
+    };
+    const getClasslist = async () => {
+      try {
+        const res = await classGroupList({ page: 1, rows: 999 });
+        state.classList = res.data.rows.map((item: any) => {
+          return {
+            label: item.name,
+            value: item.id
+          };
+        });
+      } catch (e) {
+        console.log(e);
+      }
     };
-
     const onReset = () => {
-      console.log('search');
+      state.searchForm = {
+        keyword: '',
+        gender: null as any,
+        classGroupId: null as any,
+        membership: null as any
+      };
+      search();
     };
-    const getList = () => {
+    const getList = async () => {
+      try {
+        const res = await getStudentList({
+          ...state.searchForm,
+          ...state.pagination
+        });
+        state.tableList = res.data.rows;
+        state.pagination.pageTotal = res.data.total;
+      } catch (e) {
+        console.log(e);
+      }
       console.log('getList');
     };
-
+    onMounted(() => {
+      getList();
+      getClasslist();
+    });
     const columns = () => {
       return [
         {
-          title: '姓名',
-          key: 'studentName'
+          title: '学生姓名',
+          key: 'nickname'
         },
         {
           title: '手机号',
@@ -91,38 +101,27 @@ export default defineComponent({
         },
         {
           title: '性别',
-          key: 'sex',
-          render(row: any) {
-            return <>{row.sex == '0' ? '女' : '男'}</>;
-          }
-        },
-
-        {
-          title: '班级',
-          key: 'className',
+          key: 'gender',
           render(row: any) {
             return (
               <>
-                <div>
-                  {row.classType == 'none' ? (
-                    <p style={{ color: '#EA4132' }}>{'未在班级'}</p>
-                  ) : null}
-                  {row.classType == 'graduate' ? (
-                    <p style={{ color: '#AAAAAA' }}>{'毕业'}</p>
-                  ) : null}
-                  {row.classType == 'normal' ? <p>{row.className}</p> : null}
-                </div>
+                {row.gender + '' != 'null'
+                  ? row.gender == '0'
+                    ? '女'
+                    : '男'
+                  : '--'}
               </>
             );
           }
         },
-        {
-          title: '学生类型',
-          key: 'studentType',
-          render(row: any) {
-            return <>{row.studentType == 'member' ? '会员' : '普通'}</>;
-          }
-        },
+
+        // {
+        //   title: '学生类型',
+        //   key: 'studentType',
+        //   render(row: any) {
+        //     return <>{row.studentType == 'member' ? '会员' : '普通'}</>;
+        //   }
+        // },
         {
           title: '操作',
           key: 'id',
@@ -151,9 +150,9 @@ export default defineComponent({
               <SearchInput
                 {...{ placeholder: '请输入学生姓名' }}
                 class={styles.searchInput}
-                searchWord={state.searchWord}
+                searchWord={state.searchForm.keyword}
                 onChangeValue={(val: string) =>
-                  (state.searchWord = val)
+                  (state.searchForm.keyword = val)
                 }></SearchInput>
             </NFormItem>
 
@@ -162,57 +161,59 @@ export default defineComponent({
                 {...({
                   options: [
                     {
-                      label: '竖笛',
-                      value: 'song0'
+                      label: '学生性别',
+                      value: null
                     },
                     {
-                      label: '葫芦丝',
-                      value: 'song1'
+                      label: '男',
+                      value: 1
+                    },
+                    {
+                      label: '女',
+                      value: 0
                     }
                   ],
-                  placeholder: '学生声部',
+                  placeholder: '性别',
                   clearable: true,
                   inline: true
                 } as any)}
-                v-model:value={state.subjectId}></CSelect>
+                v-model:value={state.searchForm.gender}></CSelect>
             </NFormItem>
             <NFormItem>
               <CSelect
                 {...({
                   options: [
-                    {
-                      label: '一年级2班',
-                      value: 'song0'
-                    },
-                    {
-                      label: '一年级3班',
-                      value: 'song1'
-                    }
+                    { label: '年级班级', value: null },
+                    ...state.classList
                   ],
                   placeholder: '年级班级',
                   clearable: true,
                   inline: true
                 } as any)}
-                v-model:value={state.classId}></CSelect>
+                v-model:value={state.searchForm.classGroupId}></CSelect>
             </NFormItem>
             <NFormItem>
               <CSelect
                 {...({
                   options: [
                     {
+                      label: '学生类型',
+                      value: null
+                    },
+                    {
                       label: '会员',
-                      value: 'song0'
+                      value: true
                     },
                     {
                       label: '普通',
-                      value: 'song1'
+                      value: false
                     }
                   ],
                   placeholder: '学生类型',
                   clearable: true,
                   inline: true
                 } as any)}
-                v-model:value={state.studentType}></CSelect>
+                v-model:value={state.searchForm.membership}></CSelect>
             </NFormItem>
             <NFormItem>
               <NSpace justify="end">
@@ -231,6 +232,9 @@ export default defineComponent({
           </NForm>
         </div>
         <NButton
+          onClick={() => {
+            state.addStudentVisible = true;
+          }}
           class={styles.addBtn}
           type="primary"
           v-slots={{
@@ -257,6 +261,14 @@ export default defineComponent({
             saveKey="orchestraRegistration-key"
           />
         </div>
+        {state.addStudentVisible ? (
+          <div v-model:show={state.addStudentVisible} class="n-modal-mask">
+            <AddStudentModel
+              onClose={() => {
+                state.addStudentVisible = false;
+              }}></AddStudentModel>
+          </div>
+        ) : null}
       </div>
     );
   }

+ 164 - 0
src/views/studentList/modals/addStudentModel.tsx

@@ -0,0 +1,164 @@
+import {
+  NButton,
+  NSpace,
+  useMessage,
+  NForm,
+  NFormItem,
+  NSelect,
+  NImage
+} from 'naive-ui';
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import CSelect from '/src/components/CSelect';
+import stunentStart from '../images/studentStart.png';
+import studentCLose from '../images/studentClose.png';
+import { useUserStore } from '@/store/modules/users';
+import TheQrCode from '/src/components/TheQrCode';
+import { vaildUrl } from '@/utils/urlUtils';
+import logo from '@/common/images/logo.png';
+import studentTitle from '../images/studentTitle.png';
+import studentInfo from '../images/strudentCore.png';
+import codewrapBg from '../images/cordWrap.png';
+import html2canvas from 'html2canvas';
+export default defineComponent({
+  props: {
+    activeRow: {
+      type: Object,
+      default: () => ({ id: '' })
+    },
+    gradeNumList: {
+      type: Array,
+      default: () => []
+    },
+    classArray: {
+      type: Array,
+      default: () => []
+    }
+  },
+  name: 'resetStudent',
+  emits: ['close', 'getList'],
+  setup(props, { emit }) {
+    const data = reactive({
+      uploading: false
+    });
+    const message = useMessage();
+    const userStore = useUserStore();
+    const foemsRef = ref();
+    const url = ref(
+      vaildUrl() +
+        `/classroom-app/#/student-register?sId=${userStore.getUserInfo.schoolInfos[0].id}`
+    );
+    const imgs = reactive({
+      saveLoading: false,
+      image: null as any,
+      shareLoading: false
+    });
+    const downImg = () => {
+      if (imgs.saveLoading) {
+        return;
+      }
+      imgs.saveLoading = true;
+      // 判断是否已经生成图片
+      if (imgs.image) {
+        saveImg();
+      } else {
+        const container: any = document.getElementById(`preview-container`);
+        html2canvas(container, {
+          allowTaint: true,
+          useCORS: true,
+          backgroundColor: null
+        })
+          .then(async canvas => {
+            const url = canvas.toDataURL('image/png');
+            imgs.image = url;
+            saveImg();
+          })
+          .catch(() => {
+            imgs.saveLoading = false;
+          });
+      }
+    };
+
+    const saveImg = async () => {
+      // showLoadingToast({ message: '图片生成中...', forbidClick: true });
+      setTimeout(() => {
+        imgs.saveLoading = false;
+      }, 100);
+      const link = document.createElement('a');
+      link.setAttribute('download', '报名图片' + '.png');
+      // 添加时间戳,防止浏览器缓存图片
+      // console.log(imgUrl,'imgUrl')
+
+      link.href = imgs.image;
+      link.click();
+      // const res = await promisefiyPostMessage({
+      //   api: 'savePicture',
+      //   content: {
+      //     base64: imgs.image
+      //   }
+      // });
+      // if (res?.content?.status === 'success') {
+      //   showSuccessToast('保存成功');
+      // } else {
+      //   showFailToast('保存失败');
+      // }
+    };
+    return () => (
+      <div class={[styles.addStudentWrap]}>
+        <div
+          onClick={() => {
+            console.log('点击');
+            emit('close');
+          }}>
+          <NImage
+            src={studentCLose}
+            previewDisabled
+            class={styles.studentCLose}></NImage>
+        </div>
+        <NImage
+          previewDisabled
+          class={styles.stunentStart}
+          src={stunentStart}></NImage>
+        <div class={styles.addStudentInfo} id="preview-container">
+          <NImage
+            class={styles.addTitle}
+            previewDisabled
+            src={studentTitle}></NImage>
+          <NImage
+            class={styles.studentInfoBg}
+            previewDisabled
+            src={studentInfo}></NImage>
+
+          <div class={styles.studentCore}>
+            <NImage
+              previewDisabled
+              class={styles.schoolLogo}
+              src={
+                userStore.getUserInfo.schoolInfos[0].logo +
+                `?some=${new Date().getTime()}`
+              }></NImage>
+            <div class={styles.studentCoreInfo}>
+              <h2>{userStore.getUserInfo.schoolInfos[0].name}</h2>
+              <p class={styles.studentCoreInfoSubtitle}>
+                邀请您的孩子加入
+                <span>数字化乐器课堂</span>
+              </p>
+              <div class={styles.codewrap}>
+                <TheQrCode logoSrc={logo} text={url.value} size={119} />
+              </div>
+              <div class={styles.codewrapSubmit}>
+                请扫描上方二维码 <span>完成报名</span>{' '}
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class={styles.studentBottom}>
+          <p>请将二维码图片发送给学生家长,扫码完成报名</p>
+          <div class={styles.downBtn} onClick={downImg}>
+            下载图片
+          </div>
+        </div>
+      </div>
+    );
+  }
+});

+ 2 - 2
src/views/studentList/studentDetail.tsx

@@ -22,7 +22,7 @@ import femaleIcon from '@/views/setting/images/femaleIcon.png';
 import maleIcon from '@/views/setting/images/maleIcon.png';
 import PracticeData from '@/views/studentList/components/practiceData';
 import EvaluationRecords from '@/views/studentList/components/evaluationRecords';
-
+import BaseInfo from '@/views/studentList/components/baseInfo';
 import dayjs from 'dayjs';
 export default defineComponent({
   name: 'studentDetail',
@@ -103,7 +103,7 @@ export default defineComponent({
             pane-wrapper-style="margin: 0 -4px"
             pane-style="padding-left: 4px; padding-right: 4px; box-sizing: border-box;">
             <NTabPane name="baseInfo" tab="基本信息">
-              基本信息
+              <BaseInfo></BaseInfo>
             </NTabPane>
             <NTabPane name="afterWork" tab="课后训练">
               课后训练