chao 6 months ago
parent
commit
60c5e142f5

+ 7 - 1
package-lock.json

@@ -24,6 +24,7 @@
         "lodash": "^4.17.21",
         "material-icons": "^1.13.12",
         "pinia": "^2.1.7",
+        "platform": "^1.3.6",
         "rimraf": "^5.0.5",
         "sass": "^1.70.0",
         "vite": "^6.0.5",
@@ -2024,7 +2025,7 @@
     },
     "node_modules/material-icons": {
       "version": "1.13.12",
-      "resolved": "https://mirrors.cloud.tencent.com/npm/material-icons/-/material-icons-1.13.12.tgz",
+      "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.13.12.tgz",
       "integrity": "sha512-/2YoaB79IjUK2B2JB+vIXXYGtBfHb/XG66LvoKVM5ykHW7yfrV5SP6d7KLX6iijY6/G9GqwgtPQ/sbhFnOURVA=="
     },
     "node_modules/memoize-one": {
@@ -2201,6 +2202,11 @@
         }
       }
     },
+    "node_modules/platform": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
+      "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="
+    },
     "node_modules/postcss": {
       "version": "8.4.49",
       "resolved": "https://mirrors.cloud.tencent.com/npm/postcss/-/postcss-8.4.49.tgz",

+ 1 - 0
package.json

@@ -25,6 +25,7 @@
     "lodash": "^4.17.21",
     "material-icons": "^1.13.12",
     "pinia": "^2.1.7",
+    "platform": "^1.3.6",
     "rimraf": "^5.0.5",
     "sass": "^1.70.0",
     "vite": "^6.0.5",

+ 150 - 0
src/assets/img/device-detect.svg

@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 504.727 504.727" style="enable-background:new 0 0 504.727 504.727;" xml:space="preserve">
+<circle style="fill:#FBBD5E;" cx="385.483" cy="119.545" r="118.942"/>
+<path style="fill:#4FBF9F;" d="M414.628,373.97V138.45c0-17.329-14.178-31.508-31.508-31.508H39.686
+	c-17.329,0-31.508,14.178-31.508,31.508v235.52H414.628z"/>
+<path style="fill:#183651;" d="M414.628,381.847H8.179c-4.726,0-7.877-3.151-7.877-7.877V138.45
+	c0-22.055,17.329-39.385,39.385-39.385H383.12c22.055,0,39.385,17.329,39.385,39.385v235.52
+	C422.505,378.696,418.566,381.847,414.628,381.847z M16.056,366.093h390.695V138.45c0-13.391-10.24-23.631-23.631-23.631H39.686
+	c-13.391,0-23.631,10.24-23.631,23.631V366.093z"/>
+<g>
+	<rect x="39.686" y="138.45" style="fill:#FFFFFF;" width="343.434" height="204.012"/>
+	<path style="fill:#FFFFFF;" d="M8.179,373.97v34.658c0,17.329,14.178,31.508,31.508,31.508H383.12
+		c17.329,0,31.508-14.178,31.508-31.508V373.97H8.179z"/>
+</g>
+<g>
+	<path style="fill:#183651;" d="M383.12,448.801H39.686c-22.055,0-39.385-17.329-39.385-39.385v-34.658
+		c0-4.726,3.151-7.877,7.877-7.877h406.449c4.726,0,7.877,3.151,7.877,7.877v34.658C422.505,430.684,404.388,448.801,383.12,448.801
+		z M16.056,381.847v26.782c0,13.391,10.24,23.631,23.631,23.631H383.12c13.391,0,23.631-10.24,23.631-23.631v-26.782H16.056z"/>
+	<path style="fill:#183651;" d="M267.33,504.727L267.33,504.727H155.477c-2.363,0-4.726-1.575-6.302-3.151
+		c-1.575-2.363-1.575-4.726-0.788-7.089l22.843-55.926c1.575-3.151,3.938-4.726,7.089-4.726h66.166c3.151,0,6.302,1.575,7.089,4.726
+		l22.843,55.138c0.788,1.575,1.575,2.363,1.575,4.726C275.206,501.576,272.056,504.727,267.33,504.727z M166.505,488.973h89.009
+		l-16.542-40.172h-55.926L166.505,488.973z"/>
+</g>
+<path style="fill:#183651;" d="M279.933,504.727H142.874c-4.726,0-7.877-3.151-7.877-7.877s3.151-7.877,7.877-7.877h137.058
+	c4.726,0,7.877,3.151,7.877,7.877S284.659,504.727,279.933,504.727z"/>
+<rect x="74.345" y="229.034" style="fill:#FFFFFF;" width="54.351" height="54.351"/>
+<path style="fill:#183651;" d="M129.483,292.05H74.345c-4.726,0-7.877-3.151-7.877-7.877v-54.351c0-4.726,3.151-7.877,7.877-7.877
+	h54.351c4.726,0,7.877,3.151,7.877,7.877v54.351C137.36,288.111,133.422,292.05,129.483,292.05z M82.222,276.296h38.597v-38.597
+	H82.222V276.296z"/>
+<rect x="183.834" y="229.034" style="fill:#FFFFFF;" width="54.351" height="54.351"/>
+<path style="fill:#183651;" d="M238.973,292.05h-54.351c-4.726,0-7.877-3.151-7.877-7.877v-54.351c0-4.726,3.151-7.877,7.877-7.877
+	h54.351c4.726,0,7.877,3.151,7.877,7.877v54.351C246.85,288.111,242.911,292.05,238.973,292.05z M191.711,276.296h38.597v-38.597
+	h-38.597V276.296z"/>
+<rect x="293.323" y="229.034" style="fill:#FFFFFF;" width="54.351" height="54.351"/>
+<path style="fill:#183651;" d="M348.462,292.05h-54.351c-4.726,0-7.877-3.151-7.877-7.877v-54.351c0-4.726,3.151-7.877,7.877-7.877
+	h54.351c4.726,0,7.877,3.151,7.877,7.877v54.351C356.339,288.111,352.4,292.05,348.462,292.05z M301.2,276.296h38.597v-38.597H301.2
+	V276.296z"/>
+<path style="fill:#183651;" d="M129.483,323.558H74.345c-4.726,0-7.877-3.151-7.877-7.877c0-4.726,3.151-7.877,7.877-7.877h54.351
+	c4.726,0,7.877,3.151,7.877,7.877C136.573,320.407,133.422,323.558,129.483,323.558z"/>
+<path style="fill:#183651;" d="M238.973,323.558h-54.351c-4.726,0-7.877-3.151-7.877-7.877c0-4.726,3.151-7.877,7.877-7.877h54.351
+	c4.726,0,7.877,3.151,7.877,7.877C246.85,320.407,242.911,323.558,238.973,323.558z"/>
+<g>
+	<path style="fill:#183651;" d="M348.462,323.558h-54.351c-4.726,0-7.877-3.151-7.877-7.877c0-4.726,3.151-7.877,7.877-7.877h54.351
+		c4.726,0,7.877,3.151,7.877,7.877C356.339,320.407,352.4,323.558,348.462,323.558z"/>
+	<rect x="157.053" y="399.176" style="fill:#183651;" width="15.754" height="15.754"/>
+	<rect x="203.526" y="399.176" style="fill:#183651;" width="15.754" height="15.754"/>
+	<rect x="250" y="399.176" style="fill:#183651;" width="15.754" height="15.754"/>
+</g>
+<path style="fill:#FFFFFF;" d="M238.973,145.539l11.815-25.994l-18.117-10.24c1.575-7.089,1.575-14.178,0.788-20.48l18.905-9.452
+	l-9.452-26.782l-20.48,4.726c-3.938-5.514-8.665-11.028-14.178-14.966l6.302-19.692L188.56,10.844l-10.24,17.329
+	c-7.089-1.575-14.178-1.575-20.48-0.788l-9.452-18.905l-26.782,9.452l4.726,20.48c-5.514,3.938-11.028,8.665-14.966,14.178
+	l-20.48-6.302L79.071,72.284l18.117,11.028c-1.575,7.089-1.575,14.178-0.788,20.48l-18.905,9.452l9.452,26.782l20.48-4.726
+	c3.938,5.514,8.665,11.028,14.178,14.966l-6.302,19.692l25.994,11.815l11.028-18.117c7.089,1.575,14.178,1.575,20.48,0.788
+	l9.452,18.905l26.782-9.452l-4.726-20.48c5.514-3.938,11.028-8.665,14.966-14.178L238.973,145.539z"/>
+<path style="fill:#183651;" d="M182.259,191.225c-3.151,0-5.514-1.575-7.089-3.938l-7.089-14.178c-3.938,0-7.877,0-11.815-0.788
+	l-8.665,13.391c-2.363,3.151-6.302,4.726-10.24,3.151l-25.994-11.815c-3.938-1.575-5.514-5.514-3.938-9.452l4.726-14.966
+	c-3.151-2.363-5.514-5.514-7.877-8.665l-15.754,3.938c-3.938,0.788-7.877-1.575-9.452-4.726l-9.452-26.782
+	c-1.575-3.938,0-7.877,3.938-9.452l14.178-7.089c0-3.938,0-7.877,0.788-11.815l-13.391-9.452c-3.151-2.363-4.726-6.302-3.151-10.24
+	l11.815-25.994c1.575-3.938,5.514-5.514,9.452-3.938l14.966,4.726c2.363-3.151,5.514-5.514,8.665-7.877l-3.938-15.754
+	c-0.788-3.938,1.575-7.877,4.726-9.452l26.782-9.452c3.938-1.575,7.877,0,9.452,3.938l7.877,14.178c3.938,0,7.877,0,11.815,0.788
+	l8.665-13.391c2.363-3.151,6.302-4.726,10.24-3.151l25.994,11.815c3.938,1.575,5.514,5.514,3.938,9.452l-5.514,14.966
+	c3.151,2.363,5.514,5.514,7.877,8.665l15.754-3.938c3.938-0.788,7.877,1.575,9.452,4.726l9.452,26.782
+	c1.575,3.938,0,7.877-3.938,9.452l-14.178,7.089c0,3.938,0,7.877-0.788,11.815l13.391,8.665c3.151,2.363,4.726,6.302,3.151,10.24
+	l-11.815,25.994c-1.575,3.938-5.514,5.514-9.452,3.938l-14.966-4.726c-2.363,3.151-5.514,5.514-8.665,7.877l3.938,15.754
+	c0.788,3.938-1.575,7.877-4.726,9.452l-26.782,9.452C183.834,191.225,183.046,191.225,182.259,191.225z M172.019,156.567
+	c3.151,0,5.514,1.575,7.089,3.938l6.302,12.603l13.391-4.726l-3.151-13.391c-0.788-3.151,0.788-6.302,3.151-8.665
+	c4.726-3.151,9.452-7.877,13.391-12.603c2.363-2.363,5.514-3.938,8.665-2.363l13.391,3.938l6.302-12.603l-11.815-7.089
+	c-3.151-1.575-3.938-4.726-3.938-7.877c0.788-6.302,1.575-11.815,0.788-18.117c0-3.151,1.575-6.302,3.938-7.877l12.603-6.302
+	l-4.726-13.391l-13.391,3.151c-3.151,0.788-6.302-0.788-8.665-3.151c-3.151-4.726-7.877-9.452-12.603-13.391
+	c-2.363-2.363-3.938-5.514-2.363-8.665l3.938-13.391l-12.603-6.302l-7.089,11.815c-1.575,3.151-4.726,3.938-7.877,3.938
+	c-6.302-0.788-11.815-1.575-18.117-0.788c-3.151,0-6.302-1.575-7.877-3.938l-6.302-12.603l-14.178,4.726l3.151,13.391
+	c0.788,3.151-0.788,6.302-3.151,8.665c-4.726,3.151-9.452,7.877-13.391,12.603c-2.363,2.363-5.514,3.938-8.665,2.363L94.825,56.53
+	l-6.302,12.603l11.815,7.089c3.151,1.575,3.938,4.726,3.938,7.877c-0.788,6.302-1.575,11.815-0.788,18.117
+	c0,3.151-1.575,6.302-3.938,7.877l-12.603,6.302l4.726,13.391l13.391-3.151c3.151-0.788,6.302,0.788,8.665,3.151
+	c3.151,4.726,7.877,9.452,12.603,13.391c2.363,2.363,3.938,5.514,2.363,8.665l-3.938,13.391l12.603,6.302l7.089-11.815
+	c1.575-3.151,4.726-3.938,7.877-3.938c6.302,0.788,11.815,1.575,18.117,0.788C172.019,156.567,172.019,156.567,172.019,156.567z"/>
+<circle style="fill:#F06151;" cx="164.93" cy="95.914" r="49.625"/>
+<circle style="fill:#FFFFFF;" cx="164.93" cy="95.914" r="19.692"/>
+<path style="fill:#183651;" d="M164.93,123.484c-3.938,0-7.877-0.788-11.815-2.363c-6.302-3.151-11.815-8.665-14.178-15.754
+	c-2.363-7.089-2.363-14.178,0.788-21.268c4.726-9.452,14.178-15.754,25.206-15.754c3.938,0,7.877,0.788,11.815,2.363
+	c13.391,6.302,19.692,22.843,13.391,36.234C185.41,117.182,175.17,123.484,164.93,123.484z M164.93,84.099
+	c-4.726,0-8.665,2.363-11.028,7.089c-1.575,3.151-1.575,6.302,0,8.665c1.575,2.363,3.151,5.514,6.302,6.302
+	c5.514,2.363,12.603,0,15.754-5.514c2.363-5.514,0-12.603-5.514-15.754C168.08,84.887,166.505,84.099,164.93,84.099z"/>
+<path style="fill:#FFFFFF;" d="M480.794,136.087v-30.72l-22.843-2.363c-1.575-7.089-4.726-14.178-8.665-20.48l14.178-18.117
+	l-21.268-21.268L424.08,57.318c-6.302-3.938-13.391-6.302-20.48-8.665l-2.363-22.843h-30.72l-2.363,22.843
+	c-7.089,1.575-14.178,4.726-20.48,8.665l-18.117-14.178L308.29,64.407l14.178,18.117c-3.938,6.302-6.302,13.391-8.665,20.48
+	l-22.843,2.363v30.72l22.843,2.363c1.575,7.089,4.726,14.178,8.665,20.48l-14.178,18.117l21.268,21.268l18.117-14.178
+	c6.302,3.938,13.391,6.302,20.48,8.665l2.363,22.843h30.72l2.363-22.843c7.089-1.575,14.178-4.726,20.48-8.665l18.117,14.178
+	l21.268-21.268l-14.178-18.117c3.938-6.302,6.302-13.391,8.665-20.48L480.794,136.087z"/>
+<path style="fill:#183651;" d="M401.237,223.521h-30.72c-3.938,0-7.089-3.151-7.877-7.089l-2.363-17.329
+	c-3.938-1.575-8.665-3.151-12.603-5.514l-13.391,11.028c-3.151,2.363-7.877,2.363-10.24-0.788l-21.268-21.268
+	c-3.151-3.151-3.151-7.089-0.788-10.24l11.028-13.391c-2.363-3.938-3.938-7.877-5.514-12.603l-17.329-2.363
+	c-3.938-0.788-7.089-3.938-7.089-7.877v-30.72c0-3.938,3.151-7.089,7.089-7.877l17.329-2.363c1.575-3.938,3.151-8.665,5.514-12.603
+	l-11.028-13.391c-2.363-3.151-2.363-7.877,0.788-10.24l21.268-21.268c3.151-3.151,7.089-3.151,10.24-0.788l13.391,11.028
+	c3.938-2.363,7.877-3.938,12.603-5.514l2.363-17.329c0.788-3.938,3.938-7.089,7.877-7.089h30.72c3.938,0,7.089,3.151,7.877,7.089
+	l2.363,17.329c3.938,1.575,8.665,3.151,12.603,5.514l13.391-11.028c3.151-2.363,7.877-2.363,10.24,0.788l21.268,21.268
+	c3.151,3.151,3.151,7.089,0.788,10.24l-11.028,14.178c2.363,3.938,3.938,7.877,5.514,12.603l17.329,2.363
+	c3.938,0.788,7.089,3.938,7.089,7.877v30.72c0,3.938-3.151,7.089-7.089,7.877l-17.329,1.575c-1.575,3.938-3.151,8.665-5.514,12.603
+	l11.028,13.391c2.363,3.151,2.363,7.877-0.788,10.24l-21.268,21.268c-3.151,3.151-7.089,3.151-10.24,0.788l-14.178-11.028
+	c-3.938,2.363-7.877,3.938-12.603,5.514l-2.363,17.329C408.326,220.37,405.176,223.521,401.237,223.521z M377.606,207.767h16.542
+	l1.575-15.754c0.788-3.151,2.363-6.302,6.302-7.089c6.302-1.575,12.603-3.938,18.117-7.877c3.151-1.575,6.302-1.575,8.665,0.788
+	l12.603,9.452l11.815-11.815l-9.452-12.603c-2.363-2.363-2.363-6.302-0.788-8.665c3.151-5.514,6.302-11.815,7.877-18.117
+	c0.788-3.151,3.151-5.514,7.089-6.302l15.754-1.575v-16.542l-15.754-1.575c-3.151-0.788-6.302-2.363-7.089-6.302
+	c-1.575-6.302-3.938-12.603-7.877-18.117c-1.575-3.151-1.575-6.302,0.788-8.665l9.452-11.815L441.41,53.379l-12.603,9.452
+	c-2.363,2.363-6.302,2.363-8.665,0.788c-5.514-3.151-11.815-6.302-18.117-7.877c-3.151-0.788-5.514-3.151-6.302-7.089l-1.575-15.754
+	h-16.542l-1.575,15.754c-0.788,3.151-2.363,6.302-6.302,7.089c-6.302,1.575-12.603,3.938-18.117,7.877
+	c-3.151,1.575-6.302,1.575-8.665-0.788l-12.603-9.452L318.53,65.194l9.452,12.603c2.363,2.363,2.363,6.302,0.788,8.665
+	c-3.151,5.514-6.302,11.815-7.877,18.117c-0.788,3.151-3.151,5.514-7.089,6.302l-15.754,1.575v16.542l15.754,1.575
+	c3.151,0,6.302,2.363,7.089,6.302c1.575,6.302,3.938,12.603,7.877,18.117c1.575,3.151,1.575,6.302-0.788,8.665l-9.452,12.603
+	l11.815,11.815l12.603-9.452c2.363-2.363,6.302-2.363,8.665-0.788c5.514,3.151,11.815,6.302,18.117,7.877
+	c3.151,0.788,5.514,3.151,6.302,7.089L377.606,207.767z"/>
+<circle style="fill:#E0E4E8;" cx="385.483" cy="121.121" r="52.775"/>
+<circle style="fill:#FFFFFF;" cx="385.483" cy="121.121" r="21.268"/>
+<path style="fill:#183651;" d="M385.483,149.478c-15.754,0-29.145-12.603-29.145-29.145c0-15.754,12.603-29.145,29.145-29.145
+	c15.754,0,29.145,12.603,29.145,29.145C414.628,136.874,402.025,149.478,385.483,149.478z M385.483,107.73
+	c-7.089,0-13.391,6.302-13.391,13.391c0,7.089,6.302,13.391,13.391,13.391s13.391-6.302,13.391-13.391
+	C398.874,113.244,393.36,107.73,385.483,107.73z"/>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 7 - 0
src/assets/language/en.js

@@ -129,5 +129,12 @@ export default {
         serial_port: "Serial Interactive Window",
         python_code: "Python Code",
         catLogic:"Logic",
+        update_success: "Update Success",
+        update_error: "Update Failure",
+        add_success: "Add Success",
+        add_error: "Add Failure",
+        add: "Add",
+        update: "Update",
+        ok: "OK",
     }
 }

+ 9 - 0
src/assets/language/zh-hans.js

@@ -1,3 +1,5 @@
+import { add } from "lodash";
+
 export default{
     message:{
         close:"关闭",
@@ -128,5 +130,12 @@ export default{
         upload_code_error: "上传失败",
         serial_port: "串口交互窗",
         python_code: "python 源代码",
+        update_success: "更新成功",
+        update_error: "更新失败",
+        add_success: "添加成功",
+        add_error: "添加失败",
+        add: "添加",
+        update: "更新",
+        ok: "确定",
     }
 }

+ 7 - 0
src/assets/language/zh-hant.js

@@ -129,5 +129,12 @@ export default {
         serial_port: "串口交互窗",
         python_code: "python 源代碼",
         catLogic:"邏輯",
+        update_success: "更新成功",
+        update_error: "更新失敗",
+        add_success: "添加成功",
+        add_error: "添加失敗",
+        add: "添加",
+        update: "更新",
+        ok: "確定",
     }
 }

+ 1 - 7
src/components/BlocklyComponent.vue

@@ -57,7 +57,7 @@ onMounted(() => {
   var categoryNodes = blocklyXmls.getElementsByTagName('category');
   for (var i = 0, cat; cat = categoryNodes[i]; i++) {
     var catId = cat.getAttribute('id');
-    var catText = getLocalStr(catId);
+    var catText = language.value[catId] || catId;
     if (catText) {
       cat.setAttribute('name', catText);
     }
@@ -144,12 +144,6 @@ const getLocalStorageXml = () => {
   }
 }
 
-const getLocalStr = (str) => {
-  // console.log(str, language.value[str])
-  let text = language.value[str]
-  return text || str
-}
-
 watchEffect(() => {
   // console.log(LoadBlocklyStatus.status)
   if (LoadBlocklyStatus.status) {

+ 4 - 2
src/components/device/device.vue

@@ -77,6 +77,7 @@ const wsconect = () => {
             ws = ws.close() ? null : null;
             ++fail === socketPort.length ? setTimeout(() => {
                 console.log('重连中')
+                Uploaders.uploaders.version = ''
                 Uploaders.uploaders.status = false;
                 wsconect()
             }, 2000) : null;
@@ -85,6 +86,7 @@ const wsconect = () => {
             Uploaders.uploaders.status = false;
             ++fail === socketPort.length ? setTimeout(() => {
                 console.log('重连中')
+                Uploaders.uploaders.version = ''
                 Uploaders.uploaders.status = false;
                 wsconect()
             }, 2000) : null;
@@ -128,7 +130,7 @@ const runCode = async () => {
 
 }
 const uploadCode = async () => {
-    console.log('上传代码', code.pythonCode)
+    // console.log('上传代码', code.pythonCode)
     if (!(websocket.value && websocket.value.id)) {
         return
     } else if (code.pythonCode == "") {
@@ -148,7 +150,7 @@ os.remove("${path}")`
         method: 'post',
         data: { comname: devicePort.value, sid: websocket.value.id, code: pythonuploadCode, type: true },
     })
-    console.log('data', data)
+    // console.log('data', data)
     // 上传
     if (data.data == "success") {
         await axios({

+ 201 - 3
src/components/device/deviceHeader.vue

@@ -9,22 +9,182 @@
             <img src="../../assets/img/uploader_connect.png" alt="">
         </el-tooltip>
         <el-tooltip v-else :content="$t('message.not_uploader_connection')">
-            <img  src="../../assets/img/uploader_disconnect.png" alt="">
+            <img src="../../assets/img/uploader_disconnect.png" alt="" @click="uploaderDialog = true">
         </el-tooltip>
         <img class="device-header-img-right" src="../../assets/img/plugin_download.png" alt="">
         <img class="device-header-img-right" src="../../assets/img/firmware.png" alt="">
     </div>
+    <el-dialog v-model="uploaderDialog">
+        <div slot="header">
+            <h1>环境检测</h1>
+        </div>
+        <div v-if="deviceDecetion" class="device-detect">
+            <img src="../../assets/img/device-detect.svg" alt="">
+        </div>
+        <div v-else class="device-detect">
+            <el-row class="device-detect-table">
+                <el-col :span="5">设备</el-col>
+                <el-col :span="5">结果</el-col>
+                <el-col :span="5">支持</el-col>
+                <el-col :span="9">建议</el-col>
+            </el-row>
+            <el-row class="device-detect-table-title">
+                <el-col :span="5">系统</el-col>
+                <el-col :span="5">{{ system }}</el-col>
+                <el-col :span="5">
+                    <i class="material-icons small" :style="systemSupport ? 'color:#00cf00;' : 'color:#ffcf00;'">{{
+                        systemSupport ? 'check' : 'priority_high' }}</i>
+                </el-col>
+                <el-col :span="9">{{ systemSupport?'支持':"不支持" }}</el-col>
+            </el-row>
+            <el-row class="device-detect-table-title">
+                <el-col :span="5">浏览器</el-col>
+                <el-col :span="5">{{ browser }}</el-col>
+                <el-col :span="5">
+                    <i class="material-icons small" :style="systemSupport ? 'color:#00cf00;' : 'color:#ffcf00;'">{{
+                        systemSupport ? 'check' : 'priority_high' }}</i>
+                </el-col>
+                <el-col :span="9">{{ systemSupport?'支持':"不支持" }}</el-col>
+            </el-row>
+            <el-row class="device-detect-table-title">
+                <el-col :span="5">Uploader</el-col>
+                <el-col :span="5">{{ version || "没有打开" }}</el-col>
+                <el-col :span="5"><i class="material-icons small" :style="verBool ? 'color:#00cf00;' : 'color:#ffcf00;'">{{
+                        verBool ? 'check' : 'priority_high' }}</i></el-col>
+                <el-col :span="9">
+                    {{ version ? 'uploader已连接':'Uploader 未连接' }}<br />
+                    {{ verStr }}
+                </el-col>
+            </el-row>
+            <el-row class="device-detect-table-title">
+                <el-col :span="5">补丁</el-col>
+                <el-col :span="5">
+                    <a :href="downloadLink" target="_blank" download="kb2999226 64-bit"
+                        style="color: #039be5;">kb2999226 64-bit</a>
+                </el-col>
+            </el-row>
+        </div>
+        <div class="device-detect-btn">
+            <el-button type="primary" @click="getVersion">开始检测</el-button>
+        </div>
+    </el-dialog>
 </template>
 <script setup>
-import { ref, watchEffect } from 'vue'
+import { ref, watchEffect, onMounted } from 'vue'
 import storeDevice from '@/stores/device'
+import platform from 'platform'
+import server from '../../config/index'
 import { useI18n } from 'vue-i18n'
-const {t} = useI18n()
+const { t } = useI18n()
 
 const connection = ref(t('message.wired_connection'))
 const uploader = storeDevice.useUploaders()
+const uploaderDialog = ref(false)
+const deviceDecetion = ref(true)
+const browser = ref(`${platform.name} ${platform.version}`)
+const system = ref(platform.os.toString())
+const version = ref('')
+const systemSupport = ref(false)
+const browserSupport = ref(false)
+const verBool = ref(false)
+const verStr = ref('')
+const downloadLink = ref('')
+onMounted(() => {
+    console.log("navigator.userAgent")
+    osSupportDetect(platform.os.family, platform.os.version)
+    browserDetect(platform.name, platform.version)
+    downloadLink.value = platform.os.toString().indexOf("64-bit") != -1 ?
+        "//cocorobo.cn/downloads/Windows6.1-KB2999226-x64.msu" :
+        "//cocorobo.cn/downloads/Windows6.1-KB2999226-x86.msu"
+    uploaderVersion()
+})
+const getVersion = () => {
+    deviceDecetion.value = false;
+    osSupportDetect(platform.os.family, platform.os.version)
+    browserDetect(platform.name, platform.version)
+    uploaderVersion()
+}
+const osSupportDetect = (family, version) => {
+    let mac = { int: 10, float: 9 };
+    let win = {
+        '10': 10,
+        '10 Technical Preview': 6.4,
+        '8.1': 6.3,
+        '8': 6.2,
+        '7': 6.1,
+        'Vista': 6,
+        'XP 64-bit': 5.2,
+        'XP': 5.1,
+        '2000 SP1': 5.01,
+        '2000': 5.0,
+        'NT': 4.0,
+        'ME': 4.90
+    };
+    let result = false;
+    if (family.toLowerCase().indexOf("windows") > -1) {
+        win[version] >= 5.1 ? result = true : "";
+    } else if (family.toLowerCase().indexOf("os x") > -1) {
+        const ver = version.split(".");
+        if (ver[0] > mac.int || (parseInt(ver[0]) === mac.int &&
+            ver[1] >= mac.float)) {
+            result = true;
+        }
+    }
+    systemSupport.value = result;
+}
+const browserDetect = (name, version) => {
+    let result = false;
+    const versionParse = (sep, ver) => {
+        const arr = version.split(sep);
+        return arr[0] > ver;
+    }
+    if (name === "Chrome") {
+        result = versionParse('.', 50);
+    } else if (name === "Firefox") {
+        result = versionParse('.', 50);
+    } else if (name === "Opera") {
+        result = versionParse('.', 43);
+    } else if (name === 'Safari') {
+        result = versionParse('.', 10);
+    } else if (name === 'Maxthon') {
+        result = versionParse('.', 4);
+    }
+    browserSupport.value = result;
+}
+
+const uploaderVersion = () => {
+    console.log(uploader.uploaders.version, server.uploader)
+    let ver = uploader.uploaders.version
+    if (!ver) {
+        version.value = ""
+        verBool.value = false
+        return false;
+    }
+    if(ver == server.uploader) {
+        verBool.value = true;
+    }else{
+        const newVer = compareVersions(ver, server.uploader) > 0 ? true : false;
+        verBool.value = newVer;
+        verStr.value = !newVer ? "版本不是最新,建议更新" : "";
+    }
+
+    
+
+}
+const compareVersions = (v1, v2) => {
+    const v1Parts = v1.split('.').map(Number);
+    const v2Parts = v2.split('.').map(Number);
+    for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
+        const v1Part = v1Parts[i] || 0;
+        const v2Part = v2Parts[i] || 0;
+        if (v1Part > v2Part) return 1;
+        if (v1Part < v2Part) return -1;
+    }
+    return 0;
+};
 watchEffect(() => {
     console.log(uploader.uploaders.status)
+    version.value = uploader.uploaders.version
 })
 </script>
 <style scoped lang="scss">
@@ -49,4 +209,42 @@ watchEffect(() => {
         float: right;
     }
 }
+
+.device-detect {
+    margin-top: 20px;
+
+    img {
+        position: relative;
+        width: 270px;
+        left: 53%;
+        transform: translateX(-50%);
+    }
+
+    .device-detect-table {
+        text-align: center;
+        border-bottom: 2.5px solid #0057ff6e;
+        padding: 0.25rem 0;
+        font-size: 1.45rem;
+        color: #818181
+    }
+
+    .device-detect-table-title {
+        text-align: center;
+        padding: 0.25rem 0;
+        font-size: 1.2rem;
+        color: #000;
+        margin-top: 1rem;
+    }
+}
+
+.device-detect-btn {
+    margin-top: 20px;
+    text-align: center;
+
+    button {
+        width: 240px;
+        font-size: 18px;
+        height: 40px;
+    }
+}
 </style>

+ 95 - 11
src/components/headerRight/fIleOperation.vue

@@ -10,12 +10,12 @@
         </div>
         <template #dropdown>
             <el-dropdown-menu>
-                <el-dropdown-item class="header_menu_li" @click="cloudSave()"
-                    style="color: #26a69a;">{{ $t('message.cloud_save') }}</el-dropdown-item>
-                <el-dropdown-item class="header_menu_li" @click="importFile()"
-                    style="color: #26a69a;">{{ $t('message.import') }}</el-dropdown-item>
-                <el-dropdown-item class="header_menu_li" @click="exportFile()"
-                    style="color: #26a69a;">{{ $t('message.Export') }}</el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" @click="cloudSave()" style="color: #26a69a;">{{
+                    $t('message.cloud_save') }}</el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" @click="importFile()" style="color: #26a69a;">{{
+                    $t('message.import') }}</el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" @click="exportFile()" style="color: #26a69a;">{{
+                    $t('message.Export') }}</el-dropdown-item>
             </el-dropdown-menu>
         </template>
     </el-dropdown>
@@ -24,7 +24,9 @@
             <el-col :span="7" style="margin-top: 15px;">
                 <el-card :body-style="{ padding: '0px' }">
                     <div style="padding: 14px;">
-
+                        <el-icon :size="80" @click="createFile()">
+                            <DocumentAdd />
+                        </el-icon>
                     </div>
                 </el-card>
             </el-col>
@@ -38,7 +40,10 @@
                         </div>
                     </div>
                     <div class="cloud_card_bottom" style="padding: 14px;">
-                        <span>{{ item.filename }}</span><br />
+                        <span>{{ item.filename }}</span>
+                        <el-icon :size="20">
+                            <Edit @click="update($event, item)" />
+                        </el-icon><br />
                         <span>{{ $t('message.last_version') }}{{ new Date(item.date).toLocaleDateString() }}</span>
                     </div>
                 </el-card>
@@ -50,10 +55,20 @@
             </div>
         </template>
     </el-dialog>
+    <el-dialog v-model="updateDialog" :title="updateTitle" width="400">
+        <el-input v-model="newFilename" style="margin-top: 20px;"></el-input>
+        <template #footer>
+            <div class="dialog-footer">
+                <el-button @click="sumbit" type="primary">{{ $t('message.ok') }}</el-button>
+                <el-button @click="updateDialog = false">{{ $t('message.close') }}</el-button>
+            </div>
+        </template>
+    </el-dialog>
 </template>
 <script setup>
 import { ref } from 'vue'
 import { ElMessage } from 'element-plus'
+import { Edit, DocumentAdd } from '@element-plus/icons-vue'
 import Blockly from 'blockly';
 import local_storage from '../../assets/img/local_storage.png'
 import '../../assets/css/header.css'
@@ -77,12 +92,16 @@ const importFileName = store.useImportFileNameStore()
 const LoadBlocklyStatus = store.useLoadBlocklyStatus()
 const cloudDialog = ref(false)
 const cloudData = ref([])
+const updateDialog = ref(false)
+const updateData = ref({})
+const newFilename = ref('')
+const updateTitle = ref(t('mesage.add'))
 const cloudSave = () => {
     if (JSON.stringify(user.userInfo) != "{}") {
         axios.defaults.withCredentials = true
         axios.changeOrigin = true
         axios.get(`${server.host}blockx/files`).then(res => {
-            console.table(res.data)
+            // console.table(res.data)
             cloudData.value = res.data
         })
         cloudDialog.value = true
@@ -216,9 +235,12 @@ const openFile = (e, item) => {
     e.stopPropagation();
     // https://api.cocorobo.cn/blockx/5ed71aeb0ff4fc69b32e866b_1710676497206
     axios.get(`https://api.cocorobo.cn/blockx/${item.filenameid}`).then(res => {
-        console.log(res.data.xml.slice(5))
+        console.log(res.data.xml)
         if (res.status == 200) {
-            const xml = res.data.xml.slice(5)
+            let xml = res.data.xml
+            if(xml.indexOf('$') == 4){
+                xml = xml.slice(5)
+            }
             importFileName.$patch({ fileName: item.filename })
             emit("setFileName", item.filename)
             exportXml.$patch({ xmlStr: xml })
@@ -237,6 +259,68 @@ const openFile = (e, item) => {
         }
     })
 }
+// 
+const update = (e, item) => {
+    updateDialog.value = true
+    e.stopPropagation();
+    console.log(item)
+    updateData.value = item
+    newFilename.value = item.filename
+    updateTitle.value = t('message.update')
+}
+const sumbit = () => {
+    if (updateTitle.value == t('message.add')) {
+        let params = {
+            filename: newFilename.value,
+            type: '',
+            xml: exportXml.xmlStr
+        }
+        axios.post("https://api.cocorobo.cn/blockx/", params).then(res => {
+            console.log(res)
+            if (res.statusText == "OK") {
+                cloudSave()
+                ElMessage({
+                    message: t('message.add_success'),
+                    type: 'success',
+                })
+                updateDialog.value = false
+            } else {
+                ElMessage({
+                    message: t('message.add_error'),
+                    type: 'error',
+                })
+            }
+
+        })
+    } else {
+        let data = {
+            currentFilename: updateData.value.filename,
+            newFilename: newFilename.value
+        }
+        axios.put('https://api.cocorobo.cn/blockx/modify', data).then(res => {
+            console.log(res)
+            if (res.data == "Filename update.") {
+                cloudSave()
+                ElMessage({
+                    message: t('message.update_success'),
+                    type: 'success',
+                })
+                updateDialog.value = false
+            } else {
+                ElMessage({
+                    message: t('message.update_error'),
+                    type: 'error',
+                })
+            }
+        })
+    }
+
+}
+const createFile = () => {
+    updateDialog.value = true
+    newFilename.value = ""
+    updateTitle.value = t('message.add')
+}
 </script>
 <style scoped lang="scss">
 .cloud_card_top {

+ 2 - 1
src/config/index.js

@@ -1,5 +1,6 @@
 const server = {
-    host: 'https://api.cocorobo.cn/'
+    host: 'https://api.cocorobo.cn/',
+    uploader:'1.1.0'
 }
 
 export default server