浏览代码

更新图片

lex 1 年之前
父节点
当前提交
a920a6a904
共有 72 个文件被更改,包括 2994 次插入63 次删除
  1. 303 28
      package-lock.json
  2. 4 0
      package.json
  3. 10 0
      src/component-ui/README.md
  4. 129 0
      src/component-ui/global.less
  5. 218 0
      src/component-ui/index.less
  6. 28 0
      src/component-ui/k-action-sheet/index.module.less
  7. 84 0
      src/component-ui/k-action-sheet/index.tsx
  8. 47 0
      src/component-ui/k-dialog/index.module.less
  9. 97 0
      src/component-ui/k-dialog/index.tsx
  10. 39 19
      src/components/m-header/index.tsx
  11. 45 0
      src/components/m-img-code/index.module.less
  12. 147 0
      src/components/m-img-code/index.tsx
  13. 67 0
      src/components/the-submit/index.module.less
  14. 188 0
      src/components/the-submit/index.tsx
  15. 122 0
      src/helpers/request.ts
  16. 204 0
      src/helpers/utils.ts
  17. 1 0
      src/main.ts
  18. 43 6
      src/router/index.ts
  19. 2 0
      src/shims-vue.d.ts
  20. 2 0
      src/styles/index.less
  21. 二进制
      src/views/about-us/images/banner.png
  22. 二进制
      src/views/about-us/images/img1.png
  23. 二进制
      src/views/about-us/images/img2.png
  24. 二进制
      src/views/about-us/images/title-1.png
  25. 75 0
      src/views/about-us/index.module.less
  26. 49 0
      src/views/about-us/index.tsx
  27. 二进制
      src/views/colexiu-person/images/banner.png
  28. 二进制
      src/views/colexiu-person/images/img-1-1.png
  29. 二进制
      src/views/colexiu-person/images/img-1-2.png
  30. 二进制
      src/views/colexiu-person/images/img-1-3.png
  31. 二进制
      src/views/colexiu-person/images/img-1-4.png
  32. 二进制
      src/views/colexiu-person/images/img-2-1.png
  33. 二进制
      src/views/colexiu-person/images/img-2-2.png
  34. 二进制
      src/views/colexiu-person/images/img-2-3.png
  35. 二进制
      src/views/colexiu-person/images/img-2-4.png
  36. 二进制
      src/views/colexiu-person/images/img-bg.png
  37. 二进制
      src/views/colexiu-person/images/img1.png
  38. 二进制
      src/views/colexiu-person/images/title-1.png
  39. 188 0
      src/views/colexiu-person/index.module.less
  40. 149 0
      src/views/colexiu-person/index.tsx
  41. 二进制
      src/views/colexiu-tenant/images/banner.png
  42. 二进制
      src/views/colexiu-tenant/images/img1.png
  43. 二进制
      src/views/colexiu-tenant/images/img2-1.png
  44. 二进制
      src/views/colexiu-tenant/images/img2-2.png
  45. 二进制
      src/views/colexiu-tenant/images/img2-3.png
  46. 二进制
      src/views/colexiu-tenant/images/img2-4-bg.png
  47. 二进制
      src/views/colexiu-tenant/images/img3-1.png
  48. 二进制
      src/views/colexiu-tenant/images/img3-2.png
  49. 二进制
      src/views/colexiu-tenant/images/img3-3.png
  50. 二进制
      src/views/colexiu-tenant/images/img3-4.png
  51. 二进制
      src/views/colexiu-tenant/images/point-bg.png
  52. 二进制
      src/views/colexiu-tenant/images/qrcode-bg.png
  53. 二进制
      src/views/colexiu-tenant/images/title-1.png
  54. 二进制
      src/views/colexiu-tenant/images/title-img.png
  55. 268 0
      src/views/colexiu-tenant/index.module.less
  56. 159 0
      src/views/colexiu-tenant/index.tsx
  57. 二进制
      src/views/cooperate-channels/images/banner-center.png
  58. 二进制
      src/views/cooperate-channels/images/banner.png
  59. 二进制
      src/views/cooperate-channels/images/btn-bg.png
  60. 二进制
      src/views/cooperate-channels/images/img1-bg.png
  61. 二进制
      src/views/cooperate-channels/images/img1.png
  62. 二进制
      src/views/cooperate-channels/images/img2-bg.png
  63. 二进制
      src/views/cooperate-channels/images/img2.png
  64. 二进制
      src/views/cooperate-channels/images/title-1.png
  65. 二进制
      src/views/cooperate-channels/images/title-2.png
  66. 二进制
      src/views/cooperate-channels/images/title-3.png
  67. 二进制
      src/views/cooperate-channels/images/title-4.png
  68. 182 0
      src/views/cooperate-channels/index.module.less
  69. 132 0
      src/views/cooperate-channels/index.tsx
  70. 3 2
      src/views/home/index.module.less
  71. 1 1
      src/views/home/index.tsx
  72. 8 7
      vite.config.ts

+ 303 - 28
package-lock.json

@@ -11,9 +11,13 @@
       "dependencies": {
         "@vant/use": "^1.6.0",
         "@vueuse/core": "^10.5.0",
+        "clean-deep": "^3.4.0",
         "dayjs": "^1.11.7",
+        "numeral": "^2.0.6",
         "pinia": "^2.0.34",
+        "query-string": "^8.1.0",
         "swiper": "^11.0.3",
+        "umi-request": "^1.4.0",
         "vant": "^4.1.2",
         "vue": "^3.2.47",
         "vue-router": "^4.1.6",
@@ -3303,7 +3307,6 @@
       "version": "1.0.5",
       "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.5.tgz",
       "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==",
-      "dev": true,
       "dependencies": {
         "function-bind": "^1.1.2",
         "get-intrinsic": "^1.2.1",
@@ -3434,6 +3437,19 @@
       "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
       "dev": true
     },
+    "node_modules/clean-deep": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmmirror.com/clean-deep/-/clean-deep-3.4.0.tgz",
+      "integrity": "sha512-Lo78NV5ItJL/jl+B5w0BycAisaieJGXK1qYi/9m4SjR8zbqmrUtO7Yhro40wEShGmmxs/aJLI/A+jNhdkXK8mw==",
+      "dependencies": {
+        "lodash.isempty": "^4.4.0",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.transform": "^4.6.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -3638,6 +3654,14 @@
         }
       }
     },
+    "node_modules/decode-uri-component": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz",
+      "integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==",
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
     "node_modules/deep-is": {
       "version": "0.1.4",
       "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz",
@@ -3657,7 +3681,6 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.1.tgz",
       "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
-      "dev": true,
       "dependencies": {
         "get-intrinsic": "^1.2.1",
         "gopd": "^1.0.1",
@@ -3761,6 +3784,25 @@
       "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
       "dev": true
     },
+    "node_modules/encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "dependencies": {
+        "iconv-lite": "^0.6.2"
+      }
+    },
+    "node_modules/encoding/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/errno": {
       "version": "0.1.8",
       "resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz",
@@ -4340,6 +4382,14 @@
         "node": ">=8"
       }
     },
+    "node_modules/filter-obj": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmmirror.com/filter-obj/-/filter-obj-5.1.0.tgz",
+      "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==",
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
     "node_modules/find-up": {
       "version": "5.0.0",
       "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz",
@@ -4466,8 +4516,7 @@
     "node_modules/function-bind": {
       "version": "1.1.2",
       "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
-      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "dev": true
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
     },
     "node_modules/gensync": {
       "version": "1.0.0-beta.2",
@@ -4482,7 +4531,6 @@
       "version": "1.2.2",
       "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
       "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==",
-      "dev": true,
       "dependencies": {
         "function-bind": "^1.1.2",
         "has-proto": "^1.0.1",
@@ -4600,7 +4648,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
       "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-      "dev": true,
       "dependencies": {
         "get-intrinsic": "^1.1.3"
       }
@@ -4651,7 +4698,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
       "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
-      "dev": true,
       "dependencies": {
         "get-intrinsic": "^1.2.2"
       }
@@ -4660,7 +4706,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz",
       "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       }
@@ -4669,7 +4714,6 @@
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz",
       "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       }
@@ -4678,7 +4722,6 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.0.tgz",
       "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
-      "dev": true,
       "dependencies": {
         "function-bind": "^1.1.2"
       },
@@ -5311,6 +5354,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/isomorphic-fetch": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==",
+      "dependencies": {
+        "node-fetch": "^1.0.1",
+        "whatwg-fetch": ">=0.10.0"
+      }
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -5558,12 +5610,27 @@
       "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
       "dev": true
     },
+    "node_modules/lodash.isempty": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmmirror.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
+      "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg=="
+    },
+    "node_modules/lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
+    },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz",
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
+    "node_modules/lodash.transform": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmmirror.com/lodash.transform/-/lodash.transform-4.6.0.tgz",
+      "integrity": "sha512-LO37ZnhmBVx0GvOU/caQuipEh4GN82TcWv3yHlebGDgOxbxiwwzW5Pcx2AcvpIv2WmvmSMoC492yQFNhy/l/UQ=="
+    },
     "node_modules/log-symbols": {
       "version": "5.1.0",
       "resolved": "https://registry.npmmirror.com/log-symbols/-/log-symbols-5.1.0.tgz",
@@ -5880,6 +5947,23 @@
         "tslib": "^2.0.3"
       }
     },
+    "node_modules/node-fetch": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-1.7.3.tgz",
+      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+      "dependencies": {
+        "encoding": "^0.1.11",
+        "is-stream": "^1.0.1"
+      }
+    },
+    "node_modules/node-fetch/node_modules/is-stream": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz",
+      "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/node-plop": {
       "version": "0.31.1",
       "resolved": "https://registry.npmmirror.com/node-plop/-/node-plop-0.31.1.tgz",
@@ -5983,6 +6067,19 @@
         "boolbase": "^1.0.0"
       }
     },
+    "node_modules/numeral": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmmirror.com/numeral/-/numeral-2.0.6.tgz",
+      "integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.1.tgz",
+      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ=="
+    },
     "node_modules/object-keys": {
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz",
@@ -6517,6 +6614,30 @@
         "node": ">=6"
       }
     },
+    "node_modules/qs": {
+      "version": "6.11.2",
+      "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz",
+      "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/query-string": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmmirror.com/query-string/-/query-string-8.1.0.tgz",
+      "integrity": "sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==",
+      "dependencies": {
+        "decode-uri-component": "^0.4.1",
+        "filter-obj": "^5.1.0",
+        "split-on-first": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
     "node_modules/queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -6782,8 +6903,7 @@
     "node_modules/safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "node_modules/sax": {
       "version": "1.3.0",
@@ -6816,7 +6936,6 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.1.1.tgz",
       "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
-      "dev": true,
       "dependencies": {
         "define-data-property": "^1.1.1",
         "get-intrinsic": "^1.2.1",
@@ -6848,6 +6967,16 @@
         "node": ">=8"
       }
     },
+    "node_modules/side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      }
+    },
     "node_modules/signal-exit": {
       "version": "3.0.7",
       "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -6922,6 +7051,14 @@
         "source-map": "^0.6.0"
       }
     },
+    "node_modules/split-on-first": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/split-on-first/-/split-on-first-3.0.0.tgz",
+      "integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/stdin-discarder": {
       "version": "0.1.0",
       "resolved": "https://registry.npmmirror.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
@@ -7228,6 +7365,15 @@
         "node": ">=0.8.0"
       }
     },
+    "node_modules/umi-request": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmmirror.com/umi-request/-/umi-request-1.4.0.tgz",
+      "integrity": "sha512-OknwtQZddZHi0Ggi+Vr/olJ7HNMx4AzlywyK0W3NZBT7B0stjeZ9lcztA85dBgdAj3KVk8uPJPZSnGaDjELhrA==",
+      "dependencies": {
+        "isomorphic-fetch": "^2.2.1",
+        "qs": "^6.9.1"
+      }
+    },
     "node_modules/unc-path-regex": {
       "version": "0.1.2",
       "resolved": "https://registry.npmmirror.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
@@ -7738,6 +7884,11 @@
       "integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==",
       "dev": true
     },
+    "node_modules/whatwg-fetch": {
+      "version": "3.6.19",
+      "resolved": "https://registry.npmmirror.com/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz",
+      "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw=="
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
@@ -10255,7 +10406,6 @@
       "version": "1.0.5",
       "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.5.tgz",
       "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==",
-      "dev": true,
       "requires": {
         "function-bind": "^1.1.2",
         "get-intrinsic": "^1.2.1",
@@ -10371,6 +10521,16 @@
       "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
       "dev": true
     },
+    "clean-deep": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmmirror.com/clean-deep/-/clean-deep-3.4.0.tgz",
+      "integrity": "sha512-Lo78NV5ItJL/jl+B5w0BycAisaieJGXK1qYi/9m4SjR8zbqmrUtO7Yhro40wEShGmmxs/aJLI/A+jNhdkXK8mw==",
+      "requires": {
+        "lodash.isempty": "^4.4.0",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.transform": "^4.6.0"
+      }
+    },
     "clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -10536,6 +10696,11 @@
         "ms": "2.1.2"
       }
     },
+    "decode-uri-component": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz",
+      "integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ=="
+    },
     "deep-is": {
       "version": "0.1.4",
       "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz",
@@ -10555,7 +10720,6 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.1.tgz",
       "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
-      "dev": true,
       "requires": {
         "get-intrinsic": "^1.2.1",
         "gopd": "^1.0.1",
@@ -10641,6 +10805,24 @@
       "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
       "dev": true
     },
+    "encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "requires": {
+        "iconv-lite": "^0.6.2"
+      },
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.6.3",
+          "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
+          "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3.0.0"
+          }
+        }
+      }
+    },
     "errno": {
       "version": "0.1.8",
       "resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz",
@@ -11094,6 +11276,11 @@
         "to-regex-range": "^5.0.1"
       }
     },
+    "filter-obj": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmmirror.com/filter-obj/-/filter-obj-5.1.0.tgz",
+      "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng=="
+    },
     "find-up": {
       "version": "5.0.0",
       "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz",
@@ -11189,8 +11376,7 @@
     "function-bind": {
       "version": "1.1.2",
       "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
-      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "dev": true
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
     },
     "gensync": {
       "version": "1.0.0-beta.2",
@@ -11202,7 +11388,6 @@
       "version": "1.2.2",
       "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
       "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==",
-      "dev": true,
       "requires": {
         "function-bind": "^1.1.2",
         "has-proto": "^1.0.1",
@@ -11298,7 +11483,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
       "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-      "dev": true,
       "requires": {
         "get-intrinsic": "^1.1.3"
       }
@@ -11338,7 +11522,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
       "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
-      "dev": true,
       "requires": {
         "get-intrinsic": "^1.2.2"
       }
@@ -11346,20 +11529,17 @@
     "has-proto": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz",
-      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
-      "dev": true
+      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
     },
     "has-symbols": {
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz",
-      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
-      "dev": true
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
     },
     "hasown": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.0.tgz",
       "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
-      "dev": true,
       "requires": {
         "function-bind": "^1.1.2"
       }
@@ -11844,6 +12024,15 @@
       "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
       "dev": true
     },
+    "isomorphic-fetch": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==",
+      "requires": {
+        "node-fetch": "^1.0.1",
+        "whatwg-fetch": ">=0.10.0"
+      }
+    },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -12032,12 +12221,27 @@
       "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
       "dev": true
     },
+    "lodash.isempty": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmmirror.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
+      "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg=="
+    },
+    "lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
+    },
     "lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz",
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
+    "lodash.transform": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmmirror.com/lodash.transform/-/lodash.transform-4.6.0.tgz",
+      "integrity": "sha512-LO37ZnhmBVx0GvOU/caQuipEh4GN82TcWv3yHlebGDgOxbxiwwzW5Pcx2AcvpIv2WmvmSMoC492yQFNhy/l/UQ=="
+    },
     "log-symbols": {
       "version": "5.1.0",
       "resolved": "https://registry.npmmirror.com/log-symbols/-/log-symbols-5.1.0.tgz",
@@ -12293,6 +12497,22 @@
         "tslib": "^2.0.3"
       }
     },
+    "node-fetch": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-1.7.3.tgz",
+      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+      "requires": {
+        "encoding": "^0.1.11",
+        "is-stream": "^1.0.1"
+      },
+      "dependencies": {
+        "is-stream": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz",
+          "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="
+        }
+      }
+    },
     "node-plop": {
       "version": "0.31.1",
       "resolved": "https://registry.npmmirror.com/node-plop/-/node-plop-0.31.1.tgz",
@@ -12379,6 +12599,16 @@
         "boolbase": "^1.0.0"
       }
     },
+    "numeral": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmmirror.com/numeral/-/numeral-2.0.6.tgz",
+      "integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA=="
+    },
+    "object-inspect": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.1.tgz",
+      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ=="
+    },
     "object-keys": {
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz",
@@ -12781,6 +13011,24 @@
       "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
       "dev": true
     },
+    "qs": {
+      "version": "6.11.2",
+      "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz",
+      "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
+      "requires": {
+        "side-channel": "^1.0.4"
+      }
+    },
+    "query-string": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmmirror.com/query-string/-/query-string-8.1.0.tgz",
+      "integrity": "sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==",
+      "requires": {
+        "decode-uri-component": "^0.4.1",
+        "filter-obj": "^5.1.0",
+        "split-on-first": "^3.0.0"
+      }
+    },
     "queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -12994,8 +13242,7 @@
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "sax": {
       "version": "1.3.0",
@@ -13025,7 +13272,6 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.1.1.tgz",
       "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
-      "dev": true,
       "requires": {
         "define-data-property": "^1.1.1",
         "get-intrinsic": "^1.2.1",
@@ -13048,6 +13294,16 @@
       "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
       "dev": true
     },
+    "side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "requires": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      }
+    },
     "signal-exit": {
       "version": "3.0.7",
       "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -13109,6 +13365,11 @@
         "source-map": "^0.6.0"
       }
     },
+    "split-on-first": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/split-on-first/-/split-on-first-3.0.0.tgz",
+      "integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA=="
+    },
     "stdin-discarder": {
       "version": "0.1.0",
       "resolved": "https://registry.npmmirror.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
@@ -13342,6 +13603,15 @@
       "dev": true,
       "optional": true
     },
+    "umi-request": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmmirror.com/umi-request/-/umi-request-1.4.0.tgz",
+      "integrity": "sha512-OknwtQZddZHi0Ggi+Vr/olJ7HNMx4AzlywyK0W3NZBT7B0stjeZ9lcztA85dBgdAj3KVk8uPJPZSnGaDjELhrA==",
+      "requires": {
+        "isomorphic-fetch": "^2.2.1",
+        "qs": "^6.9.1"
+      }
+    },
     "unc-path-regex": {
       "version": "0.1.2",
       "resolved": "https://registry.npmmirror.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
@@ -13688,6 +13958,11 @@
       "integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==",
       "dev": true
     },
+    "whatwg-fetch": {
+      "version": "3.6.19",
+      "resolved": "https://registry.npmmirror.com/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz",
+      "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw=="
+    },
     "which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",

+ 4 - 0
package.json

@@ -23,9 +23,13 @@
   "dependencies": {
     "@vant/use": "^1.6.0",
     "@vueuse/core": "^10.5.0",
+    "clean-deep": "^3.4.0",
     "dayjs": "^1.11.7",
+    "numeral": "^2.0.6",
     "pinia": "^2.0.34",
+    "query-string": "^8.1.0",
     "swiper": "^11.0.3",
+    "umi-request": "^1.4.0",
     "vant": "^4.1.2",
     "vue": "^3.2.47",
     "vue-router": "^4.1.6",

+ 10 - 0
src/component-ui/README.md

@@ -0,0 +1,10 @@
+### components-ui
+
+1、在 Vant3.x 基础上封装一套独立样式,因环境差异较大数据应统一输入尽量不要请求接口;
+2、注意 Vant 库等必要依赖库的版本差异;
+3、组件采用 less 的方式编写;
+
+### 使用
+
+1、把项目中 index.less 在项目的根目录中使用;
+2、一些基础组件,只会在原生有 UI 组件上变更样式;

+ 129 - 0
src/component-ui/global.less

@@ -0,0 +1,129 @@
+// 注意:为什么要写两个重复的 :root?
+// 由于 vant 中的主题变量也是在 :root 下声明的,所以在有些情况下会由于优先级的问题无法成功覆盖。通过
+// :root:root 可以显式地让你所写内容的优先级更高一些,从而确保主题变量的成功覆盖。
+:root:root {
+  // 01 品牌色
+  --k-primary: #ff8057;
+
+  // 02 背景色
+  --k-bg-1: #fff;
+  --k-bg-2: #f8f8f8;
+  --k-bg-3: #f6f6f6;
+  --k-bg-4: #f2f2f2;
+
+  // 03 辅助色
+  --k-orange: #ffebdd;
+  --k-red: #f44541;
+  --k-blue: #64a9ff;
+  --k-purple: #8f80ff;
+
+  // 04 渐变色
+  --k-gradient-1: linear-gradient(90deg, #ff9c63 0%, #ff7144 100%);
+  --k-gradient-2: linear-gradient(270deg, #ff4f44 0%, #ffafab 100%);
+  --k-gradient-3: linear-gradient(90deg, #8cccff 0%, #459aff 100%);
+  --k-gradient-4: linear-gradient(90deg, #d4a9ff 0%, #8f80ff 100%);
+  --k-gradient-5: linear-gradient(90deg, #a9f0b4 0%, #09c58c 100%);
+
+  // 05 字体颜色
+  --k-font-primary: #f67146;
+  --k-font-danger: #f44541;
+  --k-gray-1: #333333;
+  --k-gray-2: #666666;
+  --k-gray-3: #777777;
+  --k-gray-4: #aaaaaa;
+  --k-gray-5: #cccccc;
+
+  // 06 分割线
+  --k-hairline-dark: #eeeeee;
+  --k-hairline-shallow: #f2f2f2;
+
+  // 07 蒙层
+  --k-overlay-background-dark: rgba(0, 0, 0, 0.7);
+  --k-overlay-background-shallow: rgba(0, 0, 0, 0.5);
+
+  // 圆角
+  --k-radius-sm: 2px;
+  --k-radius-md: 4px;
+  --k-radius-lg: 8px;
+  --k-radius-xl: 10px;
+  --k-radius-max: 999px;
+
+  // 间距
+  --k-padding-base: 4px;
+  --k-padding-xs: 6px;
+  --k-padding-sm: 8px;
+  --k-padding-md: 12px;
+  --k-padding-lg: 16px;
+  --k-padding-xl: 20px;
+  --k-padding-page: 13px; // 页面是基础边距
+  --k-padding-card: 9px; // 卡片的基础边距
+
+  // 描边 投影
+  --k-border-color: var(--k-primary);
+  --k-border-width: 1px;
+  --k-shadow: 0px 2px 12px 0px rgba(100, 101, 102, 0.12);
+
+  // 设置Vant UI组件库中的默认样式;
+  --van-primary: var(--k-primary);
+  --van-primary-color: var(--van-primary);
+  --van-primary-text: var(--k-font-primary);
+  --van-text-color: var(--k-gray-1);
+
+  // 多选框
+  --van-checkbox-border-color: #dcdcdc;
+  --van-checkbox-label-color: var(--k-gray-1);
+  --van-checkbox-disabled-icon-color: #dcdcdc;
+  --van-checkbox-disabled-label-color: var(--k-gray-5);
+  --van-checkbox-disabled-background: #f7f8fa;
+
+  // 单选框
+  --van-radio-border-color: #dcdcdc;
+  --van-radio-disabled-icon-color: #dcdcdc;
+  --van-radio-disabled-background: #f7f8fa;
+
+  // 导航
+  --van-nav-bar-arrow-size: 20px;
+  --van-nav-bar-title-font-size: 18px;
+  --van-nav-bar-title-text-color: var(--k-gray-1);
+  --van-nav-bar-icon-color: var(--k-gray-1);
+
+  // tab 选择卡
+  --van-tab-text-color: var(--k-gray-3);
+  --van-tabs-bottom-bar-width: 40px;
+  --van-tab-active-text-color: var(--k-gray-1);
+
+  // 侧边导航栏(分类选择)
+  --van-sidebar-selected-border-width: 2px;
+  --van-sidebar-selected-border-height: 18px;
+  --van-sidebar-text-color: var(--k-gray-1);
+  --van-sidebar-selected-text-color: var(--k-primary);
+
+  // 宫格
+  --van-grid-item-text-color: var(--k-gray-1);
+  --van-grid-item-text-font-size: 14px;
+
+  // 步骤条
+  --van-step-horizontal-title-font-size: 14px;
+  --van-step-finish-text-color: var(--k-gray-1);
+  --van-step-text-color: #999;
+
+  // 按钮
+  --van-button-normal-font-size: 18px;
+
+  // 通知栏
+  --van-notice-bar-background: #ffe3d2;
+  --van-notice-bar-text-color: var(--k-font-primary);
+
+  // 开关
+  --van-switch-size: 22px;
+  --van-switch-width: calc(2em + 4px);
+  --van-switch-height: calc(1em + 4px);
+  // --van-switch-background: #fff;
+
+  // 折叠面板
+  --van-collapse-item-content-text-color: #999;
+
+  // 头部高度
+  --van-nav-bar-height: 44px;
+  --van-nav-bar-arrow-size: 22px;
+}

+ 218 - 0
src/component-ui/index.less

@@ -0,0 +1,218 @@
+// 公用变量
+@import './global.less';
+// :global {
+// 单元格
+.van-cell-group--inset {
+  margin: 0 var(--k-padding-page);
+  border-radius: var(--k-radius-xl);
+}
+.van-cell {
+  font-size: 15px;
+  padding: 12px 18px;
+  color: var(--k-gray-1);
+}
+
+// 导航 - ✅
+.van-nav-bar__left,
+.van-nav-bar__right {
+  padding: 0 var(--k-padding-md);
+}
+
+// 选项卡 侧边导航栏(分类选择) - ✅
+.van-tabs--card {
+  padding: 0;
+  .van-tabs__nav {
+    background-color: transparent;
+  }
+  .van-tabs__nav--card {
+    border-radius: var(--k-radius-max);
+    border: 0;
+  }
+  .van-tab--card {
+    margin-right: var(--k-padding-md);
+    border-right: 0;
+    color: var(--k-gray-1);
+    background-color: #fff;
+    border-radius: var(--k-radius-max);
+    &.van-tab--active {
+      color: #fff;
+      background-color: var(--k-primary);
+    }
+    &:last-child {
+      margin-right: 0;
+    }
+  }
+  .van-tab--shrink {
+    padding: 0 var(--k-padding-lg);
+  }
+}
+
+// 宫格 - ✅
+// 步骤条 - ✅
+// 按钮 - ✅
+.van-button {
+  font-weight: 500;
+  &:active:before {
+    opacity: 0.2;
+  }
+}
+.van-button--disabled {
+  position: relative;
+  opacity: 1;
+  &:active:before {
+    opacity: 0.6;
+  }
+  &:before {
+    content: ' ';
+    display: block;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    width: 100%;
+    height: 100%;
+    background: #fff;
+    border: inherit;
+    border-color: #fff;
+    border-radius: inherit;
+    transform: translate(-50%, -50%);
+    opacity: 0.6;
+  }
+}
+
+// 搜索框 - 【不处理】
+.van-search__field {
+  padding: 0 var(--van-padding-xs) 0 0;
+}
+
+// 气泡弹出框 - 【不处理】
+// 对话框 - ✅
+// 轻提示 - 【不处理】
+// 通知栏 - ✅
+// 遮罩/基础样式 - ✅
+// 定义了基础变量,如果需要对应的引入; --k-overlay-background-dark, --k-overlay-background-shallow
+
+// 单元格滑动 - 【不处理】
+// 协议 - 【不处理】
+// 缺省图 - 【不处理】
+// 输入框 - ✅
+.van-field__label {
+  color: var(--k-gray-2);
+  font-size: 15px;
+}
+.van-field__control {
+  font-size: 15px;
+}
+.van-field__control::placeholder {
+  color: var(--k-gray-5);
+}
+.van-cell__right-icon {
+  font-size: 13px;
+  font-weight: bold;
+  color: #d8d8d8;
+}
+.van-field__label--top.border {
+  position: relative;
+  padding-bottom: 10px;
+  margin-bottom: 10px;
+  &::after {
+    display: block;
+    position: absolute;
+    box-sizing: border-box;
+    content: ' ';
+    pointer-events: none;
+    right: var(--van-padding-md);
+    bottom: 0;
+    left: var(--van-padding-md);
+    border-bottom: 0.02667rem solid var(--van-cell-border-color);
+    transform: scaleY(0.5);
+  }
+}
+
+// 选择框
+// 上拉选择 - ✅
+// 选择器 - ✅
+.van-picker {
+  --van-picker-toolbar-height: 44px !important;
+  .van-picker__toolbar {
+    position: relative;
+    &::after {
+      position: absolute;
+      box-sizing: border-box;
+      content: ' ';
+      pointer-events: none;
+      right: var(--van-padding-md);
+      bottom: 0;
+      left: var(--van-padding-md);
+      border-bottom: 1px solid var(--van-cell-border-color);
+      transform: scaleY(0.5);
+    }
+  }
+  .van-picker__columns {
+    padding: 0 24px;
+  }
+  .van-picker-column {
+    position: relative;
+    z-index: 1;
+  }
+  .van-picker__frame {
+    z-index: 0;
+    &::after {
+      background: var(--k-bg-4);
+      border-radius: 8px;
+    }
+  }
+  .van-picker__cancel,
+  .van-picker__confirm {
+    font-size: 15px;
+  }
+  .van-picker__cancel {
+    color: var(--k-gray-3);
+  }
+  .van-picker__confirm {
+    color: var(--k-font-primary);
+  }
+  .van-picker-column__item {
+    color: var(--k-gray-1);
+    font-size: 16px;
+  }
+  .van-picker-column__item--selected {
+    font-weight: 600;
+  }
+}
+
+// 日历选择器 - ✅
+
+// 上拉菜单-分享面板 - 【不处理】
+// 下拉菜单/搜索样式框 - 【不处理】
+
+// 文件上传 - 【不处理】
+// 图片展示 - 【不处理】
+// 图片全屏展示 - ✅
+.van-image-preview {
+  .van-image-preview__close-icon,
+  .van-image-preview__index {
+    top: calc(var(--van-padding-md) + env(safe-area-inset-bottom));
+  }
+}
+// 弹出层 - 【不处理】
+// 开关 / 基础样式 / 禁用样式
+
+// 折叠面板 - ✅
+// 标签样式
+
+.van-tag {
+  padding-top: 1px;
+  .van-tag__close {
+    margin-top: -2px;
+  }
+}
+.van-tag--large {
+  padding-top: calc(var(--van-padding-base) + 1px);
+}
+.van-tag--medium {
+  padding-top: 3px;
+}
+// 轮播 - 【不处理】
+// 骨架屏 - 【不处理】
+// 进度条 - 【不处理】
+// }

+ 28 - 0
src/component-ui/k-action-sheet/index.module.less

@@ -0,0 +1,28 @@
+@import '../global.less';
+
+.k-sheet_content {
+  margin: 0 13px;
+  padding-top: 10px;
+  :global {
+    .van-sheet-item {
+      line-height: 52px;
+      font-size: 16px;
+      font-weight: 400;
+      color: var(--k-gray-1);
+      text-align: center;
+      padding: 0 var(--k-padding-md);
+    }
+    .van-sheet-item-active {
+      background: var(--k-bg-4);
+      border-radius: var(--k-radius-lg);
+      font-weight: 600;
+    }
+  }
+}
+.k-action-sheet_bottom__cancel {
+  margin: 0 13px;
+  width: calc(100vw - 26px);
+  line-height: 52px;
+  padding: 0;
+  color: var(--k-gray-4);
+}

+ 84 - 0
src/component-ui/k-action-sheet/index.tsx

@@ -0,0 +1,84 @@
+import { ActionSheet } from 'vant';
+import { defineComponent, PropType, reactive, watch } from 'vue';
+import styles from './index.module.less';
+
+type actionsType = {
+  name: string | number;
+  value?: string | number;
+  selected?: boolean;
+};
+
+export default defineComponent({
+  name: 'k-action-sheet',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    actions: {
+      type: Array as PropType<actionsType[]>,
+      required: true,
+      default: () => []
+    },
+    cancelText: {
+      type: String,
+      default: '取消'
+    },
+    teleport: {
+      type: [String, Element],
+      default: ''
+    }
+  },
+  emits: ['update:show', 'select'],
+  setup(props, { emit }) {
+    const form = reactive({
+      oPopover: props.show
+    });
+
+    const onSelect = (item: any) => {
+      emit('select', item);
+      emit('update:show', false);
+    };
+
+    watch(
+      () => form.oPopover,
+      () => {
+        emit('update:show', form.oPopover);
+      }
+    );
+
+    watch(
+      () => props.show,
+      () => {
+        form.oPopover = props.show;
+      }
+    );
+
+    return () => (
+      <ActionSheet v-model:show={form.oPopover} teleport={props.teleport}>
+        <div class={[styles['k-sheet_content'], 'van-hairline--bottom']}>
+          {props.actions.map((item: any) => (
+            <div
+              class={[
+                'van-sheet-item van-ellipsis',
+                item.selected && 'van-sheet-item-active'
+              ]}
+              onClick={() => onSelect(item)}>
+              {item.name}
+            </div>
+          ))}
+        </div>
+
+        <button
+          type="button"
+          class={[
+            'van-action-sheet__cancel',
+            styles['k-action-sheet_bottom__cancel']
+          ]}
+          onClick={() => emit('update:show', false)}>
+          {props.cancelText}
+        </button>
+      </ActionSheet>
+    );
+  }
+});

+ 47 - 0
src/component-ui/k-dialog/index.module.less

@@ -0,0 +1,47 @@
+@import '../global.less';
+
+.dialogTitle {
+  i {
+    display: inline-block;
+    width: 4px;
+    height: 14px;
+    background: var(--k-primary);
+    border-radius: 2px;
+    margin-right: 6px;
+  }
+
+  padding-left: 25px;
+  text-align: left;
+  font-size: 18px;
+  font-weight: 500;
+  color: var(--k-gary-1);
+  line-height: 25px;
+  padding-bottom: 12px;
+}
+
+.oDialog {
+  // margin-top: env(safe-area-inset-top);
+  :global {
+    .van-dialog__header {
+      padding-top: 20px;
+    }
+    .van-dialog__message {
+      font-size: 16px;
+      color: var(--k-gray-1);
+      font-weight: 400;
+      line-height: 24px;
+    }
+    .van-dialog__cancel,
+    .van-dialog__confirm {
+      font-size: 18px;
+      height: 50px;
+      line-height: 50px;
+    }
+    .van-dialog__cancel {
+      color: var(--k-gray-3);
+    }
+    .van-dialog__confirm {
+      color: var(--k-font-primary);
+    }
+  }
+}

+ 97 - 0
src/component-ui/k-dialog/index.tsx

@@ -0,0 +1,97 @@
+import { Dialog } from 'vant'
+import { defineComponent, PropType, reactive, watch } from 'vue'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'o-dialog',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    message: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    },
+    confirmButtonText: {
+      type: String,
+      default: '确认'
+    },
+    allowHtml: {
+      type: Boolean,
+      default: false
+    },
+    cancelButtonText: {
+      type: String,
+      default: '取消'
+    },
+    showConfirmButton: {
+      type: Boolean,
+      default: true
+    },
+    showCancelButton: {
+      type: Boolean,
+      default: false
+    },
+    messageAlign: {
+      type: String as PropType<'left' | 'center' | 'right'>,
+      default: 'center'
+    },
+    dialogMarginTop: {
+      type: String,
+      default: '0px'
+    }
+  },
+  emits: ['cancel', 'confirm', 'update:show'],
+  setup(props, { emit, slots }) {
+    const state = reactive({
+      show: props.show || false
+    })
+
+    // 监听状态
+    watch(
+      () => props.show,
+      () => {
+        state.show = props.show
+      }
+    )
+    return () => (
+      <Dialog
+        class={styles.oDialog}
+        style={{
+          marginTop: props.dialogMarginTop
+        }}
+        v-model:show={state.show}
+        message={props.message}
+        allowHtml={props.allowHtml}
+        messageAlign={props.messageAlign}
+        confirmButtonText={props.confirmButtonText}
+        cancelButtonText={props.cancelButtonText}
+        showConfirmButton={props.showConfirmButton}
+        showCancelButton={props.showCancelButton}
+        onConfirm={() => {
+          emit('update:show', false)
+          emit('confirm')
+        }}
+        onCancel={() => {
+          emit('update:show', false)
+          emit('cancel')
+        }}
+      >
+        {{
+          title: () =>
+            props.title && (
+              <div class={styles.dialogTitle}>
+                <i></i>
+                {props.title}
+              </div>
+            )
+        }}
+      </Dialog>
+    )
+  }
+})

+ 39 - 19
src/components/m-header/index.tsx

@@ -42,26 +42,46 @@ export default defineComponent({
             isActive.value = val;
           }}
           teleport={'body'}>
-          <Cell
-            title={'首页'}
-            border={false}
-            class={['/', '/home'].includes(route.path) && styles['is-active']}
-            onClick={() => onGoDetail('/')}></Cell>
-          <Cell title={'产品'} border={false}></Cell>
-          <Cell
-            title={'解决方案'}
-            isLink
-            arrowDirection={arrowStatus.value ? 'up' : 'down'}
-            border={false}
-            onClick={() => (arrowStatus.value = !arrowStatus.value)}></Cell>
-          <div
-            class={[styles.subCell, arrowStatus.value && styles.arrowActive]}>
-            <Cell title={'数字化音乐课堂'} border={false}></Cell>
-            <Cell title={'器乐教培行业解决方案'} border={false}></Cell>
-            <Cell title={'音乐达人展示平台'} border={false}></Cell>
+          <div class="van-hairline--top">
+            <Cell
+              title={'首页'}
+              border={false}
+              clickable
+              class={['/', '/home'].includes(route.path) && styles['is-active']}
+              onClick={() => onGoDetail('/')}></Cell>
+            <Cell title={'产品'} clickable border={false}></Cell>
+            <Cell
+              title={'解决方案'}
+              isLink
+              clickable
+              arrowDirection={arrowStatus.value ? 'up' : 'down'}
+              border={false}
+              onClick={() => (arrowStatus.value = !arrowStatus.value)}></Cell>
+            <div
+              class={[styles.subCell, arrowStatus.value && styles.arrowActive]}>
+              <Cell title={'数字化音乐课堂'} clickable border={false}></Cell>
+              <Cell
+                title={'器乐教培行业解决方案'}
+                clickable
+                border={false}></Cell>
+              <Cell title={'音乐达人展示平台'} clickable border={false}></Cell>
+            </div>
+            <Cell
+              title={'渠道合作'}
+              border={false}
+              clickable
+              class={
+                ['/cooperate-channels'].includes(route.path) &&
+                styles['is-active']
+              }
+              onClick={() => onGoDetail('/cooperate-channels')}></Cell>
+            <Cell
+              title={'关于我们'}
+              clickable
+              border={false}
+              class={['/about-us'].includes(route.path) && styles['is-active']}
+              onClick={() => onGoDetail('/about-us')}></Cell>
           </div>
-          <Cell title={'渠道合作'} border={false}></Cell>
-          <Cell title={'关于我们'} border={false}></Cell>
         </Popup>
       </div>
     );

+ 45 - 0
src/components/m-img-code/index.module.less

@@ -0,0 +1,45 @@
+.imgCode {
+  padding: 16px;
+
+  .codeTitle {
+    text-align: center;
+    font-size: 16px;
+    color: #4f4f4f;
+    margin: 0;
+    padding-bottom: 16px;
+  }
+
+  .img {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .imgChange {
+    display: block;
+    color: #aaaaaa;
+    font-size: 12px;
+    text-align: center;
+    padding-top: 5px;
+  }
+
+  .field {
+    background: #f4f4f4;
+    padding: 10px 12px !important;
+  }
+}
+
+.imgCodePopup {
+  width: 90%;
+  border-radius: 5px;
+  overflow: initial;
+
+  :global {
+    .van-popup__close-icon {
+      top: -37px !important;
+      right: 0 !important;
+      font-size: 25px;
+      color: #fff;
+    }
+  }
+}

+ 147 - 0
src/components/m-img-code/index.tsx

@@ -0,0 +1,147 @@
+import { defineComponent } from 'vue';
+import {
+  Col,
+  Popup,
+  Row,
+  Image as VanImage,
+  Loading,
+  Field,
+  showToast
+} from 'vant';
+import styles from './index.module.less';
+import request from '@/helpers/request';
+
+export default defineComponent({
+  name: 'o-img-code',
+  props: {
+    value: Boolean,
+    phone: [String, Number],
+    type: {
+      type: String,
+      default: 'LOGIN'
+    },
+    clientId: {
+      type: String,
+      default: 'cooleshow-student'
+    }
+  },
+  emits: ['close', 'sendCode'],
+  data() {
+    // const origin = window.location.origin;
+    return {
+      isSuffix: '/api-student',
+      showStatus: false,
+      identifyingCode: '/api-student/code/getImageCode?phone=' + this.phone,
+      code: ''
+    };
+  },
+  mounted() {
+    this.showStatus = this.value;
+    // this.sendImgCode();
+  },
+  watch: {
+    value(val) {
+      this.showStatus = val;
+    },
+    code(val) {
+      if (val.length >= 4) {
+        this.checkVerifyLoginImage();
+      }
+    }
+  },
+  methods: {
+    // async sendImgCode() {
+    //   const { data } = await request.get(this.isSuffix + '/open/sendImgCode', {
+    //     requestType: 'form',
+    //     hideLoading: true,
+    //     params: {
+    //       phone: this.phone
+    //     }
+    //   });
+    //   this.identifyingCode = data;
+    // },
+    async updateIdentifyingCode() {
+      // 刷新token
+      const origin = window.location.origin;
+      this.identifyingCode = `${origin}${
+        this.isSuffix
+      }/code/getImageCode?phone=${this.phone}&token=${Math.random()}`;
+    },
+    async checkVerifyLoginImage() {
+      try {
+        if (this.code.length < 4) {
+          return;
+        }
+        await request.post(this.isSuffix + `/code/verifyImageCode`, {
+          requestType: 'form',
+          hideLoading: true,
+          data: {
+            phone: this.phone,
+            code: this.code
+          }
+        });
+        await request.post(this.isSuffix + `/code/sendSmsCode`, {
+          requestType: 'form',
+          hideLoading: true,
+          data: {
+            mobile: this.phone,
+            type: 'LOGIN'
+          }
+        });
+        setTimeout(() => {
+          showToast('验证码已发送');
+        }, 100);
+        this.$emit('close');
+        this.$emit('sendCode');
+      } catch {
+        this.code = '';
+        setTimeout(() => {
+          this.updateIdentifyingCode();
+        }, 500);
+      }
+    }
+  },
+  render() {
+    return (
+      <Popup
+        show={this.showStatus}
+        class={styles.imgCodePopup}
+        closeOnClickOverlay={false}
+        onClose={() => {
+          this.$emit('close');
+        }}
+        closeable
+        closeIcon="close">
+        <div class={styles.imgCode}>
+          <p class={styles.codeTitle}>输入图形验证码</p>
+          <Row>
+            <Col span="14">
+              <Field
+                placeholder="请输入验证码"
+                v-model={this.code}
+                class={styles.field}
+                autocomplete="off"
+              />
+            </Col>
+            <Col span="10" class={styles.img}>
+              <VanImage
+                src={this.identifyingCode}
+                onClick={() => this.updateIdentifyingCode()}>
+                {{ loading: () => <Loading type="spinner" size="20" /> }}
+              </VanImage>
+            </Col>
+          </Row>
+          <Row style={{ display: 'flex', justifyContent: 'end' }}>
+            <Col span="10">
+              <span
+                class={styles.imgChange}
+                onClick={() => this.updateIdentifyingCode()}>
+                看不清?换一换
+              </span>
+            </Col>
+          </Row>
+        </div>
+      </Popup>
+    );
+  }
+});

+ 67 - 0
src/components/the-submit/index.module.less

@@ -0,0 +1,67 @@
+.fieldGroup {
+  padding: 0 24px;
+
+  :global {
+    .van-field {
+      margin-bottom: 10px;
+      border-radius: 7px;
+      padding: 11px 13px;
+      font-size: 12px;
+    }
+
+    .van-field__control::placeholder {
+      color: #AAAAAA;
+    }
+
+    .van-cell__right-icon {
+      color: #D8D8D8;
+    }
+  }
+
+  .smsField {
+    padding-right: 0;
+
+    .sendCms {
+      color: #FE2451;
+      font-size: 12px;
+      width: 120px;
+      display: inline-block;
+      text-align: center;
+
+      border-left: 1px solid #E5E5E5;
+    }
+
+    :global {
+      .van-count-down {
+        font-size: 12px;
+        width: 120px;
+        text-align: center;
+        border-left: 1px solid #E5E5E5;
+      }
+    }
+  }
+
+  .btnSubmit {
+    width: 268px;
+    margin: 23px auto 0;
+    height: 38px;
+    font-size: 16px;
+    font-weight: 600;
+    color: #131415;
+    border: none;
+    padding: 0;
+  }
+}
+
+.fieldTenant {
+  :global {
+    .van-field {
+      border: 1px solid #F7DFE7;
+    }
+  }
+
+  .btnSubmit {
+    background: linear-gradient(to right, #FF75A6, #FF3C81);
+    color: #fff;
+  }
+}

+ 188 - 0
src/components/the-submit/index.tsx

@@ -0,0 +1,188 @@
+import { PropType, defineComponent, nextTick, reactive, ref } from 'vue';
+import styles from './index.module.less';
+import { Button, CountDown, Field, Picker, Popup, showToast } from 'vant';
+import MImgCode from '../m-img-code';
+import { checkPhone } from '@/helpers/utils';
+import request from '@/helpers/request';
+
+export default defineComponent({
+  name: 'the-submit',
+  props: {
+    /** 类型 */
+    type: {
+      type: String as PropType<'tenant' | ''>,
+      default: ''
+    }
+  },
+  setup(props) {
+    const countDownRef = ref();
+    const state = reactive({
+      typeStatus: false,
+      countDownTime: 60 * 1000,
+      countDownStatus: true,
+      imgCodeStatus: false,
+      cooperateTenantName: null,
+      cooperateTenantNature: null,
+      cooperateTenantNatureTxt: null as any,
+      contacts: null,
+      phone: null as any,
+      code: null
+    });
+
+    const onCodeSend = () => {
+      state.countDownStatus = false;
+      nextTick(() => {
+        countDownRef.value.start();
+      });
+    };
+
+    const onSendCode = () => {
+      // 发送验证码
+      console.log(state.phone, 'state.phone');
+      if (!checkPhone(state.phone)) {
+        return showToast('请输入正确的手机号码');
+      }
+      state.imgCodeStatus = true;
+    };
+    //
+    const onFinished = () => {
+      state.countDownStatus = true;
+      countDownRef.value.reset();
+    };
+
+    const onSubmit = async () => {
+      try {
+        if (!state.cooperateTenantNature) {
+          return showToast('请选择机构性质');
+        }
+        if (!state.cooperateTenantName) {
+          return showToast('请填写机构名称');
+        }
+        if (!state.contacts) {
+          return showToast('请填写联系人');
+        }
+        if (!state.phone) {
+          return showToast('请输入联系电话');
+        }
+        if (!checkPhone(state.phone)) {
+          return showToast('请输入正确的手机号码');
+        }
+        if (!state.code) {
+          return showToast('请输入验证码');
+        }
+
+        await request.post('/api-student/open/cooperateTenant/save', {
+          data: {
+            cooperateTenantName: state.cooperateTenantName,
+            cooperateTenantNature: state.cooperateTenantNature,
+            contacts: state.contacts,
+            phone: state.phone,
+            code: state.code
+          }
+        });
+      } catch {
+        //
+      }
+    };
+    return () => (
+      <>
+        <div
+          class={[
+            styles.fieldGroup,
+            props.type === 'tenant' && styles.fieldTenant
+          ]}>
+          <Field
+            readonly
+            isLink
+            arrowDirection="down"
+            placeholder="机构性质"
+            border={false}
+            autocomplete="off"
+            modelValue={state.cooperateTenantNatureTxt}
+            onClick={() => (state.typeStatus = true)}
+          />
+          <Field
+            type="text"
+            border={false}
+            placeholder="机构名称"
+            autocomplete="off"
+            maxlength={20}
+            v-model={state.cooperateTenantName}
+          />
+          <Field
+            type="text"
+            border={false}
+            placeholder="联系人"
+            autocomplete="off"
+            maxlength={20}
+            v-model={state.contacts}
+          />
+          <Field
+            type="number"
+            maxlength={11}
+            border={false}
+            placeholder="联系电话"
+            autocomplete="off"
+            v-model={state.phone}
+          />
+          <Field
+            class={styles.smsField}
+            type="number"
+            maxlength={6}
+            border={false}
+            placeholder="短信验证码"
+            autocomplete="off"
+            v-model={state.code}>
+            {{
+              button: () =>
+                state.countDownStatus ? (
+                  <span class={styles.sendCms} onClick={onSendCode}>
+                    发送短信
+                  </span>
+                ) : (
+                  <CountDown
+                    ref={el => (countDownRef.value = el)}
+                    auto-start={false}
+                    time={state.countDownTime}
+                    onFinish={onFinished}
+                    format="ss秒"
+                  />
+                )
+            }}
+          </Field>
+          <Button block round class={styles.btnSubmit} onClick={onSubmit}>
+            确认提交
+          </Button>
+          <Popup v-model:show={state.typeStatus} position="bottom" round>
+            <Picker
+              columns={[
+                { text: '中小学学校', value: 'PRIMARY_AND_SECONDARY_SCHOOLS' },
+                { text: '教培机构', value: 'EDUCATIONAL_INSTITUTIONS' },
+                { text: '音乐达人', value: 'PLAYERS' },
+                { text: '代理商', value: 'AGENT' }
+              ]}
+              showToolbar
+              onCancel={() => (state.typeStatus = false)}
+              onConfirm={val => {
+                const selectedOptions = val.selectedOptions[0];
+                state.cooperateTenantNature = selectedOptions.value;
+                state.cooperateTenantNatureTxt = selectedOptions.text;
+                state.typeStatus = false;
+              }}
+            />
+          </Popup>
+        </div>
+        {state.imgCodeStatus ? (
+          <MImgCode
+            v-model:value={state.imgCodeStatus}
+            phone={state.phone}
+            onClose={() => {
+              state.imgCodeStatus = false;
+            }}
+            onSendCode={onCodeSend}
+          />
+        ) : null}
+      </>
+    );
+  }
+});

+ 122 - 0
src/helpers/request.ts

@@ -0,0 +1,122 @@
+import { extend } from 'umi-request';
+import cleanDeep from 'clean-deep';
+// import { browser } from '@/helpers/utils';
+import { showLoadingToast, showToast, closeToast } from 'vant';
+// import { storage } from '@/helpers/storage';
+// import { ACCESS_TOKEN } from '@/store/mutation-types';
+
+export interface SearchInitParams {
+  rows?: string | number;
+  page?: string | number;
+}
+
+const request = extend({
+  // requestType: 'form',
+  noAuthorization: false, // 默认添加token,在有的情况下
+  hideLoading: true, // 默认都不显示加载
+  timeout: 20000,
+  timeoutMessage: '请求超时'
+});
+
+// 是否是初始化接口
+let initRequest = false;
+let toast: ReturnType<typeof setTimeout>;
+
+request.interceptors.request.use(
+  (url, options) => {
+    if (!options.hideLoading) {
+      clearTimeout(toast);
+      showLoadingToast({
+        message: '加载中...',
+        forbidClick: true,
+        duration: 0
+      });
+    }
+
+    initRequest = options.initRequest || false;
+    // const Authorization = storage.get(ACCESS_TOKEN) || '';
+    const authHeaders = {};
+
+    // if (
+    //   Authorization &&
+    //   ![
+    //     '/edu-app/userlogin',
+    //     '/edu-app/smsLogin',
+    //     '/edu-app/open/sendSms'
+    //   ].includes(url) &&
+    //   !options.noAuthorization
+    // ) {
+    //   authHeaders.Authorization = Authorization;
+    // }
+
+    return {
+      url,
+      options: {
+        ...options,
+        params: cleanDeep(options.params),
+        data: cleanDeep(options.data),
+        headers: {
+          ...options.headers,
+          ...authHeaders
+        }
+      }
+    };
+  },
+  { global: false }
+);
+
+request.interceptors.response.use(
+  async res => {
+    toast = setTimeout(() => {
+      closeToast();
+    }, 100);
+
+    if (res.status > 299 || res.status < 200) {
+      const msg = '服务器错误,状态码' + res.status;
+      clearTimeout(toast);
+      setTimeout(() => {
+        showToast(msg);
+      }, 60);
+      throw new Error(msg);
+    }
+    const data = await res.clone().json();
+    // 999 为特殊code码
+    const otherCode = [999, 5435, 5436];
+    if (
+      data.code !== 200 &&
+      data.errCode !== 0 &&
+      !otherCode.includes(data.code)
+    ) {
+      let msg = data.msg || data.message || '处理失败,请重试';
+      if (initRequest) {
+        // if (data.code === 403 || data.code === 5000) {
+        //   setLogout();
+        // } else {
+        //   setLoginError();
+        // }
+      }
+      if (!(data.code === 403 || data.code === 5000)) {
+        clearTimeout(toast);
+        setTimeout(() => {
+          showToast(msg);
+        }, 60);
+      }
+      // const browserInfo = browser();
+      if (data.code === 5000 || data.code === 403) {
+        msg += ' authentication ' + data.code;
+        // if (browserInfo.isApp) {
+        //   postMessage({
+        //     api: 'login'
+        //   });
+        // } else {
+        //   setLogout();
+        // }
+      }
+      throw new Error(msg);
+    }
+    return res;
+  },
+  { global: false }
+);
+
+export default request;

+ 204 - 0
src/helpers/utils.ts

@@ -0,0 +1,204 @@
+import numeral from 'numeral';
+import dayjs from 'dayjs';
+import qs from 'query-string';
+
+export const browser = () => {
+  const u = navigator.userAgent;
+  return {
+    trident: u.indexOf('Trident') > -1, //IE内核
+    presto: u.indexOf('Presto') > -1, //opera内核
+    webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
+    gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
+    mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
+    ios: !!u.match(/Mac OS X/), //ios终端
+    // ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
+    android: u.indexOf('COLEXIUSTUDENT') > -1 || u.indexOf('Adr') > -1, //android终端
+    iPhone: u.indexOf('COLEXIUAPPI') > -1, //是否为iPhone或者QQHD浏览器
+    isApp:
+      u.indexOf('COLEXIUAPPI') > -1 ||
+      u.indexOf('COLEXIUAPPA') > -1 ||
+      u.indexOf('Adr') > -1,
+    iPad: u.indexOf('iPad') > -1, //是否iPad
+    webApp: u.indexOf('Safari') == -1, //是否web应该程序,没有头部与底部
+    weixin: u.indexOf('MicroMessenger') > -1, //是否微信 (2015-01-22新增)
+    alipay: u.indexOf('AlipayClient') > -1, //是否支付宝
+    huawei: !!u.match(/huawei/i) || !!u.match(/honor/i),
+    xiaomi: !!u.match(/mi\s/i) || !!u.match(/redmi/i) || !!u.match(/mix/i)
+  };
+};
+
+// 获取授权的code码
+export const getUrlCode = (name = 'code') => {
+  // 截取url中的code方法
+  // const url = location.search;
+  // const theRequest: any = new Object();
+  // if (url.indexOf('?') != -1) {
+  //   const str = url.substr(1);
+  //   const strs = str.split('&');
+  //   for (let i = 0; i < strs.length; i++) {
+  //     theRequest[strs[i].split('=')[0]] = strs[i].split('=')[1];
+  //   }
+  // }
+  // console.log(theRequest, 'theRequest');
+  // return theRequest[name];
+  let search: any = {};
+  try {
+    search = {
+      ...qs.parse(location.search),
+      ...qs.parse(location.hash.split('?')[1])
+    };
+  } catch (error) {
+    //
+  }
+  return search[name];
+};
+
+export const getRandomKey = () => {
+  const key = '' + new Date().getTime() + Math.floor(Math.random() * 1000000);
+  return key;
+};
+
+export function checkPhone(phone: string) {
+  const phoneRule =
+    /^((13[0-9])|(14(0|[5-7]|9))|(15([0-3]|[5-9]))|(16(2|[5-7]))|(17[0-8])|(18[0-9])|(19([0-3]|[5-9])))\d{8}$/;
+  return phoneRule.test(phone);
+}
+
+/**
+ * @description 格式化日期控件显示内容
+ * @param type
+ * @param option
+ * @returns OBJECT
+ */
+export const formatterDatePicker = (type: any, option: any) => {
+  if (type === 'year') {
+    option.text += '年';
+  }
+  if (type === 'month') {
+    option.text += '月';
+  }
+  if (type === 'day') {
+    option.text += '日';
+  }
+  return option;
+};
+
+/**
+ * 数字转成汉字
+ * @params num === 要转换的数字
+ * @return 汉字
+ * */
+export const toChinesNum = (num: any) => {
+  const changeNum = [
+    '零',
+    '一',
+    '二',
+    '三',
+    '四',
+    '五',
+    '六',
+    '七',
+    '八',
+    '九'
+  ];
+  const unit = ['', '十', '百', '千', '万'];
+  num = parseInt(num);
+  const getWan = (temp: any) => {
+    const strArr = temp.toString().split('').reverse();
+    let newNum = '';
+    const newArr: string[] = [];
+    strArr.forEach((item: any, index: any) => {
+      newArr.unshift(
+        item === '0' ? changeNum[item] : changeNum[item] + unit[index]
+      );
+    });
+    const numArr: number[] = [];
+    newArr.forEach((m, n) => {
+      if (m !== '零') numArr.push(n);
+    });
+    if (newArr.length > 1) {
+      newArr.forEach((m, n) => {
+        if (newArr[newArr.length - 1] === '零') {
+          if (n <= numArr[numArr.length - 1]) {
+            newNum += m;
+          }
+        } else {
+          newNum += m;
+        }
+      });
+    } else {
+      newNum = newArr[0];
+    }
+
+    return newNum;
+  };
+  const overWan = Math.floor(num / 10000);
+  let noWan: any = num % 10000;
+  if (noWan.toString().length < 4) {
+    noWan = '0' + noWan;
+  }
+  return overWan ? getWan(overWan) + '万' + getWan(noWan) : getWan(num);
+};
+
+// 秒转分
+export const getSecondRPM = (second: number, type?: string) => {
+  if (isNaN(second)) return '00:00';
+  const mm = Math.floor(second / 60)
+    .toString()
+    .padStart(2, '0');
+  const dd = Math.floor(second % 60)
+    .toString()
+    .padStart(2, '0');
+  if (type === 'cn') {
+    return mm + '分' + dd + '秒';
+  } else {
+    return mm + ':' + dd;
+  }
+};
+
+export const getWeekCh = (week: number, type = 0) => {
+  const template = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
+  const template2 = [
+    '星期天',
+    '星期一',
+    '星期二',
+    '星期三',
+    '星期四',
+    '星期五',
+    '星期六'
+  ];
+  return type ? template2[week] : template[week];
+};
+
+export const getGradeCh = (grade: number) => {
+  const template = [
+    '一年级',
+    '二年级',
+    '三年级',
+    '四年级',
+    '五年级',
+    '六年级',
+    '七年级',
+    '八年级',
+    '九年级'
+  ];
+
+  return template[grade];
+};
+
+export const numberFormat = (num: number, type?: string) => {
+  if (type === 'percent') {
+    return numeral(num).format('0.0%');
+  }
+  return numeral(num).format('0,0');
+};
+
+export const moneyFormat = (value: number, format = '0,0.00') => {
+  return numeral(value).format(format);
+};
+export const dateFormat = (
+  value: string | Date,
+  format = 'YYYY-MM-DD HH:mm:ss'
+) => {
+  return dayjs(value).format(format);
+};

+ 1 - 0
src/main.ts

@@ -4,6 +4,7 @@ import dayjs from 'dayjs';
 import 'dayjs/locale/zh-cn';
 import { setupStore } from '@/stores';
 import 'vant/lib/index.css';
+import './component-ui/index.less';
 import './styles/index.less';
 import router from '@/router';
 

+ 43 - 6
src/router/index.ts

@@ -17,14 +17,51 @@ const router: Router = createRouter({
       meta: {
         title: '首页'
       }
+    },
+    {
+      path: '/colexiu-person',
+      name: 'colexiu-person',
+      component: () => import('@/views/colexiu-person'),
+      meta: {
+        title: '酷乐秀个人版'
+      }
+    },
+    {
+      path: '/colexiu-tenant',
+      name: 'colexiu-tenant',
+      component: () => import('@/views/colexiu-tenant'),
+      meta: {
+        title: '酷乐秀机构版'
+      }
+    },
+    {
+      path: '/cooperate-channels',
+      name: 'cooperate-channels',
+      component: () => import('@/views/cooperate-channels'),
+      meta: {
+        title: '合作渠道'
+      }
+    },
+    {
+      path: '/about-us',
+      name: 'about-us',
+      component: () => import('@/views/about-us'),
+      meta: {
+        title: '关于我们'
+      }
     }
   ],
-  scrollBehavior(to) {
-    if (to.hash) {
-      return {
-        el: to.hash,
-        behavior: 'smooth'
-      };
+  scrollBehavior(to, form, savedPosition) {
+    // if (to.hash) {
+    //   return {
+    //     el: to.hash,
+    //     behavior: 'smooth'
+    //   };
+    // }
+    if (savedPosition) {
+      return savedPosition;
+    } else {
+      return { left: 0, top: 0 };
     }
   }
 });

+ 2 - 0
src/shims-vue.d.ts

@@ -3,3 +3,5 @@ declare module '*.vue' {
   const component: DefineComponent<{}, {}, any>;
   export default component;
 }
+
+declare module 'numeral';

+ 2 - 0
src/styles/index.less

@@ -22,6 +22,8 @@ textarea {
   margin: 0;
   border: 0;
   box-sizing: border-box;
+  -webkit-touch-callout: none;
+  user-select: none;
 }
 
 #app {

二进制
src/views/about-us/images/banner.png


二进制
src/views/about-us/images/img1.png


二进制
src/views/about-us/images/img2.png


二进制
src/views/about-us/images/title-1.png


+ 75 - 0
src/views/about-us/index.module.less

@@ -0,0 +1,75 @@
+.banner {
+  width: 100%;
+  min-height: 381px;
+  line-height: 0;
+
+  .bannerImg {
+    width: 100%;
+    min-height: 381px;
+    object-fit: cover;
+  }
+}
+
+.title {
+  position: relative;
+  text-align: center;
+  font-size: 22px;
+  font-weight: 600;
+  color: #000000;
+  line-height: 30px;
+  letter-spacing: 1px;
+
+  span {
+    position: relative;
+    z-index: 9;
+
+    &::before {
+      content: '';
+      position: absolute;
+      bottom: -6px;
+      right: -15px;
+      width: 111px;
+      height: 39px;
+      background: url('./images/title-1.png') no-repeat center;
+      background-size: contain;
+      z-index: -1;
+    }
+  }
+}
+
+.content {
+  padding: 8px 24px 0;
+  font-size: 14px;
+  color: #3E635E;
+  line-height: 24px;
+}
+
+.section1 {
+  padding: 30px 0;
+  background-color: #fff;
+
+  img {
+    padding: 35px 0 22px;
+  }
+
+  .content {
+    padding: 0 17px 0;
+    font-size: 12px;
+    color: #50616A;
+    line-height: 21px;
+
+    p {
+      text-indent: 2em;
+    }
+  }
+}
+
+.section2 {
+  padding: 27px 0 18px;
+  // background-color: #fff;
+  background: linear-gradient(180deg, #EDFDFF 0%, #FFFFFF 21%, #FFFFFF 88%, #DDF0F2 100%);
+
+  img {
+    padding-top: 19px;
+  }
+}

+ 49 - 0
src/views/about-us/index.tsx

@@ -0,0 +1,49 @@
+import { defineComponent } from 'vue';
+import styles from './index.module.less';
+import banner from './images/banner.png';
+import MHeader from '@/components/m-header';
+import MFooter from '@/components/m-footer';
+
+import img1 from './images/img1.png';
+import img2 from './images/img2.png';
+
+export default defineComponent({
+  name: 'about-us',
+  setup() {
+    return () => (
+      <div class={styles.aboutUs}>
+        <MHeader />
+
+        <div class={styles.banner}>
+          <img class={styles.bannerImg} src={banner} />
+        </div>
+
+        <div class={styles.section1}>
+          <div class={[styles.title]}>
+            <span>关于酷乐秀</span>
+          </div>
+
+          <img src={img1} class="w100" />
+          <div class={styles.content}>
+            <p>
+              我们是一家专注于音乐教育创新的企业,深度融合新技术,为广大音乐爱好者和机构、学校提供高质量的音乐教育服务。
+            </p>
+            <p>
+              未来数字化音乐教学将更加注重与人工智能、虚拟现实等新技术的深度融合,为音乐教学提供更加智能化、个性化的解决方案。我们深知数字化音乐课堂的重要性,因此积极布局数字化教育领域,现已拥有一系列成熟的音乐教学软件、教学团队及硬件供应链,助力音乐教育迈向新高峰。
+            </p>
+          </div>
+        </div>
+
+        <div class={styles.section2}>
+          <div class={[styles.title]}>
+            <span>选择我们你将得到</span>
+          </div>
+
+          <img src={img2} class="w100" />
+        </div>
+
+        <MFooter />
+      </div>
+    );
+  }
+});

二进制
src/views/colexiu-person/images/banner.png


二进制
src/views/colexiu-person/images/img-1-1.png


二进制
src/views/colexiu-person/images/img-1-2.png


二进制
src/views/colexiu-person/images/img-1-3.png


二进制
src/views/colexiu-person/images/img-1-4.png


二进制
src/views/colexiu-person/images/img-2-1.png


二进制
src/views/colexiu-person/images/img-2-2.png


二进制
src/views/colexiu-person/images/img-2-3.png


二进制
src/views/colexiu-person/images/img-2-4.png


二进制
src/views/colexiu-person/images/img-bg.png


二进制
src/views/colexiu-person/images/img1.png


二进制
src/views/colexiu-person/images/title-1.png


+ 188 - 0
src/views/colexiu-person/index.module.less

@@ -0,0 +1,188 @@
+.banner {
+  width: 100%;
+  min-height: 381px;
+  line-height: 0;
+
+  .bannerImg {
+    width: 100%;
+    min-height: 381px;
+    object-fit: cover;
+  }
+}
+
+.tabGroup {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  z-index: 99;
+
+  span {
+    display: block;
+    width: 107px;
+    line-height: 27px;
+    background: #FFFFFF;
+    border-radius: 15px;
+    border: 2px solid #D7F8EF;
+    font-size: 14px;
+    font-weight: 500;
+    color: #000000;
+    text-align: center;
+    margin: 0 8px;
+
+    &.active {
+      color: #FFFFFF;
+      background: #07B1B2 linear-gradient(124deg, #0E86A0 0%, #03C5BA 100%);
+
+    }
+  }
+}
+
+.title {
+  position: relative;
+  text-align: center;
+  font-size: 16px;
+  font-weight: 600;
+  color: #000000;
+  line-height: 23px;
+
+  span {
+    position: relative;
+    z-index: 9;
+
+    &::before {
+      content: '';
+      position: absolute;
+      top: 4px;
+      left: 50%;
+      width: 55px;
+      height: 12px;
+      transform: translate(-50%);
+      background: url('./images/title-1.png') no-repeat center;
+      background-size: contain;
+      z-index: -1;
+    }
+  }
+}
+
+.content {
+  padding: 8px 24px 0;
+  font-size: 14px;
+  color: #3E635E;
+  line-height: 24px;
+}
+
+.sectionBg::before {
+  content: '';
+  position: absolute;
+  top: 7px;
+  left: 0;
+  right: 0;
+  min-height: 241px;
+  background: url('./images/img-bg.png') no-repeat top center;
+  background-size: contain;
+}
+
+.section1 {
+  background: #fff;
+  padding: 30px 25px 34px;
+}
+
+
+.section2 {
+  position: relative;
+  padding: 32px 0 25px;
+  background: linear-gradient(137deg, #CEF9FF 0%, #E3F3F2 21%, #EDFFEA 35%, #EAFCEA 52%, #DEF2EB 74%, #F3FFEC 100%);
+
+  .content {
+    padding-top: 11px;
+  }
+
+  .loveImg img {
+    padding: 30px 68px 13px
+  }
+
+  .musicImg img {
+    padding: 36px 36px 12px
+  }
+}
+
+.section3 {
+  padding: 56px 0 40px;
+  background: #fff;
+  position: relative;
+
+  &.sectionBg::before {
+    top: 53px;
+  }
+
+  img {
+    position: relative;
+    padding: 0 44px;
+  }
+}
+
+.section4 {
+  padding: 52px 0 48px;
+  background: linear-gradient(180deg, #E4F3F5 0%, #DDF2E9 100%), linear-gradient(137deg, #CEF9FF 0%, #E3F3F2 21%, #EDFFEA 35%, #EAFCEA 52%, #DEF2EB 74%, #F3FFEC 100%);
+  position: relative;
+
+  &.sectionBg::before {
+    top: 11px;
+  }
+
+  img {
+    position: relative;
+    padding: 0 15px;
+  }
+}
+
+.section5 {
+  padding: 80px 0 48px;
+  background: #fff;
+  position: relative;
+
+  &.sectionBg::before {
+    top: 54px;
+  }
+
+  img {
+    position: relative;
+    padding: 0 57px 0 59px;
+  }
+}
+
+.sectionMusic {
+  .section3 {
+    padding: 54px 0 34px;
+
+    &.sectionBg::before {
+      top: 50px;
+    }
+
+    img {
+      padding: 0 36px;
+    }
+  }
+
+  .section4 {
+    padding: 65px 0 32px;
+
+    img {
+      padding: 0 16px;
+    }
+  }
+
+  .section5 {
+    padding: 57px 0 54px;
+
+
+    &.sectionBg::before {
+      top: 28px;
+    }
+
+    img {
+      padding: 0 24px;
+    }
+  }
+}

+ 149 - 0
src/views/colexiu-person/index.tsx

@@ -0,0 +1,149 @@
+import { defineComponent, ref } from 'vue';
+import styles from './index.module.less';
+import MHeader from '@/components/m-header';
+import banner from './images/banner.png';
+import img1 from './images/img1.png';
+import img11 from './images/img-1-1.png';
+import img12 from './images/img-1-2.png';
+import img13 from './images/img-1-3.png';
+import img14 from './images/img-1-4.png';
+import img21 from './images/img-2-1.png';
+import img22 from './images/img-2-2.png';
+import img23 from './images/img-2-3.png';
+import img24 from './images/img-2-4.png';
+import MFooter from '@/components/m-footer';
+
+export default defineComponent({
+  name: 'colexiu-person',
+  setup() {
+    const activeTab = ref<'love' | 'music'>('love');
+    return () => (
+      <div class={styles.person}>
+        <MHeader />
+
+        <div class={styles.banner}>
+          <img class={styles.bannerImg} src={banner} />
+        </div>
+
+        <div class={styles.section1}>
+          <img src={img1} class="w100" />
+        </div>
+
+        <div class={[styles.section2, styles.sectionBg]}>
+          <div class={styles.tabGroup}>
+            <span
+              onClick={() => (activeTab.value = 'love')}
+              class={[activeTab.value === 'love' && styles.active]}>
+              器乐爱好者
+            </span>
+            <span
+              onClick={() => (activeTab.value = 'music')}
+              class={[activeTab.value === 'music' && styles.active]}>
+              音乐达人
+            </span>
+          </div>
+
+          <div
+            class={styles.loveImg}
+            style={{ display: activeTab.value === 'love' ? 'block' : 'none' }}>
+            <img src={img11} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>找寻你感兴趣的乐曲</span>
+            </div>
+            <div class={styles.content}>
+              音乐达人提供不同级别、不同风格的海量乐谱,让您轻松打破练习路上最大阻碍,更让你能找到音乐道路上志同道合的朋友。
+            </div>
+          </div>
+
+          <div
+            class={styles.musicImg}
+            style={{ display: activeTab.value === 'music' ? 'block' : 'none' }}>
+            <img src={img21} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>曲目分享</span>
+            </div>
+            <div class={styles.content}>
+              还在为自己创作的乐谱无人问津而苦恼吗?还在为自己的才华无处展示而失落吗?酷乐秀音乐分享平台就是你的归处,让你的创作才能得到同好的认可,用你的编曲技巧折服演奏者。
+            </div>
+          </div>
+        </div>
+
+        <div style={{ display: activeTab.value === 'love' ? 'block' : 'none' }}>
+          <div class={[styles.section3, styles.sectionBg]}>
+            <img src={img12} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>寻求导师</span>
+            </div>
+            <div class={styles.content}>
+              在器乐练习的路上难免遇到困难,平台中有着许多乐器上钻研多年的演奏高手,让他们帮助你克服困难,学习更多演奏知识。
+            </div>
+          </div>
+
+          <div class={[styles.section4, styles.sectionBg]}>
+            <img src={img13} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>全方位的视频教学</span>
+            </div>
+            <div class={styles.content}>
+              各种声部不同程度的教学视频、达人演奏经验分享,让您在练习途中更快的迈过困难。
+            </div>
+          </div>
+
+          <div class={[styles.section5, styles.sectionBg]}>
+            <img src={img14} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>练习分享</span>
+            </div>
+            <div class={styles.content}>
+              将你得意的演奏成果分享给跟众多同好,大家一起沟通、一起交流,在友好的演奏、分享氛围中不断的精进自己的演奏技艺。
+            </div>
+          </div>
+        </div>
+
+        <div
+          class={styles.sectionMusic}
+          style={{ display: activeTab.value === 'music' ? 'block' : 'none' }}>
+          <div class={[styles.section3, styles.sectionBg]}>
+            <img src={img22} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>邀约学生</span>
+            </div>
+            <div class={styles.content}>
+              酷乐秀音乐分享平台集合了众多在乐器练习中不得要领的苦行僧,他们需要你的点拨,将你的毕生所学传授下去,让他们也能成长未一个器乐演奏达人。
+            </div>
+          </div>
+
+          <div class={[styles.section4, styles.sectionBg]}>
+            <img src={img23} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>线上授课</span>
+            </div>
+            <div class={styles.content}>
+              只需一部手机,一个良好的网络环境,您便可以将自己的技艺传授给别人,通过云酷琴房、直播秀场让更多的学习者沾染你的演奏精髓。
+            </div>
+          </div>
+
+          <div class={[styles.section5, styles.sectionBg]}>
+            <img src={img24} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>风采展示</span>
+            </div>
+            <div class={styles.content}>
+              你有一肚子的演奏心得无处传播?你的得意的演奏技巧无法展示?在这里分享你的演奏心得,展示你的演奏技巧,让更多的器乐爱好者得到你的指点,将你的才能传播得更加广阔
+            </div>
+          </div>
+        </div>
+
+        <MFooter />
+      </div>
+    );
+  }
+});

二进制
src/views/colexiu-tenant/images/banner.png


二进制
src/views/colexiu-tenant/images/img1.png


二进制
src/views/colexiu-tenant/images/img2-1.png


二进制
src/views/colexiu-tenant/images/img2-2.png


二进制
src/views/colexiu-tenant/images/img2-3.png


二进制
src/views/colexiu-tenant/images/img2-4-bg.png


二进制
src/views/colexiu-tenant/images/img3-1.png


二进制
src/views/colexiu-tenant/images/img3-2.png


二进制
src/views/colexiu-tenant/images/img3-3.png


二进制
src/views/colexiu-tenant/images/img3-4.png


二进制
src/views/colexiu-tenant/images/point-bg.png


二进制
src/views/colexiu-tenant/images/qrcode-bg.png


二进制
src/views/colexiu-tenant/images/title-1.png


二进制
src/views/colexiu-tenant/images/title-img.png


+ 268 - 0
src/views/colexiu-tenant/index.module.less

@@ -0,0 +1,268 @@
+.banner {
+  width: 100%;
+  min-height: 381px;
+  line-height: 0;
+
+  .bannerImg {
+    width: 100%;
+    min-height: 381px;
+    object-fit: cover;
+  }
+}
+
+.title {
+  position: relative;
+  text-align: center;
+  font-size: 16px;
+  font-weight: 600;
+  color: #000000;
+  line-height: 30px;
+  letter-spacing: 1px;
+
+  span {
+    position: relative;
+    z-index: 9;
+
+    &::before {
+      content: '';
+      position: absolute;
+      top: -3px;
+      left: -12px;
+      width: 18px;
+      height: 18px;
+      background: url('./images/title-1.png') no-repeat center;
+      background-size: contain;
+      z-index: -1;
+    }
+  }
+}
+
+
+.tabGroup {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  z-index: 99;
+
+  span {
+    display: block;
+    width: 117px;
+    line-height: 27px;
+    background: #FFFFFF;
+    border-radius: 15px;
+    border: 2px solid #FFEEF8;
+    font-size: 14px;
+    font-weight: 500;
+    color: #000000;
+    text-align: center;
+    margin: 0 6px;
+
+    &.active {
+      color: #FFFFFF;
+      background: linear-gradient(270deg, #FF3C81 0%, #FF76A6 100%);
+
+    }
+  }
+}
+
+.sectionBg::before {
+  content: '';
+  position: absolute;
+  top: 7px;
+  left: 0;
+  right: 0;
+  display: inline-block;
+  min-height: 241px;
+  background: url('./images/point-bg.png') no-repeat top center;
+  background-size: contain;
+}
+
+.content {
+  padding: 8px 24px 0;
+  font-size: 13px;
+  color: #3E635E;
+  line-height: 24px;
+}
+
+.section1 {
+  background: #fff;
+  padding: 30px 0 40px;
+
+  .content {
+    padding: 10px 0 26px;
+    color: #7C647C;
+    font-size: 13px;
+    text-align: center;
+  }
+
+  img {
+    padding: 0 20px;
+  }
+}
+
+.section2 {
+  position: relative;
+  padding: 31px 0 23px;
+  background: linear-gradient(180deg, #FFEBED 0%, #FAF8F8 9%, #FFF7F8 59%, #FFEAEC 100%);
+
+  &.sectionBg::before {
+    top: 31px;
+  }
+
+  .content {
+    padding-top: 11px;
+  }
+
+  .loveImg img {
+    // padding: 30px 68px 13px
+  }
+
+  .musicImg img {
+    padding: 36px 36px 12px;
+  }
+}
+
+.section3 {
+  position: relative;
+  padding: 40px 24px;
+  background-color: #fff;
+
+
+  &.sectionBg::before {
+    top: -16px;
+  }
+
+  img {
+    position: relative;
+    padding-bottom: 26px;
+  }
+
+  .content {
+    padding: 0;
+    color: #7C647C;
+  }
+}
+
+
+.section4 {
+  position: relative;
+  padding: 26px 0 33px;
+  background: linear-gradient(180deg, #FFEBED 0%, #FAF8F8 9%, #FFF7F8 59%, #FFEAEC 100%);
+
+
+  &.sectionBg::before {
+    top: -16px;
+  }
+
+  img {
+    position: relative;
+    padding: 0 40px 21px;
+  }
+
+  .content {
+    padding: 0 31px;
+    color: #7C647C;
+  }
+}
+
+.section6 {
+  padding: 31px 0 23px;
+  background: url('./images/img2-4-bg.png') no-repeat top center;
+  background-size: cover;
+
+  .title6 {
+    font-size: 19px;
+    font-weight: 600;
+    color: #000000;
+    line-height: 32px;
+    text-align: center;
+
+    span {
+      color: #FE3E64;
+    }
+  }
+
+  .content {
+    font-size: 12px;
+    color: #7C647C;
+    text-align: center;
+    padding: 10px 0 22px;
+  }
+}
+
+.section7 {
+  padding: 23px 0 35px;
+  background-color: #fff;
+
+  .title7 {
+    width: 251px;
+    height: 35px;
+    background: url('./images/title-img.png') no-repeat center;
+    background-size: contain;
+    margin: 0 auto;
+  }
+
+  .content {
+    padding: 24px 0 21px;
+    text-align: center;
+    font-size: 14px;
+    color: #7C647C;
+    line-height: 26px;
+  }
+
+  .qrcode {
+    text-align: center;
+
+    img {
+      width: 112px;
+      height: 112px;
+    }
+
+    p {
+      font-size: 12px;
+      color: #7C647C;
+      line-height: 26px;
+    }
+  }
+}
+
+.sectionJuvenile {
+  .section3 {
+    padding: 33px 0 40px;
+
+    img {
+      padding: 0 60px 10px;
+    }
+
+    .content {
+      padding: 10px 24px 0;
+    }
+  }
+
+  .section4 {
+    padding: 16px 0 30px;
+    background: linear-gradient(180deg, #FFEBED 0%, #FAF8F8 9%, #FFF7F8 59%, #FFEAEC 100%);
+
+    img {
+      padding: 0 52px 20px;
+    }
+
+    .content {
+      padding: 10px 24px 0;
+    }
+  }
+
+  .section5 {
+    padding: 30px 0 40px;
+    background: #fff;
+
+    img {
+      padding: 0 48px 10px;
+    }
+
+    .content {
+      padding: 10px 24px 0;
+    }
+  }
+}

+ 159 - 0
src/views/colexiu-tenant/index.tsx

@@ -0,0 +1,159 @@
+import { defineComponent, ref } from 'vue';
+import styles from './index.module.less';
+import banner from './images/banner.png';
+import MHeader from '@/components/m-header';
+import MFooter from '@/components/m-footer';
+import img1 from './images/img1.png';
+import img21 from './images/img2-1.png';
+import img22 from './images/img2-2.png';
+import img23 from './images/img2-3.png';
+import qrcode from './images/qrcode-bg.png';
+import TheSubmit from '@/components/the-submit';
+import img31 from './images/img3-1.png';
+import img32 from './images/img3-2.png';
+import img33 from './images/img3-3.png';
+import img34 from './images/img3-4.png';
+
+export default defineComponent({
+  name: 'about-us',
+  setup() {
+    const activeTab = ref<'trade' | 'juvenile'>('trade');
+    return () => (
+      <div class={styles.aboutUs}>
+        <MHeader />
+
+        <div class={styles.banner}>
+          <img class={styles.bannerImg} src={banner} />
+        </div>
+
+        <div class={[styles.section1]}>
+          <div class={[styles.title]}>
+            <span>美育培训解决方案</span>
+          </div>
+          <div class={styles.content}>器乐 学 / 练 / 评 / 管 / 演 一步到位</div>
+
+          <img class="w100" src={img1} />
+        </div>
+
+        <div class={[styles.section2, styles.sectionBg]}>
+          <div class={styles.tabGroup}>
+            <span
+              onClick={() => (activeTab.value = 'trade')}
+              class={[activeTab.value === 'trade' && styles.active]}>
+              管乐团曲目训练
+            </span>
+            <span
+              onClick={() => (activeTab.value = 'juvenile')}
+              class={[activeTab.value === 'juvenile' && styles.active]}>
+              少儿美育培训
+            </span>
+          </div>
+
+          <div
+            class={styles.loveImg}
+            style={{ display: activeTab.value === 'trade' ? 'block' : 'none' }}>
+            <img src={img21} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>解决音乐课堂数字化问题</span>
+            </div>
+            <div class={styles.content}>
+              利用小酷AI的合奏曲谱将总谱分给各个声部的演奏者,让
+              他们单独练习自己的部分。练习过程统一各声部的练习进
+              度和标准;以便后续在合排的基础上,对曲目进行细化练 习.
+            </div>
+          </div>
+
+          <div
+            class={styles.musicImg}
+            style={{
+              display: activeTab.value === 'juvenile' ? 'block' : 'none'
+            }}>
+            <img src={img31} class="w100" />
+
+            <div class={[styles.title]}>
+              <span>解决新课标器乐进课堂问题</span>
+            </div>
+            <div class={styles.content}>
+              我国政府高度重视青少年美育工作,提倡通过多元化的教育方式培养学生的审美情趣和艺术素养。在此背景下,美育培训应运而生,成为一种注重培养学生全面发展的新型教育模式。
+            </div>
+          </div>
+        </div>
+
+        <div
+          style={{ display: activeTab.value === 'trade' ? 'block' : 'none' }}>
+          <div class={[styles.section3, styles.sectionBg]}>
+            <img class="w100" src={img22} />
+            <div class={styles.content}>
+              同时,注意乐团的整体平衡,确保各个声部之间协调-致;在细化练习的基础上,让乐团从起始点到结束连续演奏整个曲目。在合排过程中,团员需要掌握曲目中的难点,提高演奏的流畅性。
+            </div>
+          </div>
+          <div class={[styles.section4, styles.sectionBg]}>
+            <img class="w100" src={img23} />
+            <div class={styles.content}>
+              针对演奏中出现的问题,进行反复练习。练习模式让团员跟随动态乐谱和伴奏重叠起来的效果会给团员有即时表演的乐趣和身处乐团中震撼力,审美得到立体、全面的熏陶。
+            </div>
+          </div>
+        </div>
+        <div
+          class={[styles.sectionJuvenile]}
+          style={{
+            display: activeTab.value === 'juvenile' ? 'block' : 'none'
+          }}>
+          <div class={[styles.section3, styles.sectionBg]}>
+            <img class="w100" src={img32} />
+            <div class={[styles.title]}>
+              <span>基本乐理</span>
+            </div>
+            <div class={styles.content}>
+              学习音乐的基本知识,包括音符、节拍、音高、音程、和声等。了解音乐的基本构成,为后续学习作曲和编曲打下基础。
+            </div>
+          </div>
+          <div class={[styles.section4, styles.sectionBg]}>
+            <img class="w100" src={img33} />
+
+            <div class={[styles.title]}>
+              <span>视唱练耳</span>
+            </div>
+            <div class={styles.content}>
+              通过听音乐、分析音乐、演唱音乐等方式,提高学员的音准、节奏感和音乐感知能力。视唱练耳训练可以帮助学员更好地理解和把握音乐作品。
+            </div>
+          </div>
+          <div class={[styles.section5, styles.sectionBg]}>
+            <img class="w100" src={img34} />
+            <div class={[styles.title]}>
+              <span>乐器演奏</span>
+            </div>
+            <div class={styles.content}>
+              学习一门或多门乐器,如钢琴、吉他、小提琴等。通过乐器演奏,培养学员的音乐表现力和创作能力。
+            </div>
+          </div>
+        </div>
+
+        <div class={styles.section6}>
+          <div class={[styles.title6]}>
+            <span>提交</span>合作信息
+          </div>
+
+          <div class={styles.content}>我们将在提交后尽快与您取得联系</div>
+
+          <TheSubmit type="tenant" />
+        </div>
+
+        <div class={styles.section7}>
+          <div class={[styles.title7]}></div>
+
+          <div class={styles.content}>
+            咨询热线:18186104867 <br /> 周一至周五 09:00~21:00
+          </div>
+          <div class={styles.qrcode}>
+            <img src={qrcode} />
+            <p>扫一扫添加微信好友</p>
+          </div>
+        </div>
+
+        <MFooter />
+      </div>
+    );
+  }
+});

二进制
src/views/cooperate-channels/images/banner-center.png


二进制
src/views/cooperate-channels/images/banner.png


二进制
src/views/cooperate-channels/images/btn-bg.png


二进制
src/views/cooperate-channels/images/img1-bg.png


二进制
src/views/cooperate-channels/images/img1.png


二进制
src/views/cooperate-channels/images/img2-bg.png


二进制
src/views/cooperate-channels/images/img2.png


二进制
src/views/cooperate-channels/images/title-1.png


二进制
src/views/cooperate-channels/images/title-2.png


二进制
src/views/cooperate-channels/images/title-3.png


二进制
src/views/cooperate-channels/images/title-4.png


+ 182 - 0
src/views/cooperate-channels/index.module.less

@@ -0,0 +1,182 @@
+@keyframes move-top {
+  0% {
+    transform: translateY(0);
+  }
+
+  50% {
+    transform: translateY(10px);
+  }
+
+  100% {
+    transform: translateY(0px);
+  }
+}
+
+.banner {
+  width: 100%;
+  min-height: 381px;
+  background-color: #fff;
+  position: relative;
+  line-height: 0;
+
+  .bannerImg {
+    width: 100%;
+    min-height: 381px;
+    object-fit: cover;
+  }
+
+  .bannerCenter {
+    position: absolute;
+    top: 114px;
+    left: 42px;
+    width: 291px;
+    height: 312px;
+    animation: move-top 1.6s infinite ease-in-out;
+  }
+}
+
+.title {
+  position: relative;
+  margin: 0 auto;
+  width: 156px;
+  height: 47px
+}
+
+.content {
+  padding: 8px 24px 0;
+  font-size: 14px;
+  color: #3E635E;
+  line-height: 24px;
+}
+
+.section1 {
+  padding: 31px 24px 60px;
+  background: #fff;
+
+  .title1 {
+    background: url('./images/title-1.png') no-repeat center;
+    background-size: contain;
+  }
+
+  .content {
+    padding: 18px 0 0;
+    font-size: 14px;
+    color: #333333;
+    line-height: 24px;
+
+    p {
+      text-indent: 2em;
+    }
+
+    .green {
+      color: #00C46F
+    }
+  }
+}
+
+.section2 {
+  padding: 40px 0 48px;
+  background: url('./images/img1-bg.png') no-repeat top center;
+  background-size: cover;
+
+  .title2 {
+    background: url('./images/title-2.png') no-repeat center;
+    background-size: contain;
+  }
+
+  img {
+    padding-top: 24px;
+  }
+}
+
+.section3 {
+  padding: 40px 0 47px;
+  background-color: #fff;
+
+  .title3 {
+    background: url('./images/title-3.png') no-repeat center;
+    background-size: contain;
+  }
+
+  img {
+    padding-top: 15px;
+  }
+}
+
+.section4 {
+  padding: 40px 0 56px;
+  background: url('./images/img2-bg.png') no-repeat top center;
+  background-size: cover;
+
+  .title4 {
+    width: 188px;
+    background: url('./images/title-4.png') no-repeat center;
+    background-size: contain;
+  }
+
+}
+
+.fieldGroup {
+  padding: 40px 24px 0;
+
+  .fieldTips {
+    text-align: center;
+    padding: 4px 0 18px;
+    color: rgba(0, 0, 0, .34);
+    font-size: 14px;
+  }
+
+  :global {
+    .van-field {
+      margin-bottom: 16px;
+      border-radius: 7px;
+      padding: 11px 14px;
+      font-size: 16px;
+    }
+
+    .van-field__control::placeholder {
+      color: #AAAAAA;
+    }
+
+    .van-cell__right-icon {
+      color: #D8D8D8;
+    }
+  }
+
+  .smsField {
+    padding: 4px 4px 4px 14px;
+
+    :global {
+      .van-button {
+        width: 88px;
+        line-height: 36px;
+        background: linear-gradient(224deg, #ABF172 0%, #53E6A3 100%);
+        font-size: 15px;
+        font-weight: 500;
+        border: none;
+      }
+
+      .van-count-down {
+        width: 88px;
+        line-height: 36px;
+        background: #ECECEC;
+        border-radius: 7px;
+        font-size: 15px;
+        font-weight: 500;
+        text-align: center;
+      }
+    }
+  }
+
+  .btnSubmit {
+    width: 327px;
+    height: 50px;
+    background: url('./images/btn-bg.png') no-repeat center;
+    background-size: contain;
+    font-size: 18px;
+    font-weight: 600;
+    color: #131415;
+    border: none;
+    padding: 0;
+  }
+}

+ 132 - 0
src/views/cooperate-channels/index.tsx

@@ -0,0 +1,132 @@
+import { defineComponent, reactive, ref } from 'vue';
+import styles from './index.module.less';
+import banner from './images/banner.png';
+import bannerCenter from './images/banner-center.png';
+import MHeader from '@/components/m-header';
+import MFooter from '@/components/m-footer';
+import img1 from './images/img1.png';
+import img2 from './images/img2.png';
+import { Button, CountDown, Field } from 'vant';
+
+export default defineComponent({
+  name: 'about-us',
+  setup() {
+    const countDownRef = ref();
+    const state = reactive({
+      countDownTime: 60 * 1000,
+      countDownStatus: true
+    });
+
+    //
+    const onFinished = () => {
+      //
+    };
+
+    return () => (
+      <div class={styles.aboutUs}>
+        <MHeader />
+
+        <div class={styles.banner}>
+          <img class={styles.bannerImg} src={banner} />
+
+          <img class={styles.bannerCenter} src={bannerCenter} />
+        </div>
+
+        <div class={styles.section1}>
+          <div class={[styles.title, styles.title1]}></div>
+          <div class={styles.content}>
+            <p>
+              在科技飞速发展的当下,音乐教育也在不断地创新与变革。为了更好地推进音乐课堂的数字化转型,提高音乐教育质量。化繁为简、化难为易,提高学生的兴趣和参与度。将更加注重线上线下相结合,
+              <span class={styles.green}>
+                提供多元化的教学模式,满足学生多样化的学习需求
+              </span>
+            </p>
+            <p>
+              同时器乐教学对学生具有重要的意义,不仅有助于提高音乐素养和协调能力,还可以培养个性、团队合作意识等。学习乐器丰富学生的情感体验,拓展就业和升学途径,传承民族文化。
+            </p>
+            <p class={styles.green}>
+              我们特此发起寻找数字化音乐课堂合作伙伴,诚邀您的加入!
+            </p>
+          </div>
+        </div>
+
+        <div class={styles.section2}>
+          <div class={[styles.title, styles.title2]}></div>
+
+          <img class={'w100'} src={img1} />
+        </div>
+
+        <div class={styles.section3}>
+          <div class={[styles.title, styles.title3]}></div>
+
+          <img class={'w100'} src={img2} />
+        </div>
+
+        <div class={styles.section4}>
+          <div class={[styles.title, styles.title4]}></div>
+
+          <div class={styles.fieldGroup}>
+            <Field
+              readonly
+              isLink
+              arrowDirection="down"
+              placeholder="机构性质"
+              border={false}
+              autocomplete="off"
+            />
+
+            <Field
+              type="text"
+              border={false}
+              placeholder="机构名称"
+              autocomplete="off"
+            />
+            <Field
+              type="text"
+              border={false}
+              placeholder="联系人"
+              autocomplete="off"
+            />
+            <Field
+              type="number"
+              maxlength={11}
+              border={false}
+              placeholder="联系电话"
+              autocomplete="off"
+            />
+            <Field
+              class={styles.smsField}
+              type="number"
+              maxlength={6}
+              border={false}
+              placeholder="短信验证码"
+              autocomplete="off">
+              {{
+                button: () =>
+                  state.countDownStatus ? (
+                    <Button size="small">发送短信</Button>
+                  ) : (
+                    <CountDown
+                      ref={(el: any) => (countDownRef.value = el)}
+                      auto-start={false}
+                      time={state.countDownTime}
+                      onFinish={onFinished}
+                      format="ss秒"
+                    />
+                  )
+              }}
+            </Field>
+
+            <p class={styles.fieldTips}>我们将在提交后尽快与您联系</p>
+
+            <Button block round class={styles.btnSubmit}>
+              确认提交
+            </Button>
+          </div>
+        </div>
+
+        <MFooter />
+      </div>
+    );
+  }
+});

+ 3 - 2
src/views/home/index.module.less

@@ -1,10 +1,11 @@
 .banner {
   width: 100%;
-  height: 422px;
+  min-height: 422px;
+  line-height: 0;
 
   .bannerImg {
     width: 100%;
-    height: 422px;
+    min-height: 422px;
     object-fit: cover;
     transition: all 0.2s ease-in-out;
   }

+ 1 - 1
src/views/home/index.tsx

@@ -18,7 +18,7 @@ export default defineComponent({
   name: 'home-page',
   setup() {
     const state = reactive({
-      activeTab: 4,
+      activeTab: 1,
       banner: aiBanner
     });
     return () => (

+ 8 - 7
vite.config.ts

@@ -13,6 +13,7 @@ function resolve(dir: string) {
 }
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
+const proxyUrl = 'https://dev.colexiu.com';
 export default defineConfig({
   base: './',
   plugins: [
@@ -65,12 +66,12 @@ export default defineConfig({
     port: 9005,
     strictPort: true,
     cors: true,
-    https: false
-    // proxy: {
-    //   '/edu-app': {
-    //     target: proxyUrl,
-    //     changeOrigin: true
-    //   }
-    // }
+    https: false,
+    proxy: {
+      '/api-student': {
+        target: proxyUrl,
+        changeOrigin: true
+      }
+    }
   }
 });