Selaa lähdekoodia

物联网平台web端 初次上传

1037015548@qq.com 1 vuosi sitten
vanhempi
commit
cf84f8824f
100 muutettua tiedostoa jossa 20685 lisäystä ja 0 poistoa
  1. 4 0
      .browserslistrc
  2. 1 0
      .dockerignore
  3. 6 0
      .eslintignore
  4. 89 0
      .eslintrc.js
  5. 27 0
      .gitignore
  6. 23 0
      .prettierrc.js
  7. 29 0
      Dockerfile
  8. 201 0
      LICENSE
  9. 31 0
      Makefile
  10. 9 0
      auto-imports.d.ts
  11. 19 0
      babel.config.js
  12. 31 0
      dc3.code-workspace
  13. 25 0
      dc3/bin/deploy.sh
  14. 56 0
      dc3/bin/tag.sh
  15. 24 0
      dc3/dependencies/README.md
  16. 14 0
      dc3/dependencies/conf.crt/dc3.site/README
  17. 31 0
      dc3/dependencies/conf.crt/dc3.site/cert.pem
  18. 27 0
      dc3/dependencies/conf.crt/dc3.site/chain.pem
  19. 58 0
      dc3/dependencies/conf.crt/dc3.site/fullchain.pem
  20. 28 0
      dc3/dependencies/conf.crt/dc3.site/privkey.pem
  21. 31 0
      dc3/docker-compose.yml
  22. 25 0
      dc3/nginx/conf.d/default.conf
  23. 13 0
      dc3/nginx/location/default.conf
  24. 13 0
      dc3/nginx/location/default.env
  25. 34 0
      dc3/nginx/nginx.conf
  26. 59 0
      index.html
  27. 14861 0
      package-lock.json
  28. 71 0
      package.json
  29. 7 0
      public/css/animate/animate.min.css
  30. 14 0
      public/css/index/index.min.css
  31. BIN
      public/favicon.ico
  32. BIN
      public/images/app/app1.png
  33. BIN
      public/images/app/app2.png
  34. BIN
      public/images/app/app3.png
  35. BIN
      public/images/app/application.png
  36. BIN
      public/images/common/avatar.png
  37. BIN
      public/images/common/device.png
  38. BIN
      public/images/common/driver.png
  39. BIN
      public/images/common/gateway.png
  40. 6 0
      public/images/common/loading-init.svg
  41. BIN
      public/images/common/point-info-disable.png
  42. BIN
      public/images/common/point-info.png
  43. BIN
      public/images/common/point.png
  44. BIN
      public/images/common/profile.png
  45. BIN
      public/images/dashboard/dashboard.jpg
  46. 630 0
      public/images/error/403.svg
  47. 773 0
      public/images/error/404.svg
  48. 528 0
      public/images/error/500.svg
  49. BIN
      public/images/logo/logo-white.png
  50. BIN
      public/images/logo/logo.png
  51. 6 0
      public/js/prefixfree.min.js
  52. 35 0
      src/App.vue
  53. 40 0
      src/api/attribute.ts
  54. 183 0
      src/api/device.ts
  55. 69 0
      src/api/dictionary.ts
  56. 44 0
      src/api/driver.ts
  57. 13 0
      src/api/index.ts
  58. 119 0
      src/api/info.ts
  59. 182 0
      src/api/point.ts
  60. 105 0
      src/api/profile.ts
  61. 70 0
      src/api/token.ts
  62. 29 0
      src/components/card/base/BaseCard.vue
  63. 21 0
      src/components/card/base/index.ts
  64. 38 0
      src/components/card/base/style.scss
  65. 29 0
      src/components/card/blank/BlankCard.vue
  66. 29 0
      src/components/card/blank/index.ts
  67. 34 0
      src/components/card/blank/style.scss
  68. 29 0
      src/components/card/detail/DetailCard.vue
  69. 21 0
      src/components/card/detail/index.ts
  70. 41 0
      src/components/card/detail/style.scss
  71. 66 0
      src/components/card/skeleton/SkeletonCard.vue
  72. 41 0
      src/components/card/skeleton/index.ts
  73. 50 0
      src/components/card/skeleton/style.scss
  74. 71 0
      src/components/card/styles/edit-card.scss
  75. 232 0
      src/components/card/styles/things-card.scss
  76. 67 0
      src/components/card/styles/tool-card.scss
  77. 32 0
      src/components/card/title/TitleCard.vue
  78. 27 0
      src/components/card/title/index.ts
  79. 43 0
      src/components/card/title/style.scss
  80. 85 0
      src/components/dialog/styles/things-dialog.scss
  81. 34 0
      src/components/error/403.vue
  82. 34 0
      src/components/error/404.vue
  83. 34 0
      src/components/error/500.vue
  84. 51 0
      src/components/error/style.scss
  85. 76 0
      src/components/layout/Layout.vue
  86. 65 0
      src/components/layout/index.ts
  87. 88 0
      src/components/layout/style.scss
  88. 425 0
      src/components/particles/particles.vue
  89. 82 0
      src/config/axios/index.ts
  90. 21 0
      src/config/constant/common.ts
  91. 1 0
      src/config/env/.env
  92. 3 0
      src/config/env/.env.dev
  93. 3 0
      src/config/env/.env.mock
  94. 3 0
      src/config/env/.env.pre
  95. 3 0
      src/config/env/.env.pro
  96. 3 0
      src/config/env/.env.test
  97. 35 0
      src/config/plugins/element/element-variables.scss
  98. 29 0
      src/config/plugins/element/element.ts
  99. 46 0
      src/config/plugins/highlight/highlight.ts
  100. 0 0
      src/config/plugins/index.ts

+ 4 - 0
.browserslistrc

@@ -0,0 +1,4 @@
+> 1%
+last 2 versions
+not dead
+not ie 11

+ 1 - 0
.dockerignore

@@ -0,0 +1 @@
+node_modules

+ 6 - 0
.eslintignore

@@ -0,0 +1,6 @@
+node_modules
+.vscode
+.idea
+dc3
+public
+dist

+ 89 - 0
.eslintrc.js

@@ -0,0 +1,89 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+module.exports = {
+    root: true,
+    env: {
+        browser: true,
+        es2021: true,
+        node: true,
+    },
+    parser: 'vue-eslint-parser',
+    parserOptions: {
+        parser: '@typescript-eslint/parser',
+        sourceType: 'module',
+    },
+    extends: ['plugin:vue/vue3-recommended', '@vue/typescript/recommended', 'eslint:recommended', 'plugin:prettier/recommended'],
+    plugins: ['vue', '@typescript-eslint'],
+    overrides: [
+        {
+            files: ['*.ts', '*.tsx', '*.vue'],
+            rules: {
+                'no-undef': 'off',
+            },
+        },
+    ],
+    rules: {
+        '@typescript-eslint/ban-ts-ignore': 'off',
+        '@typescript-eslint/explicit-function-return-type': 'off',
+        '@typescript-eslint/no-explicit-any': 'off',
+        '@typescript-eslint/no-var-requires': 'off',
+        '@typescript-eslint/no-empty-function': 'off',
+        '@typescript-eslint/no-use-before-define': 'off',
+        '@typescript-eslint/ban-ts-comment': 'off',
+        '@typescript-eslint/ban-types': 'off',
+        '@typescript-eslint/no-non-null-assertion': 'off',
+        '@typescript-eslint/explicit-module-boundary-types': 'off',
+        '@typescript-eslint/no-redeclare': 'error',
+        '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
+        '@typescript-eslint/no-unused-vars': [2],
+        'vue/custom-event-name-casing': 'off',
+        'vue/attributes-order': 'off',
+        'vue/one-component-per-file': 'off',
+        'vue/html-closing-bracket-newline': 'off',
+        'vue/max-attributes-per-line': 'off',
+        'vue/multiline-html-element-content-newline': 'off',
+        'vue/singleline-html-element-content-newline': 'off',
+        'vue/attribute-hyphenation': 'off',
+        'vue/html-self-closing': 'off',
+        'vue/no-multiple-template-root': 'off',
+        'vue/require-default-prop': 'off',
+        'vue/no-v-model-argument': 'off',
+        'vue/no-arrow-functions-in-watch': 'off',
+        'vue/no-template-key': 'off',
+        'vue/no-v-html': 'off',
+        'vue/comment-directive': 'off',
+        'vue/no-parsing-error': 'off',
+        'vue/no-deprecated-v-on-native-modifier': 'off',
+        'vue/multi-word-component-names': 'off',
+        'no-useless-escape': 'off',
+        'no-sparse-arrays': 'off',
+        'no-prototype-builtins': 'off',
+        'no-constant-condition': 'off',
+        'no-use-before-define': 'off',
+        'no-restricted-globals': 'off',
+        'no-restricted-syntax': 'off',
+        'generator-star-spacing': 'off',
+        'no-unreachable': 'off',
+        'no-multiple-template-root': 'off',
+        'no-unused-vars': 'error',
+        'no-v-model-argument': 'off',
+        'no-case-declarations': 'off',
+        'eol-last': 'off',
+        'no-console': 'off',
+        'no-redeclare': 'off',
+    },
+}

+ 27 - 0
.gitignore

@@ -0,0 +1,27 @@
+.DS_Store
+node_modules
+/dist
+
+/express/node_modules
+/express/public
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+components.d.ts

+ 23 - 0
.prettierrc.js

@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+module.exports = {
+    tabWidth: 4 /* 指定每个缩进级别的空格数 */,
+    printWidth: 180 /* 一行最多多少个字符 */,
+    semi: false /* 在语句末尾打印分号 */,
+    singleQuote: true /* 使用单引号而不是双引号 */,
+    endOfLine: 'auto' /* 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>" */,
+}

+ 29 - 0
Dockerfile

@@ -0,0 +1,29 @@
+#
+#  Copyright 2019 Pnoker. All Rights Reserved.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+FROM registry.cn-beijing.aliyuncs.com/dc3/alpine-nginx:1.22.1
+MAINTAINER pnoker pnokers@icloud.com
+
+RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+
+COPY ./dc3/nginx/ /etc/nginx/
+COPY ./dist/ /usr/share/nginx/html/
+COPY ./dc3/dependencies/conf.crt/ /etc/letsencrypt/live/
+
+EXPOSE 80 443
+VOLUME /var/log/nginx
+
+CMD envsubst < /etc/nginx/location/default.env > /etc/nginx/location/default.conf ; nginx -g "daemon off;"

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don"t include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 31 - 0
Makefile

@@ -0,0 +1,31 @@
+#
+#  Copyright 2019 Pnoker. All Rights Reserved.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+Default:
+    @echo "make serve: npm run serve"
+    @echo "make build: npm run build"
+    @echo "make lint: npn run lint"
+
+.PHONY: serve build lint
+
+serve:
+	npm run serve
+build:
+	npm run build
+	cd ./dc3
+	docker-compose build
+lint:
+	npm run lint

+ 9 - 0
auto-imports.d.ts

@@ -0,0 +1,9 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// noinspection JSUnusedGlobalSymbols
+// Generated by unplugin-auto-import
+export {}
+declare global {
+
+}

+ 19 - 0
babel.config.js

@@ -0,0 +1,19 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+module.exports = {
+    presets: ['@vue/cli-plugin-babel/preset'],
+}

+ 31 - 0
dc3.code-workspace

@@ -0,0 +1,31 @@
+{
+    "folders": [
+        {
+            "path": "src",
+            "name": "web"
+        },
+        {
+            "path": "dc3",
+            "name": "dc3"
+        },
+        {
+            "path": ".",
+            "name": "root"
+        }
+    ],
+    "launch": {
+        "version": "2022.1.0",
+        "configurations": [
+            {
+                "type": "node",
+                "request": "launch",
+                "cwd": "${workspaceFolder:web}",
+                "name": "yarn serve",
+                "runtimeExecutable": "yarn",
+                "runtimeArgs": [
+                    "serve"
+                ]
+            }
+        ]
+    }
+}

+ 25 - 0
dc3/bin/deploy.sh

@@ -0,0 +1,25 @@
+#!/bin/bash
+
+#
+# Copyright 2022 Pnoker All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+cd ../../
+
+yarn
+yarn build
+cp -r ./dist/* /usr/share/nginx/html/

+ 56 - 0
dc3/bin/tag.sh

@@ -0,0 +1,56 @@
+#!/bin/bash
+
+#
+# Copyright 2022 Pnoker All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+cd ../../
+
+type=""
+
+# shellcheck disable=SC2092
+# shellcheck disable=SC2006
+if `git status | grep "develop" &>/dev/null`; then
+    type="test"
+fi
+
+# shellcheck disable=SC2092
+# shellcheck disable=SC2006
+if `git status | grep "pre" &>/dev/null`; then
+    type="pre"
+fi
+
+# shellcheck disable=SC2092
+# shellcheck disable=SC2006
+if `git status | grep "release" &>/dev/null`; then
+    type="pro"
+fi
+
+if [[ ${type} == "" ]]; then
+    echo -e "This branch doesn't support tagging, please switch to the \033[31mdevelop\033[0m, \033[31mpre\033[0m or \033[31mrelease\033[0m branch."
+    exit
+fi
+
+git pull --tags
+
+# shellcheck disable=SC2046
+# shellcheck disable=SC2116
+tag=$(echo dc3.${type}.$(date +'%Y%m%d').$(git tag -l "dc3.${type}.$(date +'%Y%m%d').*" | wc -l | xargs printf '%02d'))
+echo "${tag}" 
+git tag "${tag}"
+
+git push origin --tags

+ 24 - 0
dc3/dependencies/README.md

@@ -0,0 +1,24 @@
+## 安装 acme.sh
+
+https://get.acme.sh | sh
+
+## DNS-API
+
+> 阿里云控制台中申请子账号 API Token,并配置环境变量如下
+
+```bash
+export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
+export Ali_Secret="jlsdflanljkljlfdsaklkjflsa"
+```
+
+## 生成证书
+
+```bash
+acme.sh --issue --dns dns_ali -d example.com -d www.example.com
+```
+
+## 安装证书
+
+```bash
+acme.sh --installcert -d dc3.site --key-file /etc/letsencrypt/live/dc3.site/dc3.site.key --fullchain-file /etc/letsencrypt/live/dc3.site/fullchain.cer --reloadcmd "service nginx force-reload"
+```

+ 14 - 0
dc3/dependencies/conf.crt/dc3.site/README

@@ -0,0 +1,14 @@
+This directory contains your keys and certificates.
+
+`privkey.pem`  : the private key for your certificate.
+`fullchain.pem`: the certificate file used in most server software.
+`chain.pem`    : used for OCSP stapling in Nginx >=1.3.7.
+`cert.pem`     : will break many server configurations, and should not be used
+                 without reading further documentation (see link below).
+
+WARNING: DO NOT MOVE OR RENAME THESE FILES!
+         Certbot expects these files to remain in this location in order
+         to function properly!
+
+We recommend not moving these files. For more information, see the Certbot
+User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.

+ 31 - 0
dc3/dependencies/conf.crt/dc3.site/cert.pem

@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFVDCCBDygAwIBAgISAyRVdBS/p8SjMmqjZK8h8q4BMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA2MTkwMjIyMTRaFw0y
+MDA5MTcwMjIyMTRaMBMxETAPBgNVBAMTCGRjMy5zaXRlMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAwrL0zWWpSo1przf6TSyRu/zfNSG36HThEmnibFn8
+D3HYUZzS+veuvH6uqPR1VVUOK80/2iiCBMQfFDufdTQjZAATJEcc6152VbZOWm80
+bD86FIP0W3FSzovVWmUDT/gdxgoAMr2ZxYTd5T+hSxMqTKYIVTzJS2fNr/1yi3IZ
+O4bV0J4ZVnYeT3lFKKuchlbKIkwXgLQKBGqHvUGHIVXM5uy+kVSV0oZBWYgwCLwC
+M6SkL1rYub4yOEJ6KrIT8/Znq8sIBo+exh0eP61eH9UM7dMCSvN0nw/2v6VxLNSp
+GC3gV3OF0YPLgWK/8OCDMkt4htcm4yt6aAQSozm/BO2dXwIDAQABo4ICaTCCAmUw
+DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAM
+BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT4PekdG7ZXD5B8h+OGrzebEpbJDTAfBgNV
+HSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEwLgYI
+KwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcwLwYI
+KwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcvMB8G
+A1UdEQQYMBaCCiouZGMzLnNpdGWCCGRjMy5zaXRlMEwGA1UdIARFMEMwCAYGZ4EM
+AQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0
+c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYAXqdz+d9WwOe1
+Nkh90EngMnqRmgyEoRIShBh1loFxRVgAAAFyypkpBgAABAMARzBFAiEArZaIwTLF
+PlqVJkn0QlWVCg2opdsITWGwWyCX/8zW0CkCIHeSLi5Q8k9teZ2RMvdmJne38ww8
+pexE87f9VmQzynHuAHYAB7dcG+V9aP/xsMYdIxXHuuZXfFeUt2ruvGE6GmnTohwA
+AAFyypko8QAABAMARzBFAiEAzmWlqO/fHa1B7i9rEICX5L5UF4RbaMiUjSzSPvgR
+YuICIGXy6oRkrQxEjyK4+nKPdubI1wuxAwfIPXSls1Rd2RukMA0GCSqGSIb3DQEB
+CwUAA4IBAQBx0N4epRYqvmNLzlJfPD09PXeEalB+7zN2ls44A7ao/PsN/vlN7hhX
+JtjDMaUfoTyjtJxzDo/jcXsq7DzAe3bhG13bidLeh0naWVv147Is3Yz4khnuMjDb
+90/YhMu5AKS9KCjPuJ72GDTWFPleJFMI1jUYxaapMSgGMjCDRSpegmGqDome+vzZ
+QDI4wNCrxNSu4O6suWjMD8ACQMD97MnM1ILZekcJ9rMXIWVYDDCkgkrQqDObiR0f
+k9jnL7XnrRbMQzHWRey9o3VBIJRo7TE82U+Lsn2su+PepYhOPK1dZv4iqyG+OXtm
+PwwMZuwR8Yl4hCBJ//yhPq6Beh/aSbhV
+-----END CERTIFICATE-----

+ 27 - 0
dc3/dependencies/conf.crt/dc3.site/chain.pem

@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
+SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
+GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
+q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
+SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
+Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
+a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
+/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
+AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
+CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
+bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
+c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
+VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
+ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
+MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
+Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
+AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
+uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
+wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
+X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
+PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
+KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+-----END CERTIFICATE-----

+ 58 - 0
dc3/dependencies/conf.crt/dc3.site/fullchain.pem

@@ -0,0 +1,58 @@
+-----BEGIN CERTIFICATE-----
+MIIFVDCCBDygAwIBAgISAyRVdBS/p8SjMmqjZK8h8q4BMA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA2MTkwMjIyMTRaFw0y
+MDA5MTcwMjIyMTRaMBMxETAPBgNVBAMTCGRjMy5zaXRlMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAwrL0zWWpSo1przf6TSyRu/zfNSG36HThEmnibFn8
+D3HYUZzS+veuvH6uqPR1VVUOK80/2iiCBMQfFDufdTQjZAATJEcc6152VbZOWm80
+bD86FIP0W3FSzovVWmUDT/gdxgoAMr2ZxYTd5T+hSxMqTKYIVTzJS2fNr/1yi3IZ
+O4bV0J4ZVnYeT3lFKKuchlbKIkwXgLQKBGqHvUGHIVXM5uy+kVSV0oZBWYgwCLwC
+M6SkL1rYub4yOEJ6KrIT8/Znq8sIBo+exh0eP61eH9UM7dMCSvN0nw/2v6VxLNSp
+GC3gV3OF0YPLgWK/8OCDMkt4htcm4yt6aAQSozm/BO2dXwIDAQABo4ICaTCCAmUw
+DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAM
+BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT4PekdG7ZXD5B8h+OGrzebEpbJDTAfBgNV
+HSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEwLgYI
+KwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcwLwYI
+KwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcvMB8G
+A1UdEQQYMBaCCiouZGMzLnNpdGWCCGRjMy5zaXRlMEwGA1UdIARFMEMwCAYGZ4EM
+AQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0
+c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYAXqdz+d9WwOe1
+Nkh90EngMnqRmgyEoRIShBh1loFxRVgAAAFyypkpBgAABAMARzBFAiEArZaIwTLF
+PlqVJkn0QlWVCg2opdsITWGwWyCX/8zW0CkCIHeSLi5Q8k9teZ2RMvdmJne38ww8
+pexE87f9VmQzynHuAHYAB7dcG+V9aP/xsMYdIxXHuuZXfFeUt2ruvGE6GmnTohwA
+AAFyypko8QAABAMARzBFAiEAzmWlqO/fHa1B7i9rEICX5L5UF4RbaMiUjSzSPvgR
+YuICIGXy6oRkrQxEjyK4+nKPdubI1wuxAwfIPXSls1Rd2RukMA0GCSqGSIb3DQEB
+CwUAA4IBAQBx0N4epRYqvmNLzlJfPD09PXeEalB+7zN2ls44A7ao/PsN/vlN7hhX
+JtjDMaUfoTyjtJxzDo/jcXsq7DzAe3bhG13bidLeh0naWVv147Is3Yz4khnuMjDb
+90/YhMu5AKS9KCjPuJ72GDTWFPleJFMI1jUYxaapMSgGMjCDRSpegmGqDome+vzZ
+QDI4wNCrxNSu4O6suWjMD8ACQMD97MnM1ILZekcJ9rMXIWVYDDCkgkrQqDObiR0f
+k9jnL7XnrRbMQzHWRey9o3VBIJRo7TE82U+Lsn2su+PepYhOPK1dZv4iqyG+OXtm
+PwwMZuwR8Yl4hCBJ//yhPq6Beh/aSbhV
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
+SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
+GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
+q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
+SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
+Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
+a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
+/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
+AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
+CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
+bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
+c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
+VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
+ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
+MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
+Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
+AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
+uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
+wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
+X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
+PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
+KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+-----END CERTIFICATE-----

+ 28 - 0
dc3/dependencies/conf.crt/dc3.site/privkey.pem

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDCsvTNZalKjWmv
+N/pNLJG7/N81IbfodOESaeJsWfwPcdhRnNL69668fq6o9HVVVQ4rzT/aKIIExB8U
+O591NCNkABMkRxzrXnZVtk5abzRsPzoUg/RbcVLOi9VaZQNP+B3GCgAyvZnFhN3l
+P6FLEypMpghVPMlLZ82v/XKLchk7htXQnhlWdh5PeUUoq5yGVsoiTBeAtAoEaoe9
+QYchVczm7L6RVJXShkFZiDAIvAIzpKQvWti5vjI4QnoqshPz9merywgGj57GHR4/
+rV4f1Qzt0wJK83SfD/a/pXEs1KkYLeBXc4XRg8uBYr/w4IMyS3iG1ybjK3poBBKj
+Ob8E7Z1fAgMBAAECggEAY5dMl2AAF418WM9mbmF07lbsCe6EdxiKJHQbCNeCkpfm
+UeDJHuzg6bRXPT9GYW7Pf+JOXhZIY426ZAwXhck0rStIn07s4QyBtVg6fhHSG+i/
+mczhioDOHa7zZHi1GAvPlwR4k3vek2ViZ6iDpbZY9bocGxWr1bF0Sih3lhK4C3UJ
+ICRNiQr6661BeTTMITODDH7CCS07CfK1yLR2+sT9FWVURJOzopeFTasLZ+D3u+tS
+8XovU2dBw6kIxwXE5OG9a/Ddzxqd+ERoXSrB5GRe5lsfB+hGbW+prLZtegcT1GP7
+1b4sFtECneYQ0GrRBITEvlS2NjRDgyknR82QpJ8c4QKBgQDvzP4e3wbajmrN4KCo
+bUcQZXum6JnIP0dYaZC1Sk/TfZ7ovf4Of0z+Q92OXhssWEVExTbSZhsEszEeQVTI
+paigMqQ5hMcq/hjsSFDDvp5FcP3DuW3rXxayWjOJFiHwo//0+RtSngEKOuDMUkou
+baKtZMg8EWJwGr0Qb6dnCHs8DwKBgQDP2f6sjktlZU9Gs6mfhexUBrzLaJIWhd7c
+205m+tyleaC5lCNeqIHoyeTf+UQ+xMh/nJ/9hGxBJXenpoKJynBPMUJI7b7Kngz4
+7p/lVsXXEXpteM6zCBqhYjbClQSGOYRPWSq5w9FetBwa7cIV0UyqByDZ83ODWHW3
+znj6tEp5sQKBgDmCOutiZz1g7EJFfaIG2wUWoWns3HyGmHCemIKxuKUqukJs1hHZ
++7f6xJaRAQlIfgw5E6WvsQkWhFASMOgRunf4zSOyMSWhXI7F5QCcpU5YA7O9s5u/
+6SyKr1NQCIGygv7YAvJ0TCGM7z5w+bNavanBwreNH8Ns1iyr6kSuZweHAoGAajoJ
+VHsswVdzmri7mhHB5HfFCVgaQXSNn+ZdPXg8SD3PDMlPAlOwgR6d4HHulP3RUpbj
+lZeWE/1oF8CbunxBxddw/wCyn68DBj4+beFZHz+JiGVTjmA36/7b6bprI4ZFvp/d
+nC8d0/7M1l5o8OmU+tjFy14GzTvqfdQCNG7sGSECgYBuHM3hBjeuTLTZ5lwv0KXX
+GOYbcQV9dFjCmJ2/Hc65LIAWUTlUzJA0uN+YgyaPLeYca6nKzoVTA3W7uWG5C7yJ
+xhvtKYwcJAZ/QNxduvfuNSdn4sXadUB/Q47rmpZQn9RQh9I6uBs6TJUFhLTI+E0d
+crEIYAM+SnPsZwG53VgLRQ==
+-----END PRIVATE KEY-----

+ 31 - 0
dc3/docker-compose.yml

@@ -0,0 +1,31 @@
+version: '3'
+
+services:
+  web:
+    build:
+      context: ../
+      dockerfile: ./Dockerfile
+    image: registry.cn-beijing.aliyuncs.com/dc3/iot-dc3-web:2023.4.0.dev
+    restart: always
+    ports:
+      - 8080:80
+      - 443:443
+    environment:
+      - APP_API_PATH=dc3-gateway
+      - APP_API_PORT=8000
+    container_name: iot-dc3-web
+    hostname: iot-dc3-web
+    volumes:
+      - nginx:/var/log/nginx
+    networks:
+      dc3net:
+        aliases:
+          - iot-dc3-web
+
+volumes:
+  nginx:
+
+networks:
+  dc3net:
+    driver: 'bridge'
+...

+ 25 - 0
dc3/nginx/conf.d/default.conf

@@ -0,0 +1,25 @@
+server {
+    listen                     80;
+    listen                     [::]:80;
+
+    include                    /etc/nginx/location/*.conf;
+}
+
+server {
+    listen                     443 ssl http2;
+    listen                     [::]:443 ssl http2;
+
+    add_header                 X-Xss-Protection 1;
+    add_header                 X-Frame-Options DENY;
+    add_header                 X-Content-Type-Options nosniff;
+
+    ssl_prefer_server_ciphers  on;
+    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
+    ssl_ciphers                HIGH:!aNULL:!MD5;
+
+    ssl_certificate            /etc/letsencrypt/live/dc3.site/fullchain.pem;
+    ssl_certificate_key        /etc/letsencrypt/live/dc3.site/privkey.pem;
+
+    include                    /etc/nginx/location/*.conf;
+}
+

+ 13 - 0
dc3/nginx/location/default.conf

@@ -0,0 +1,13 @@
+location / {
+    root                       /usr/share/nginx/html;
+    index                      index.html index.htm;
+}
+
+location ^~/api/ {
+    proxy_pass                 http://dc3-gateway:8000/api/;
+}
+
+error_page   500 502 503 504   /50x.html;
+location = /50x.html {
+    root                       /usr/share/nginx/html;
+}

+ 13 - 0
dc3/nginx/location/default.env

@@ -0,0 +1,13 @@
+location / {
+    root                       /usr/share/nginx/html;
+    index                      index.html index.htm;
+}
+
+location ^~/api/ {
+    proxy_pass                 http://${APP_API_PATH}:${APP_API_PORT}/api/;
+}
+
+error_page   500 502 503 504   /50x.html;
+location = /50x.html {
+    root                       /usr/share/nginx/html;
+}

+ 34 - 0
dc3/nginx/nginx.conf

@@ -0,0 +1,34 @@
+user                           nginx;
+worker_processes               auto;
+
+error_log                      /var/log/nginx/error.log warn;
+pid                            /var/run/nginx.pid;
+
+events {
+    multi_accept               on;
+    worker_connections         2048;
+    use                        epoll;
+}
+
+http {
+    include                    /etc/nginx/mime.types;
+    default_type               application/octet-stream;
+
+    log_format                 main  '$remote_addr - $remote_user [$time_local] "$request" '
+                                     '$status $body_bytes_sent "$http_referer" '
+                                     '"$http_user_agent" "$http_x_forwarded_for"';
+
+    access_log                 /var/log/nginx/access.log  main;
+
+    gzip                       on;
+    sendfile                   on;
+    tcp_nopush                 on;
+    tcp_nodelay                on;
+    keepalive_timeout          65;
+    types_hash_max_size        4096;
+
+    ssl_session_timeout        10m;
+    ssl_session_cache          shared:SSL:1m;
+
+    include                    /etc/nginx/conf.d/*.conf;
+}

+ 59 - 0
index.html

@@ -0,0 +1,59 @@
+<!--
+  ~ Copyright 2022 Pnoker All Rights Reserved
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8"/>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+    <meta name="format-detection" content="telephone=no"/>
+    <meta name="apple-mobile-web-app-capable" content="yes"/>
+    <meta name="apple-mobile-web-app-status-bar-style" content="black"/>
+    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0"/>
+    <meta name="description" content="IoT DC3, 一个基于Spring Cloud的开源的、分布式的物联网(IOT)平台,用于快速开发物联网项目和管理物联设备,是一整套物联系统解决方案。"/>
+
+    <link rel="icon" href="/favicon.ico"/>
+    <link rel="stylesheet" href="/css/animate/animate.min.css"/>
+    <link rel="stylesheet" href="/css/index/index.min.css"/>
+
+    <title>IoT DC3 平台</title>
+</head>
+
+<body ondragstart="return false">
+<noscript>
+    <strong>很抱歉,如果没有 JavaScript 支持,IoT DC3 WEB 将不能正常工作。请启用浏览器的 JavaScript 然后继续。</strong>
+</noscript>
+<script type="text/javascript" src="/js/prefixfree.min.js" charset="utf-8"></script>
+
+<div id="app">
+    <div class="base">
+        <div class="cube"></div>
+        <div class="cube"></div>
+        <div class="cube"></div>
+        <div class="cube"></div>
+        <div class="cube"></div>
+        <div class="cube"></div>
+        <div class="cube"></div>
+        <div class="cube"></div>
+        <div class="cube"></div>
+    </div>
+</div>
+
+<script type="module" src="/src/main.ts"></script>
+</body>
+</html>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 14861 - 0
package-lock.json


+ 71 - 0
package.json

@@ -0,0 +1,71 @@
+{
+    "name": "iot-dc3-web",
+    "version": "2023.4.5",
+    "private": true,
+    "author": "pnoker",
+    "description": "DC3 IoT 平台前端页面",
+    "scripts": {
+        "serve": "vite --host --mode dev",
+        "pre": "vite --host --mode pre",
+        "build": "vite build --mode pro",
+        "build:dev": "vue-tsc && vite build --mode dev",
+        "build:mock": "vue-tsc && vite build --mode mock",
+        "build:test": "vue-tsc && vite build --mode test",
+        "build:pre": "vue-tsc && vite build --mode pre",
+        "preview": "vite preview",
+        "lint": "vue-cli-service lint"
+    },
+    "dependencies": {
+        "@amap/amap-jsapi-loader": "^1.0.1",
+        "@antv/g2plot": "^2.4.31",
+        "@element-plus/icons-vue": "^2.1.0",
+        "axios": "^1.4.0",
+        "clipboard": "^2.0.11",
+        "core-js": "^3.31.1",
+        "dotenv": "^16.3.1",
+        "echarts": "^5.4.2",
+        "element-plus": "^2.3.7",
+        "highlight.js": "^11.8.0",
+        "js-base64": "^3.7.5",
+        "js-cookie": "^3.0.5",
+        "marked": "^5.1.1",
+        "minimist": "^1.2.8",
+        "mitt": "^3.0.1",
+        "moment": "^2.29.4",
+        "nprogress": "^0.2.0",
+        "path": "^0.12.7",
+        "pinia": "^2.1.4",
+        "screenfull": "^6.0.2",
+        "ts-md5": "^1.3.1",
+        "vue": "^3.3.4",
+        "vue-class-component": "^8.0.0-0",
+        "vue-router": "^4.2.4",
+        "vuex": "^4.1.0"
+    },
+    "devDependencies": {
+        "@types/highlight.js": "^10.1.0",
+        "@types/js-base64": "^3.3.1",
+        "@types/js-cookie": "^3.0.3",
+        "@types/node": "^20.4.2",
+        "@types/nprogress": "^0.2.0",
+        "@typescript-eslint/eslint-plugin": "^6.0.0",
+        "@typescript-eslint/parser": "^6.0.0",
+        "@vitejs/plugin-legacy": "^4.1.0",
+        "@vitejs/plugin-vue": "^4.2.3",
+        "@vue/eslint-config-typescript": "^11.0.3",
+        "eslint": "^8.44.0",
+        "eslint-config-prettier": "^8.8.0",
+        "eslint-plugin-prettier": "^5.0.0",
+        "eslint-plugin-vue": "^9.15.1",
+        "prettier": "^3.0.0",
+        "prettier-eslint": "^15.0.1",
+        "sass": "^1.63.6",
+        "terser": "^5.19.0",
+        "typescript": "~5.1.6",
+        "unplugin-auto-import": "^0.16.6",
+        "unplugin-vue-components": "^0.25.1",
+        "vite": "^4.4.3",
+        "vue-template-compiler": "^2.7.14",
+        "vue-tsc": "^1.8.4"
+    }
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 7 - 0
public/css/animate/animate.min.css


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 14 - 0
public/css/index/index.min.css


BIN
public/favicon.ico


BIN
public/images/app/app1.png


BIN
public/images/app/app2.png


BIN
public/images/app/app3.png


BIN
public/images/app/application.png


BIN
public/images/common/avatar.png


BIN
public/images/common/device.png


BIN
public/images/common/driver.png


BIN
public/images/common/gateway.png


+ 6 - 0
public/images/common/loading-init.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="white">
+  <path opacity=".25" d="M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4"/>
+  <path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z">
+    <animateTransform attributeName="transform" type="rotate" from="0 16 16" to="360 16 16" dur="0.8s" repeatCount="indefinite" />
+  </path>
+</svg>

BIN
public/images/common/point-info-disable.png


BIN
public/images/common/point-info.png


BIN
public/images/common/point.png


BIN
public/images/common/profile.png


BIN
public/images/dashboard/dashboard.jpg


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 630 - 0
public/images/error/403.svg


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 773 - 0
public/images/error/404.svg


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 528 - 0
public/images/error/500.svg


BIN
public/images/logo/logo-white.png


BIN
public/images/logo/logo.png


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 6 - 0
public/js/prefixfree.min.js


+ 35 - 0
src/App.vue

@@ -0,0 +1,35 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div id="app">
+        <router-view />
+    </div>
+</template>
+
+<script lang="ts">
+export default {
+    name: 'App',
+}
+</script>
+
+<style lang="scss">
+#app {
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+}
+</style>

+ 40 - 0
src/api/attribute.ts

@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+
+/**
+ * 通过驱动ID查询驱动属性
+ *
+ * @param id 驱动ID
+ * @returns MyAxiosPromise
+ */
+export const getDriverAttributeByDriverId = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/driver_attribute/driver_id/${id}`,
+        method: 'get',
+    })
+
+/**
+ * 通过驱动ID查询位号属性
+ * @param id 驱动ID
+ * @returns MyAxiosPromise
+ */
+export const getPointAttributeByDriverId = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/point_attribute/driver_id/${id}`,
+        method: 'get',
+    })

+ 183 - 0
src/api/device.ts

@@ -0,0 +1,183 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+
+/**
+ * 新增设备
+ *
+ * @param device Device
+ * @returns MyAxiosPromise
+ */
+export const addDevice = (device: any) =>
+    request<R>({
+        url: `api/v3/manager/device/add`,
+        method: 'post',
+        data: device,
+    })
+
+/**
+ * 删除设备
+ *
+ * @param id 设备ID
+ * @returns MyAxiosPromise
+ */
+export const deleteDevice = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/device/delete/${id}`,
+        method: 'post',
+    })
+
+/**
+ * 更新设备
+ *
+ * @param device Device
+ * @returns MyAxiosPromise
+ */
+export const updateDevice = (device: any) =>
+    request<R>({
+        url: `api/v3/manager/device/update`,
+        method: 'post',
+        data: device,
+    })
+
+/**
+ * 通过设备ID查询设备
+ *
+ * @param id 设备ID
+ * @returns MyAxiosPromise
+ */
+export const getDeviceById = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/device/id/${id}`,
+        method: 'get',
+    })
+
+/**
+ * 通过设备ID集查询设备
+ *
+ * @param deviceIds DeviceId Array
+ * @returns MyAxiosPromise
+ */
+export const getDeviceByIds = (deviceIds: any) =>
+    request<R>({
+        url: `api/v3/manager/device/ids`,
+        method: 'post',
+        data: deviceIds,
+    })
+
+/**
+ * 通过驱动ID查询设备
+ *
+ * @param driverId 驱动ID
+ * @returns MyAxiosPromise
+ */
+export const getDeviceByDriverId = (driverId: string) =>
+    request<R>({
+        url: `api/v3/manager/device/driver_id/${driverId}`,
+        method: 'get',
+    })
+
+/**
+ * 通过模板ID查询设备
+ *
+ * @param profileId 模板ID
+ * @returns MyAxiosPromise
+ */
+export const getDeviceByProfileId = (profileId: string) =>
+    request<R>({
+        url: `api/v3/manager/device/profile_id/${profileId}`,
+        method: 'get',
+    })
+
+/**
+ * 分页查询设备
+ *
+ * @param device Device
+ * @returns MyAxiosPromise
+ */
+export const getDeviceList = (device: any) =>
+    request<R>({
+        url: `api/v3/manager/device/list`,
+        method: 'post',
+        data: device,
+    })
+
+/**
+ * 分页查询设备状态
+ *
+ * @param device Device
+ * @returns MyAxiosPromise
+ */
+export const getDeviceStatus = (device: any) =>
+    request<R>({
+        url: `api/v3/data/device/status/device`,
+        method: 'post',
+        data: device,
+    })
+
+/**
+ * 通过驱动ID查询设备状态
+ *
+ * @param driverId 驱动ID
+ * @returns MyAxiosPromise
+ */
+export const getDeviceStatusByDriverId = (driverId: string) =>
+    request<R>({
+        url: `api/v3/data/device/status/device/driver_id/${driverId}`,
+        method: 'get',
+    })
+
+/**
+ * 通过模板ID查询设备状态
+ *
+ * @param profileId 模板ID
+ * @returns MyAxiosPromise
+ */
+export const getDeviceStatusByProfileId = (profileId: string) =>
+    request<R>({
+        url: `api/v3/data/device/status/device/profile_id/${profileId}`,
+        method: 'get',
+    })
+
+/**
+ * 通过驱动ID和模板ID获取设备导入模板
+ *
+ * @param device Device
+ * @returns MyAxiosPromise
+ */
+export const importDeviceTemplate = (device: any) =>
+    request<R>({
+        url: `api/v3/manager/device/import/template`,
+        responseType: 'blob',
+        method: 'post',
+        data: device,
+    })
+
+/**
+ * 通过驱动ID和模板ID获取设备导入模板
+ *
+ * @param device Device
+ * @returns MyAxiosPromise
+ */
+export const importDevice = (device: any) =>
+    request<R>({
+        url: `api/v3/manager/device/import`,
+        method: 'post',
+        timeout: 0,
+        headers: { 'Content-Type': 'multipart/form-data' },
+        data: device,
+    })

+ 69 - 0
src/api/dictionary.ts

@@ -0,0 +1,69 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+
+/**
+ * 查询驱动字典
+ *
+ * @param dictionary Dictionary
+ * @returns MyAxiosPromise
+ */
+export const getDriverDictionary = (dictionary: any) =>
+    request<R>({
+        url: `api/v3/manager/dictionary/driver`,
+        method: 'post',
+        data: dictionary,
+    })
+
+/**
+ * 查询设备字典
+ *
+ * @param dictionary Dictionary
+ * @returns MyAxiosPromise
+ */
+export const getDeviceDictionary = (dictionary: any) =>
+    request<R>({
+        url: `api/v3/manager/dictionary/device`,
+        method: 'post',
+        data: dictionary,
+    })
+
+/**
+ * 查询模板字典
+ *
+ * @param dictionary Dictionary
+ * @returns MyAxiosPromise
+ */
+export const getProfileDictionary = (dictionary: any) =>
+    request<R>({
+        url: `api/v3/manager/dictionary/profile`,
+        method: 'post',
+        data: dictionary,
+    })
+
+/**
+ * 查询位号字典
+ *
+ * @param dictionary Dictionary
+ * @returns MyAxiosPromise
+ */
+export const getPointDictionary = (dictionary: any) =>
+    request<R>({
+        url: `api/v3/manager/dictionary/point`,
+        method: 'post',
+        data: dictionary,
+    })

+ 44 - 0
src/api/driver.ts

@@ -0,0 +1,44 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+
+export const getDriverById = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/driver/id/${id}`,
+        method: 'get',
+    })
+
+export const getDriverByIds = (driverIds: any) =>
+    request<R>({
+        url: `api/v3/manager/driver/ids`,
+        method: 'post',
+        data: driverIds,
+    })
+
+export const getDriverList = (driver: any) =>
+    request<R>({
+        url: `api/v3/manager/driver/list`,
+        method: 'post',
+        data: driver,
+    })
+
+export const getDriverStatus = (driver: any) =>
+    request<R>({
+        url: `api/v3/data/driver/status/driver`,
+        method: 'post',
+        data: driver,
+    })

+ 13 - 0
src/api/index.ts

@@ -0,0 +1,13 @@
+import request from '@/config/axios'
+
+export const getStatisticsData = () =>
+    request<R>({
+        url: "api/v3/manager/statistics",
+        method: 'get',
+    })
+
+export const getWeatherDeviceList = () =>
+    request<R>({
+        url: "api/v3/manager/weatherDeviceList",
+        method: 'get',
+    })

+ 119 - 0
src/api/info.ts

@@ -0,0 +1,119 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+
+/**
+ * 新增驱动配置
+ *
+ * @param driverInfo DriverInfo
+ * @returns MyAxiosPromise
+ */
+export const addDriverInfo = (driverInfo: any) =>
+    request<R>({
+        url: `api/v3/manager/driver_attribute_config/add`,
+        method: 'post',
+        data: driverInfo,
+    })
+
+/**
+ * 更新驱动配置
+ *
+ * @param driverInfo DriverInfo
+ * @returns MyAxiosPromise
+ */
+export const updateDriverInfo = (driverInfo: any) =>
+    request<R>({
+        url: `api/v3/manager/driver_attribute_config/update`,
+        method: 'post',
+        data: driverInfo,
+    })
+
+/**
+ * 通过设备ID和属性ID查询驱动配置
+ *
+ * @param deviceId DeviceId
+ * @param attributeId AttributeId
+ * @returns MyAxiosPromise
+ */
+export const getDriverInfoByDeviceIdAndAttributeId = (deviceId: string, attributeId: string) =>
+    request<R>({
+        url: `api/v3/manager/driver_attribute_config/device_id/${deviceId}/attribute_id/${attributeId}`,
+        method: 'get',
+    })
+
+/**
+ * 通过设备ID查询驱动配置
+ *
+ * @param deviceId DeviceId
+ * @returns MyAxiosPromise
+ */
+export const getDriverInfoByDeviceId = (deviceId: string) =>
+    request<R>({
+        url: `api/v3/manager/driver_attribute_config/device_id/${deviceId}`,
+        method: 'get',
+    })
+
+/**
+ * 新增位号配置
+ *
+ * @param pointInfo PointInfo
+ * @returns MyAxiosPromise
+ */
+export const addPointInfo = (pointInfo: any) =>
+    request<R>({
+        url: `api/v3/manager/point_attribute_config/add`,
+        method: 'post',
+        data: pointInfo,
+    })
+
+/**
+ * 更新位号配置
+ *
+ * @param pointInfo PointInfo
+ * @returns MyAxiosPromise
+ */
+export const updatePointInfo = (pointInfo: any) =>
+    request<R>({
+        url: `api/v3/manager/point_attribute_config/update`,
+        method: 'post',
+        data: pointInfo,
+    })
+
+/**
+ * 通过设备ID和位号ID查询位号配置
+ *
+ * @param deviceId DeviceId
+ * @param pointId PointId
+ * @returns MyAxiosPromise
+ */
+export const getPointInfoByDeviceIdAndPointId = (deviceId: string, pointId: string) =>
+    request<R>({
+        url: `api/v3/manager/point_attribute_config/device_id/${deviceId}/point_id/${pointId}`,
+        method: 'get',
+    })
+
+/**
+ * 通过设备ID查询位号配置
+ *
+ * @param deviceId DeviceId
+ * @returns MyAxiosPromise
+ */
+export const getPointInfoByDeviceId = (deviceId: string) =>
+    request<R>({
+        url: `api/v3/manager/point_attribute_config/device_id/${deviceId}`,
+        method: 'get',
+    })

+ 182 - 0
src/api/point.ts

@@ -0,0 +1,182 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+
+/**
+ * 新增位号
+ *
+ * @param point Point
+ * @returns MyAxiosPromise
+ */
+export const pointAddApi = (point: any) =>
+    request<R>({
+        url: `api/v3/manager/point/add`,
+        method: 'post',
+        data: point,
+    })
+
+/**
+ * 新增位号
+ *
+ * @param point Point
+ * @returns MyAxiosPromise
+ */
+export const pointDeleteApi = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/point/delete/${id}`,
+        method: 'post',
+    })
+
+/**
+ * 更新位号
+ *
+ * @param point Point
+ * @returns MyAxiosPromise
+ */
+export const getPointUpdate = (point: any) =>
+    request<R>({
+        url: `api/v3/manager/point/update`,
+        method: 'post',
+        data: point,
+    })
+
+/**
+ * 通过位号ID查询位号
+ *
+ * @param id 位号ID
+ * @returns MyAxiosPromise
+ */
+export const getPointById = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/point/id/${id}`,
+        method: 'get',
+    })
+
+/**
+ * 通过位号ID集查询位号
+ *
+ * @param pointIds PointId Array
+ * @returns MyAxiosPromise
+ */
+export const getPointByIds = (pointIds: any) =>
+    request<R>({
+        url: `api/v3/manager/point/ids`,
+        method: 'post',
+        data: pointIds,
+    })
+
+/**
+ * 模糊分页查询位号
+ *
+ * @param point Point
+ * @returns MyAxiosPromise
+ */
+export const getPointList = (point: any) =>
+    request<R>({
+        url: `api/v3/manager/point/list`,
+        method: 'post',
+        data: point,
+    })
+
+/**
+ * 通过位号ID集查询位号单位
+ *
+ * @param pointIds PointId Array
+ * @returns MyAxiosPromise
+ */
+export const getPointUnit = (pointIds: any) =>
+    request<R>({
+        url: `api/v3/manager/point/unit`,
+        method: 'post',
+        data: pointIds,
+    })
+
+/**
+ * 通过模板ID查询位号
+ *
+ * @param profileId 模板ID
+ * @returns MyAxiosPromise
+ */
+export const getPointByProfileId = (profileId: string) =>
+    request<R>({
+        url: `api/v3/manager/point/profile_id/${profileId}`,
+        method: 'get',
+    })
+
+/**
+ * 通过设备ID查询位号
+ *
+ * @param deviceId 设备ID
+ * @returns MyAxiosPromise
+ */
+export const getPointByDeviceId = (deviceId: string) =>
+    request<R>({
+        url: `api/v3/manager/point/device_id/${deviceId}`,
+        method: 'get',
+    })
+
+/**
+ * 分页查询最新位号值
+ *
+ * @param pointValue PointValue
+ * @returns MyAxiosPromise
+ */
+export const getPointValueLatest = (pointValue: any) =>
+    request<R>({
+        url: `api/v3/data/point_value/latest`,
+        method: 'post',
+        data: pointValue,
+    })
+
+/**
+ * 分页查询位号值
+ *
+ * @param pointValue PointValue
+ * @returns MyAxiosPromise
+ */
+export const getPointValueList = (pointValue: any) =>
+    request<R>({
+        url: `api/v3/data/point_value/list`,
+        method: 'post',
+        data: pointValue,
+    })
+
+/**
+ * 读位号值
+ *
+ * @param pointValueReadVO PointValueReadVO
+ * @returns MyAxiosPromise
+ */
+export const readPointValue = (pointValueReadVO: any) =>
+    request<R>({
+        url: `api/v3/data/point_value_command/read`,
+        method: 'post',
+        data: pointValueReadVO,
+    })
+
+/**
+ * 写位号值
+ *
+ * @param pointValueWriteVO PointValueWriteVO
+ * @returns MyAxiosPromise
+ */
+export const writePointValue = (pointValueWriteVO: any) =>
+    request<R>({
+        url: `api/v3/data/point_value_command/write`,
+        method: 'post',
+        data: pointValueWriteVO,
+    })

+ 105 - 0
src/api/profile.ts

@@ -0,0 +1,105 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+
+/**
+ * 新增模板
+ *
+ * @param profile Profile
+ * @returns MyAxiosPromise
+ */
+export const addProfile = (profile: any) =>
+    request<R>({
+        url: `api/v3/manager/profile/add`,
+        method: 'post',
+        data: profile,
+    })
+
+/**
+ * 删除模板
+ *
+ * @param id 模板ID
+ * @returns MyAxiosPromise
+ */
+export const deleteProfile = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/profile/delete/${id}`,
+        method: 'post',
+    })
+
+/**
+ * 修改模板
+ *
+ * @param profile Profile
+ * @returns MyAxiosPromise
+ */
+export const updateProfile = (profile: any) =>
+    request<R>({
+        url: `api/v3/manager/profile/update`,
+        method: 'post',
+        data: profile,
+    })
+
+/**
+ * 通过模板ID查询模板
+ *
+ * @param id 模板ID
+ * @returns MyAxiosPromise
+ */
+export const getProfileById = (id: string) =>
+    request<R>({
+        url: `api/v3/manager/profile/id/${id}`,
+        method: 'get',
+    })
+
+/**
+ * 通过模板ID集查询模板
+ *
+ * @param profileIds ProfileId Array
+ * @returns MyAxiosPromise
+ */
+export const getProfileByIds = (profileIds: any) =>
+    request<R>({
+        url: `api/v3/manager/profile/ids`,
+        method: 'post',
+        data: profileIds,
+    })
+
+/**
+ * 通过设备ID查询模板
+ *
+ * @param deviceId DeviceId
+ * @returns MyAxiosPromise
+ */
+export const getProfileByDeviceId = (deviceId: string) =>
+    request<R>({
+        url: `api/v3/manager/profile/device_id/${deviceId}`,
+        method: 'get',
+    })
+
+/**
+ * 分页查询
+ *
+ * @param profile Profile
+ * @returns MyAxiosPromise
+ */
+export const getProfileList = (profile: any) =>
+    request<R>({
+        url: `api/v3/manager/profile/list`,
+        method: 'post',
+        data: profile,
+    })

+ 70 - 0
src/api/token.ts

@@ -0,0 +1,70 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/config/axios'
+import { Login } from '@/config/types'
+
+/**
+ * 获取 Salt
+ *
+ * @param login Login
+ * @returns MyAxiosPromise
+ */
+export const generateSalt = (login: Login) =>
+    request<R>({
+        url: `api/v3/auth/token/salt`,
+        method: 'post',
+        data: login,
+    })
+
+/**
+ * 登录
+ *
+ * @param login Login
+ * @returns MyAxiosPromise
+ */
+export const generateToken = (login: Login) =>
+    request<R>({
+        url: `api/v3/auth/token/generate`,
+        method: 'post',
+        data: login,
+    })
+
+/**
+ * 注销
+ *
+ * @param login Login
+ * @returns MyAxiosPromise
+ */
+export const cancelToken = (login: Login) =>
+    request<R>({
+        url: `api/v3/auth/token/cancel`,
+        method: 'post',
+        data: login,
+    })
+
+/**
+ * 校验 Token
+ *
+ * @param login Login
+ * @returns MyAxiosPromise
+ */
+export const checkTokenValid = (login: Login) =>
+    request<R>({
+        url: `api/v3/auth/token/check`,
+        method: 'post',
+        data: login,
+    })

+ 29 - 0
src/components/card/base/BaseCard.vue

@@ -0,0 +1,29 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="base-card">
+        <el-card shadow="hover">
+            <slot />
+        </el-card>
+    </div>
+</template>
+
+<script src="./index.ts" lang="ts" />
+
+<style lang="scss">
+@import './style.scss';
+</style>

+ 21 - 0
src/components/card/base/index.ts

@@ -0,0 +1,21 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+    name: 'BaseCard',
+})

+ 38 - 0
src/components/card/base/style.scss

@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.base-card {
+  border-radius: 5px;
+  box-sizing: border-box;
+
+  ul {
+    list-style: none;
+
+    li {
+      font-size: 13px;
+      margin-top: 8px;
+    }
+  }
+
+  .el-card {
+    width: 100%;
+    box-sizing: border-box;
+  }
+
+  .el-card__body {
+    padding: 10px;
+  }
+}

+ 29 - 0
src/components/card/blank/BlankCard.vue

@@ -0,0 +1,29 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="blank-card">
+        <el-card class="blank-card-body" :shadow="!embedded ? 'hover' : 'never'">
+            <slot />
+        </el-card>
+    </div>
+</template>
+
+<script src="./index.ts" lang="ts" />
+
+<style lang="scss">
+@import './style.scss';
+</style>

+ 29 - 0
src/components/card/blank/index.ts

@@ -0,0 +1,29 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+    name: 'BlankCard',
+    props: {
+        embedded: {
+            type: Boolean,
+            default: () => {
+                return false
+            },
+        },
+    },
+})

+ 34 - 0
src/components/card/blank/style.scss

@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.blank-card {
+    ul {
+        list-style: none;
+
+        li {
+            font-size: 13px;
+            margin-top: 8px;
+        }
+    }
+
+    .el-card.blank-card-body {
+        border: 0;
+    }
+
+    .el-card__body {
+        padding: 10px 3px;
+    }
+}

+ 29 - 0
src/components/card/detail/DetailCard.vue

@@ -0,0 +1,29 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="detail-card">
+        <el-card shadow="hover">
+            <slot />
+        </el-card>
+    </div>
+</template>
+
+<script src="./index.ts" lang="ts" />
+
+<style lang="scss">
+@import './style.scss';
+</style>

+ 21 - 0
src/components/card/detail/index.ts

@@ -0,0 +1,21 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+    name: 'DetailCard',
+})

+ 41 - 0
src/components/card/detail/style.scss

@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.detail-card {
+    margin-left: 3px;
+    margin-right: 3px;
+    margin-bottom: 6px;
+    border-radius: 5px;
+    box-sizing: border-box;
+
+    ul {
+        list-style: none;
+
+        li {
+            font-size: 13px;
+            margin-top: 8px;
+        }
+    }
+
+    .el-card {
+        width: 100%;
+        box-sizing: border-box;
+    }
+
+    .el-card__body {
+        padding: 10px 3px;
+    }
+}

+ 66 - 0
src/components/card/skeleton/SkeletonCard.vue

@@ -0,0 +1,66 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <el-skeleton :loading="loading" animated>
+        <template #template>
+            <div class="things-card">
+                <el-card shadow="hover">
+                    <div class="things-card-content">
+                        <div v-if="!header" class="things-card__header">
+                            <el-skeleton-item class="things-card-header-icon skeleton" ariant="image" />
+                            <el-skeleton-item class="things-card-header-name skeleton" variant="text" />
+                        </div>
+                        <div class="things-card__body">
+                            <div class="things-card-body-content" :class="{ left: header, center: !header }">
+                                <ul>
+                                    <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                    <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                    <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                    <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                    <div v-if="header">
+                                        <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                        <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                        <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                        <el-skeleton-item class="nowrap-item skeleton" variant="text" />
+                                    </div>
+                                </ul>
+                            </div>
+                            <div v-if="!header" class="things-card-body-content">
+                                <el-skeleton-item class="nowrap-description skeleton" variant="text" />
+                            </div>
+                        </div>
+                        <div v-if="!footer" class="things-card__footer">
+                            <div class="things-card-footer-operation">
+                                <el-skeleton-item class="operation-tooltip skeleton" variant="button" />
+                                <el-skeleton-item class="operation-tooltip skeleton" variant="button" />
+                                <el-skeleton-item class="operation-tooltip skeleton" variant="button" />
+                                <el-skeleton-item class="operation-tooltip skeleton" variant="button" />
+                                <el-skeleton-item class="operation-tooltip skeleton" variant="button" />
+                            </div>
+                        </div>
+                    </div>
+                </el-card>
+            </div>
+        </template>
+    </el-skeleton>
+</template>
+
+<script src="./index.ts" lang="ts" />
+
+<style lang="scss">
+@import './style.scss';
+</style>

+ 41 - 0
src/components/card/skeleton/index.ts

@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+    name: 'SkeletonCard',
+    props: {
+        loading: {
+            type: Boolean,
+            default: () => {
+                return false
+            },
+        },
+        header: {
+            type: Boolean,
+            default: () => {
+                return false
+            },
+        },
+        footer: {
+            type: Boolean,
+            default: () => {
+                return false
+            },
+        },
+    },
+})

+ 50 - 0
src/components/card/skeleton/style.scss

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import '@/components/card/styles/things-card.scss';
+
+.things-card-header-icon.skeleton {
+    width: 55px !important;
+}
+
+.things-card-header-name.skeleton {
+    margin-top: 10px;
+    height: 28px !important;
+}
+
+.nowrap-item.skeleton {
+    margin-bottom: 12px;
+}
+
+.nowrap-description.skeleton {
+    margin-top: 10px;
+    margin-bottom: 17px;
+}
+
+.things-card-body-content.center {
+    justify-content: center !important;
+}
+
+.things-card-body-content.left {
+    margin-left: 30px;
+    justify-content: left !important;
+}
+
+.operation-tooltip.skeleton {
+    width: 28px;
+    height: 20px;
+    margin-top: 15px;
+}

+ 71 - 0
src/components/card/styles/edit-card.scss

@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.edit-card {
+    margin-top: 1px;
+
+    .edit-card-header {
+        margin-bottom: 4px;
+
+        .el-card {
+            border: 0;
+        }
+    }
+
+    .edit-card-body {
+
+        .edit-form-item {
+            display: flex;
+            margin-top: 10px;
+            margin-bottom: 10px;
+            justify-content: center;
+
+            .el-row {
+                justify-content: center;
+            }
+
+            .el-alert {
+                margin-bottom: 10px;
+            }
+
+            .el-textarea__inner {
+                height: 80px;
+            }
+        }
+
+        .edit-form-button {
+            display: flex;
+            margin-top: 10px;
+
+            .el-form-item__content {
+                justify-content: center;
+            }
+        }
+    }
+
+    .el-form-item__label {
+        display: block;
+        width: 100px;
+        height: 32px;
+        text-align: justify;
+    }
+
+    .el-form-item__label::after {
+        display: inline-block;
+        width: 100%;
+        content: "";
+    }
+}

+ 232 - 0
src/components/card/styles/things-card.scss

@@ -0,0 +1,232 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.things-card {
+    margin-left: 3px;
+    margin-right: 3px;
+    margin-bottom: 6px;
+    border-radius: 5px;
+    box-sizing: border-box;
+
+    .things-card-content {
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+
+        .things-card__header {
+            width: 100%;
+            height: 55px;
+            display: flex;
+
+            .things-card-header-icon {
+                width: 48px;
+                height: 48px;
+                margin-right: 12px;
+                border-radius: 10px;
+                overflow: hidden;
+
+                img {
+                    width: 100%;
+                    height: 100%;
+                }
+            }
+
+            .things-card-header-name {
+                height: 48px;
+                line-height: 48px;
+                font-size: 14px;
+                font-weight: bold;
+                color: rgba(0, 0, 0, .85);
+                cursor: pointer;
+
+                &:hover {
+                    color: #1890ff;
+                }
+            }
+
+            .things-card-header-status {
+                height: 48px;
+                line-height: 48px;
+                text-align: right;
+                flex: 1;
+            }
+        }
+
+        .things-card__body {
+            display: flex;
+            flex-direction: column;
+
+            ul {
+                padding-inline-start: 5px;
+                list-style: none;
+
+                li {
+                    font-size: 13px;
+                    margin-top: 8px;
+                }
+            }
+
+            .things-card-body-content {
+                display: flex;
+                justify-content: space-around;
+
+                p.nowrap-description {
+                    text-align: center;
+                }
+            }
+
+            .things-card-body-content-time {
+                display: flex;
+                justify-content: center;
+                margin-top: 5px;
+            }
+
+            .things-card-body-content-value {
+                display: flex;
+                flex-direction: column;
+                list-style: none;
+                text-align: center;
+
+                .value {
+                    font-weight: bold;
+                    font-size: xx-large;
+                    animation: hue 1s ease-in;
+                    cursor: pointer;
+                }
+
+                .value-edit {
+                    cursor: pointer;
+                    color: #1296DB;
+                }
+
+                .value-detail {
+                    margin-top: 8px;
+                    margin-bottom: -4px;
+                    cursor: pointer;
+                    color: #1296DB;
+                    font-size: 18px;
+                }
+
+                .value-point {
+                    height: 17px;
+                }
+
+                @keyframes hue {
+                    0% {
+                        color: #1296DB;
+                    }
+
+                    50% {
+                        color: #f3f4fe;
+                    }
+
+                    100% {
+                        color: #1296DB;
+                    }
+                }
+            }
+
+            .things-body-content-item-column-2 {
+                width: 200px;
+            }
+
+        }
+
+        .things-card__footer {
+            height: 35px;
+            margin-top: 2px;
+            display: flex;
+            justify-content: flex-end;
+            border-top: 1px solid #dcdfe6;
+
+            .things-card-footer-title {
+                text-align: center;
+                font-size: 14px;
+                font-weight: bold;
+                width: 100%;
+                margin-top: 5px;
+            }
+
+            .things-card-footer-copy-id {
+                height: 35px;
+                line-height: 35px;
+                text-align: center;
+            }
+
+            .things-card-footer-operation {
+                height: 35px;
+                display: flex;
+
+                .operation-tooltip {
+                    margin-right: 10px;
+                }
+            }
+        }
+    }
+
+
+    .nowrap-name {
+        display: block;
+        width: 200px;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+    }
+
+    .nowrap-item {
+        display: block;
+        width: 300px;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+    }
+
+    .nowrap-description {
+        display: block;
+        width: 350px;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+    }
+
+    .el-card {
+        width: 100%;
+        min-width: 300px;
+        min-height: 230px;
+        box-sizing: border-box;
+    }
+
+    .el-card__body {
+        padding: 10px;
+    }
+}
+
+.cursor-pointer {
+    cursor: pointer;
+}
+
+.header-enable {
+    border-bottom: 1px solid #c2e7b0;
+}
+
+.header-disable {
+    border-bottom: 1px solid #fbc4c4;
+}
+
+.el-popover.el-popper {
+    width: 300px;
+}

+ 67 - 0
src/components/card/styles/tool-card.scss

@@ -0,0 +1,67 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.tool-card {
+    margin-top: 1px;
+    margin-bottom: 4px;
+
+    .el-card {
+        border: 0;
+    }
+}
+
+.tool-card-body {
+    display: flex;
+    flex-direction: column;
+
+    .tool-card-body-form {
+        display: flex;
+        justify-content: center;
+    }
+
+    .tool-card-body-button {
+        .el-form-item__content {
+            display: flex;
+            justify-content: center;
+        }
+    }
+}
+
+.tool-card-footer {
+    display: flex;
+    justify-content: space-between;
+
+    .tool-card-footer-button {
+        display: flex;
+    }
+
+    .tool-card-footer-page {
+        display: flex;
+    }
+}
+
+.tool-select {
+    .tool-select-input {
+        margin-left: 10px;
+        margin-right: 10px;
+        margin-bottom: 5px;
+    }
+
+    .tool-select-pagination {
+        justify-content: center;
+        margin-bottom: 5px;
+    }
+}

+ 32 - 0
src/components/card/title/TitleCard.vue

@@ -0,0 +1,32 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="title-card">
+        <el-card shadow="hover">
+            <slot name="header">
+                <span class="title-card__header">{{ title }}</span>
+            </slot>
+            <slot />
+        </el-card>
+    </div>
+</template>
+
+<script src="./index.ts" lang="ts" />
+
+<style lang="scss">
+@import './style.scss';
+</style>

+ 27 - 0
src/components/card/title/index.ts

@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+    name: 'TitleCard',
+    props: {
+        title: {
+            type: String,
+            default: '',
+        },
+    },
+})

+ 43 - 0
src/components/card/title/style.scss

@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.title-card {
+    border-radius: 5px;
+    box-sizing: border-box;
+
+    .title-card__header {
+        font-size: 14px;
+        font-weight: bold;
+    }
+
+    .el-card {
+        width: 100%;
+        box-sizing: border-box;
+    }
+
+    .el-card__header {
+        padding: 10px;
+    }
+
+    .el-card__body {
+        padding: 10px;
+    }
+
+    &:first-child {
+        padding-top: 0;
+        padding-left: 0;
+    }
+}

+ 85 - 0
src/components/dialog/styles/things-dialog.scss

@@ -0,0 +1,85 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.things-dialog {
+    .things-dialog-form-item {
+        display: flex;
+
+        .el-form-item__label {
+            width: 100px;
+            height: 32px;
+            display: block;
+            text-align: justify;
+        }
+
+        .el-form-item__label::after {
+            display: inline-block;
+            width: 100%;
+            content: '';
+        }
+    }
+
+    .things-dialog-upload {
+        margin-top: 20px;
+
+        .el-upload__icon {
+            font-size: 71px;
+            color: var(--el-text-color-placeholder);
+            margin-bottom: 16px;
+            line-height: 35px;
+        }
+
+        .el-upload__text {
+            color: var(--el-text-color-regular);
+            font-size: 14px;
+            text-align: center;
+        }
+    }
+
+    .things-dialog-form-alert {
+        margin-bottom: 10px;
+    }
+
+    .things-dialog-footer {
+        display: flex;
+        justify-content: flex-end;
+    }
+
+    .el-dialog__title {
+        font-size: 16px;
+        font-weight: bold;
+    }
+
+    .el-dialog__body {
+        padding: 30px 30px 15px 30px;
+
+        pre {
+            margin: auto;
+        }
+    }
+
+    .el-form-item__content {
+        width: 100%;
+
+        .el-select {
+            width: 100%;
+        }
+
+        .el-textarea__inner {
+            height: 100px;
+        }
+    }
+}

+ 34 - 0
src/components/error/403.vue

@@ -0,0 +1,34 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="error">
+        <div class="img" style="background-image: url('/images/error/403.svg')"></div>
+        <div class="content">
+            <h1>403</h1>
+            <div class="desc">抱歉,你无权访问该页面</div>
+            <div class="actions">
+                <router-link :to="{ path: '/' }">
+                    <el-button type="primary" plain>返回首页</el-button>
+                </router-link>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+@import 'style.scss';
+</style>

+ 34 - 0
src/components/error/404.vue

@@ -0,0 +1,34 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="error">
+        <div class="img" style="background-image: url('/images/error/404.svg')"></div>
+        <div class="content">
+            <h1>404</h1>
+            <div class="desc">抱歉,你访问的页面不存在</div>
+            <div class="actions">
+                <router-link :to="{ path: '/' }">
+                    <el-button type="primary" plain>返回首页</el-button>
+                </router-link>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+@import 'style.scss';
+</style>

+ 34 - 0
src/components/error/500.vue

@@ -0,0 +1,34 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="error">
+        <div class="img" style="background-image: url('/images/error/500.svg')"></div>
+        <div class="content">
+            <h1>500</h1>
+            <div class="desc">抱歉,服务器出错了</div>
+            <div class="actions">
+                <router-link :to="{ path: '/' }">
+                    <el-button type="primary" plain>返回首页</el-button>
+                </router-link>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+@import 'style.scss';
+</style>

+ 51 - 0
src/components/error/style.scss

@@ -0,0 +1,51 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.error {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+
+    .img {
+        height: 360px;
+        width: 100%;
+        max-width: 430px;
+        background-repeat: no-repeat;
+        background-position: 50% 50%;
+        background-size: contain;
+    }
+
+    .content {
+        text-align: center;
+
+        h1 {
+            color: #1296DB;
+            font-size: 72px;
+            font-weight: 600;
+            line-height: 72px;
+            margin-bottom: 24px;
+        }
+
+        .desc {
+            color: black;
+            font-size: 15px;
+            line-height: 28px;
+            margin-bottom: 16px;
+        }
+    }
+}

+ 76 - 0
src/components/layout/Layout.vue

@@ -0,0 +1,76 @@
+<!--
+  - Copyright 2022 Pnoker All Rights Reserved
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -      https://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  -->
+
+<template>
+    <div class="container">
+        <div class="header">
+            <el-col :span="4" class="header_item">
+                <img class="header_logo" src="/images/logo/logo.png" />
+            </el-col>
+            <el-col :span="16" class="header_item">
+                <el-menu :default-active="handleMenuEnter($route.path)" mode="horizontal" :router="true" class="header_menu">
+                    <el-menu-item index="/home">
+                        <el-icon>
+                            <HomeFilled />
+                        </el-icon>
+                        首页
+                    </el-menu-item>
+                    <template v-for="menu in menus">
+                        <el-sub-menu v-if="menu.children" :key="menu.name" :index="menu.path">
+                            <template #title>{{ menu.meta.title }}</template>
+                            <el-menu-item v-for="m in menu.children" :key="m.path" :index="m.path">{{ m.meta.title }}</el-menu-item>
+                        </el-sub-menu>
+                        <el-menu-item v-else :key="menu.name" :index="menu.path">
+                            <el-icon>
+                                <component :is="menu.meta.icon"></component>
+                            </el-icon>
+                            {{ menu.meta.title }}
+                        </el-menu-item>
+                    </template>
+                </el-menu>
+            </el-col>
+            <el-col :span="4" class="header_item header_user">
+                <el-dropdown class="user_avatar" trigger="click" @command="handleCommand">
+                    <span class="el-dropdown-link">
+                        <el-avatar>
+                            <img src="/images/common/avatar.png" />
+                        </el-avatar>
+                    </span>
+                    <template #dropdown>
+                        <el-dropdown-menu>
+                            <el-dropdown-item command="help">关于</el-dropdown-item>
+                            <el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
+                        </el-dropdown-menu>
+                    </template>
+                </el-dropdown>
+                <el-badge :value="3" :max="99" class="user_badge" type="primary">
+                    <span class="small" @click="handleMessage">管理员</span>
+                </el-badge>
+            </el-col>
+        </div>
+        <div class="body">
+            <el-scrollbar>
+                <router-view />
+            </el-scrollbar>
+        </div>
+    </div>
+</template>
+
+<script src="./index.ts" lang="ts" />
+
+<style lang="scss">
+@import '@/components/layout/style.scss';
+</style>

+ 65 - 0
src/components/layout/index.ts

@@ -0,0 +1,65 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import router from '@/config/router'
+import menu from '@/config/router/views'
+import { warning } from '@/utils/MessageUtils'
+import { HomeFilled } from '@element-plus/icons-vue'
+import { computed, defineComponent } from 'vue'
+import { useStore } from 'vuex'
+
+export default defineComponent({
+    components: {
+        HomeFilled,
+    },
+    setup() {
+        const store = useStore()
+
+        const menus = computed(() => {
+            const children = menu?.children || []
+            return children.filter((view) => view.name !== 'home')
+        })
+
+        const handleMenuEnter = (index: string) => {
+            if (index.indexOf('/') === 0) {
+                const split = index.split('/')
+                if (split.length > 2) {
+                    return '/' + split[1]
+                }
+            }
+            return index
+        }
+
+        const handleMessage = () => {
+            warning('待开发')
+        }
+
+        const handleCommand = (command: string) => {
+            if (command === 'logout') {
+                store.dispatch('auth/logout').then(() => router.push({ path: '/login' }))
+            } else if (command === 'help') {
+                window.open('https://doc.dc3.site')
+            }
+        }
+
+        return {
+            menus,
+            handleMenuEnter,
+            handleMessage,
+            handleCommand,
+        }
+    },
+})

+ 88 - 0
src/components/layout/style.scss

@@ -0,0 +1,88 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+body {
+    margin: 0;
+    min-width: 1280px;
+    min-height: 768px;
+}
+
+.container {
+    color: #2c3e50;
+    -moz-osx-font-smoothing: grayscale;
+    -webkit-font-smoothing: antialiased;
+    font-family: 'Avenir', Helvetica, Arial, sans-serif;
+}
+
+.header {
+    top: 0;
+    width: 100%;
+    height: 60px;
+    display: flex;
+    border-bottom: 1px solid #dcdfe6;
+
+    .header_item {
+        height: 100%;
+    }
+
+    .header_logo {
+        height: 60px;
+        margin-left: 10px;
+    }
+
+    .header_menu {
+        display: flex;
+        justify-content: center;
+        border-bottom: none !important;
+    }
+
+    .header_menu .el-menu-item {
+        font-size: 15px;
+    }
+
+    .header_user {
+        display: flex;
+        justify-content: flex-end;
+        padding-right: 10px;
+
+        .user_avatar {
+            top: 10px;
+            cursor: pointer;
+        }
+
+        .user_badge {
+            top: 25px;
+            cursor: pointer;
+            margin-right: 40px;
+        }
+
+        .small {
+            color: #909399;
+            font-size: 14px;
+            margin: 20px 10px;
+        }
+    }
+}
+
+.body {
+    top: 60px;
+    right: 0;
+    left: 0;
+    bottom: 0;
+    padding: 5px 0 5px 0;
+    position: absolute;
+    background: #f0f2f5;
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 425 - 0
src/components/particles/particles.vue


+ 82 - 0
src/config/axios/index.ts

@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import axios, { AxiosInstance } from 'axios'
+
+import CommonConstant from '@/config/constant/common'
+import { logout } from '@/utils/CommonUtils'
+import { failMessage } from '@/utils/NotificationUtils'
+import { getStorage } from '@/utils/StorageUtils'
+import { isNull } from '@/utils/utils'
+import { encode } from 'js-base64'
+
+const request: AxiosInstance = axios.create({
+    timeout: 15000,
+    withCredentials: true,
+    headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
+    validateStatus: (status) => status >= 200 && status <= 500,
+})
+
+request.interceptors.request.use(
+    (config) => {
+        const headers = config.headers
+        if (!headers) {
+            return config
+        }
+
+        const tenant = getStorage(CommonConstant.TENANT_HEADER)
+        if (!isNull(tenant)) {
+            headers[CommonConstant.TENANT_HEADER] = encode(tenant)
+        }
+
+        const user = getStorage(CommonConstant.USER_LOGIN)
+        if (!isNull(user)) {
+            headers[CommonConstant.USER_LOGIN] = encode(user)
+        }
+
+        const token = getStorage(CommonConstant.TOKEN_HEADER)
+        if (!isNull(token)) {
+            headers[CommonConstant.TOKEN_HEADER] = encode(JSON.stringify(token))
+        }
+
+        return config
+    },
+    (error: any) => {
+        return Promise.reject(error)
+    }
+)
+
+request.interceptors.response.use(
+    (response) => {
+        const ok = response.data.ok || false
+        const status = response.status || 401
+        const responseType = response.config.responseType
+
+        if (ok || responseType === 'blob') return response
+
+        if (status === 401) {
+            logout()
+        } else {
+            failMessage('接口请求异常,请联系系统管理员。', response.data.code, response.data)
+        }
+        return Promise.reject()
+    },
+    (error: any) => {
+        return Promise.reject(error)
+    }
+)
+
+export default request

+ 21 - 0
src/config/constant/common.ts

@@ -0,0 +1,21 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default {
+    TENANT_HEADER: 'X-Auth-Tenant',
+    USER_LOGIN: 'X-Auth-Login',
+    TOKEN_HEADER: 'X-Auth-Token',
+}

+ 1 - 0
src/config/env/.env

@@ -0,0 +1 @@
+APP_CLI_PORT = "8080"

+ 3 - 0
src/config/env/.env.dev

@@ -0,0 +1,3 @@
+APP_API_PATH = "http://localhost"
+APP_API_PORT = "8000"
+APP_API_PREFIX = "/api"

+ 3 - 0
src/config/env/.env.mock

@@ -0,0 +1,3 @@
+APP_API_PATH = "http://dc3-gateway"
+APP_API_PORT = "8000"
+APP_API_PREFIX = "/api"

+ 3 - 0
src/config/env/.env.pre

@@ -0,0 +1,3 @@
+APP_API_PATH = "http://dc3-gateway"
+APP_API_PORT = "8000"
+APP_API_PREFIX = "/api"

+ 3 - 0
src/config/env/.env.pro

@@ -0,0 +1,3 @@
+APP_API_PATH = "http://dc3-gateway"
+APP_API_PORT = "8000"
+APP_API_PREFIX = "/api"

+ 3 - 0
src/config/env/.env.test

@@ -0,0 +1,3 @@
+APP_API_PATH = "http://dc3-gateway"
+APP_API_PORT = "8000"
+APP_API_PREFIX = "/api"

+ 35 - 0
src/config/plugins/element/element-variables.scss

@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.edit-form-small {
+    width: 120px;
+}
+
+.edit-form-medium {
+    width: 150px;
+}
+
+.edit-form-default {
+    width: 250px;
+}
+
+.edit-form-special {
+    width: 300px;
+}
+
+.edit-form-large {
+    width: 500px;
+}

+ 29 - 0
src/config/plugins/element/element.ts

@@ -0,0 +1,29 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Hide, Histogram, List, Management, Promotion, View } from '@element-plus/icons-vue'
+import element from 'element-plus'
+import 'element-plus/dist/index.css'
+import './element-variables.scss'
+import locale from 'element-plus/es/locale/lang/zh-cn'
+
+export default (app: any) => {
+    const Icons = [Hide, Histogram, List, Management, Promotion, View]
+    Icons.forEach((icon) => {
+        app.component(icon.name, icon)
+    })
+    app.use(element, { locale })
+}

+ 46 - 0
src/config/plugins/highlight/highlight.ts

@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 Pnoker All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import hljs from 'highlight.js'
+import 'highlight.js/styles/atom-one-dark.css'
+
+export default (app: any) => {
+    app.directive('highlight', {
+        // Directive has a set of lifecycle hooks:
+        // called before bound element's parent component is mounted
+        beforeMount(el: any) {
+            // on first bind, highlight all targets
+            const blocks = el.querySelectorAll('pre code')
+            for (let i = 0; i < blocks.length; i++) {
+                const item = blocks[i]
+                console.log(item)
+                hljs.highlightBlock(item)
+            }
+        },
+        // called after the containing component's VNode and the VNodes of its children // have updated
+        updated(el: any, binding: any) {
+            // after an update, re-fill the content and then highlight
+            const targets = el.querySelectorAll('code')
+            for (let i = 0; i < targets.length; i += 1) {
+                const target = targets[i]
+                if (typeof binding.value === 'string') {
+                    target.textContent = binding.value
+                }
+                hljs.highlightBlock(target)
+            }
+        },
+    })
+}

+ 0 - 0
src/config/plugins/index.ts


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä