chao 1 년 전
부모
커밋
083681ce82
81개의 변경된 파일1403개의 추가작업 그리고 78개의 파일을 삭제
  1. BIN
      dist/assets/cocoblockly-navbar_labs-icon-6EIlABjy.png
  2. 1 1
      dist/assets/index-DkR7hYw5.js
  3. 0 0
      dist/assets/index-ieosR263.css
  4. 0 0
      dist/assets/index-yjGHODhS.css
  5. BIN
      dist/assets/learn_nav_icon-uetDIr7g.png
  6. BIN
      dist/assets/local_storage-RdZXse2B.png
  7. BIN
      dist/assets/logo1-xImG6MHd.png
  8. BIN
      dist/assets/material-icons-69IKE8Hh.woff
  9. BIN
      dist/assets/material-icons-JAMAXUYH.woff2
  10. BIN
      dist/assets/material-icons-outlined-2YYhrxAP.woff2
  11. BIN
      dist/assets/material-icons-outlined-aVm8Jdp-.woff
  12. BIN
      dist/assets/material-icons-round-64qylwcb.woff2
  13. BIN
      dist/assets/material-icons-round-Q5cMfrL_.woff
  14. BIN
      dist/assets/material-icons-sharp-IInc7Yq0.woff2
  15. BIN
      dist/assets/material-icons-sharp-h9SpFbu_.woff
  16. BIN
      dist/assets/material-icons-two-tone-7jSKWhI8.woff2
  17. BIN
      dist/assets/material-icons-two-tone-e8M-5hA2.woff
  18. BIN
      dist/assets/user-_Ytma4Ez.png
  19. 2 2
      dist/index.html
  20. 221 1
      package-lock.json
  21. 3 0
      package.json
  22. 33 9
      src/App.vue
  23. 1 1
      src/assets/css/base.css
  24. 0 16
      src/assets/css/blockly.css
  25. 43 0
      src/assets/css/header.css
  26. 140 0
      src/assets/css/main.css
  27. BIN
      src/assets/img/APPCenter_test.jpg
  28. BIN
      src/assets/img/AppCenter_ai_emotion.jpg
  29. BIN
      src/assets/img/AppCenter_ai_gesture_recognition.jpg
  30. BIN
      src/assets/img/AppCenter_ai_speech.jpg
  31. BIN
      src/assets/img/AppCenter_ai_teachableMachine.jpg
  32. BIN
      src/assets/img/AppCenter_comingSoon.jpg
  33. BIN
      src/assets/img/AppCenter_game_floppy-bird.jpg
  34. BIN
      src/assets/img/AppCenter_game_space_lamb.jpg
  35. BIN
      src/assets/img/AppCenter_iot_ifttt.jpg
  36. BIN
      src/assets/img/AppCenter_iot_thingspeak.jpg
  37. BIN
      src/assets/img/WeTech.jpg
  38. BIN
      src/assets/img/adb1.png
  39. BIN
      src/assets/img/adb2.png
  40. BIN
      src/assets/img/adb3.png
  41. BIN
      src/assets/img/adb4.jpg
  42. BIN
      src/assets/img/cocoblockly-navbar_labs-icon.png
  43. BIN
      src/assets/img/error.png
  44. BIN
      src/assets/img/firmware.png
  45. BIN
      src/assets/img/home_icon.png
  46. BIN
      src/assets/img/labs_aihub1.jpg
  47. BIN
      src/assets/img/labs_aihub2.jpg
  48. BIN
      src/assets/img/labs_aihub3.jpg
  49. BIN
      src/assets/img/language2.png
  50. BIN
      src/assets/img/learn_nav_icon.png
  51. BIN
      src/assets/img/local_storage.png
  52. BIN
      src/assets/img/logo1.png
  53. BIN
      src/assets/img/nav_help.png
  54. BIN
      src/assets/img/object_recognition_header.jpg
  55. BIN
      src/assets/img/posenet_recogition.png
  56. BIN
      src/assets/img/tm_with_pose.jpg
  57. BIN
      src/assets/img/uploader_connect.png
  58. BIN
      src/assets/img/uploader_disconnect.png
  59. BIN
      src/assets/img/user.png
  60. BIN
      src/assets/img/加载.png
  61. 0 1
      src/assets/logo.svg
  62. 0 23
      src/assets/main.css
  63. 17 15
      src/components/BlocklyComponent.vue
  64. 30 6
      src/components/codemirror/codemirror.vue
  65. 14 0
      src/components/footer/footer.vue
  66. 33 0
      src/components/header/header.vue
  67. 85 0
      src/components/header/headerLeft.vue
  68. 46 0
      src/components/header/headerRight.vue
  69. 15 0
      src/components/headerRight/example.vue
  70. 74 0
      src/components/headerRight/fIleOperation.vue
  71. 123 0
      src/components/headerRight/labs.vue
  72. 24 0
      src/components/headerRight/languareSwitch.vue
  73. 45 0
      src/components/headerRight/linkStudy.vue
  74. 235 0
      src/components/headerRight/user.vue
  75. 81 0
      src/components/labs/ai.vue
  76. 23 0
      src/components/labs/iot.vue
  77. 0 0
      src/components/labs/robotContro.vue
  78. 59 0
      src/components/labs/targetCard.vue
  79. 18 0
      src/gloabl/globalMethods.js
  80. 5 3
      src/main.js
  81. 32 0
      src/stores/blockly.js

BIN
dist/assets/cocoblockly-navbar_labs-icon-6EIlABjy.png


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/assets/index-DkR7hYw5.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/assets/index-ieosR263.css


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/assets/index-yjGHODhS.css


BIN
dist/assets/learn_nav_icon-uetDIr7g.png


BIN
dist/assets/local_storage-RdZXse2B.png


BIN
dist/assets/logo1-xImG6MHd.png


BIN
dist/assets/material-icons-69IKE8Hh.woff


BIN
dist/assets/material-icons-JAMAXUYH.woff2


BIN
dist/assets/material-icons-outlined-2YYhrxAP.woff2


BIN
dist/assets/material-icons-outlined-aVm8Jdp-.woff


BIN
dist/assets/material-icons-round-64qylwcb.woff2


BIN
dist/assets/material-icons-round-Q5cMfrL_.woff


BIN
dist/assets/material-icons-sharp-IInc7Yq0.woff2


BIN
dist/assets/material-icons-sharp-h9SpFbu_.woff


BIN
dist/assets/material-icons-two-tone-7jSKWhI8.woff2


BIN
dist/assets/material-icons-two-tone-e8M-5hA2.woff


BIN
dist/assets/user-_Ytma4Ez.png


+ 2 - 2
dist/index.html

@@ -5,8 +5,8 @@
     <link rel="icon" href="/favicon.ico">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Mini Pi</title>
-    <script type="module" crossorigin src="/assets/index-9OBswdoC.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-ieosR263.css">
+    <script type="module" crossorigin src="/assets/index-DkR7hYw5.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-yjGHODhS.css">
   </head>
   <body>
     <div id="app"></div>

+ 221 - 1
package-lock.json

@@ -31,10 +31,13 @@
         "@yume-chan/struct": "file:../ya-webadb/libraries/struct",
         "@yume-chan/tabby-launcher": "file:../ya-webadb/libraries/tabby-launcher",
         "@yume-chan/tabby-tango": "file:../ya-webadb/libraries/tabby-tango",
+        "axios": "^1.6.5",
         "blockly": "^10.3.0",
         "element-plus": "^2.5.1",
         "ll": "^1.2.0",
+        "material-icons": "^1.13.12",
         "pinia": "^2.1.7",
+        "sass": "^1.70.0",
         "vue": "^3.3.11",
         "vue-codemirror": "^6.1.1",
         "vue-router": "^4.2.5"
@@ -1586,11 +1589,41 @@
         "node": ">= 6.0.0"
       }
     },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
       "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
     },
+    "node_modules/axios": {
+      "version": "1.6.5",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
+      "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
+      "dependencies": {
+        "follow-redirects": "^1.15.4",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/blockly": {
       "version": "10.3.0",
       "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.3.0.tgz",
@@ -1599,6 +1632,43 @@
         "jsdom": "22.1.0"
       }
     },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
     "node_modules/codemirror": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
@@ -1795,6 +1865,36 @@
       "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
       "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
     },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.5",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+      "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/form-data": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@@ -1812,7 +1912,6 @@
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
       "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "dev": true,
       "hasInstallScript": true,
       "optional": true,
       "os": [
@@ -1822,6 +1921,17 @@
         "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
       }
     },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/html-encoding-sniffer": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
@@ -1869,6 +1979,49 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/immutable": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
+      "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA=="
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
     "node_modules/is-potential-custom-element-name": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
@@ -1951,6 +2104,11 @@
         "node": ">=12"
       }
     },
+    "node_modules/material-icons": {
+      "version": "1.13.12",
+      "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.13.12.tgz",
+      "integrity": "sha512-/2YoaB79IjUK2B2JB+vIXXYGtBfHb/XG66LvoKVM5ykHW7yfrV5SP6d7KLX6iijY6/G9GqwgtPQ/sbhFnOURVA=="
+    },
     "node_modules/memoize-one": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
@@ -1997,6 +2155,14 @@
         "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
       }
     },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/normalize-wheel-es": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
@@ -2023,6 +2189,17 @@
       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
       "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
     },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
     "node_modules/pinia": {
       "version": "2.1.7",
       "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz",
@@ -2100,6 +2277,11 @@
         "node": "^10 || ^12 || >=14"
       }
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+    },
     "node_modules/psl": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -2118,6 +2300,17 @@
       "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
       "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
     },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
     "node_modules/requires-port": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -2165,6 +2358,22 @@
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
+    "node_modules/sass": {
+      "version": "1.70.0",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz",
+      "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==",
+      "dependencies": {
+        "chokidar": ">=3.0.0 <4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
     "node_modules/saxes": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
@@ -2194,6 +2403,17 @@
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
       "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
     },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
     "node_modules/tough-cookie": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",

+ 3 - 0
package.json

@@ -32,10 +32,13 @@
     "@yume-chan/struct": "file:../ya-webadb/libraries/struct",
     "@yume-chan/tabby-launcher": "file:../ya-webadb/libraries/tabby-launcher",
     "@yume-chan/tabby-tango": "file:../ya-webadb/libraries/tabby-tango",
+    "axios": "^1.6.5",
     "blockly": "^10.3.0",
     "element-plus": "^2.5.1",
     "ll": "^1.2.0",
+    "material-icons": "^1.13.12",
     "pinia": "^2.1.7",
+    "sass": "^1.70.0",
     "vue": "^3.3.11",
     "vue-codemirror": "^6.1.1",
     "vue-router": "^4.2.5"

+ 33 - 9
src/App.vue

@@ -1,23 +1,47 @@
 <script setup>
-import { ref } from "vue";
+import { ref, watch, watchEffect } from "vue";
 import BlocklyComponent from "./components/BlocklyComponent.vue";
+import Header from './components/header/header.vue'
+import Footer from './components/footer/footer.vue'
 import ConnectAdb from './components/webadb/connect.vue'
+import store from './stores/blockly'
+
+const xmlStr = store.useyXmlStore()
+const pythonCode = store.useyPythonCodeStore()
+
+// watch(xmlStr,(newVal,oldVal)=>{
+//   console.log("newVal",newVal.xmlStr)
+//   console.log("oldVal",oldVal.xmlStr)
+// })
+watchEffect(() => {
+  console.log(xmlStr.xmlStr, pythonCode.pythonCode)
+})
 </script>
 
 <template>
-  <div id="blockly">
-    <BlocklyComponent id="blockly1">
-    </BlocklyComponent>
-    <!-- <ConnectAdb/> -->
+  <div class="main">
+    <Header></Header>
+    <div id="blockly">
+      <BlocklyComponent></BlocklyComponent>
+    </div>
+    <Footer></Footer>
   </div>
 </template>
 
-<style scoped>
-#blockly{
-  width: 100%;
+<style scoped lang="scss">
+.main {
   height: 100%;
+  display: flex;
+  flex-flow: wrap;
+
+  #blockly {
+    width: 100%;
+    height: calc(100% - 120px);
+  }
 }
-#blockly1{
+
+
+#blockly1 {
   /* width: 90vw;
   height: 90vh; */
 }

+ 1 - 1
src/assets/base.css → src/assets/css/base.css

@@ -83,4 +83,4 @@ body {
   text-rendering: optimizeLegibility;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
-}
+}

+ 0 - 16
src/assets/blockly.css → src/assets/css/blockly.css

@@ -69,7 +69,6 @@
 @media only screen and (min-width: 1380px) {
 
 	#blockpy-container,
-	#header>div,
 	#footer>div,
 	#blockpy-div {
 		width: 100%;
@@ -90,7 +89,6 @@
 @media only screen and (min-width: 1075px) and (max-width: 1379px) {
 
 	#blockpy-container,
-	#header>div,
 	#footer>div,
 	#blockpy-div {
 		width: 100%;
@@ -109,7 +107,6 @@
 @media only screen and (min-width: 601px) and (max-width: 1074px) {
 
 	#blockpy-container,
-	#header>div,
 	#footer>div,
 	#blockpy-div {
 		width: 100%;
@@ -132,11 +129,6 @@
 }
 
 @media only screen and (min-width: 0px) and (max-width: 992px) {
-	#header>div {
-		grid-template-columns: max-content !important;
-		justify-content: center;
-	}
-
 	#nav {
 		display: none;
 	}
@@ -145,7 +137,6 @@
 @media only screen and (min-width: 0px) and (max-width: 600px) {
 
 	#blockpy-container,
-	#header>div,
 	#footer>div,
 	#blockpy-div {
 		width: 100%;
@@ -234,13 +225,6 @@ body {
 	color: #ffffff;
 }
 
-#header>div {
-	margin: 0 auto;
-	height: 100%;
-	display: grid;
-	grid-template-columns: max-content auto;
-}
-
 #logo {
 	align-self: center;
 }

+ 43 - 0
src/assets/css/header.css

@@ -0,0 +1,43 @@
+.header_right_icon {
+    height: 30px;
+    margin-top: 5px;
+    margin-right: 5px;
+}
+
+.header_right_title_span {
+    color: #fff;
+    display: inline-block;
+    line-height: 40px;
+}
+
+.el-dropdown-menu .header_menu_li {
+    font-size: 16px;
+    color: #26a69a;
+    display: block;
+    line-height: 22px;
+    padding: 14px 16px;
+}
+
+.link_stydy .header_menu_li {
+    padding: 0
+}
+
+.link_stydy .header_menu_li a {
+    display: block;
+    padding: 14px;
+}
+
+.el-dropdown-menu .header_menu_li:hover {
+    color: #26a69a;
+}
+
+.el_row_card {
+    max-height: 340px;
+    overflow: auto;
+    min-height: 260px;
+}
+
+.card_style {
+    padding: 0 0.75rem;
+    margin-bottom: 15px;
+}

+ 140 - 0
src/assets/css/main.css

@@ -0,0 +1,140 @@
+@import './base.css';
+
+/* 清零所有标签的内外边距 */
+* {
+  margin: 0;
+  padding: 0;
+  /* CSS3盒子模型 */
+  /* 可以不用考虑padding和border是否会撑大盒子的情况了*/
+  box-sizing: border-box;
+}
+
+/* em 和 i 斜体的文字不倾斜 */
+em,
+i {
+  font-style: normal
+}
+
+/* 去掉li 的小圆点 */
+li {
+  list-style: none
+}
+
+/* 插入图片的设置 */
+img {
+  /* border 0 照顾低版本浏览器 如果 图片外面包含了链接会有边框的问题 */
+  border: 0;
+  /* 取消图片底侧有空白缝隙的问题 */
+  vertical-align: middle
+}
+
+button {
+  /* 当我们鼠标经过button 按钮的时候,鼠标变成小手 */
+  cursor: pointer
+}
+
+a {
+  color: #666;
+  text-decoration: none
+}
+
+button,
+input {
+  /* "\5B8B\4F53" 就是宋体的意思 这样浏览器兼容性比较好 */
+  font-family: Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, "\5B8B\4F53", sans-serif;
+  /* 手动去掉默认的灰色边框 */
+  border: 0;
+  /* 手动去掉input输入时的蓝色/加粗边框 */
+  outline: none;
+}
+
+body {
+  /* CSS3 抗锯齿形 让文字显示的更加清晰 */
+  -webkit-font-smoothing: antialiased;
+  background-color: #fff;
+  font: 12px/1.5 Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, "\5B8B\4F53", sans-serif;
+  color: #666
+}
+
+.hide,
+.none {
+  display: none
+}
+
+#app {
+  height: 100%;
+}
+
+a,
+.green {
+  text-decoration: none;
+  color: hsla(160, 100%, 37%, 1);
+  transition: 0.4s;
+  padding: 3px;
+}
+
+.left {
+  float: left;
+}
+
+.right {
+  float: right;
+}
+
+.flex {
+  display: flex;
+}
+
+
+#app .el-dialog__header {
+  padding: 0;
+  padding-bottom: 0;
+}
+
+#app .el-dialog__body {
+  padding: 0;
+  padding-bottom: 0;
+  color: #000;
+}
+#app .el-card__body{
+  padding: 0;
+}
+.background_blue {
+  background-color: #2196F3 !important;
+}
+
+/* 清除浮动 */
+.clearfix:after,
+.clearfix:before {
+  content: "";
+  display: table;
+}
+
+.clearfix:after {
+  clear: both;
+}
+
+.clearfix {
+  zoom: 1;
+}
+
+a {
+  color: #26a69a;
+}
+
+a:hover {
+  background-color: #fff;
+}
+
+@media (hover: hover) {
+
+  a:hover {
+    background-color: rgba(0, 0, 0, 0);
+  }
+
+  span:hover {
+    background-color: rgba(0, 0, 0, 0);
+  }
+}
+
+@media (min-width: 1024px) {}

BIN
src/assets/img/APPCenter_test.jpg


BIN
src/assets/img/AppCenter_ai_emotion.jpg


BIN
src/assets/img/AppCenter_ai_gesture_recognition.jpg


BIN
src/assets/img/AppCenter_ai_speech.jpg


BIN
src/assets/img/AppCenter_ai_teachableMachine.jpg


BIN
src/assets/img/AppCenter_comingSoon.jpg


BIN
src/assets/img/AppCenter_game_floppy-bird.jpg


BIN
src/assets/img/AppCenter_game_space_lamb.jpg


BIN
src/assets/img/AppCenter_iot_ifttt.jpg


BIN
src/assets/img/AppCenter_iot_thingspeak.jpg


BIN
src/assets/img/WeTech.jpg


BIN
src/assets/img/adb1.png


BIN
src/assets/img/adb2.png


BIN
src/assets/img/adb3.png


BIN
src/assets/img/adb4.jpg


BIN
src/assets/img/cocoblockly-navbar_labs-icon.png


BIN
src/assets/img/error.png


BIN
src/assets/img/firmware.png


BIN
src/assets/img/home_icon.png


BIN
src/assets/img/labs_aihub1.jpg


BIN
src/assets/img/labs_aihub2.jpg


BIN
src/assets/img/labs_aihub3.jpg


BIN
src/assets/img/language2.png


BIN
src/assets/img/learn_nav_icon.png


BIN
src/assets/img/local_storage.png


BIN
src/assets/img/logo1.png


BIN
src/assets/img/nav_help.png


BIN
src/assets/img/object_recognition_header.jpg


BIN
src/assets/img/posenet_recogition.png


BIN
src/assets/img/tm_with_pose.jpg


BIN
src/assets/img/uploader_connect.png


BIN
src/assets/img/uploader_disconnect.png


BIN
src/assets/img/user.png


BIN
src/assets/img/加载.png


+ 0 - 1
src/assets/logo.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

+ 0 - 23
src/assets/main.css

@@ -1,23 +0,0 @@
-@import './base.css';
-
-#app {
-  
-}
-
-a,
-.green {
-  text-decoration: none;
-  color: hsla(160, 100%, 37%, 1);
-  transition: 0.4s;
-  padding: 3px;
-}
-
-@media (hover: hover) {
-  a:hover {
-    background-color: hsla(160, 100%, 37%, 0.2);
-  }
-}
-
-@media (min-width: 1024px) {
-  
-}

+ 17 - 15
src/components/BlocklyComponent.vue

@@ -1,19 +1,16 @@
 
 <template>
-  <div>
-    <el-button @click="getPythonCode">获取Python code</el-button>
-    <el-button @click="getWorkspaceXml">获取当前工作区xml</el-button>
-    <div>
-      <el-row :gutter="20">
-        <el-col :span="16">
-          <div id="blocklyDiv" style="height: calc(100vh - 80px); width: 100%;"></div>
-        </el-col>
-        <el-col :span="8">
-          <div class="grid-content ep-bg-purple-light" >
-            <codeMirrorPython :pythonCode="pythonCode" />
-          </div></el-col>
-      </el-row>
-    </div>
+  <div style="height: 100%;">
+    <el-row style="height: 100%;">
+      <el-col :span="16">
+        <div id="blocklyDiv" style="height: 100%; width: 100%;"></div>
+      </el-col>
+      <el-col :span="8">
+        <div style="height: 100%;">
+          <codeMirrorPython :pythonCode="pythonCode" />
+        </div>
+      </el-col>
+    </el-row>
   </div>
 </template>
 <script setup>
@@ -29,6 +26,7 @@ import BlocklyStyle from '../blockly/style/blockly'
 import BlocklyPython from '../blockly/pythonCode/index'
 
 import codeMirrorPython from './codemirror/codemirror.vue'
+import store from '../stores/blockly'
 
 const workspace = ref(null)
 const pythonCode = ref('')
@@ -79,11 +77,15 @@ const addBlocklyEventListeners = (event) => {
   // 积木区域操作是生成代码
   getPythonCode()
 }
+const xmlStr = store.useyXmlStore()
+const storePythonCode = store.useyPythonCodeStore()
 const getPythonCode = () => {
   let code = Blockly.Python.workspaceToCode(workspace.value);
+  var xml = Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(workspace.value))
   // console.log('--------Python code-------');
   pythonCode.value = code
-  // console.log(code)
+  storePythonCode.$patch({ pythonCode: code })
+  xmlStr.$patch({ xmlStr: xml })
 }
 const getWorkspaceXml = () => {
   var xml = Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(workspace.value))

+ 30 - 6
src/components/codemirror/codemirror.vue

@@ -1,8 +1,9 @@
 <template>
     <!-- :indent-with-tab="true" 是否自动获取焦点-->
-    <div>
-        <codemirror :modelValue="pythonCode" placeholder="" :style="{ height: '100%' }" :autofocus="true" :tabSize="2"
-            :extensions="extensions" :indent-with-tab="true" />
+    <div class="codemirrorDiv">
+        <codemirror :modelValue="pythonCode" placeholder="" style="height: 100%" :autofocus="true" :tabSize="2"
+            :extensions="extensions" :indent-with-tab="true" @change="onchangeCodemirror()" />
+        <div v-if="codeMirrorShow" class="codeMirrorMask"></div>
     </div>
 </template>
 
@@ -47,8 +48,7 @@ let myTheme = EditorView.theme({
         border: "none"
     },
 }, {
-    dark: true,
-    readOnly: true
+    dark: false,
 })
 const extensions = [python(), myTheme];
 // 接受的参数
@@ -58,13 +58,37 @@ const props = defineProps({
         require: true,
         default: ""
     },
+    codeMirrorShow: {
+        type: Boolean,
+        require: true,
+        default:true
+    }
+
 })
 const cmOptions = ref({})
 onMounted(() => {
 
 })
+const onchangeCodemirror = () => {
+
+}
 // watch(()=>props.pythonCode,(newVal,oldVal)=>{
 //     console.log("newVal:",newVal)
 //     console.log("oldVal:",oldVal)
 // })
-</script>
+</script>
+<style scoped>
+.codemirrorDiv {
+    position: relative;
+    width: 100%;
+    height: 100%;
+}
+
+.codeMirrorMask {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    background: rgba(0, 0, 0, 0);
+}
+</style>

+ 14 - 0
src/components/footer/footer.vue

@@ -0,0 +1,14 @@
+<template>
+    <div id="footer">
+        footer
+    </div>
+</template>
+<script setup>
+
+</script>
+<style lang="scss" scoped>
+#footer{
+    width: 100%;
+    height: 60px;
+}
+</style>

+ 33 - 0
src/components/header/header.vue

@@ -0,0 +1,33 @@
+<template>
+    <div id="header">
+        <div class="header-left">
+            <headerLeftVue @setFileName="setFileName" :exportImportFileName="exportImportFileName"/>
+        </div>
+        <div class="header-right">
+            <headerRightVue @setFileName="setFileName" :exportImportFileName="exportImportFileName" />
+        </div>
+    </div>
+</template>
+<script setup>
+import {ref,watchEffect} from 'vue'
+import headerLeftVue from "./headerLeft.vue";
+import headerRightVue from "./headerRight.vue";
+import store from '../../stores/blockly'
+
+const exportImportFileName = ref('未命名')
+const setFileName = (e)=>{
+    exportImportFileName.value = e
+}
+</script>
+<style lang="scss" scoped>
+#header {
+    width: 100%;
+    height: 60px;
+    display: flex;
+    padding: 0 10px;
+
+    .header-right{
+        width: 100%;
+    }
+}
+</style>

+ 85 - 0
src/components/header/headerLeft.vue

@@ -0,0 +1,85 @@
+<template>
+    <div class="headerLeft">
+        <img :src="LOGO" />
+        <el-input v-model="inputMode" placeholder="" @input="getInputName()" style="--el-input-width:150px"></el-input>
+        <el-button round @click="saveXmlFile()">保存</el-button>
+        <i class="material-icons" @click="shareLink()">share</i>
+        <i class="material-icons" @click="deleteBlockly()">delete</i>
+        <i class="material-icons" @click="saveBlocklyPhoto()">photo_camera</i>
+    </div>
+</template>
+<script setup>
+import { ref, defineProps, watchEffect } from 'vue'
+import { ElMessage } from 'element-plus'
+import LOGO from '../../assets/img/logo1.png'
+import store from '../../stores/blockly'
+import { exportFileGlobal } from '../../gloabl/globalMethods'
+const props = defineProps({
+    exportImportFileName: {
+        type: String,
+        require: true,
+        default: "未命名"
+    }
+})
+const emit = defineEmits(["setFileName"])
+
+
+const inputMode = ref(props.exportImportFileName)
+const xmlStr = store.useyXmlStore()
+const saveXmlFile = () => {
+    console.log(inputMode.value, xmlStr.xmlStr)
+    if (xmlStr.xmlStr && xmlStr.xmlStr !=`<xml xmlns="https://developers.google.com/blockly/xml"></xml>`) {
+        exportFileGlobal(xmlStr.xmlStr, inputMode.value+".xml")
+    } else {
+        ElMessage({
+            message: '导出内容为空',
+            type: 'warning',
+        })
+    }
+}
+const shareLink = () => {
+    console.log("分享")
+}
+const deleteBlockly = () => {
+    console.log("删除当前页面积木")
+}
+const saveBlocklyPhoto = () => {
+    console.log("保存当前积木图片")
+}
+const getInputName = () => {
+    emit("setFileName", inputMode.value)
+}
+watchEffect(() => {
+    if (props.exportImportFileName) {
+        inputMode.value = props.exportImportFileName
+    }
+
+})
+</script>
+<style lang="scss" scoped>
+.headerLeft {
+    margin-left: 10px;
+    display: flex;
+    padding: 10px 0;
+
+    img {
+        height: 40px;
+        margin-right: 10px;
+        border-right: 1px solid #fff;
+    }
+
+    .el-button {
+        margin-left: 10px;
+        margin-right: 5px;
+        margin-top: 5px;
+        background: #fff;
+        color: #2c4fcd;
+    }
+
+    .material-icons {
+        cursor: pointer;
+        margin-top: 8px;
+        margin-right: 3px;
+    }
+}
+</style>

+ 46 - 0
src/components/header/headerRight.vue

@@ -0,0 +1,46 @@
+<template>
+    <div class="headerRight">
+        <div class="example headerRightDiv">
+            <Example></Example>
+        </div>
+        <div class="headerRightDiv">
+            <Labs></Labs>
+        </div>
+        <div class="study headerRightDiv">
+            <LinkStudy></LinkStudy>
+        </div>
+        <div class="file headerRightDiv ">
+            <File v-bind="$attrs"></File>
+        </div>
+        <div class="lang headerRightDiv">
+            <Languare></Languare>
+        </div>
+        <div class="user headerRightDiv">
+            <User></User>
+        </div>
+    </div>
+</template>
+<script setup>
+import {ref,defineProps} from 'vue'
+import User from '../headerRight/user.vue'
+import Example from '../headerRight/example.vue'
+import Labs from '../headerRight/labs.vue'
+import Languare from '../headerRight/languareSwitch.vue'
+import File from '../headerRight/fIleOperation.vue'
+import LinkStudy from '../headerRight/linkStudy.vue'
+
+</script>
+<style lang="scss" scoped>
+.headerRight{
+    width: 100%;
+    display: flex;
+    justify-content: flex-end;
+    .headerRightDiv{
+        padding: 10px;
+        cursor: pointer;
+    }
+    .headerRightDiv:hover{
+        background: #2847B8;
+    }
+}
+</style>

+ 15 - 0
src/components/headerRight/example.vue

@@ -0,0 +1,15 @@
+<template>
+    <div>
+        <div class="el-dropdown-link" title="实验室">
+            <span class="header_right_title_span">实验室</span>
+        </div>
+    </div>
+</template>
+<script setup>
+import {ref} from 'vue';
+import imgIcon from '../../assets/img/cocoblockly-navbar_labs-icon.png'
+
+</script>
+<style lang="sass">
+
+</style>

+ 74 - 0
src/components/headerRight/fIleOperation.vue

@@ -0,0 +1,74 @@
+<template>
+    <el-dropdown trigger="click">
+        <div class="el-dropdown-link" title="文件">
+            <img :src="local_storage" alt="" class="header_right_icon left">
+            <span class="header_right_title_span">文件</span>
+        </div>
+        <template #dropdown>
+            <el-dropdown-menu>
+                <el-dropdown-item class="header_menu_li" @click="cloudSave()"
+                    style="color: #26a69a;">云端存储</el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" @click="importFile()" style="color: #26a69a;">导入</el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" @click="exportFile()" style="color: #26a69a;">导出</el-dropdown-item>
+            </el-dropdown-menu>
+        </template>
+    </el-dropdown>
+</template>
+<script setup>
+import { ref, watchEffect, defineProps } from 'vue'
+import { ElMessage } from 'element-plus'
+import local_storage from '../../assets/img/local_storage.png'
+import '../../assets/css/header.css'
+import store from '../../stores/blockly'
+import { exportFileGlobal } from '../../gloabl/globalMethods'
+
+const props = defineProps({
+    exportImportFileName: {
+        type: String
+    }
+})
+const emit = defineEmits(["setFileName"])
+
+const exportXml = store.useyXmlStore()
+const importFileName = store.useImportFileNameStore()
+const cloudSave = () => {
+    console.log("云端存储")
+}
+const importFile = () => {
+    console.log("导入xml文件", importFileName)
+    importFileName.$patch({ fileName: "2222" })
+    emit("setFileName", "22")
+}
+// console.log(getCurrentInstance().appContext.config.globalProperties)
+// $exportFile(exportXml,props.exportImportFileName + '.xml')
+const exportFile = () => {
+    let name = props.exportImportFileName + '.xml'
+    if (exportXml.xmlStr && exportXml.xmlStr != `<xml xmlns="https://developers.google.com/blockly/xml"></xml>`) {
+        exportFileGlobal(exportXml.xmlStr, name)
+    } else {
+        ElMessage({
+            message: '导出内容为空',
+            type: 'warning',
+        })
+    }
+
+    // let blob = new Blob([exportXml], { type: 'text/plain;charset=utf-8' })
+    // // 创建一个指向Blob对象的URL
+    // const textURL = window.URL.createObjectURL(blob);
+    // // 创建一个临时的a标签用于触发下载
+    // const link = document.createElement('a');
+    // link.href = textURL;
+    // link.download = props.exportImportFileName + '.xml'; // 指定下载文件的名称
+    // document.body.appendChild(link); // 将a标签添加到文档中
+    // // 触发点击事件以开始下载
+    // link.click();
+
+    // // 清理:移除a标签,释放创建的URL
+    // document.body.removeChild(link);
+    // window.URL.revokeObjectURL(textURL);
+}
+
+</script>
+<style scoped lang="sass">
+
+</style>

+ 123 - 0
src/components/headerRight/labs.vue

@@ -0,0 +1,123 @@
+<template>
+    <div class="labs">
+        <div class="el-dropdown-link" title="实验室" @click="dialogVisible = true">
+            <img :src="imgIcon" alt="" class="header_right_icon left">
+            <span class="header_right_title_span">实验室</span>
+        </div>
+        <el-dialog v-model="dialogVisible" title="" width="820px" :show-close="false">
+            <template #header="{ close }">
+                <div class="my-header">
+                    <span class="labs_title">CocoBlockly Pi 实验室</span>
+                    <i class="material-icons right" style="margin-top: 10px;cursor: pointer;" @click="close">close</i>
+                </div>
+            </template>
+            <el-row class="labs_body">
+                <el-col class="labs_class_content" :span="6">
+                    <p class="all_class">所有分类:</p>
+                    <ul class="labs_class_left">
+                        <li :class="calssActive == 1 ? 'active' : ''" @click="getClassData(1, '人工智能')">人工智能</li>
+                        <li :class="calssActive == 2 ? 'active' : ''" @click="getClassData(2, '物联网')">物联网</li>
+                        <li :class="calssActive == 3 ? 'active' : ''" @click="getClassData(3, '机器人控制')">机器人控制</li>
+                        <li :class="calssActive == 4 ? 'active' : ''" @click="getClassData(4, '科学实验')">科学实验</li>
+                        <li :class="calssActive == 5 ? 'active' : ''" @click="getClassData(5, '互动游戏')">互动游戏</li>
+                        <li :class="calssActive == 6 ? 'active' : ''" @click="getClassData(6, 'AR/VR')">AR/VR</li>
+                    </ul>
+                </el-col>
+                <el-col :span="18" style="padding:0 0.75rem;">
+                    <h5>{{ titleNmae }}</h5>
+                    <ul class="labs_class_right">
+                        <li v-if="calssActive == 1">
+                            <AI></AI>
+                        </li>
+                        <li v-else-if="calssActive == 2">
+                            <Iot></Iot>
+                        </li>
+                        <li v-else-if="calssActive == 3">机器人控制</li>
+                        <li v-else-if="calssActive == 4">科学实验</li>
+                        <li v-else-if="calssActive == 5">互动游戏</li>
+                        <li v-else>AR/VR</li>
+                    </ul>
+                </el-col>
+            </el-row>
+        </el-dialog>
+    </div>
+</template>
+<script setup>
+import { ref } from 'vue';
+import imgIcon from '../../assets/img/cocoblockly-navbar_labs-icon.png'
+import AI from '../labs/ai.vue'
+import Iot from '../labs/iot.vue'
+
+const dialogVisible = ref(false)
+const calssActive = ref(1)
+const titleNmae = ref("人工智能")
+
+const getClassData = (val, name) => {
+    calssActive.value = val
+    titleNmae.value = name
+}
+
+</script>
+<style lang="scss">
+.labs {
+    color: #000;
+    cursor: default;
+
+    .el-dropdown-link {
+        cursor: pointer;
+    }
+
+    .my-header {
+        padding: 20px;
+    }
+
+    .labs_title {
+        color: #000;
+        font-size: 2.28rem;
+    }
+
+    .labs_body {
+        border-top: 1px solid #ddd;
+        margin: 0px 20px;
+        padding-bottom: 20px;
+
+        h5 {
+            font-size: 1.64rem;
+            line-height: 110%;
+            margin: 1.0933333333rem 0 0.656rem 0;
+        }
+
+        .labs_class_content {
+            .all_class {
+                font-weight: bold;
+                margin: 1rem 0;
+            }
+
+
+            ul.labs_class_left {
+                border: 1px solid #dddddd;
+                border-bottom: none;
+                border-radius: 2px;
+
+                li {
+                    background-color: #fff;
+                    line-height: 1.5rem;
+                    padding: 10px 20px;
+                    margin: 0;
+                    border-bottom: 1px solid #e0e0e0;
+                    font-weight: bold;
+                    cursor: pointer;
+                }
+
+                .active {
+                    background-color: #2196F3;
+                    color: white;
+                    border-radius: 2px;
+                }
+            }
+
+            ul.labs_class_right {}
+        }
+    }
+}
+</style>

+ 24 - 0
src/components/headerRight/languareSwitch.vue

@@ -0,0 +1,24 @@
+<template>
+    <el-dropdown trigger="click">
+        <div class="el-dropdown-link" title="语言设定">
+            <img :src="languareIcon" alt="" class="header_right_icon left">
+            <span class="header_right_title_span">语言</span>
+        </div>
+        <template #dropdown>
+            <el-dropdown-menu>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">Englsh</el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">中文繁體</el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">中文简体</el-dropdown-item>
+            </el-dropdown-menu>
+        </template>
+    </el-dropdown>
+</template>
+<script setup>
+import {ref} from 'vue'
+import languareIcon from '../../assets/img/language2.png'
+import '../../assets/css/header.css'
+
+</script>
+<style scoped lang="sass">
+
+</style>

+ 45 - 0
src/components/headerRight/linkStudy.vue

@@ -0,0 +1,45 @@
+<template>
+    <el-dropdown trigger="click">
+        <div class="el-dropdown-link" title="学习">
+            <img :src="imgIcon" alt="" class="header_right_icon left">
+            <span class="header_right_title_span">学习</span>
+        </div>
+        <template #dropdown>
+            <el-dropdown-menu class="link_stydy">
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//edu.cocorobo.cn/" target="_blank" rel="noopener noreferrer">前往教学平台</a>
+                </el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//xunlian.cocorobo.cn" target="_blank" rel="noopener noreferrer">学习人工智能:训练平台</a>
+                </el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//biaoji.cocorobo.cn/" target="_blank" rel="noopener noreferrer">学习人工智能:标记平台</a>
+                </el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//aihub.cocorobo.cn" target="_blank" rel="noopener noreferrer">学习人工智能: 原理</a>
+                </el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//aihub.cocorobo.cn/vision" target="_blank" rel="noopener noreferrer">学习人工智能: 视觉处理</a>
+                </el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//aihub.cocorobo.cn/speech" target="_blank" rel="noopener noreferrer">学习人工智能: 语音识别</a>
+                </el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//aihub.cocorobo.cn/text" target="_blank" rel="noopener noreferrer">学习人工智能: 文本分析</a>
+                </el-dropdown-item>
+                <el-dropdown-item class="header_menu_li" style="color: #26a69a;">
+                    <a href="//aihub.cocorobo.cn/art" target="_blank" rel="noopener noreferrer">学习人工智能: 艺术</a>
+                </el-dropdown-item>
+            </el-dropdown-menu>
+        </template>
+    </el-dropdown>
+</template>
+<script setup>
+import { ref } from 'vue'
+import imgIcon from '../../assets/img/learn_nav_icon.png'
+import '../../assets/css/header.css'
+
+</script>
+<style scoped lang="sass">
+
+</style>

+ 235 - 0
src/components/headerRight/user.vue

@@ -0,0 +1,235 @@
+<template>
+    <div style="position: relative;">
+        <div class="user" @click="loginDialogVisible = true">
+            <iframe src="//cocorobo.cn/login" frameborder="0" scrolling="no" style="display: none;"></iframe>
+            <div v-if="isLogin" class="user_login_style">
+                <img :src="userPng" alt="">
+                <span class="user_name">{{ userName }}</span>
+            </div>
+            <div v-else class="user_login_style">
+                <img :src="userPng" alt="">
+                <span class="login_button">登录</span>
+            </div>
+
+        </div>
+        <el-dialog class="loginModel" v-model="loginDialogVisible" title="" width="350px" :show-close="false">
+            <template #header="{ close }">
+                <div class="my-header">
+                    <i class="material-icons right" style="color: #000;margin-top: 10px;" @click="close">close</i>
+                </div>
+            </template>
+            <div v-if="!isLogin" class="loginIframe">
+                <iframe src="//cocorobo.cn/login" frameborder="0" scrolling="no"></iframe>
+            </div>
+            <div class="cloud" v-else>
+                <h4>{{ userName }}</h4>
+                <p><span class="user_span_color">您的邮箱:</span>{{ userEmail }}</p>
+                <p><span class="user_span_color">您所属的学校:</span>{{ userSchool }}</p>
+                <div>
+                    <p>
+                        <span class="user_span_color">云端项目:</span>
+                        <el-tooltip class="box-item" effect="dark" content="点击刷新云端事件" placement="bottom">
+                            <i class="material-icons cloud-icon right" @click="refreshCloud()">autorenew</i>
+                        </el-tooltip>
+                    </p>
+                    <el-select v-model="apiMode" @change="getApiKey">
+                        <el-option v-for="item in cloudList" :key="item.id" :value="item.value">
+                            {{ item.value }}
+                        </el-option>
+                    </el-select>
+                    <p>
+                        <span class="user_span_color">APT key:</span>
+                        <el-tooltip class="box-item" effect="dark" content="复制api-key到粘贴板上" placement="bottom">
+                            <i class="material-icons cloud-icon right" @click="refreshCloud()">content_copy</i>
+                        </el-tooltip>
+                    </p>
+                    <el-input v-model="apiKeyModel"></el-input>
+                </div>
+                <div class="clearfix" style="margin-top: 20px;">
+                    <el-button class="background_blue left" style="color: #fff;" @click="goCloud()">前往云端服务</el-button>
+                    <el-button class="background_blue right" style="color: #fff;" @click="loginOut()">登出</el-button>
+                </div>
+            </div>
+            <!-- <template #footer>
+            <span class="dialog-footer">
+                <el-button @click="centerDialogVisible = false">Cancel</el-button>
+                <el-button type="primary" @click="centerDialogVisible = false">
+                    Confirm
+                </el-button>
+            </span>
+        </template> -->
+        </el-dialog>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref } from 'vue'
+import userPng from '../../assets/img/user.png'
+import { ElMessage } from 'element-plus';
+import axios from 'axios'
+
+const isLogin = ref(false)
+const loginDialogVisible = ref(false)
+const userName = ref("")
+const userEmail = ref("")
+const userSchool = ref("")
+const cloudList = ref([])
+const apiKey = ref("")
+const apiMode = ref("")
+const apiKeyModel = ref("")
+const apiUrl = ref("")
+const cnOrHk = ref(false)
+
+onMounted(() => {
+    cnOrHk.value = window.location.host.indexOf("cocorobo.hk") > -1
+    window.addEventListener('message', function (e) {
+        console.log(e)
+        if (e.data.id == 'loginVerify') {
+            if (e.data.status === 'logged') {
+                isLogin.value = true
+                userName.value = e.data.data.alias
+                userEmail.value = e.data.data.username
+                userSchool.value = e.data.data.defaultSchool
+                apiKey.value = e.data.data.apiKey
+                refreshCloud()
+            }
+        }
+    })
+})
+
+const refreshCloud = () => {
+    const event = cnOrHk.value ? `https://api.cocorobo.hk/iot/data/apikey/${apiKey.value}/event/` : `https://api.cocorobo.cn/iot/data/apikey/${apiKey.value}/event/`
+    axios.get(event).then(res => {
+        // console.log(res)
+        if (res.data.length > 0) {
+            let list = []
+            res.data.map(x => {
+                let obj = {
+                    id: x.eventAPIKey,
+                    value: x.name,
+                    url: x.url
+                }
+                list.push(obj)
+                return x
+            })
+            apiMode.value = list[0].value
+            apiKeyModel.value = list[0].id
+            apiUrl.value = list[0].url
+            cloudList.value = list
+        }
+    })
+}
+
+const getApiKey = (e) => {
+    let obj = cloudList.value.filter(x => x.value == e)[0]
+    apiKeyModel.value = obj.id
+    apiUrl.value = obj.url
+}
+
+const goCloud = () => {
+    const cloudUrl = cnOrHk.value ? "//cocorobo.hk/cloud" : "//cocorobo.cn/cloud"
+    window.open(cloudUrl)
+}
+const loginOut = () => {
+    // 登出
+    const cloudUrl = cnOrHk.value ? "//api.cocorobo.hk/api/logout" : "//api.cocorobo.cn/api/logout"
+    axios.defaults.withCredentials = true
+    axios.get(cloudUrl).then(res => {
+        if (res.data == "logout") {
+            isLogin.value = false
+            ElMessage({
+                message: '登出成功',
+                type: 'warning',
+            })
+        }
+    })
+}
+</script>
+
+<style lang="scss">
+.user {
+    cursor: pointer;
+    position: relative;
+
+    .user_login_style {
+        margin-top: 5px;
+
+        .user_name {
+            position: relative;
+            top: 3px;
+            margin-left: 10px;
+        }
+
+        img {
+            // position: absolute;
+            height: 27px;
+            // top: 0;
+            // left: -40px;
+            vertical-align: middle;
+        }
+
+        .login_button {
+            padding: 8px 25px;
+            margin-top: 10px;
+            margin-left: 15px;
+            position: relative;
+            top: 3px;
+            border: 2px solid #fff;
+            border-radius: 20px;
+        }
+    }
+
+
+
+}
+
+.loginModel {
+    position: fixed !important;
+    top: -70px;
+    right: 5px;
+
+    .loginIframe {
+        height: 400px;
+        margin: 24px;
+        overflow: hidden;
+
+        iframe {
+            margin-top: -370px;
+            width: 100%;
+            height: 800px;
+        }
+    }
+
+    .cloud {
+        padding: 24px 24px 15px 24px;
+        cursor: default;
+
+        h4 {
+            font-size: 20px;
+            font-weight: bold;
+            // padding-bottom: 10px
+        }
+
+        p {
+            padding-top: 5px;
+        }
+
+        .user_span_color {
+            color: rgba(0, 0, 0, 0.87);
+        }
+
+        div {
+
+            p {
+
+                // padding: 10px 0;
+                .cloud-icon {
+                    cursor: pointer;
+                    font-size: 1rem;
+                    color: #2c4fcd;
+                }
+            }
+        }
+    }
+}
+</style>

+ 81 - 0
src/components/labs/ai.vue

@@ -0,0 +1,81 @@
+<template>
+    <div>
+        <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+            <el-tab-pane label="视觉识别" name="first">
+                <el-row class="el_row_card">
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="deepLearningImg" :linkSrc="''" :title="'深度学习机器'" @getNextValue="getNextValue"
+                            :comingSoon="false"></Card>
+                    </el-col>
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="emotionImg" :linkSrc="''" :title="'情绪识别'" @getNextValue="getNextValue"
+                            :comingSoon="false"></Card>
+                    </el-col>
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="gestureImg" :linkSrc="''" :title="'手势识别'" @getNextValue="getNextValue"
+                            :comingSoon="false"></Card>
+                    </el-col>
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="objectImg" :linkSrc="''" :title="'物体识别'" @getNextValue="getNextValue"
+                            :comingSoon="false"></Card>
+                    </el-col>
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="postureImg" :linkSrc="''" :title="'姿态识别'" @getNextValue="getNextValue"
+                            :comingSoon="false"></Card>
+                    </el-col>
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="discerningEyeImg" :linkSrc="''" :title="'慧眼识人'" @getNextValue="getNextValue"
+                            :comingSoon="false"></Card>
+                    </el-col>
+                </el-row>
+            </el-tab-pane>
+            <el-tab-pane label="语音识别" name="second">
+                <el-row class="el_row_card">
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="speechImg" :linkSrc="''" :title="'语音识别'" @getNextValue="getNextValue"
+                            :comingSoon="false"></Card>
+                    </el-col>
+                </el-row>
+            </el-tab-pane>
+            <el-tab-pane label="文本处理" name="third">
+                <el-row class="el_row_card">
+                    <el-col :span="12" class="card_style">
+                        <Card :imgSrc="comingSoonImg" :linkSrc="''" :title="'敬请期待'" @getNextValue="getNextValue"
+                            :comingSoon="true"></Card>
+                    </el-col>
+                </el-row>
+            </el-tab-pane>
+        </el-tabs>
+    </div>
+</template>
+<script setup>
+import { ref } from 'vue'
+import '../../assets/css/header.css'
+import Card from "./targetCard.vue"
+import deepLearningImg from '../../assets/img/AppCenter_ai_teachableMachine.jpg'
+import emotionImg from '../../assets/img/AppCenter_ai_emotion.jpg'
+import gestureImg from '../../assets/img/AppCenter_ai_gesture_recognition.jpg'
+import objectImg from '../../assets/img/object_recognition_header.jpg'
+import postureImg from '../../assets/img/posenet_recogition.png'
+import discerningEyeImg from '../../assets/img/tm_with_pose.jpg'
+import speechImg from '../../assets/img/AppCenter_ai_speech.jpg'
+import comingSoonImg from '../../assets/img/AppCenter_comingSoon.jpg'
+
+const activeName = ref("first")
+const getNextValue = (val) => {
+    console.log(val)
+}
+</script>
+
+<style lang="scss">
+// .el_row_card {
+//     max-height: 340px;
+//     overflow: auto;
+//     min-height: 260px;
+
+//     .card_style {
+//         padding: 0 0.75rem;
+//         margin-bottom: 15px;
+//     }
+// }
+</style>

+ 23 - 0
src/components/labs/iot.vue

@@ -0,0 +1,23 @@
+<template>
+    <div>
+        <el-row class="el_row_card">
+            <el-col :span="12" class="card_style">
+                <Card :imgSrc="thingSpeakImg" :linkSrc="'//thingspeak.com/'" :title="'ThingSpeak'"
+                    @getNextValue="getNextValue" :comingSoon="false">
+                </Card>
+            </el-col>
+            <el-col :span="12" class="card_style">
+                <Card :imgSrc="IFTTTImg" :linkSrc="'//ifttt.com/maker_webhooks'" :title="'IFTTT'"
+                    @getNextValue="getNextValue" :comingSoon="false">
+                </Card>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+<script setup>
+import Card from './targetCard.vue'
+import '../../assets/css/header.css'
+import thingSpeakImg from '../../assets/img/AppCenter_iot_thingspeak.jpg'
+import IFTTTImg from '../../assets/img/AppCenter_iot_ifttt.jpg'
+
+</script>

+ 0 - 0
src/components/labs/robotContro.vue


+ 59 - 0
src/components/labs/targetCard.vue

@@ -0,0 +1,59 @@
+<template>
+    <el-card style="border-radius:10px"> 
+        <img class="labs_card_img" :src="imgSrc" alt="">
+        <div style="padding:20px;">
+            <p class="labs_card_p">{{ title }}</p>
+            <el-button v-if="!comingSoon">
+                <a :href="linkSrc" target="_Blank" v-if="linkSrc != ''">进入</a>
+                <span v-else @click="goNext(title)">进入</span>
+            </el-button>
+        </div>
+    </el-card>
+</template>
+<script setup>
+const props = defineProps({
+    imgSrc: {
+        type: String,
+        default: ""
+    },
+    linkSrc: {
+        type: String,
+        default: ""
+    },
+    title: {
+        type: String,
+        default: ""
+    },
+    comingSoon: {
+        type: Boolean,
+        default: false
+    }
+})
+const emit = defineEmits("getNextValue")
+const goNext = (value) => {
+    emit("getNextValue", value)
+}
+</script>
+<style scoped>
+.labs_card_img {
+    width: 100%;
+}
+
+.labs_card_p {
+    line-height: 32px;
+    margin-bottom: 8px;
+    font-size: 24px;
+}
+
+.el-button {
+    background-color: #2979FF;
+    color: #fff;
+
+    a {
+        color: #fff;
+    }
+    a:hover{
+        color: (--el-button-hover-text-color)
+    }
+}
+</style>

+ 18 - 0
src/gloabl/globalMethods.js

@@ -0,0 +1,18 @@
+export const exportFileGlobal = (file, name) => {
+    let blob = new Blob([file], { type: 'text/plain;charset=utf-8' })
+    // 创建一个指向Blob对象的URL
+    const textURL = window.URL.createObjectURL(blob);
+    // 创建一个临时的a标签用于触发下载
+    const link = document.createElement('a');
+    link.href = textURL;
+    link.download = name; // 指定下载文件的名称
+    document.body.appendChild(link); // 将a标签添加到文档中
+    // 触发点击事件以开始下载
+    link.click();
+
+    // 清理:移除a标签,释放创建的URL
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(textURL);
+}
+
+// export default {exportFile}

+ 5 - 3
src/main.js

@@ -1,17 +1,19 @@
-import './assets/main.css'
-import './assets/blockly.css'
-
+import './assets/css/main.css'
+import './assets/css/blockly.css'
+import 'material-icons/iconfont/material-icons.css';
 import App from './App.vue'
 import router from './router'
 import { createApp } from 'vue'
 import { createPinia } from 'pinia'
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
+// import { exportFile } from './gloabl/globalMethods';
 
 
 
 const app = createApp(App)
 
+// app.config.globalProperties.$exportFile = exportFile
 app.use(ElementPlus);
 app.use(createPinia())
 app.use(router)

+ 32 - 0
src/stores/blockly.js

@@ -0,0 +1,32 @@
+import { ref, computed } from 'vue'
+import { defineStore } from 'pinia'
+
+const useyXmlStore = defineStore('Xml', () => {
+  const xmlStr = ref('')
+  const doubleCount = computed(() => xmlStr)
+  function increment() {
+    xmlStr
+  }
+
+  return { xmlStr, doubleCount, increment }
+})
+const useyPythonCodeStore = defineStore('code', () => {
+  const pythonCode = ref('')
+  const doubleCount = computed(() => pythonCode)
+  function increment() {
+    pythonCode
+  }
+
+  return { pythonCode, doubleCount, increment }
+})
+
+const useImportFileNameStore = defineStore("fileName", () => {
+  const fileName = ref("")
+  const doubleCount = computed(() => fileName)
+  function increment() {
+    fileName
+  }
+  return { fileName, doubleCount, increment }
+})
+
+export default { useyXmlStore, useyPythonCodeStore,useImportFileNameStore }

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.