Sfoglia il codice sorgente

Merge branch 'v2.0' into v2.0_ch

chenlei 3 mesi fa
parent
commit
8706fde0d3

+ 4 - 0
index.html

@@ -5,10 +5,14 @@
     <link rel="icon" type="image/x-icon" href="/fa.ico" id="icon"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>ETA社区</title>
+    <link href='/froala_editor.pkgd.min.css' rel='stylesheet' type='text/css' />
   </head>
   <body>
     <div id="app"></div>
     <script type="module" src="/src/main.js"></script>
+    <script src="/jquery-3.6.0.min.js"></script>
+    <script type='text/javascript' src='/froala_editor.pkgd.min.js'></script>
+    <script type='text/javascript' src='/froala_editor_zh_cn.js'></script>
     	<!-- oss SDK -->
     <script type="text/javascript" src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.16.0.min.js"></script>
   </body>

+ 1 - 2
package.json

@@ -15,14 +15,13 @@
     "@vueuse/core": "^10.9.0",
     "axios": "^1.6.8",
     "dagre": "^0.8.5",
-    "element-plus": "^2.7.1",
     "highcharts": "^11.4.1",
     "js-md5": "^0.8.3",
     "lodash": "^4.17.21",
     "moment": "^2.30.1",
     "normalize.css": "^8.0.1",
     "tdesign-icons-vue-next": "^0.2.2",
-    "tdesign-vue-next": "^1.10.4",
+    "tdesign-vue-next": "^1.10.5",
     "vue": "^3.5.13",
     "vue-router": "^4.3.2"
   },

+ 4 - 137
pnpm-lock.yaml

@@ -16,9 +16,6 @@ dependencies:
   dagre:
     specifier: ^0.8.5
     version: 0.8.5
-  element-plus:
-    specifier: ^2.7.1
-    version: 2.7.6(vue@3.5.13)
   highcharts:
     specifier: ^11.4.1
     version: 11.4.3
@@ -35,8 +32,8 @@ dependencies:
     specifier: ^0.2.2
     version: 0.2.2(vue@3.5.13)
   tdesign-vue-next:
-    specifier: ^1.10.4
-    version: 1.10.4(vue@3.5.13)
+    specifier: ^1.10.5
+    version: 1.10.5(vue@3.5.13)
   vue:
     specifier: ^3.5.13
     version: 3.5.13
@@ -381,19 +378,6 @@ packages:
       '@babel/helper-string-parser': 7.25.9
       '@babel/helper-validator-identifier': 7.25.9
 
-  /@ctrl/tinycolor@3.6.1:
-    resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
-    engines: {node: '>=10'}
-    dev: false
-
-  /@element-plus/icons-vue@2.3.1(vue@3.5.13):
-    resolution: {integrity: sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==}
-    peerDependencies:
-      vue: ^3.2.0
-    dependencies:
-      vue: 3.5.13
-    dev: false
-
   /@esbuild/aix-ppc64@0.21.5:
     resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
     engines: {node: '>=12'}
@@ -601,23 +585,6 @@ packages:
     dev: true
     optional: true
 
-  /@floating-ui/core@1.6.3:
-    resolution: {integrity: sha512-1ZpCvYf788/ZXOhRQGFxnYQOVgeU+pi0i+d0Ow34La7qjIXETi6RNswGVKkA6KcDO8/+Ysu2E/CeUmmeEBDvTg==}
-    dependencies:
-      '@floating-ui/utils': 0.2.3
-    dev: false
-
-  /@floating-ui/dom@1.6.6:
-    resolution: {integrity: sha512-qiTYajAnh3P+38kECeffMSQgbvXty2VB6rS+42iWR4FPIlZjLK84E9qtLnMTLIpPz2znD/TaFqaiavMUrS+Hcw==}
-    dependencies:
-      '@floating-ui/core': 1.6.3
-      '@floating-ui/utils': 0.2.3
-    dev: false
-
-  /@floating-ui/utils@0.2.3:
-    resolution: {integrity: sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==}
-    dev: false
-
   /@isaacs/cliui@8.0.2:
     resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
     engines: {node: '>=12'}
@@ -846,10 +813,6 @@ packages:
     dev: true
     optional: true
 
-  /@sxzz/popperjs-es@2.11.7:
-    resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
-    dev: false
-
   /@trysound/sax@0.2.0:
     resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
     engines: {node: '>=10.13.0'}
@@ -859,20 +822,10 @@ packages:
     resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
     dev: true
 
-  /@types/lodash-es@4.17.12:
-    resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
-    dependencies:
-      '@types/lodash': 4.17.6
-    dev: false
-
   /@types/lodash@4.14.182:
     resolution: {integrity: sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==}
     dev: false
 
-  /@types/lodash@4.17.6:
-    resolution: {integrity: sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==}
-    dev: false
-
   /@types/node@20.14.9:
     resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==}
     dependencies:
@@ -897,10 +850,6 @@ packages:
     resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==}
     dev: false
 
-  /@types/web-bluetooth@0.0.16:
-    resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
-    dev: false
-
   /@types/web-bluetooth@0.0.20:
     resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
 
@@ -1053,25 +1002,9 @@ packages:
       - '@vue/composition-api'
       - vue
 
-  /@vueuse/core@9.13.0(vue@3.5.13):
-    resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
-    dependencies:
-      '@types/web-bluetooth': 0.0.16
-      '@vueuse/metadata': 9.13.0
-      '@vueuse/shared': 9.13.0(vue@3.5.13)
-      vue-demi: 0.14.10(vue@3.5.13)
-    transitivePeerDependencies:
-      - '@vue/composition-api'
-      - vue
-    dev: false
-
   /@vueuse/metadata@10.11.0:
     resolution: {integrity: sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ==}
 
-  /@vueuse/metadata@9.13.0:
-    resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
-    dev: false
-
   /@vueuse/shared@10.11.0(vue@3.5.13):
     resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==}
     dependencies:
@@ -1080,15 +1013,6 @@ packages:
       - '@vue/composition-api'
       - vue
 
-  /@vueuse/shared@9.13.0(vue@3.5.13):
-    resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
-    dependencies:
-      vue-demi: 0.14.10(vue@3.5.13)
-    transitivePeerDependencies:
-      - '@vue/composition-api'
-      - vue
-    dev: false
-
   /abort-controller@3.0.0:
     resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
     engines: {node: '>=6.5'}
@@ -1215,10 +1139,6 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /async-validator@4.2.5:
-    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
-    dev: false
-
   /async@3.2.6:
     resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
     dev: true
@@ -1588,10 +1508,6 @@ packages:
     resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
     dev: false
 
-  /dayjs@1.11.11:
-    resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
-    dev: false
-
   /debug@2.6.9:
     resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
     peerDependencies:
@@ -1724,31 +1640,6 @@ packages:
     resolution: {integrity: sha512-8wGNxG9tAG5KhGd3eeA0o6ixhiNdgr0DcHWm85XPCphwZgD1lIEoi6t3VERayWao7SF7AAZTw6oARGJeVjH8Kg==}
     dev: true
 
-  /element-plus@2.7.6(vue@3.5.13):
-    resolution: {integrity: sha512-36sw1K23hYjgeooR10U6CiCaCp2wvOqwoFurADZVlekeQ9v5U1FhJCFGEXO6i/kZBBMwsE1c9fxjLs9LENw2Rg==}
-    peerDependencies:
-      vue: ^3.2.0
-    dependencies:
-      '@ctrl/tinycolor': 3.6.1
-      '@element-plus/icons-vue': 2.3.1(vue@3.5.13)
-      '@floating-ui/dom': 1.6.6
-      '@popperjs/core': /@sxzz/popperjs-es@2.11.7
-      '@types/lodash': 4.17.6
-      '@types/lodash-es': 4.17.12
-      '@vueuse/core': 9.13.0(vue@3.5.13)
-      async-validator: 4.2.5
-      dayjs: 1.11.11
-      escape-html: 1.0.3
-      lodash: 4.17.21
-      lodash-es: 4.17.21
-      lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21)
-      memoize-one: 6.0.0
-      normalize-wheel-es: 1.2.0
-      vue: 3.5.13
-    transitivePeerDependencies:
-      - '@vue/composition-api'
-    dev: false
-
   /emoji-regex@8.0.0:
     resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
     dev: true
@@ -1899,10 +1790,6 @@ packages:
     engines: {node: '>=6'}
     dev: true
 
-  /escape-html@1.0.3:
-    resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
-    dev: false
-
   /escape-string-regexp@1.0.5:
     resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
     engines: {node: '>=0.8.0'}
@@ -2642,18 +2529,6 @@ packages:
     resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
     dev: false
 
-  /lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21):
-    resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==}
-    peerDependencies:
-      '@types/lodash-es': '*'
-      lodash: '*'
-      lodash-es: '*'
-    dependencies:
-      '@types/lodash-es': 4.17.12
-      lodash: 4.17.21
-      lodash-es: 4.17.21
-    dev: false
-
   /lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
 
@@ -2694,10 +2569,6 @@ packages:
     resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
     dev: true
 
-  /memoize-one@6.0.0:
-    resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
-    dev: false
-
   /merge-options@1.0.1:
     resolution: {integrity: sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==}
     engines: {node: '>=4'}
@@ -2840,10 +2711,6 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /normalize-wheel-es@1.2.0:
-    resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
-    dev: false
-
   /normalize.css@8.0.1:
     resolution: {integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==}
     dev: false
@@ -3580,8 +3447,8 @@ packages:
       vue: 3.5.13
     dev: false
 
-  /tdesign-vue-next@1.10.4(vue@3.5.13):
-    resolution: {integrity: sha512-DdRf2WZKNwDVZ3y9+xxJi9XJmYyZjSnkJDDlDsUopPhg3jiUiJEdyUuAkAJIljgda6GZk+scrg8b8Am+kySbrw==}
+  /tdesign-vue-next@1.10.5(vue@3.5.13):
+    resolution: {integrity: sha512-z00HyuKI3xnXSzkBMPjjl87FnXrkxmF1MPJbEzys2Eh80ofRC+Pc+iPQbcbEOxJhJ0yeQYf2jzwgl/wmKesSrg==}
     peerDependencies:
       vue: '>=3.1.0'
     dependencies:

File diff suppressed because it is too large
+ 6 - 0
public/froala_editor.pkgd.min.css


File diff suppressed because it is too large
+ 6 - 0
public/froala_editor.pkgd.min.js


+ 304 - 0
public/froala_editor_zh_cn.js

@@ -0,0 +1,304 @@
+/*!
+ * froala_editor v4.0.19 (https://www.froala.com/wysiwyg-editor)
+ * License https://froala.com/wysiwyg-editor/terms/
+ * Copyright 2014-2023 Froala Labs
+ */
+
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('froala-editor')) :
+  typeof define === 'function' && define.amd ? define(['froala-editor'], factory) :
+  (factory(global.FroalaEditor));
+}(this, (function (FE) { 'use strict';
+
+  FE = FE && FE.hasOwnProperty('default') ? FE['default'] : FE;
+
+  /**
+  * Simplified Chinese spoken in China.
+  */
+  FE.LANGUAGE['zh_cn'] = {
+    translation: {
+      // Place holder
+      'Type something': '输入内容',
+      // Basic formatting
+      'Bold': '粗体',
+      'Italic': '斜体',
+      'Underline': '下划线',
+      'Strikethrough': '删除线',
+      // Main buttons
+      'Insert': '插入',
+      'Delete': '删除',
+      'Cancel': '取消',
+      'OK': '确定',
+      'Back': '后退',
+      'Remove': '删除',
+      'More': '更多',
+      'Update': '更新',
+      'Style': '样式',
+      // Font
+      'Font Family': '字体',
+      'Font Size': '字号',
+      // Colors
+      'Colors': '颜色',
+      'Background': '背景',
+      'Text': '字体',
+      'HEX Color': '十六进制颜色',
+      // Paragraphs
+      'Paragraph Format': '段落格式',
+      'Normal': '正文',
+      'Code': '代码',
+      'Heading 1': '标题1',
+      'Heading 2': '标题2',
+      'Heading 3': '标题3',
+      'Heading 4': '标题4',
+      // Style
+      'Paragraph Style': '段落样式',
+      'Inline Style': '内联样式',
+      // Alignment
+      'Align': '对齐方式',
+      'Align Left': '左对齐',
+      'Align Center': '居中',
+      'Align Right': '右对齐',
+      'Align Justify': '两端对齐',
+      'None': '无',
+      // Lists
+      'Ordered List': '编号',
+      'Unordered List': '项目符号',
+      // Indent
+      'Decrease Indent': '减少缩进量',
+      'Increase Indent': '增加缩进量',
+      // Links
+      'Insert Link': '插入超链接',
+      'Open in new tab': '在新标签页中打开',
+      'Open Link': '打开超链接',
+      'Edit Link': '编辑超链接',
+      'Unlink': '删除超链接',
+      'Choose Link': '选择超链接',
+      // Images
+      'Insert Image': '插入图片',
+      'Upload Image': '上传图片',
+      'By URL': '通过 URL',
+      'Browse': '浏览',
+      'Drop image': '拖入图片',
+      'or click': '或点击',
+      'Manage Images': '管理图片',
+      'Loading': '加载中',
+      'Deleting': '删除中',
+      'Tags': '标签',
+      'Are you sure? Image will be deleted.': '图片将会被删除,是否确认?',
+      'Replace': '替换',
+      'Uploading': '上传中',
+      'Loading image': '图片加载中',
+      'Display': '显示',
+      'Inline': '嵌入型',
+      'Break Text': '上下型环绕',
+      'Alternative Text': '替换文字',
+      'Change Size': '改变大小',
+      'Width': '宽度',
+      'Height': '高度',
+      'Something went wrong. Please try again.': '发生错误,请重试。',
+      'Image Caption': '图片标题',
+      'Advanced Edit': '高级编辑',
+      // Video
+      'Insert Video': '插入视频',
+      'Embedded Code': '嵌入代码',
+      'Paste in a video URL': '粘贴视频网址',
+      'Drop video': '拖入视频',
+      'Your browser does not support HTML5 video.': '您的浏览器不支持 HTML5 视频。',
+      'Upload Video': '上传视频',
+      // Tables
+      'Insert Table': '插入表格',
+      'Table Header': '表头',
+      'Remove Table': '删除表格',
+      'Table Style': '表格样式',
+      'Horizontal Align': '水平对齐方式',
+      'Row': '行',
+      'Insert row above': '在上方插入',
+      'Insert row below': '在下方插入',
+      'Delete row': '删除行',
+      'Column': '列',
+      'Insert column before': '在左侧插入',
+      'Insert column after': '在右侧插入',
+      'Delete column': '删除列',
+      'Cell': '单元格',
+      'Merge cells': '合并单元格',
+      'Horizontal split': '水平分割',
+      'Vertical split': '垂直分割',
+      'Cell Background': '单元格背景',
+      'Vertical Align': '垂直对齐方式',
+      'Top': '靠上',
+      'Middle': '居中',
+      'Bottom': '靠下',
+      'Align Top': '靠上对齐',
+      'Align Middle': '居中对齐',
+      'Align Bottom': '靠下对齐',
+      'Cell Style': '单元格样式',
+      // Files
+      'Upload File': '上传文件',
+      'Drop file': '拖入文件',
+      // Emoticons
+      'Emoticons': '表情符号',
+      'Grinning face': '露齿笑脸',
+      'Grinning face with smiling eyes': '露齿笑到眯起眼',
+      'Face with tears of joy': '笑哭',
+      'Smiling face with open mouth': '张嘴微笑',
+      'Smiling face with open mouth and smiling eyes': '眯眼张嘴微笑',
+      'Smiling face with open mouth and cold sweat': '带冷汗的张嘴微笑',
+      'Smiling face with open mouth and tightly-closed eyes': '紧闭双眼张嘴微笑',
+      'Smiling face with halo': '带光环微笑',
+      'Smiling face with horns': '带牛角的微笑',
+      'Winking face': '眨眼',
+      'Smiling face with smiling eyes': '眯眼微笑',
+      'Face savoring delicious food': '馋',
+      'Relieved face': '如释重负',
+      'Smiling face with heart-shaped eyes': '桃心眼微笑',
+      'Smiling face with sunglasses': '戴太阳镜微笑',
+      'Smirking face': '得意地笑',
+      'Neutral face': '中性脸',
+      'Expressionless face': '面无表情',
+      'Unamused face': '不高兴',
+      'Face with cold sweat': '冷汗',
+      'Pensive face': '沉思',
+      'Confused face': '迷惑',
+      'Confounded face': '困惑',
+      'Kissing face': '嘴巴嘟嘟',
+      'Face throwing a kiss': '飞吻',
+      'Kissing face with smiling eyes': '眯眼接吻',
+      'Kissing face with closed eyes': '闭眼接吻',
+      'Face with stuck out tongue': '吐舌',
+      'Face with stuck out tongue and winking eye': '眨眼吐舌',
+      'Face with stuck out tongue and tightly-closed eyes': '眯眼吐舌',
+      'Disappointed face': '失望',
+      'Worried face': '担心',
+      'Angry face': '生气',
+      'Pouting face': '撅嘴',
+      'Crying face': '大哭',
+      'Persevering face': '坚强',
+      'Face with look of triumph': '扬眉吐气',
+      'Disappointed but relieved face': '失望',
+      'Frowning face with open mouth': '皱眉',
+      'Anguished face': '痛苦',
+      'Fearful face': '害怕',
+      'Weary face': '疲惫',
+      'Sleepy face': '困了',
+      'Tired face': '累了',
+      'Grimacing face': '扭曲脸',
+      'Loudly crying face': '大哭',
+      'Face with open mouth': '张开嘴',
+      'Hushed face': '安静',
+      'Face with open mouth and cold sweat': '冷汗',
+      'Face screaming in fear': '害怕尖叫',
+      'Astonished face': '惊讶',
+      'Flushed face': '脸红',
+      'Sleeping face': '熟睡',
+      'Dizzy face': '眩晕',
+      'Face without mouth': '没有嘴的脸',
+      'Face with medical mask': '口罩脸',
+      // Line breaker
+      'Break': '换行',
+      // Math
+      'Subscript': '下标',
+      'Superscript': '上标',
+      // Full screen
+      'Fullscreen': '全屏',
+      // Horizontal line
+      'Insert Horizontal Line': '插入水平线',
+      // Clear formatting
+      'Clear Formatting': '清除格式',
+      // Save
+      'Save': '保存',
+      // Undo, redo
+      'Undo': '撤消',
+      'Redo': '恢复',
+      // Select all
+      'Select All': '全选',
+      // Code view
+      'Code View': '代码视图',
+      // Quote
+      'Quote': '引用',
+      'Increase': '增加引用级别',
+      'Decrease': '减少引用级别',
+      // Quick Insert
+      'Quick Insert': '快速插入',
+      // Spcial Characters
+      'Special Characters': '特殊字符',
+      'Latin': '拉丁字母',
+      'Greek': '希腊字母',
+      'Cyrillic': '西里尔字母',
+      'Punctuation': '标点',
+      'Currency': '货币',
+      'Arrows': '箭头',
+      'Math': '数学',
+      'Misc': '杂项',
+      // Print.
+      'Print': '打印',
+      // Spell Checker.
+      'Spell Checker': '拼写检查器',
+      // Help
+      'Help': '帮助',
+      'Shortcuts': '快捷键',
+      'Inline Editor': '内联编辑器',
+      'Show the editor': '显示编辑器',
+      'Common actions': '常用操作',
+      'Copy': '复制',
+      'Cut': '剪切',
+      'Paste': '粘贴',
+      'Basic Formatting': '基本格式',
+      'Increase quote level': '增加引用级别',
+      'Decrease quote level': '减少引用级别',
+      'Image / Video': '图像/视频',
+      'Resize larger': '放大',
+      'Resize smaller': '缩小',
+      'Table': '表格',
+      'Select table cell': '选择单元格',
+      'Extend selection one cell': '增加选中的单元格',
+      'Extend selection one row': '增加选中的行',
+      'Navigation': '导航',
+      'Focus popup / toolbar': '焦点弹出/工具栏',
+      'Return focus to previous position': '将焦点返回到上一个位置',
+      // Embed.ly
+      'Embed URL': '嵌入网址',
+      'Paste in a URL to embed': '粘贴要嵌入的网址',
+      // Word Paste.
+      'The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?': '粘贴的内容来自微软 Word 文档。你想保留还是清除格式?',
+      'Keep': '保留',
+      'Clean': '清除',
+      'Word Paste Detected': '检测到粘贴自 Word 的内容',
+      // Character Counter
+      'Characters': '字数统计',
+      // More Buttons
+      'More Text': ' 更多文字',
+      'More Paragraph': '更多段落',
+      'More Rich': '更多丰富',
+      'More Misc': '更多杂项',
+      'Rounded': '圆角',
+      'Bordered': '边框',
+      'Shadow': '阴影',
+      'Download PDF': '下载PDF',
+      'Text Color': '字体颜色',
+      'Background Color': '背景颜色',
+      'Inline Class': '内联类',
+      'Highlighted': '高亮',
+      'Transparent': '透明',
+      'Big Red': '大号红',
+      'Small Blue': '小号蓝',
+      'Default': '默认',
+      'Lower Alpha': 'a,b,c...',
+      'Lower Greek': 'α,β,γ...',
+      'Lower Roman': 'i,ii,iii...',
+      'Upper Alpha': 'A,B,C...',
+      'Upper Roman': 'Ⅰ,Ⅱ,Ⅲ...',
+      'Circle': '○ 空心圆',
+      'Disc': '● 实心圆',
+      'Square': '■ 实心方块',
+      'Gray': '灰色',
+      'Spaced': '字母间隙',
+      'Uppercase': '大写',
+      'Line Height': '行高',
+      'Single': '1',
+      'Double': '2'
+    },
+    direction: 'ltr'
+  };
+
+})));
+//# sourceMappingURL=zh_cn.js.map

File diff suppressed because it is too large
+ 1 - 0
public/jquery-3.6.0.min.js


+ 5 - 5
src/api/index.js

@@ -67,22 +67,22 @@ _axios.interceptors.response.use(
 
     if(response.status!==200){
       setTimeout(() => {
-        MessagePlugin.warning('网络异常')
+        MessagePlugin.error('网络异常')
       }, 100);
     }
 
     if(!data){
       setTimeout(() => {
-        MessagePlugin.warning('服务器开了个小差')
+        MessagePlugin.error('服务器开了个小差')
       }, 100);
     }
     if(data.Ret===408){//token失效
-      MessagePlugin.warning(data.Msg)
+      MessagePlugin.error(data.Msg)
       
     }
     if(data.Ret===403){
       setTimeout(() => {
-        MessagePlugin.warning(data.Msg||'网络异常')
+        MessagePlugin.error(data.Msg||'网络异常')
       }, 100);
     }
 
@@ -96,7 +96,7 @@ _axios.interceptors.response.use(
     }
     console.log(error);
     setTimeout(() => {
-      MessagePlugin.warning(error.message)
+      MessagePlugin.error(error.message)
     }, 300);
     // Do something with response error
     return Promise.reject(error);

+ 45 - 0
src/api/system/helpCenter.js

@@ -0,0 +1,45 @@
+import {get,post} from '@/api/index'
+// 帮助中心
+export default{
+  // 分类列表
+  classifyList:params=>{
+    return get('/help_doc/classify/list',params)
+  },
+  // 新增分类
+  classifyAdd:params=>{
+    return post('/help_doc/classify/add',params)
+  },
+  // 编辑分类
+  classifyEdit:params=>{
+    return post('/help_doc/classify/edit',params)
+  },
+  // 移动分类
+  classifyMove:params=>{
+    return post('/help_doc/classify/move',params)
+  },
+  // 删除分类
+  classifyDelete:params=>{
+    return get('/help_doc/classify/delete',params)
+  },
+
+  // 获取文章列表
+  getDocmentList:params=>{
+    return get('/help_doc/list',params)
+  },
+  // 删除文章
+  deleteDocment:params=>{
+    return post('/help_doc/delete',params)
+  },
+  // 发布\取消发布文章
+  publishDocment:params=>{
+    return post('/help_doc/publish',params)
+  },
+  // 新增文章
+  addDocment:params=>{
+    return post('/help_doc/add',params)
+  },
+  // 文章详情
+  docmentInfo:params=>{
+    return get('/help_doc/detail',params)
+  }
+}

+ 3 - 1
src/api/system/index.js

@@ -1,8 +1,10 @@
 import apiSystemSet from './set'
 import apiSystemCommon from './common'
+import apiSystemHelpCenter from './helpCenter'
 
 export {
     apiSystemSet,
-    apiSystemCommon
+    apiSystemCommon,
+    apiSystemHelpCenter
 }
 

+ 132 - 0
src/hooks/useFroalaEditor.js

@@ -0,0 +1,132 @@
+import { ref,nextTick } from "vue";
+
+export function useInitFroalaEditor() {
+	let frolaEditorContentChange=ref(false)//富文本内容是否改变
+	let lastFocusPosition=ref(null)//最后焦点位置
+	let imgUploadFlag=ref(true)//图片是否上传完成
+
+	let options = {
+		toolbarButtons: [
+			"insertImage",
+			"insertVideo",
+			"embedly",
+			"insertFile",
+			"textColor",
+			"bold",
+			"italic",
+			"underline",
+			"strikeThrough",
+			"subscript",
+			"superscript",
+			"fontFamily",
+			"fontSize",
+			"color",
+			"inlineClass",
+			"inlineStyle",
+			"paragraphStyle",
+			"lineHeight",
+			"paragraphFormat",
+			"align",
+			"formatOL",
+			"formatUL",
+			"outdent",
+			"indent",
+			"quote",
+			"insertTable",
+			"emoticons",
+			"fontAwesome",
+			"specialCharacters",
+			"insertHR",
+			"selectAll",
+			"clearFormatting",
+			"html",
+			"undo",
+			"redo"
+		],
+		height: 500,
+		fontSize: ["6","8","10","12", "13", "14", "15", "16", "18", "20", "24", "28", "32", "36", "40"],
+		
+		fontSizeDefaultSelection: "16",
+		theme: "dark", //主题
+		placeholderText: "请输入内容",
+		language: "zh_cn", //国际化
+		imageUploadURL: import.meta.env.VITE_APP_API_URL + '/report/uploadImg', //上传url
+		videoUploadURL: import.meta.env.VITE_APP_API_URL + '/report/uploadImg', //上传url
+		fileUploadURL: import.meta.env.VITE_APP_API_URL + '/report/uploadImg', //上传url 更多上传介绍 请访问https://www.froala.com/wysiwyg-editor/docs/options
+		imageDefaultWidth: false,
+		quickInsertEnabled: false,
+		// quickInsertButtons: ['image', 'ul', 'ol'], //快速插入项
+		toolbarVisibleWithoutSelection: true, //是否开启 不选中模式
+		toolbarSticky: false, //操作栏是否自动吸顶
+		saveInterval: 0,
+		charCounterCount: false,
+		events:{
+			'xhr.beforeSend': function (xhr) {
+				console.log(xhr);
+				xhr.setRequestHeader('Authorization', sessionStorage.getItem('token')||''); // 替换为你的 Token
+			},
+			// 内容变化事件
+			contentChanged:function (){
+				frolaEditorContentChange.value=true
+				getSelection().rangeCount&&(lastFocusPosition.value=getSelection().getRangeAt(0))
+			},
+			keyup:function(e,editor){
+				nextTick(()=>{
+					getSelection().rangeCount&&(lastFocusPosition.value=getSelection().getRangeAt(0))
+				})
+			},
+			click:function(e,editor){
+				nextTick(()=>{
+					getSelection().rangeCount&&(lastFocusPosition.value=getSelection().getRangeAt(0))
+				})
+			},
+			'image.beforePasteUpload':function(){
+				imgUploadFlag.value=false
+			},
+			'image.beforeUpload':function(){
+				imgUploadFlag.value=false
+			},
+			'image.inserted':function(){
+				imgUploadFlag.value=true
+			},
+			'image.error':function(){
+				imgUploadFlag.value=true
+			},
+		}
+	};
+
+	/**
+	 * 初始化编辑器
+	 * @param  el domid
+	 * @param  opts 配置项
+	 * 由于要获取到富文本实例 要在new FroalaEditor(el,opt,callback)的callback中才能获取到
+	 * 方案一返回一个promise
+	 * 方案二直接返回富文本实例 无法在调用initFroalaEditor方法后立即执行实例上的一些方法或者读取属性
+	 * 一般写个settimeout 可以解决
+	 */
+	const initFroalaEditor = (el,opts) => {
+		// 方案一
+		// let ins=null
+		// return new Promise((resolve,reject)=>{
+		// 	options.height=opts?.height??500
+		// 	console.log(options);
+		// 	ins=new FroalaEditor(el, options,()=>{
+		// 		// console.log(ins);
+		// 		resolve(ins)
+		// 	})
+		// })
+
+		// 方案二
+		options={...options,...opts}
+		// options.height=options.height<350?350:options.height
+		console.log(options);
+		return new FroalaEditor(el, options);
+	};
+
+	return {
+		lastFocusPosition,
+		frolaEditorContentChange,
+		imgUploadFlag,
+		initFroalaEditor,
+	}
+}

+ 34 - 0
src/router/modules/system.js

@@ -36,5 +36,39 @@ export default[
         },
       },
     ]
+  },
+  {
+    path:'/system',
+    name:'System',
+    component:LayoutIndex,
+    meta:{
+      title:'系统设置'
+    },
+    children:[
+      {
+        path:'helpCenter',
+        name:'SystemHelpCenter',
+        component:()=>import('@/views/system/helpCenter/Index.vue'),
+        meta:{
+          title:'帮助中心配置'
+        },
+      },
+      {
+        path:'helpCenter/addDoc',
+        name:'SystemHelpCenterAddDoc',
+        component:()=>import('@/views/system/helpCenter/AddDocment.vue'),
+        meta:{
+          title:'添加文章'
+        },
+      },
+      {
+        path:'helpCenter/detail',
+        name:'SystemHelpCenterDetail',
+        component:()=>import('@/views/system/helpCenter/DocmentDetail.vue'),
+        meta:{
+          title:'查看文章'
+        },
+      },
+    ]
   }
 ]

+ 7 - 1
src/styles/common.scss

@@ -72,4 +72,10 @@ ul li{
 	-webkit-line-clamp: 3;
 	line-break: anywhere;
 	-webkit-box-orient: vertical;
-}
+}
+
+// froala样式
+.fr-second-toolbar {
+    display: none !important;
+}
+a[href="https://froala.com/wysiwyg-editor"], a[href="https://www.froala.com/wysiwyg-editor?k=u"]{ border:1px solid #eaeaea; background:#fff !important; color:#ccc !important; }

+ 2 - 2
src/styles/tdesign.scss

@@ -1,8 +1,8 @@
 // 重写tdesign样式模块
 
 .t-dialog{
-  padding: 0;
-  border: none;
+  padding: 0 !important;
+  border: none !important;
   overflow: hidden;
   .t-dialog__header{
     padding: var(--td-comp-paddingTB-l);

+ 1 - 1
src/views/etaChart/components/ChartWrap.vue

@@ -145,7 +145,7 @@ function handleGoEdbSource(data) {
       </div>
       <div class="table-wrap">
         <t-table
-          row-key="ChartInfoId"
+          row-key="EdbInfoId"
           :data="tableData"
           :columns="columns"
           bordered

+ 97 - 170
src/views/etaChart/components/ClassifyWrap.vue

@@ -1,10 +1,8 @@
 <script setup>
-import { computed, reactive, ref, watch } from 'vue'
+import { computed, reactive, ref, useTemplateRef, watch } from 'vue'
 import { SearchIcon, Icon } from 'tdesign-icons-vue-next';
 import { apiETAChart } from '@/api/etaChart'
 import { apiSystemCommon } from '@/api/system'
-import { ElTree } from 'element-plus'
-import 'element-plus/es/components/tree/style/css'
 import { useClassify } from '../hooks/useClassify'
 import MoveClassify from './MoveClassify.vue'
 
@@ -83,8 +81,8 @@ function handleSelectChart(value, context) {
 //分类列表
 const classifyTreeKeys = {
   label: 'ChartClassifyName',
+  value: 'ChartClassifyId',
   children: 'Children',
-  isLeaf: 'isLeaf'
 }
 const { classifyActived } = useClassify()//当前选中的分类
 const classifyList = ref([])
@@ -98,45 +96,44 @@ async function getClassify() {
     classifyList.value = arr.map(item => {
       return {
         ...item,
-        Children: null
+        draggable:item.ChartClassifyId===0?false:true,//未分类不允许拖动
+        Children: true
       }
     })
   }
 }
 getClassify()
 // 懒加载分类
-async function classifyLoad(node, resolve) {
-  if (node.level === 0) {
-    resolve(classifyList.value)
-  } else {
-    let nodes = []
-    const res = await apiETAChart.classifyList({
-      ParentId: node.data.ChartClassifyId,
-      SysUserIds: userVal.value?.join(',')
+async function classifyLoad(node) {
+  let nodes = []
+  const res = await apiETAChart.classifyList({
+    ParentId: node.data.ChartClassifyId,
+    SysUserIds: userVal.value?.join(',')
+  })
+  if (res.Ret === 200) {
+    const arr = res.Data.AllNodes || []
+    nodes = arr.map(item => {
+      return {
+        ...item,
+        Children: item.ChartInfoId !== 0 ?false:true,
+        ChartClassifyId: item.ChartInfoId ? item.UniqueCode : item.ChartClassifyId,//如果是指标则将分类id设置为图表id
+      }
     })
-    if (res.Ret === 200) {
-      const arr = res.Data.AllNodes || []
-      nodes = arr.map(item => {
-        return {
-          ...item,
-          isLeaf: item.ChartInfoId !== 0 ? true : false,
-          ChartClassifyId: item.ChartInfoId ? item.UniqueCode : item.ChartClassifyId,//如果是指标则将分类id设置为图表id
-        }
-      })
-    }
-    resolve(nodes);
   }
+  return nodes
 }
-function handleClassifyActiveChange(data, node) {
-  classifyActived.value = data.ChartClassifyId
-  if (data.ChartInfoId) {//选择的是图表
-    emits('change', data)
+// 点击分类或者指标
+function handleClassifyActiveChange({node}) {
+  if(classifyActived.value === node.data.ChartClassifyId) return
+  classifyActived.value = node.data.ChartClassifyId
+  if (node.data.ChartInfoId) {//选择的是图表
+    emits('change', node.data)
   } else {
     emits('filter')
   }
 }
 // 控制分类操作按钮显示
-function showClassifyOpt(node, data) {
+function showClassifyOpt(data) {
   return (classifyActived.value === data.ChartClassifyId) && data.ChartClassifyId !== 0 && data.ChartInfoId === 0
 }
 
@@ -179,26 +176,23 @@ async function handleConfirmClassify() {
 
 
 }
-// 递归获取父节点
-function getAllParent(data, arr) {
-  if (data.level === 0) return
-  arr.push({ ChartClassifyName: data.data.ChartClassifyName, ChartClassifyId: data.data.ChartClassifyId })
-  getAllParent(data.parent, arr)
-  return arr
-}
-function handleClassifyOpt(node, data, type) {
+function handleClassifyOpt(node, type) {
+  const data=node.data
   if (type === 'edit') {
     classifyEditState.id = data.ChartClassifyId
     classifyEditState.name = data.ChartClassifyName
-    let parr = getAllParent(node, [])
-    parr.shift()
-    classifyEditState.parent = parr.reverse()
-    classifyEditState.parentId = node.parent.id || 0
+    let parr = node.getParents()
+    classifyEditState.parent =parr.map(item=>{
+      return item.data
+    }).reverse()
+    classifyEditState.parentId = node.getParent()?.value || 0
     showEditClassify.value = true
   }
   if (type === 'add') {
-    let parr = getAllParent(node, [])
-    classifyEditState.parent = parr.reverse()
+    let parr = node.getPath()
+    classifyEditState.parent =parr.map(item=>{
+      return item.data
+    })
     classifyEditState.parentId = data.ChartClassifyId
     showEditClassify.value = true
   }
@@ -217,21 +211,7 @@ function handleClassifyOpt(node, data, type) {
 
 
 const defaultShowNodes = ref([])//当前展开的数据
-function handleNodeExpand(data) {
-  // 保存当前展开的节点
-  let flag = defaultShowNodes.value.some((item) => item === data.ChartClassifyId);
-  if (!flag) { // 不存在则存到数组里
-    defaultShowNodes.value.push(data.ChartClassifyId)
-  }
-}
-function handleNodeCollapse(data) {
-  defaultShowNodes.value.some((item, index) => {
-    if (item === data.ChartClassifyId) {
-      // 删除关闭节点
-      defaultShowNodes.value.length = index
-    }
-  })
-}
+
 // 有筛选条件时不允许拖动排序
 const canDragSort = computed(() => {
   if (userVal.value.length>0) return false
@@ -241,52 +221,39 @@ function allowDrag({ data }) {
   if (data.ChartClassifyId === 0) return false //未分类不允许拖动
   return true
 }
-function allowDrop(draggingNode, dropNode, type) {
+// 判断节点是否可以执行 drop 操作 dropPosition -1放在dropNode前面 0里面 1后面
+function allowDrop({dragNode, dropNode, dropPosition}) {
   let canDrop = false
   // 如果拖动的是指标
-  if (draggingNode.data.ChartInfoId) {
-    if (!(dropNode.level === 1 && type !== 'inner')) {
+  if (dragNode.data.ChartInfoId) {
+    if (!(dropNode.getLevel() === 0 && dropPosition !== 0)) {
       canDrop = true
     }
   } else {//拖动的是目录
-    // console.log(dropNode.level,draggingNode.level);
+    // console.log(dropNode.level,dragNode.level);
     //目录层级不能改变
-    if ((dropNode.level + 1 == draggingNode.level && type === 'inner' && !dropNode.data.ChartInfoId) || (dropNode.level === draggingNode.level && type !== 'inner')) {
+    if ((dropNode.getLevel() + 1 == dragNode.getLevel() && dropPosition === 0 && !dropNode.data.ChartInfoId) || (dropNode.getLevel() === dragNode.getLevel() && dropPosition !== 0)) {
       canDrop = true
     }
   }
   return canDrop
 }
-function handleDropOver(b, a, i, e) {
+function handleDropOver({dragNode,dropNode,dropPosition}) {
   // 被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置
-  console.log(b, a, i);
-  const isEDB = b.data.ChartInfoId ? true : false
-  let list = a.parent.childNodes;
+  // console.log(dragNode,dropNode,dropPosition);
+  
+  const isEDB = dragNode.data.ChartInfoId ? true : false
+  let list = dragNode.getSiblings();
   let targetIndex = 0, PrevClassifyId = 0, NextClassifyId = 0, ParentClassifyId = 0;
   let ClassifyId = 0, ChartInfoId = 0, PrevChartInfoId = 0, NextChartInfoId = 0;
 
-  ClassifyId = isEDB ? 0 : b.data.ChartClassifyId
-  ChartInfoId = isEDB ? b.data.ChartInfoId : 0
-
-
-  if (i !== 'inner') {
-    ParentClassifyId = a.parent.data.ChartClassifyId || 0
-    list.forEach((item, index) => {
-      if (isEDB) {
-        if (item.data.ChartInfoId === b.data.ChartInfoId) {
-          targetIndex = index
-        }
-      } else {
-        if (item.data.ChartClassifyId === b.data.ChartClassifyId) {
-          targetIndex = index
-        }
-      }
-
-    })
-
-    console.log(targetIndex);
+  ClassifyId = isEDB ? 0 : dragNode.data.ChartClassifyId
+  ChartInfoId = isEDB ? dragNode.data.ChartInfoId : 0
 
 
+  if (dropPosition !== 0) {
+    ParentClassifyId = dragNode.getParent()?.value || 0
+    targetIndex=dragNode.getIndex()
     if (targetIndex === 0) {
       const data = list[targetIndex + 1].data
       NextClassifyId = data.ChartInfoId ? 0 : data.ChartClassifyId
@@ -306,7 +273,7 @@ function handleDropOver(b, a, i, e) {
       NextChartInfoId = nData.ChartInfoId ? nData.ChartInfoId : 0
     }
   } else {
-    ParentClassifyId = a.data.ChartClassifyId || 0
+    ParentClassifyId = dropNode.data.ChartClassifyId || 0
   }
 
   const params = {
@@ -318,7 +285,7 @@ function handleDropOver(b, a, i, e) {
     PrevChartInfoId,
     NextChartInfoId
   }
-  console.log(params);
+  // console.log(params);
   apiETAChart.classifySort(params).then(res => {
     if (res.Ret === 200) {
       MessagePlugin.success('移动成功!')
@@ -363,92 +330,48 @@ const showBatchMove = ref(false)
       </template>
     </t-select>
     <div class="classify-list-box">
-      <el-tree
-        :data="classifyList"
-        :props="classifyTreeKeys"
-        :current-node-key="classifyActived"
-        :default-expanded-keys="defaultShowNodes"
-        @node-expand="handleNodeExpand"
-        @node-collapse="handleNodeCollapse"
-        :draggable="canDragSort"
-        check-on-click-node
-        :expand-on-click-node="false"
-        node-key="ChartClassifyId"
-        check-strictly
-        highlight-current
-        empty-text="暂无目录"
-        lazy
-        icon="span"
-        @current-change="handleClassifyActiveChange"
-        :load="classifyLoad"
-        :allow-drop="allowDrop"
-        :allow-drag="allowDrag"
-        @node-drop="handleDropOver"
-      >
-        <template #default="{ node, data }">
-          <div class="classify-item-box">
-            <div class="label">{{ node.label }}</div>
-            <div class="opt-box" v-show="showClassifyOpt(node, data)">
-              <span v-if="canDragSort">
-                <t-icon name="drag-move" />
-              </span>
-              <span v-if="node.level<6" @click.stop="handleClassifyOpt(node, data, 'add')">
-                <t-icon name="add" />
-              </span>
-              <span @click.stop="handleClassifyOpt(node, data, 'edit')">
-                <t-icon name="edit-2" />
-              </span>
-              <span @click.stop="handleClassifyOpt(node, data, 'del')">
-                <t-icon name="close" />
-              </span>
-            </div>
-          </div>
-        </template>
-      </el-tree>
-
-      <!-- <t-tree
-        v-model:actived="classifyActived"
+      <t-tree
+        v-model:expanded="defaultShowNodes"
+        :defaultExpanded="defaultShowNodes"
+        :actived="[classifyActived]"
         :data="classifyList"
         activable
         transition
-        draggable
-        :load="classifyLoad"
-        value-mode="all"
+        expandParent
+        :draggable="canDragSort"
+        value-mode="onlyLeaf"
         :keys="classifyTreeKeys"
         check-strictly
-        :onDragOver="canDrag"
-        @drop="handleClassifyDrop"
+        :allow-drop="allowDrop"
+        :load="classifyLoad"
+        empty="暂无目录"
+        @click="handleClassifyActiveChange"
+        @drop="handleDropOver"
       >
         <template #icon="{ node }">
+          <!-- 指标无展开收起按钮 -->
           <t-icon
-            name="add-rectangle"
-            v-if="node.getChildren() && !node.expanded"
-          />
-          <t-icon
-            name="minus-rectangle"
-            v-if="node.getChildren() && node.expanded"
+            :name="node.expanded?'minus-rectangle':'add-rectangle'"
+            v-if="node.data.ChartInfoId === 0"
           />
         </template>
-        <template #label="{ node }">
-          <div class="classify-item-box">
-            <div class="label">{{ node.label }}</div>
-            <div class="opt-box" v-show="showClassifyOpt(node)">
-              <span>
-                <t-icon name="drag-move" />
-              </span>
-              <span @click.stop="handleClassifyOpt(node,'add')" v-if="node.data.Level<6">
-                <t-icon name="add" />
-              </span>
-              <span @click.stop="handleClassifyOpt(node,'edit')">
-                <t-icon name="edit-2" />
-              </span>
-              <span @click.stop="handleClassifyOpt(node,'del')">
-                <t-icon name="close" />
-              </span>
-            </div>
+        <template #operations="{ node }">
+          <div class="opt-box" v-show="showClassifyOpt(node.data)">
+            <span>
+              <t-icon name="drag-move" />
+            </span>
+            <span @click.stop="handleClassifyOpt(node,'add')" v-if="node.getLevel()<5">
+              <t-icon name="add" />
+            </span>
+            <span @click.stop="handleClassifyOpt(node,'edit')">
+              <t-icon name="edit-2" />
+            </span>
+            <span @click.stop="handleClassifyOpt(node,'del')">
+              <t-icon name="close" />
+            </span>
           </div>
         </template>
-      </t-tree> -->
+      </t-tree>
     </div>
     <div class="classify-add-box" @click="showEditClassify = true">
       <t-icon name="add-rectangle" />
@@ -546,6 +469,16 @@ const showBatchMove = ref(false)
     padding-top: 10px;
     height: calc(100vh - 340px);
     overflow-y: auto;
+    :deep(.t-is-active){
+      background-color: var(--td-brand-color-light);
+    }
+    .opt-box {
+      display: flex;
+      gap: 0 5px;
+      .t-icon {
+        color: var(--td-brand-color);
+      }
+    }
     .classify-item-box {
       flex: 1;
       display: flex;
@@ -554,13 +487,7 @@ const showBatchMove = ref(false)
       .label {
         flex: 1;
       }
-      .opt-box {
-        display: flex;
-        gap: 0 5px;
-        .t-icon {
-          color: var(--td-brand-color);
-        }
-      }
+      
     }
   }
   .classify-add-box {

+ 341 - 0
src/views/system/helpCenter/AddDocment.vue

@@ -0,0 +1,341 @@
+<script setup>
+import { apiSystemHelpCenter } from '@/api/system'
+import { useInitFroalaEditor } from '@/hooks/useFroalaEditor'
+import { useTemplateRef } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+
+const { lastFocusPosition, initFroalaEditor, frolaEditorContentChange } = useInitFroalaEditor()
+const router=useRouter()
+const route=useRoute()
+
+let reportContentEditorIns = null//报告内容编辑器实例
+
+// 锚点数据
+let anchorData = []
+// 搜索标题标签h1,h2
+function searchTitleTag(searchPosition, firstLevel) {
+  let htmlContent=reportContentEditorIns.html.get(true)
+  console.log(htmlContent);
+
+  let frontH1Posiiton, nextH1Posiiton, H2Posiiton = 0
+  let frontH1RightPosiiton, H2RightPosiiton = 0
+  let backH1Posiiton, backH2Posiiton = 0
+  // 本次搜索第一个h1的位置
+  frontH1Posiiton = htmlContent.indexOf('<h1', searchPosition)
+  // 右闭合标签
+  frontH1RightPosiiton = htmlContent.indexOf('>', frontH1Posiiton)
+
+  if (frontH1Posiiton == -1) return
+
+  let anchorText = `id="doc_anchor_${firstLevel}"`
+  // console.log(frontH1Posiiton,firstLevel,'firstLevel');
+  htmlContent = htmlContent.substring(0, frontH1Posiiton + 3)
+    + " " + anchorText + htmlContent.substring(frontH1RightPosiiton);
+  // 再次获取右闭合标签
+  frontH1RightPosiiton = htmlContent.indexOf('>', frontH1Posiiton)
+  // 对应的</h1>的位置 原本用的</h1>,后来发现> 和 </h1>之间会掺其他标签
+  backH1Posiiton = htmlContent.indexOf('<', frontH1RightPosiiton)
+  // 获取标题
+  let AnchorTitle = htmlContent.substring(frontH1RightPosiiton + 1, backH1Posiiton)
+
+  anchorData.push({
+    AnchorId: `${firstLevel}`,
+    Anchor: `doc_anchor_${firstLevel}`,
+    AnchorName: AnchorTitle,
+    Child: []
+  })
+  // 本次搜索下一个h1的位置
+  nextH1Posiiton = htmlContent.indexOf('<h1', backH1Posiiton) == -1 ?
+    htmlContent.length : htmlContent.indexOf('<h1', backH1Posiiton)
+  // 从第一个h1的位置开始查找h2标签
+  H2Posiiton = htmlContent.indexOf('<h2', backH1Posiiton)
+
+  let secondLevel = 1
+  while (!(H2Posiiton == -1 || H2Posiiton > nextH1Posiiton)) {
+    // 右闭合标签
+    H2RightPosiiton = htmlContent.indexOf('>', H2Posiiton)
+
+    // 找到了,并且位置小于下一个h1的位置 
+    let anchorTextH2 = `id="doc_anchor_${firstLevel}_${secondLevel}"`
+    // console.log(H2Posiiton,secondLevel,'secondLevel');
+    htmlContent = htmlContent.substring(0, H2Posiiton + 3)
+      + " " + anchorTextH2 + htmlContent.substring(H2RightPosiiton);
+    // 再次获取右闭合标签
+    H2RightPosiiton = htmlContent.indexOf('>', H2Posiiton)
+    // 对应的</h2>的位置  原本用的</h2>,后来发现> 和 </h2>之间会掺其他标签
+    backH2Posiiton = htmlContent.indexOf('<', H2RightPosiiton)
+    // 获取标题
+    let AnchorTitleLevelTwo = htmlContent.substring(H2RightPosiiton + 1, backH2Posiiton)
+    anchorData[firstLevel - 1].Child.push(
+      {
+        AnchorId: `${firstLevel}_${secondLevel}`,
+        Anchor: `doc_anchor_${firstLevel}_${secondLevel}`,
+        AnchorName: AnchorTitleLevelTwo,
+        Child: []
+      })
+    // nextH1Posiiton 和 secondLevel 随之增加
+    // nextH1Posiiton +=anchorTextH2.length+1
+    // 更新nextH1Posiiton位置
+    nextH1Posiiton = htmlContent.indexOf('<h1', backH1Posiiton) == -1 ?
+      htmlContent.length : htmlContent.indexOf('<h1', backH1Posiiton)
+    secondLevel++
+    H2Posiiton = htmlContent.indexOf('<h2', backH2Posiiton)
+  }
+  // 结束一轮 <h1></h1>标签的寻找
+  if (htmlContent.indexOf('<h1', backH1Posiiton + 4) != -1) {
+    // 如果有下一个h1的标签,说明寻找还没结束,继续寻找
+    firstLevel++
+    searchTitleTag(nextH1Posiiton, firstLevel)
+  }
+}
+// 生成锚点
+function generateAnchor() {
+  anchorData = []
+  // 搜索富文本中的h1和h2标签 当做一级和二级的锚点
+  searchTitleTag(0, 1)
+}
+
+const classifyOpts = ref([])
+async function getClassify() {
+  const res = await apiSystemHelpCenter.classifyList()
+  if (res.Ret !== 200) return
+  classifyOpts.value = res.Data.AllNodes || []
+}
+getClassify()
+
+const btnLoading = ref(false)
+const modifyTime=ref('')
+const FORM_RULES = {
+  title: [{ required: true, message: '文章标题不能为空' }],
+  classifyId: [{ required: true, message: '文章所属分类不能为空' }],
+  author: [{ required: true, message: '文章作者不能为空' }],
+};
+const formIns = useTemplateRef('formIns')
+const formData = reactive({
+  title: '',
+  classifyId: '',
+  author: '',
+  Status: 1,
+  AnchorData: [],
+  RecommendData: [{ Name: "", Url: "" }, { Name: "", Url: "" }]
+})
+
+let autoSaveTimer=null//自动保存定时器
+async function handleSaveDocument(type, isAuto) {
+  if (btnLoading.value) return
+  const validRes = await formIns.value.validate()
+  if (validRes !== true) return
+  const htmlContent = reportContentEditorIns.html.get(true)
+  if (!htmlContent) {
+    MessagePlugin.warning('文章内容不能为空')
+    return
+  }
+  if (!isAuto) {
+    btnLoading.value = true
+  }
+  if (type === '发布') {
+    formData.Status = 2
+  }
+  generateAnchor()
+  console.log(anchorData);
+  formData.AnchorData=anchorData
+  const res=await apiSystemHelpCenter.addDocment({
+    IsChange:frolaEditorContentChange.value,
+    Title:formData.title,
+    ClassifyId:formData.classifyId,
+    Author:formData.author,
+    Status:formData.Status,
+    Content:htmlContent,
+    AnchorData:formData.AnchorData,
+    RecommendData:formData.RecommendData,
+    Id:route.query.DocId?Number(route.query.DocId):0
+  })
+  if(res.Ret!==200) return
+  frolaEditorContentChange.value=false
+  if(!isAuto){
+    MessagePlugin.success('操作成功')
+  }
+  if(type==='发布'){
+    setTimeout(() => {
+      router.back()
+    }, 1000);
+  }else{
+    btnLoading.value=false
+    modifyTime.value=res.Data.ModifyTime
+    if(!route.query.DocId){
+      //新增
+      setTimeout(()=>{
+        router.replace("/system/helpCenter/addDoc?DocId="+res.Data.HelpDocId)
+        if(!autoSaveTimer){
+          autoSaveTimer=setInterval(()=>{
+            handleSaveDocument('保存',true)
+          },6000)
+        }
+      },1000)
+    }
+  }
+}
+
+//预览
+function handlePreviewDoc(){
+  if(btnLoading.value) return
+  const htmlContent = reportContentEditorIns.html.get(true)
+  if (!htmlContent) {
+    MessagePlugin.warning('文章内容不能为空')
+    return
+  }
+  sessionStorage.setItem("documentDocContent",htmlContent)
+  sessionStorage.setItem("Recommend",JSON.stringify(formData.RecommendData))
+  let { href } = router.resolve({ path: "/system/helpCenter/detail" });
+  window.open(href, "_blank");
+}
+
+
+// 获取文章详情
+async function handleGetDocmentInfo(){
+  const res=await apiSystemHelpCenter.docmentInfo({
+    DocId:Number(route.query.DocId)
+  })
+  if(res.Ret!==200) return
+  formData.title=res.Data.Title
+  formData.classifyId=res.Data.ClassifyId
+  formData.author=res.Data.Author
+  formData.Status=res.Data.Status
+  formData.RecommendData=res.Data.Recommend || [{Name:"",Url:""},{Name:"",Url:""}]
+  reportContentEditorIns.html.set(res.Data.Content)
+  modifyTime.value=res.Data.ModifyTime
+  if(!autoSaveTimer){
+    autoSaveTimer=setInterval(()=>{
+      handleSaveDocument('保存',true)
+    },6000)
+  }
+}
+
+onMounted(() => {
+  const el = document.getElementById('editor')
+  reportContentEditorIns = initFroalaEditor('#editor', { height: el.offsetHeight - 80 })
+  if(route.query.DocId){
+    handleGetDocmentInfo()
+  }
+})
+
+
+</script>
+
+<template>
+  <div class="flex add-docment-page">
+    <div class="bg-white left-content-wrap" id="editor"></div>
+    <div class="bg-white right-wrap">
+      <div class="flex top-btn-box">
+        <t-button theme="primary" :loading="btnLoading" @click="handlePreviewDoc">预览</t-button>
+        <t-button
+          theme="primary"
+          :loading="btnLoading"
+          @click="handleSaveDocument('保存')"
+          >保存</t-button
+        >
+        <t-button
+          theme="primary"
+          :loading="btnLoading"
+          @click="handleSaveDocument('发布')"
+          >发布</t-button
+        >
+      </div>
+      <t-form
+        ref="formIns"
+        :rules="FORM_RULES"
+        :data="formData"
+        :colon="false"
+        labelAlign="top"
+      >
+        <t-form-item label="文章标题" name="title">
+          <t-input
+            v-model="formData.title"
+            placeholder="请输入文章标题"
+          ></t-input>
+        </t-form-item>
+        <t-form-item label="所属分类" name="classifyId">
+          <t-cascader
+            v-model="formData.classifyId"
+            :options="classifyOpts"
+            :keys="{
+              value: 'ClassifyId',
+              label: 'ClassifyName',
+              children: 'Children',
+            }"
+            clearable
+            placeholder="所属分类"
+          />
+        </t-form-item>
+        <t-form-item label="文章作者" name="author">
+          <t-input
+            v-model="formData.author"
+            placeholder="请输入文章作者"
+          ></t-input>
+        </t-form-item>
+        <t-form-item label="相关推荐" name="RecommendData">
+          <div style="width: 100%">
+            <div
+              v-for="(item, index) in formData.RecommendData"
+              :key="index"
+              class="form-item-recommendedLink"
+            >
+              <t-input
+                v-model="item.Name"
+                placeholder="请输入链接名称"
+                style="width: 190px"
+              ></t-input>
+              <div class="recommendedLink-line"></div>
+              <t-input
+                v-model="item.Url"
+                placeholder="请输入链接"
+                style="width: 190px"
+              ></t-input>
+            </div>
+          </div>
+        </t-form-item>
+      </t-form>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.add-docment-page {
+  gap: 0 20px;
+  .left-content-wrap {
+    flex: 1;
+    height: calc(100vh - 130px);
+  }
+  .right-wrap {
+    width: 440px;
+    flex-shrink: 0;
+    border: 1px solid var(--border-color);
+    .top-btn-box {
+      padding: 20px;
+      gap: 20px;
+      box-shadow: 0 5px 10px #ececec;
+      .t-button {
+        flex: 1;
+      }
+    }
+    .t-form {
+      padding: 20px;
+      .form-item-recommendedLink {
+        display: flex;
+        align-items: center;
+        justify-content: flex-start;
+        width: 100%;
+        margin-bottom: 20px;
+        &:last-child {
+          margin-bottom: 0;
+        }
+        .recommendedLink-line {
+          flex: 1;
+          height: 1px;
+          background-color: #dcdfe6;
+        }
+      }
+    }
+  }
+}
+</style>

+ 49 - 0
src/views/system/helpCenter/DocmentDetail.vue

@@ -0,0 +1,49 @@
+<script setup>
+import { useRoute } from "vue-router";
+import {apiSystemHelpCenter} from '@/api/system'
+
+function createBottomHref(RecommendData){
+  let hrefStringBuiler='<ul style="margin-top:40px">'
+  RecommendData.map(item =>{
+    if(item.Name){
+      hrefStringBuiler+=`<li><a href="${item.Url}" target="_blank" style="text-decoration: underline;">${item.Name}</a></li>`
+    }
+  })
+  return hrefStringBuiler+"</ul>"
+}
+
+const route=useRoute()
+
+const content=ref('')
+async function getDocmentDetail(){
+  if(route.query.DocId){
+    const res=await apiSystemHelpCenter.docmentInfo({
+      DocId:Number(route.query.DocId)
+    })
+    if(res.Ret!==200) return
+    content.value=res.Data.Content + createBottomHref(res.Data.Recommend || [{Name:"",Url:""},{Name:"",Url:""}])
+  }else{
+    const Recommend=sessionStorage.getItem("Recommend")?JSON.parse(sessionStorage.getItem("Recommend")):''
+    content.value = sessionStorage.getItem("documentDocContent") +createBottomHref(Recommend || [{Name:"",Url:""},{Name:"",Url:""}])
+  }
+}
+
+getDocmentDetail()
+
+</script>
+
+<template>
+  <div class="assistance-detail-container">
+    <div class="assistance-detail-box fr-view" v-html="content"></div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.assistance-detail-container{
+  background-color: white;
+  min-height: calc(100vh - 180px);
+  padding: 20px;
+  box-sizing: border-box;
+  border: solid 1px #ECECEC;
+}
+</style>

+ 154 - 0
src/views/system/helpCenter/Index.vue

@@ -0,0 +1,154 @@
+<script setup>
+import { SearchIcon } from 'tdesign-icons-vue-next';
+import {apiSystemHelpCenter} from '@/api/system'
+
+const keyword=ref('')
+
+// 分类
+const classifyValue=ref('')
+const classifyOpts=ref([])
+async function getClassify(){
+  const res=await apiSystemHelpCenter.classifyList()
+  if(res.Ret!==200) return
+  classifyOpts.value=res.Data.AllNodes||[]
+}
+getClassify()
+
+// 获取列表
+const tableData = ref([])
+const columns = [
+  { align: 'center', colKey: 'Title', title: '文章标题' },
+  { align: 'center', colKey: 'ClassifyName', title: '所属分类' },
+  { align: 'center', colKey: 'Author', title: '文章作者' },
+  { align: 'center', colKey: 'Status', title: '发布状态' },
+  { align: 'center', colKey: 'CreateTime', title: '创建时间' },
+  { align: 'center', colKey: 'ModifyTime', title: '更新时间'},
+  {
+    align: 'center',
+    colKey: 'opt',
+    title: '操作',
+  },
+]
+const tablePagination = ref({
+  current: 1,
+  pageSize: 20,
+  total: 0,
+  showPageSize:false
+})
+async function getList(){
+  const res=await apiSystemHelpCenter.getDocmentList({
+    PageSize:tablePagination.pageSize,
+    CurrentIndex:tablePagination.current,
+    ClassifyIds:classifyValue.value?classifyValue.value.join(','):'',
+    KeyWord:keyword.value,
+  })
+  if(res.Ret!==200) return
+  tableData.value=res.Data.List||[]
+  tablePagination.value.total=res.Data.Paging.Totals
+}
+getList()
+function handlePageChange(e){
+  tablePagination.value.current=e.current
+  getList()
+}
+function handleRefreshList(){
+  tablePagination.value.current=1
+  tableData.value=[]
+  getList()
+}
+
+// 删除文章
+async function handleDelDoc(row){
+  await $confirmDialog({
+    body:'删除后不可恢复,是否确认删除?',
+  })
+  const res=await apiSystemHelpCenter.deleteDocment({
+    DocId:row.Id
+  })
+  if(res.Ret!==200) return
+  MessagePlugin.success('删除成功')
+  handleRefreshList()
+}
+
+//发布状态变更
+async function handleDocPublishChange(row){
+  await $confirmDialog({
+    body:`是否确认${row.Status==2?'取消发布':'发布'}?`
+  })
+  const res=await apiSystemHelpCenter.publishDocment({
+    DocId:row.Id,
+    Status:3-row.Status
+  })
+  if(res.Ret!==200) return
+  MessagePlugin.success(`${row.Status==2?'取消发布':'发布'}成功`)
+  handleRefreshList()
+}
+
+</script>
+
+<template>
+  <div class="bg-white help-center-page">
+    <div class="flex top-wrap">
+      <t-button theme="primary" @click="$router.push('/system/helpCenter/addDoc')">添加文章</t-button>
+      <t-button theme="primary">分类管理</t-button>
+      <t-cascader 
+        v-model="classifyValue" 
+        :options="classifyOpts"
+        :keys="{
+          value:'ClassifyId',
+          label:'ClassifyName',
+          children:'Children'
+        }" 
+        :showAllLevels="false"
+        multiple 
+        clearable
+        :minCollapsedNum="1"
+        placeholder="所属分类"
+        @change="handleRefreshList"
+        style="width:200px;margin-left:auto"
+      />
+      <t-input
+        style="width: 310px;"
+        placeholder="文章标题"
+        v-model="keyword"
+        clearable
+        @change="handleRefreshList"
+      >
+        <template #prefixIcon><SearchIcon /></template>
+      </t-input>
+    </div>
+    <t-table
+      rowKey="UserId"
+      :data="tableData"
+      :columns="columns"
+      bordered
+      :pagination="tablePagination"
+      show-header
+      resizable
+      @page-change="handlePageChange"
+    >
+      <template #Title="{row}">
+        <t-link theme="primary" @click="$router.push({path:'/system/helpCenter/detail',query:{DocId:row.Id}})">{{row.Title}}</t-link>
+      </template>
+      <template #Status="{row}">
+        <t-button variant="text" :theme="row.Status==2?'success':'danger'">{{row.Status==2?"已发布":"未发布"}}</t-button>
+      </template>
+      <template #opt="{ row }">
+        <t-button size="small" variant="text" theme="primary" @click="$router.push({path:'/system/helpCenter/addDoc',query:{DocId:row.Id}})" v-if="row.Status==1">编辑</t-button>
+        <t-button size="small" variant="text" theme="primary" @click="handleDocPublishChange(row)" v-if="row.Status==1">发布</t-button>
+        <t-button size="small" variant="text" theme="primary" @click="handleDocPublishChange(row)" v-if="row.Status==2">取消发布</t-button>
+        <t-button size="small" variant="text" theme="danger" @click="handleDelDoc(row)">删除</t-button>
+      </template>
+    </t-table>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.help-center-page{
+  padding: 20px;
+  .top-wrap{
+    gap: 20px;
+    margin-bottom: 20px;
+  }
+}
+</style>

+ 2 - 2
vite.config.js

@@ -93,8 +93,8 @@ export default defineConfig(({ mode }) => {
       proxy:{
         '/v1': {
           // target: 'http://192.168.20.10:8912/v1',
-          // target: 'http://8.136.199.33:8900/v1',
-          target: 'http://8.136.199.33:7777/adminapi/',
+          target: 'http://8.136.199.33:8900/v1',
+          // target: 'http://8.136.199.33:7777/adminapi/',
           changeOrigin: true,
           rewrite: (path) => path.replace(/^\/v1/, ''),
         }

Some files were not shown because too many files changed in this diff